diff --git a/CREDITS b/CREDITS index 0bf31eac6dc2..787564bc248b 100644 --- a/CREDITS +++ b/CREDITS @@ -3382,7 +3382,7 @@ S: Germany N: Geert Uytterhoeven E: geert@linux-m68k.org -W: http://home.tvd.be/cr26864/ +W: http://users.telenet.be/geertu/ P: 1024/862678A6 C51D 361C 0BD1 4C90 B275 C553 6EEA 11BA 8626 78A6 D: m68k/Amiga and PPC/CHRP Longtrail coordinator D: Frame buffer device and XF68_FBDev maintainer @@ -3392,8 +3392,8 @@ D: Amiga Buddha and Catweasel chipset IDE D: Atari Falcon chipset IDE D: Amiga Gayle chipset IDE D: mipsel NEC DDB Vrc-5074 -S: Emiel Vlieberghlaan 2A/21 -S: B-3010 Kessel-Lo +S: Haterbeekstraat 55B +S: B-3200 Aarschot S: Belgium N: Chris Vance diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt index 1af0f2d50220..2ffb0d62f0fe 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -33,7 +33,9 @@ pci_alloc_consistent(struct pci_dev *dev, size_t size, Consistent memory is memory for which a write by either the device or the processor can immediately be read by the processor or device -without having to worry about caching effects. +without having to worry about caching effects. (You may however need +to make sure to flush the processor's write buffers before telling +devices to read that memory.) This routine allocates a region of bytes of consistent memory. it also returns a which may be cast to an unsigned @@ -304,12 +306,12 @@ dma address with dma_mapping_error(). A non zero return value means the mapping could not be created and the driver should take appropriate action (eg reduce current DMA mapping usage or delay and try again later). -int -dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -int -pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents, int direction) + int + dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) + int + pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, + int nents, int direction) Maps a scatter gather list from the block layer. @@ -327,12 +329,33 @@ critical that the driver do something, in the case of a block driver aborting the request or even oopsing is better than doing nothing and corrupting the filesystem. -void -dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -void -pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents, int direction) +With scatterlists, you use the resulting mapping like this: + + int i, count = dma_map_sg(dev, sglist, nents, direction); + struct scatterlist *sg; + + for (i = 0, sg = sglist; i < count; i++, sg++) { + hw_address[i] = sg_dma_address(sg); + hw_len[i] = sg_dma_len(sg); + } + +where nents is the number of entries in the sglist. + +The implementation is free to merge several consecutive sglist entries +into one (e.g. with an IOMMU, or if several pages just happen to be +physically contiguous) and returns the actual number of sg entries it +mapped them to. On failure 0, is returned. + +Then you should loop count times (note: this can be less than nents times) +and use sg_dma_address() and sg_dma_len() macros where you previously +accessed sg->address and sg->length as shown above. + + void + dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nhwentries, enum dma_data_direction direction) + void + pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, + int nents, int direction) unmap the previously mapped scatter/gather list. All the parameters must be the same as those and passed in to the scatter/gather mapping diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt index ee4bb73683cd..7c717699032c 100644 --- a/Documentation/DMA-mapping.txt +++ b/Documentation/DMA-mapping.txt @@ -58,11 +58,15 @@ translating each of those pages back to a kernel address using something like __va(). [ EDIT: Update this when we integrate Gerd Knorr's generic code which does this. ] -This rule also means that you may not use kernel image addresses -(ie. items in the kernel's data/text/bss segment, or your driver's) -nor may you use kernel stack addresses for DMA. Both of these items -might be mapped somewhere entirely different than the rest of physical -memory. +This rule also means that you may use neither kernel image addresses +(items in data/text/bss segments), nor module image addresses, nor +stack addresses for DMA. These could all be mapped somewhere entirely +different than the rest of physical memory. Even if those classes of +memory could physically work with DMA, you'd need to ensure the I/O +buffers were cacheline-aligned. Without that, you'd see cacheline +sharing problems (data corruption) on CPUs with DMA-incoherent caches. +(The CPU could write to one word, DMA would write to a different one +in the same cache line, and one of them could be overwritten.) Also, this means that you cannot take the return of a kmap() call and DMA to/from that. This is similar to vmalloc(). @@ -194,7 +198,7 @@ document for how to handle this case. Finally, if your device can only drive the low 24-bits of address during PCI bus mastering you might do something like: - if (pci_set_dma_mask(pdev, 0x00ffffff)) { + if (pci_set_dma_mask(pdev, DMA_24BIT_MASK)) { printk(KERN_WARNING "mydev: 24-bit DMA addressing not available.\n"); goto ignore_this_device; @@ -212,7 +216,7 @@ functions (for example a sound card provides playback and record functions) and the various different functions have _different_ DMA addressing limitations, you may wish to probe each mask and only provide the functionality which the machine can handle. It -is important that the last call to pci_set_dma_mask() be for the +is important that the last call to pci_set_dma_mask() be for the most specific mask. Here is pseudo-code showing how this might be done: @@ -284,6 +288,11 @@ There are two types of DMA mappings: in order to get correct behavior on all platforms. + Also, on some platforms your driver may need to flush CPU write + buffers in much the same way as it needs to flush write buffers + found in PCI bridges (such as by reading a register's value + after writing it). + - Streaming DMA mappings which are usually mapped for one DMA transfer, unmapped right after it (unless you use pci_dma_sync_* below) and for which hardware can optimize for sequential accesses. @@ -303,6 +312,9 @@ There are two types of DMA mappings: Neither type of DMA mapping has alignment restrictions that come from PCI, although some devices may have such restrictions. +Also, systems with caches that aren't DMA-coherent will work better +when the underlying buffers don't share cache lines with other data. + Using Consistent DMA mappings. diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 7d87dd73cbe4..5a2882d275ba 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -2,7 +2,7 @@ # This makefile is used to generate the kernel documentation, # primarily based on in-line comments in various source files. # See Documentation/kernel-doc-nano-HOWTO.txt for instruction in how -# to ducument the SRC - and how to read it. +# to document the SRC - and how to read it. # To add a new book the only step required is to add the book to the # list of DOCBOOKS. diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 8c9c6704e85b..ca02e04a906c 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -322,7 +322,6 @@ X!Earch/i386/kernel/mca.c The Filesystem for Exporting Kernel Objects !Efs/sysfs/file.c -!Efs/sysfs/dir.c !Efs/sysfs/symlink.c !Efs/sysfs/bin.c diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl index d260d92089ad..f869b03929db 100644 --- a/Documentation/DocBook/libata.tmpl +++ b/Documentation/DocBook/libata.tmpl @@ -120,14 +120,27 @@ void (*dev_config) (struct ata_port *, struct ata_device *); void (*set_piomode) (struct ata_port *, struct ata_device *); void (*set_dmamode) (struct ata_port *, struct ata_device *); -void (*post_set_mode) (struct ata_port *ap); +void (*post_set_mode) (struct ata_port *); +unsigned int (*mode_filter) (struct ata_port *, struct ata_device *, unsigned int); Hooks called prior to the issue of SET FEATURES - XFER MODE - command. dev->pio_mode is guaranteed to be valid when - ->set_piomode() is called, and dev->dma_mode is guaranteed to be - valid when ->set_dmamode() is called. ->post_set_mode() is + command. The optional ->mode_filter() hook is called when libata + has built a mask of the possible modes. This is passed to the + ->mode_filter() function which should return a mask of valid modes + after filtering those unsuitable due to hardware limits. It is not + valid to use this interface to add modes. + + + dev->pio_mode and dev->dma_mode are guaranteed to be valid when + ->set_piomode() and when ->set_dmamode() is called. The timings for + any other drive sharing the cable will also be valid at this point. + That is the library records the decisions for the modes of each + drive on a channel before it attempts to set any of them. + + + ->post_set_mode() is called unconditionally, after the SET FEATURES - XFER MODE command completes successfully. @@ -230,6 +243,32 @@ void (*dev_select)(struct ata_port *ap, unsigned int device); + Private tuning method + +void (*set_mode) (struct ata_port *ap); + + + + By default libata performs drive and controller tuning in + accordance with the ATA timing rules and also applies blacklists + and cable limits. Some controllers need special handling and have + custom tuning rules, typically raid controllers that use ATA + commands but do not actually do drive timing. + + + + + This hook should not be used to replace the standard controller + tuning logic when a controller has quirks. Replacing the default + tuning logic in that case would bypass handling for drive and + bridge quirks that may be important to data reliability. If a + controller needs to filter the mode selection it should use the + mode_filter hook instead. + + + + + Reset ATA bus void (*phy_reset) (struct ata_port *ap); @@ -666,7 +705,7 @@ and other resources, etc. ata_scsi_error() - ata_scsi_error() is the current hostt->eh_strategy_handler() + ata_scsi_error() is the current transportt->eh_strategy_handler() for libata. As discussed above, this will be entered in two cases - timeout and ATAPI error completion. This function calls low level libata driver's eng_timeout() callback, the diff --git a/Documentation/acpi-hotkey.txt b/Documentation/acpi-hotkey.txt index 744f1aec6553..38040fa37649 100644 --- a/Documentation/acpi-hotkey.txt +++ b/Documentation/acpi-hotkey.txt @@ -30,7 +30,7 @@ specific hotkey(event)) echo "event_num:event_type:event_argument" > /proc/acpi/hotkey/action. The result of the execution of this aml method is -attached to /proc/acpi/hotkey/poll_method, which is dnyamically +attached to /proc/acpi/hotkey/poll_method, which is dynamically created. Please use command "cat /proc/acpi/hotkey/polling_method" to retrieve it. diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 495858b236b6..293fed113dff 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -71,14 +71,6 @@ Who: Mauro Carvalho Chehab --------------------------- -What: remove EXPORT_SYMBOL(panic_timeout) -When: April 2006 -Files: kernel/panic.c -Why: No modular usage in the kernel. -Who: Adrian Bunk - ---------------------------- - What: remove EXPORT_SYMBOL(insert_resource) When: April 2006 Files: kernel/resource.c @@ -127,13 +119,6 @@ Who: Christoph Hellwig --------------------------- -What: EXPORT_SYMBOL(lookup_hash) -When: January 2006 -Why: Too low-level interface. Use lookup_one_len or lookup_create instead. -Who: Christoph Hellwig - ---------------------------- - What: CONFIG_FORCED_INLINING When: June 2006 Why: Config option is there to see if gcc is good enough. (in january @@ -241,3 +226,15 @@ Why: The USB subsystem has changed a lot over time, and it has been Who: Greg Kroah-Hartman --------------------------- + +What: find_trylock_page +When: January 2007 +Why: The interface no longer has any callers left in the kernel. It + is an odd interface (compared with other find_*_page functions), in + that it does not take a refcount to the page, only the page lock. + It should be replaced with find_get_page or find_lock_page if possible. + This feature removal can be reevaluated if users of the interface + cannot cleanly use something else. +Who: Nick Piggin + +--------------------------- diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index adaa899e5c90..3a2e5520c1e3 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -694,7 +694,7 @@ struct file_operations ---------------------- This describes how the VFS can manipulate an open file. As of kernel -2.6.13, the following members are defined: +2.6.17, the following members are defined: struct file_operations { loff_t (*llseek) (struct file *, loff_t, int); @@ -723,6 +723,10 @@ struct file_operations { int (*check_flags)(int); int (*dir_notify)(struct file *filp, unsigned long arg); int (*flock) (struct file *, int, struct file_lock *); + ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned +int); + ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned +int); }; Again, all methods are called without any locks being held, unless @@ -790,6 +794,12 @@ otherwise noted. flock: called by the flock(2) system call + splice_write: called by the VFS to splice data from a pipe to a file. This + method is used by the splice(2) system call + + splice_read: called by the VFS to splice data from file to a pipe. This + method is used by the splice(2) system call + Note that the file operations are implemented by the specific filesystem in which the inode resides. When opening a device node (character or block special) most filesystems will call special diff --git a/Documentation/fujitsu/frv/kernel-ABI.txt b/Documentation/fujitsu/frv/kernel-ABI.txt index 0ed9b0a779bc..8b0a5fc8bfd9 100644 --- a/Documentation/fujitsu/frv/kernel-ABI.txt +++ b/Documentation/fujitsu/frv/kernel-ABI.txt @@ -1,17 +1,19 @@ - ================================= - INTERNAL KERNEL ABI FOR FR-V ARCH - ================================= + ================================= + INTERNAL KERNEL ABI FOR FR-V ARCH + ================================= -The internal FRV kernel ABI is not quite the same as the userspace ABI. A number of the registers -are used for special purposed, and the ABI is not consistent between modules vs core, and MMU vs -no-MMU. +The internal FRV kernel ABI is not quite the same as the userspace ABI. A +number of the registers are used for special purposed, and the ABI is not +consistent between modules vs core, and MMU vs no-MMU. -This partly stems from the fact that FRV CPUs do not have a separate supervisor stack pointer, and -most of them do not have any scratch registers, thus requiring at least one general purpose -register to be clobbered in such an event. Also, within the kernel core, it is possible to simply -jump or call directly between functions using a relative offset. This cannot be extended to modules -for the displacement is likely to be too far. Thus in modules the address of a function to call -must be calculated in a register and then used, requiring two extra instructions. +This partly stems from the fact that FRV CPUs do not have a separate +supervisor stack pointer, and most of them do not have any scratch +registers, thus requiring at least one general purpose register to be +clobbered in such an event. Also, within the kernel core, it is possible to +simply jump or call directly between functions using a relative offset. +This cannot be extended to modules for the displacement is likely to be too +far. Thus in modules the address of a function to call must be calculated +in a register and then used, requiring two extra instructions. This document has the following sections: @@ -39,7 +41,8 @@ When a system call is made, the following registers are effective: CPU OPERATING MODES =================== -The FR-V CPU has three basic operating modes. In order of increasing capability: +The FR-V CPU has three basic operating modes. In order of increasing +capability: (1) User mode. @@ -47,42 +50,46 @@ The FR-V CPU has three basic operating modes. In order of increasing capability: (2) Kernel mode. - Normal kernel mode. There are many additional control registers available that may be - accessed in this mode, in addition to all the stuff available to user mode. This has two - submodes: + Normal kernel mode. There are many additional control registers + available that may be accessed in this mode, in addition to all the + stuff available to user mode. This has two submodes: (a) Exceptions enabled (PSR.T == 1). - Exceptions will invoke the appropriate normal kernel mode handler. On entry to the - handler, the PSR.T bit will be cleared. + Exceptions will invoke the appropriate normal kernel mode + handler. On entry to the handler, the PSR.T bit will be cleared. (b) Exceptions disabled (PSR.T == 0). - No exceptions or interrupts may happen. Any mandatory exceptions will cause the CPU to - halt unless the CPU is told to jump into debug mode instead. + No exceptions or interrupts may happen. Any mandatory exceptions + will cause the CPU to halt unless the CPU is told to jump into + debug mode instead. (3) Debug mode. - No exceptions may happen in this mode. Memory protection and management exceptions will be - flagged for later consideration, but the exception handler won't be invoked. Debugging traps - such as hardware breakpoints and watchpoints will be ignored. This mode is entered only by - debugging events obtained from the other two modes. + No exceptions may happen in this mode. Memory protection and + management exceptions will be flagged for later consideration, but + the exception handler won't be invoked. Debugging traps such as + hardware breakpoints and watchpoints will be ignored. This mode is + entered only by debugging events obtained from the other two modes. - All kernel mode registers may be accessed, plus a few extra debugging specific registers. + All kernel mode registers may be accessed, plus a few extra debugging + specific registers. ================================= INTERNAL KERNEL-MODE REGISTER ABI ================================= -There are a number of permanent register assignments that are set up by entry.S in the exception -prologue. Note that there is a complete set of exception prologues for each of user->kernel -transition and kernel->kernel transition. There are also user->debug and kernel->debug mode -transition prologues. +There are a number of permanent register assignments that are set up by +entry.S in the exception prologue. Note that there is a complete set of +exception prologues for each of user->kernel transition and kernel->kernel +transition. There are also user->debug and kernel->debug mode transition +prologues. REGISTER FLAVOUR USE - =============== ======= ==================================================== + =============== ======= ============================================== GR1 Supervisor stack pointer GR15 Current thread info pointer GR16 GP-Rel base register for small data @@ -92,10 +99,12 @@ transition prologues. GR31 NOMMU Destroyed by debug mode entry GR31 MMU Destroyed by TLB miss kernel mode entry CCR.ICC2 Virtual interrupt disablement tracking - CCCR.CC3 Cleared by exception prologue (atomic op emulation) + CCCR.CC3 Cleared by exception prologue + (atomic op emulation) SCR0 MMU See mmu-layout.txt. SCR1 MMU See mmu-layout.txt. - SCR2 MMU Save for EAR0 (destroyed by icache insns in debug mode) + SCR2 MMU Save for EAR0 (destroyed by icache insns + in debug mode) SCR3 MMU Save for GR31 during debug exceptions DAMR/IAMR NOMMU Fixed memory protection layout. DAMR/IAMR MMU See mmu-layout.txt. @@ -104,18 +113,21 @@ transition prologues. Certain registers are also used or modified across function calls: REGISTER CALL RETURN - =============== =============================== =============================== + =============== =============================== ====================== GR0 Fixed Zero - GR2 Function call frame pointer GR3 Special Preserved GR3-GR7 - Clobbered - GR8 Function call arg #1 Return value (or clobbered) - GR9 Function call arg #2 Return value MSW (or clobbered) + GR8 Function call arg #1 Return value + (or clobbered) + GR9 Function call arg #2 Return value MSW + (or clobbered) GR10-GR13 Function call arg #3-#6 Clobbered GR14 - Clobbered GR15-GR16 Special Preserved GR17-GR27 - Preserved - GR28-GR31 Special Only accessed explicitly + GR28-GR31 Special Only accessed + explicitly LR Return address after CALL Clobbered CCR/CCCR - Mostly Clobbered @@ -124,46 +136,53 @@ Certain registers are also used or modified across function calls: INTERNAL DEBUG-MODE REGISTER ABI ================================ -This is the same as the kernel-mode register ABI for functions calls. The difference is that in -debug-mode there's a different stack and a different exception frame. Almost all the global -registers from kernel-mode (including the stack pointer) may be changed. +This is the same as the kernel-mode register ABI for functions calls. The +difference is that in debug-mode there's a different stack and a different +exception frame. Almost all the global registers from kernel-mode +(including the stack pointer) may be changed. REGISTER FLAVOUR USE - =============== ======= ==================================================== + =============== ======= ============================================== GR1 Debug stack pointer GR16 GP-Rel base register for small data - GR31 Current debug exception frame pointer (__debug_frame) + GR31 Current debug exception frame pointer + (__debug_frame) SCR3 MMU Saved value of GR31 -Note that debug mode is able to interfere with the kernel's emulated atomic ops, so it must be -exceedingly careful not to do any that would interact with the main kernel in this regard. Hence -the debug mode code (gdbstub) is almost completely self-contained. The only external code used is -the sprintf family of functions. +Note that debug mode is able to interfere with the kernel's emulated atomic +ops, so it must be exceedingly careful not to do any that would interact +with the main kernel in this regard. Hence the debug mode code (gdbstub) is +almost completely self-contained. The only external code used is the +sprintf family of functions. -Futhermore, break.S is so complicated because single-step mode does not switch off on entry to an -exception. That means unless manually disabled, single-stepping will blithely go on stepping into -things like interrupts. See gdbstub.txt for more information. +Futhermore, break.S is so complicated because single-step mode does not +switch off on entry to an exception. That means unless manually disabled, +single-stepping will blithely go on stepping into things like interrupts. +See gdbstub.txt for more information. ========================== VIRTUAL INTERRUPT HANDLING ========================== -Because accesses to the PSR is so slow, and to disable interrupts we have to access it twice (once -to read and once to write), we don't actually disable interrupts at all if we don't have to. What -we do instead is use the ICC2 condition code flags to note virtual disablement, such that if we -then do take an interrupt, we note the flag, really disable interrupts, set another flag and resume -execution at the point the interrupt happened. Setting condition flags as a side effect of an -arithmetic or logical instruction is really fast. This use of the ICC2 only occurs within the +Because accesses to the PSR is so slow, and to disable interrupts we have +to access it twice (once to read and once to write), we don't actually +disable interrupts at all if we don't have to. What we do instead is use +the ICC2 condition code flags to note virtual disablement, such that if we +then do take an interrupt, we note the flag, really disable interrupts, set +another flag and resume execution at the point the interrupt happened. +Setting condition flags as a side effect of an arithmetic or logical +instruction is really fast. This use of the ICC2 only occurs within the kernel - it does not affect userspace. The flags we use are: (*) CCR.ICC2.Z [Zero flag] - Set to virtually disable interrupts, clear when interrupts are virtually enabled. Can be - modified by logical instructions without affecting the Carry flag. + Set to virtually disable interrupts, clear when interrupts are + virtually enabled. Can be modified by logical instructions without + affecting the Carry flag. (*) CCR.ICC2.C [Carry flag] @@ -176,8 +195,9 @@ What happens is this: ICC2.Z is 0, ICC2.C is 1. - (2) An interrupt occurs. The exception prologue examines ICC2.Z and determines that nothing needs - doing. This is done simply with an unlikely BEQ instruction. + (2) An interrupt occurs. The exception prologue examines ICC2.Z and + determines that nothing needs doing. This is done simply with an + unlikely BEQ instruction. (3) The interrupts are disabled (local_irq_disable) @@ -187,48 +207,56 @@ What happens is this: ICC2.Z would be set to 0. - A TIHI #2 instruction (trap #2 if condition HI - Z==0 && C==0) would be used to trap if - interrupts were now virtually enabled, but physically disabled - which they're not, so the - trap isn't taken. The kernel would then be back to state (1). + A TIHI #2 instruction (trap #2 if condition HI - Z==0 && C==0) would + be used to trap if interrupts were now virtually enabled, but + physically disabled - which they're not, so the trap isn't taken. The + kernel would then be back to state (1). - (5) An interrupt occurs. The exception prologue examines ICC2.Z and determines that the interrupt - shouldn't actually have happened. It jumps aside, and there disabled interrupts by setting - PSR.PIL to 14 and then it clears ICC2.C. + (5) An interrupt occurs. The exception prologue examines ICC2.Z and + determines that the interrupt shouldn't actually have happened. It + jumps aside, and there disabled interrupts by setting PSR.PIL to 14 + and then it clears ICC2.C. (6) If interrupts were then saved and disabled again (local_irq_save): - ICC2.Z would be shifted into the save variable and masked off (giving a 1). + ICC2.Z would be shifted into the save variable and masked off + (giving a 1). - ICC2.Z would then be set to 1 (thus unchanged), and ICC2.C would be unaffected (ie: 0). + ICC2.Z would then be set to 1 (thus unchanged), and ICC2.C would be + unaffected (ie: 0). (7) If interrupts were then restored from state (6) (local_irq_restore): - ICC2.Z would be set to indicate the result of XOR'ing the saved value (ie: 1) with 1, which - gives a result of 0 - thus leaving ICC2.Z set. + ICC2.Z would be set to indicate the result of XOR'ing the saved + value (ie: 1) with 1, which gives a result of 0 - thus leaving + ICC2.Z set. ICC2.C would remain unaffected (ie: 0). - A TIHI #2 instruction would be used to again assay the current state, but this would do - nothing as Z==1. + A TIHI #2 instruction would be used to again assay the current state, + but this would do nothing as Z==1. (8) If interrupts were then enabled (local_irq_enable): - ICC2.Z would be cleared. ICC2.C would be left unaffected. Both flags would now be 0. + ICC2.Z would be cleared. ICC2.C would be left unaffected. Both + flags would now be 0. - A TIHI #2 instruction again issued to assay the current state would then trap as both Z==0 - [interrupts virtually enabled] and C==0 [interrupts really disabled] would then be true. + A TIHI #2 instruction again issued to assay the current state would + then trap as both Z==0 [interrupts virtually enabled] and C==0 + [interrupts really disabled] would then be true. - (9) The trap #2 handler would simply enable hardware interrupts (set PSR.PIL to 0), set ICC2.C to - 1 and return. + (9) The trap #2 handler would simply enable hardware interrupts + (set PSR.PIL to 0), set ICC2.C to 1 and return. (10) Immediately upon returning, the pending interrupt would be taken. -(11) The interrupt handler would take the path of actually processing the interrupt (ICC2.Z is - clear, BEQ fails as per step (2)). +(11) The interrupt handler would take the path of actually processing the + interrupt (ICC2.Z is clear, BEQ fails as per step (2)). -(12) The interrupt handler would then set ICC2.C to 1 since hardware interrupts are definitely - enabled - or else the kernel wouldn't be here. +(12) The interrupt handler would then set ICC2.C to 1 since hardware + interrupts are definitely enabled - or else the kernel wouldn't be here. (13) On return from the interrupt handler, things would be back to state (1). -This trap (#2) is only available in kernel mode. In user mode it will result in SIGILL. +This trap (#2) is only available in kernel mode. In user mode it will +result in SIGILL. diff --git a/Documentation/i2c/busses/i2c-parport b/Documentation/i2c/busses/i2c-parport index d9f23c0763f1..77b995dfca22 100644 --- a/Documentation/i2c/busses/i2c-parport +++ b/Documentation/i2c/busses/i2c-parport @@ -12,18 +12,22 @@ meant as a replacement for the older, individual drivers: teletext adapters) It currently supports the following devices: - * Philips adapter - * home brew teletext adapter - * Velleman K8000 adapter - * ELV adapter - * Analog Devices evaluation boards (ADM1025, ADM1030, ADM1031, ADM1032) - * Barco LPT->DVI (K5800236) adapter + * (type=0) Philips adapter + * (type=1) home brew teletext adapter + * (type=2) Velleman K8000 adapter + * (type=3) ELV adapter + * (type=4) Analog Devices ADM1032 evaluation board + * (type=5) Analog Devices evaluation boards: ADM1025, ADM1030, ADM1031 + * (type=6) Barco LPT->DVI (K5800236) adapter These devices use different pinout configurations, so you have to tell the driver what you have, using the type module parameter. There is no way to autodetect the devices. Support for different pinout configurations can be easily added when needed. +Earlier kernels defaulted to type=0 (Philips). But now, if the type +parameter is missing, the driver will simply fail to initialize. + Building your own adapter ------------------------- diff --git a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt index 88a011c9f985..d537c48cc6d0 100644 --- a/Documentation/input/joystick-parport.txt +++ b/Documentation/input/joystick-parport.txt @@ -36,12 +36,12 @@ with them. All NES and SNES use the same synchronous serial protocol, clocked from the computer's side (and thus timing insensitive). To allow up to 5 NES -and/or SNES gamepads connected to the parallel port at once, the output -lines of the parallel port are shared, while one of 5 available input lines -is assigned to each gamepad. +and/or SNES gamepads and/or SNES mice connected to the parallel port at once, +the output lines of the parallel port are shared, while one of 5 available +input lines is assigned to each gamepad. This protocol is handled by the gamecon.c driver, so that's the one -you'll use for NES and SNES gamepads. +you'll use for NES, SNES gamepads and SNES mice. The main problem with PC parallel ports is that they don't have +5V power source on any of their pins. So, if you want a reliable source of power @@ -106,7 +106,7 @@ A, Turbo B, Select and Start, and is connected through 5 wires, then it is either a NES or NES clone and will work with this connection. SNES gamepads also use 5 wires, but have more buttons. They will work as well, of course. -Pinout for NES gamepads Pinout for SNES gamepads +Pinout for NES gamepads Pinout for SNES gamepads and mice +----> Power +-----------------------\ | 7 | o o o o | x x o | 1 @@ -454,6 +454,7 @@ uses the following kernel/module command line: 6 | N64 pad 7 | Sony PSX controller 8 | Sony PSX DDR controller + 9 | SNES mouse The exact type of the PSX controller type is autoprobed when used so hot swapping should work (but is not recomended). diff --git a/Documentation/isdn/README.gigaset b/Documentation/isdn/README.gigaset new file mode 100644 index 000000000000..85a64defd385 --- /dev/null +++ b/Documentation/isdn/README.gigaset @@ -0,0 +1,286 @@ +GigaSet 307x Device Driver +========================== + +1. Requirements + ------------ +1.1. Hardware + -------- + This release supports the connection of the Gigaset 307x/417x family of + ISDN DECT bases via Gigaset M101 Data, Gigaset M105 Data or direct USB + connection. The following devices are reported to be compatible: + 307x/417x: + Gigaset SX255isdn + Gigaset SX353isdn + Sinus 45 [AB] isdn (Deutsche Telekom) + Sinus 721X/XA + Vox Chicago 390 ISDN (KPN Telecom) + M101: + Sinus 45 Data 1 (Telekom) + M105: + Gigaset USB Adapter DECT + Sinus 45 Data 2 (Telekom) + Sinus 721 data + Chicago 390 USB (KPN) + See also http://www.erbze.info/sinus_gigaset.htm and + http://gigaset307x.sourceforge.net/ + + We had also reports from users of Gigaset M105 who could use the drivers + with SX 100 and CX 100 ISDN bases (only in unimodem mode, see section 2.4.) + If you have another device that works with our driver, please let us know. + For example, Gigaset SX205isdn/Sinus 721 X SE and Gigaset SX303isdn bases + are just versions without answering machine of models known to work, so + they should work just as well; but so far we are lacking positive reports + on these. + + Chances of getting an USB device to work are good if the output of + lsusb + at the command line contains one of the following: + ID 0681:0001 + ID 0681:0002 + ID 0681:0009 + ID 0681:0021 + ID 0681:0022 + +1.2. Software + -------- + The driver works with ISDN4linux and so can be used with any software + which is able to use ISDN4linux for ISDN connections (voice or data). + CAPI4Linux support is planned but not yet available. + + There are some user space tools available at + http://sourceforge.net/projects/gigaset307x/ + which provide access to additional device specific functions like SMS, + phonebook or call journal. + + +2. How to use the driver + --------------------- +2.1. Modules + ------- + To get the device working, you have to load the proper kernel module. You + can do this using + modprobe modulename + where modulename is usb_gigaset (M105) or bas_gigaset (direct USB + connection to the base). + +2.2. Device nodes for user space programs + ------------------------------------ + The device can be accessed from user space (eg. by the user space tools + mentioned in 1.2.) through the device nodes: + + - /dev/ttyGU0 for M105 (USB data boxes) + - /dev/ttyGB0 for the base driver (direct USB connection) + + You can also select a "default device" which is used by the frontends when + no device node is given as parameter, by creating a symlink /dev/ttyG to + one of them, eg.: + + ln -s /dev/ttyGB0 /dev/ttyG + +2.3. ISDN4linux + ---------- + This is the "normal" mode of operation. After loading the module you can + set up the ISDN system just as you'd do with any ISDN card. + Your distribution should provide some configuration utility. + If not, you can use some HOWTOs like + http://www.linuxhaven.de/dlhp/HOWTO/DE-ISDN-HOWTO-5.html + If this doesn't work, because you have some recent device like SX100 where + debug output (see section 3.2.) shows something like this when dialing + CMD Received: ERROR + Available Params: 0 + Connection State: 0, Response: -1 + gigaset_process_response: resp_code -1 in ConState 0 ! + Timeout occurred + you might need to use unimodem mode: + +2.4. Unimodem mode + ------------- + This is needed for some devices [e.g. SX100] as they have problems with + the "normal" commands. + + If you have installed the command line tool gigacontr, you can enter + unimodem mode using + gigacontr --mode unimodem + You can switch back using + gigacontr --mode isdn + + You can also load the driver using e.g. + modprobe usb_gigaset startmode=0 + to prevent the driver from starting in "isdn4linux mode". + + In this mode the device works like a modem connected to a serial port + (the /dev/ttyGU0, ... mentioned above) which understands the commands + ATZ init, reset + => OK or ERROR + ATD + ATDT dial + => OK, CONNECT, + BUSY, + NO DIAL TONE, + NO CARRIER, + NO ANSWER + +++ change to command mode when connected + ATH hangup + + You can use some configuration tool of your distribution to configure this + "modem" or configure pppd/wvdial manually. There are some example ppp + configuration files and chat scripts in the gigaset-VERSION/ppp directory. + Please note that the USB drivers are not able to change the state of the + control lines (the M105 driver can be configured to use some undocumented + control requests, if you really need the control lines, though). This means + you must use "Stupid Mode" if you are using wvdial or you should use the + nocrtscts option of pppd. + You must also assure that the ppp_async module is loaded with the parameter + flag_time=0. You can do this e.g. by adding a line like + + options ppp_async flag_time=0 + + to /etc/modprobe.conf. If your distribution has some local module + configuration file like /etc/modprobe.conf.local, + using that should be preferred. + +2.5. Call-ID (CID) mode + ------------------ + Call-IDs are numbers used to tag commands to, and responses from, the + Gigaset base in order to support the simultaneous handling of multiple + ISDN calls. Their use can be enabled ("CID mode") or disabled ("Unimodem + mode"). Without Call-IDs (in Unimodem mode), only a very limited set of + functions is available. It allows outgoing data connections only, but + does not signal incoming calls or other base events. + + DECT cordless data devices (M10x) permanently occupy the cordless + connection to the base while Call-IDs are activated. As the Gigaset + bases only support one DECT data connection at a time, this prevents + other DECT cordless data devices from accessing the base. + + During active operation, the driver switches to the necessary mode + automatically. However, for the reasons above, the mode chosen when + the device is not in use (idle) can be selected by the user. + - If you want to receive incoming calls, you can use the default + settings (CID mode). + - If you have several DECT data devices (M10x) which you want to use + in turn, select Unimodem mode by passing the parameter "cidmode=0" to + the driver ("modprobe usb_gigaset cidmode=0" or modprobe.conf). + + If you want both of these at once, you are out of luck. + + You can also use /sys/module//parameters/cidmode for changing + the CID mode setting ( is usb_gigaset or bas_gigaset). + + +3. Troubleshooting + --------------- +3.1. Solutions to frequently reported problems + ----------------------------------------- + Problem: + You have a slow provider and isdn4linux gives up dialing too early. + Solution: + Load the isdn module using the dialtimeout option. You can do this e.g. + by adding a line like + + options isdn dialtimeout=15 + + to /etc/modprobe.conf. If your distribution has some local module + configuration file like /etc/modprobe.conf.local, + using that should be preferred. + + Problem: + Your isdn script aborts with a message about isdnlog. + Solution: + Try deactivating (or commenting out) isdnlog. This driver does not + support it. + + Problem: + You have two or more DECT data adapters (M101/M105) and only the + first one you turn on works. + Solution: + Select Unimodem mode for all DECT data adapters. (see section 2.4.) + +3.2. Telling the driver to provide more information + ---------------------------------------------- + Building the driver with the "Gigaset debugging" kernel configuration + option (CONFIG_GIGASET_DEBUG) gives it the ability to produce additional + information useful for debugging. + + You can control the amount of debugging information the driver produces by + writing an appropriate value to /sys/module/gigaset/parameters/debug, e.g. + echo 0 > /sys/module/gigaset/parameters/debug + switches off debugging output completely, + echo 0x10a020 > /sys/module/gigaset/parameters/debug + enables the standard set of debugging output messages. These values are + bit patterns where every bit controls a certain type of debugging output. + See the constants DEBUG_* in the source file gigaset.h for details. + + The initial value can be set using the debug parameter when loading the + module "gigaset", e.g. by adding a line + options gigaset debug=0 + to /etc/modprobe.conf, ... + + Generated debugging information can be found + - as output of the command + dmesg + - in system log files written by your syslog daemon, usually + in /var/log/, e.g. /var/log/messages. + +3.3. Reporting problems and bugs + --------------------------- + If you can't solve problems with the driver on your own, feel free to + use one of the forums, bug trackers, or mailing lists on + http://sourceforge.net/projects/gigaset307x + or write an electronic mail to the maintainers. + + Try to provide as much information as possible, such as + - distribution + - kernel version (uname -r) + - gcc version (gcc --version) + - hardware architecture (uname -m, ...) + - type and firmware version of your device (base and wireless module, + if any) + - output of "lsusb -v" (if using an USB device) + - error messages + - relevant system log messages (it would help if you activate debug + output as described in 3.2.) + + For help with general configuration problems not specific to our driver, + such as isdn4linux and network configuration issues, please refer to the + appropriate forums and newsgroups. + +3.4. Reporting problem solutions + --------------------------- + If you solved a problem with our drivers, wrote startup scripts for your + distribution, ... feel free to contact us (using one of the places + mentioned in 3.3.). We'd like to add scripts, hints, documentation + to the driver and/or the project web page. + + +4. Links, other software + --------------------- + - Sourceforge project developing this driver and associated tools + http://sourceforge.net/projects/gigaset307x + - Yahoo! Group on the Siemens Gigaset family of devices + http://de.groups.yahoo.com/group/Siemens-Gigaset + - Siemens Gigaset/T-Sinus compatibility table + http://www.erbze.info/sinus_gigaset.htm + + +5. Credits + ------- + Thanks to + + Karsten Keil + for his help with isdn4linux + Deti Fliegl + for his base driver code + Dennis Dietrich + for his kernel 2.6 patches + Andreas Rummel + for his work and logs to get unimodem mode working + Andreas Degert + for his logs and patches to get cx 100 working + Dietrich Feist + for his generous donation of one M105 and two M101 cordless adapters + Christoph Schweers + for his generous donation of a M34 device + + and all the other people who sent logs and other information. + diff --git a/Documentation/kbuild/modules.txt b/Documentation/kbuild/modules.txt index fcccf2432f98..61fc079eb966 100644 --- a/Documentation/kbuild/modules.txt +++ b/Documentation/kbuild/modules.txt @@ -44,7 +44,7 @@ What is covered within this file is mainly information to authors of modules. The author of an external modules should supply a makefile that hides most of the complexity so one only has to type 'make' to build the module. A complete example will be present in -chapter ¤. Creating a kbuild file for an external module". +chapter 4, "Creating a kbuild file for an external module". === 2. How to build external modules diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index f8cb55c30b0f..b3a6187e5305 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1,4 +1,4 @@ -February 2003 Kernel Parameters v2.5.59 + Kernel Parameters ~~~~~~~~~~~~~~~~~ The following is a consolidated list of the kernel parameters as implemented @@ -17,9 +17,17 @@ are specified on the kernel command line with the module name plus usbcore.blinkenlights=1 -The text in square brackets at the beginning of the description states the -restrictions on the kernel for the said kernel parameter to be valid. The -restrictions referred to are that the relevant option is valid if: +This document may not be entirely up to date and comprehensive. The command +"modinfo -p ${modulename}" shows a current list of all parameters of a loadable +module. Loadable modules, after being loaded into the running kernel, also +reveal their parameters in /sys/module/${modulename}/parameters/. Some of these +parameters may be changed at runtime by the command +"echo -n ${value} > /sys/module/${modulename}/parameters/${parm}". + +The parameters listed below are only valid if certain kernel build options were +enabled and if respective hardware is present. The text in square brackets at +the beginning of each description states the restrictions within which a +parameter is applicable: ACPI ACPI support is enabled. ALSA ALSA sound support is enabled. @@ -1046,10 +1054,10 @@ running once the system is up. noltlbs [PPC] Do not use large page/tlb entries for kernel lowmem mapping on PPC40x. - nomce [IA-32] Machine Check Exception - nomca [IA-64] Disable machine check abort handling + nomce [IA-32] Machine Check Exception + noresidual [PPC] Don't use residual data on PReP machines. noresume [SWSUSP] Disables resume and restores original swap @@ -1682,20 +1690,6 @@ running once the system is up. ______________________________________________________________________ -Changelog: - -2000-06-?? Mr. Unknown - The last known update (for 2.4.0) - the changelog was not kept before. - -2002-11-24 Petr Baudis - Randy Dunlap - Update for 2.5.49, description for most of the options introduced, - references to other documentation (C files, READMEs, ..), added S390, - PPC, SPARC, MTD, ALSA and OSS category. Minor corrections and - reformatting. - -2005-10-19 Randy Dunlap - Lots of typos, whitespace, some reformatting. TODO: diff --git a/Documentation/laptop-mode.txt b/Documentation/laptop-mode.txt index b18e21675906..5696e879449b 100644 --- a/Documentation/laptop-mode.txt +++ b/Documentation/laptop-mode.txt @@ -919,11 +919,11 @@ int main(int argc, char **argv) int settle_time = 60; /* Parse the simple command-line */ - if (ac == 2) - disk = av[1]; - else if (ac == 4) { - settle_time = atoi(av[2]); - disk = av[3]; + if (argc == 2) + disk = argv[1]; + else if (argc == 4) { + settle_time = atoi(argv[2]); + disk = argv[3]; } else usage(); diff --git a/Documentation/leds-class.txt b/Documentation/leds-class.txt new file mode 100644 index 000000000000..8c35c0426110 --- /dev/null +++ b/Documentation/leds-class.txt @@ -0,0 +1,71 @@ +LED handling under Linux +======================== + +If you're reading this and thinking about keyboard leds, these are +handled by the input subsystem and the led class is *not* needed. + +In its simplest form, the LED class just allows control of LEDs from +userspace. LEDs appear in /sys/class/leds/. The brightness file will +set the brightness of the LED (taking a value 0-255). Most LEDs don't +have hardware brightness support so will just be turned on for non-zero +brightness settings. + +The class also introduces the optional concept of an LED trigger. A trigger +is a kernel based source of led events. Triggers can either be simple or +complex. A simple trigger isn't configurable and is designed to slot into +existing subsystems with minimal additional code. Examples are the ide-disk, +nand-disk and sharpsl-charge triggers. With led triggers disabled, the code +optimises away. + +Complex triggers whilst available to all LEDs have LED specific +parameters and work on a per LED basis. The timer trigger is an example. + +You can change triggers in a similar manner to the way an IO scheduler +is chosen (via /sys/class/leds//trigger). Trigger specific +parameters can appear in /sys/class/leds/ once a given trigger is +selected. + + +Design Philosophy +================= + +The underlying design philosophy is simplicity. LEDs are simple devices +and the aim is to keep a small amount of code giving as much functionality +as possible. Please keep this in mind when suggesting enhancements. + + +LED Device Naming +================= + +Is currently of the form: + +"devicename:colour" + +There have been calls for LED properties such as colour to be exported as +individual led class attributes. As a solution which doesn't incur as much +overhead, I suggest these become part of the device name. The naming scheme +above leaves scope for further attributes should they be needed. + + +Known Issues +============ + +The LED Trigger core cannot be a module as the simple trigger functions +would cause nightmare dependency issues. I see this as a minor issue +compared to the benefits the simple trigger functionality brings. The +rest of the LED subsystem can be modular. + +Some leds can be programmed to flash in hardware. As this isn't a generic +LED device property, this should be exported as a device specific sysfs +attribute rather than part of the class if this functionality is required. + + +Future Development +================== + +At the moment, a trigger can't be created specifically for a single LED. +There are a number of cases where a trigger might only be mappable to a +particular LED (ACPI?). The addition of triggers provided by the LED driver +should cover this option and be possible to add without breaking the +current interface. + diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt new file mode 100644 index 000000000000..92f0056d928c --- /dev/null +++ b/Documentation/memory-barriers.txt @@ -0,0 +1,1941 @@ + ============================ + LINUX KERNEL MEMORY BARRIERS + ============================ + +By: David Howells + +Contents: + + (*) Abstract memory access model. + + - Device operations. + - Guarantees. + + (*) What are memory barriers? + + - Varieties of memory barrier. + - What may not be assumed about memory barriers? + - Data dependency barriers. + - Control dependencies. + - SMP barrier pairing. + - Examples of memory barrier sequences. + + (*) Explicit kernel barriers. + + - Compiler barrier. + - The CPU memory barriers. + - MMIO write barrier. + + (*) Implicit kernel memory barriers. + + - Locking functions. + - Interrupt disabling functions. + - Miscellaneous functions. + + (*) Inter-CPU locking barrier effects. + + - Locks vs memory accesses. + - Locks vs I/O accesses. + + (*) Where are memory barriers needed? + + - Interprocessor interaction. + - Atomic operations. + - Accessing devices. + - Interrupts. + + (*) Kernel I/O barrier effects. + + (*) Assumed minimum execution ordering model. + + (*) The effects of the cpu cache. + + - Cache coherency. + - Cache coherency vs DMA. + - Cache coherency vs MMIO. + + (*) The things CPUs get up to. + + - And then there's the Alpha. + + (*) References. + + +============================ +ABSTRACT MEMORY ACCESS MODEL +============================ + +Consider the following abstract model of the system: + + : : + : : + : : + +-------+ : +--------+ : +-------+ + | | : | | : | | + | | : | | : | | + | CPU 1 |<----->| Memory |<----->| CPU 2 | + | | : | | : | | + | | : | | : | | + +-------+ : +--------+ : +-------+ + ^ : ^ : ^ + | : | : | + | : | : | + | : v : | + | : +--------+ : | + | : | | : | + | : | | : | + +---------->| Device |<----------+ + : | | : + : | | : + : +--------+ : + : : + +Each CPU executes a program that generates memory access operations. In the +abstract CPU, memory operation ordering is very relaxed, and a CPU may actually +perform the memory operations in any order it likes, provided program causality +appears to be maintained. Similarly, the compiler may also arrange the +instructions it emits in any order it likes, provided it doesn't affect the +apparent operation of the program. + +So in the above diagram, the effects of the memory operations performed by a +CPU are perceived by the rest of the system as the operations cross the +interface between the CPU and rest of the system (the dotted lines). + + +For example, consider the following sequence of events: + + CPU 1 CPU 2 + =============== =============== + { A == 1; B == 2 } + A = 3; x = A; + B = 4; y = B; + +The set of accesses as seen by the memory system in the middle can be arranged +in 24 different combinations: + + STORE A=3, STORE B=4, x=LOAD A->3, y=LOAD B->4 + STORE A=3, STORE B=4, y=LOAD B->4, x=LOAD A->3 + STORE A=3, x=LOAD A->3, STORE B=4, y=LOAD B->4 + STORE A=3, x=LOAD A->3, y=LOAD B->2, STORE B=4 + STORE A=3, y=LOAD B->2, STORE B=4, x=LOAD A->3 + STORE A=3, y=LOAD B->2, x=LOAD A->3, STORE B=4 + STORE B=4, STORE A=3, x=LOAD A->3, y=LOAD B->4 + STORE B=4, ... + ... + +and can thus result in four different combinations of values: + + x == 1, y == 2 + x == 1, y == 4 + x == 3, y == 2 + x == 3, y == 4 + + +Furthermore, the stores committed by a CPU to the memory system may not be +perceived by the loads made by another CPU in the same order as the stores were +committed. + + +As a further example, consider this sequence of events: + + CPU 1 CPU 2 + =============== =============== + { A == 1, B == 2, C = 3, P == &A, Q == &C } + B = 4; Q = P; + P = &B D = *Q; + +There is an obvious data dependency here, as the value loaded into D depends on +the address retrieved from P by CPU 2. At the end of the sequence, any of the +following results are possible: + + (Q == &A) and (D == 1) + (Q == &B) and (D == 2) + (Q == &B) and (D == 4) + +Note that CPU 2 will never try and load C into D because the CPU will load P +into Q before issuing the load of *Q. + + +DEVICE OPERATIONS +----------------- + +Some devices present their control interfaces as collections of memory +locations, but the order in which the control registers are accessed is very +important. For instance, imagine an ethernet card with a set of internal +registers that are accessed through an address port register (A) and a data +port register (D). To read internal register 5, the following code might then +be used: + + *A = 5; + x = *D; + +but this might show up as either of the following two sequences: + + STORE *A = 5, x = LOAD *D + x = LOAD *D, STORE *A = 5 + +the second of which will almost certainly result in a malfunction, since it set +the address _after_ attempting to read the register. + + +GUARANTEES +---------- + +There are some minimal guarantees that may be expected of a CPU: + + (*) On any given CPU, dependent memory accesses will be issued in order, with + respect to itself. This means that for: + + Q = P; D = *Q; + + the CPU will issue the following memory operations: + + Q = LOAD P, D = LOAD *Q + + and always in that order. + + (*) Overlapping loads and stores within a particular CPU will appear to be + ordered within that CPU. This means that for: + + a = *X; *X = b; + + the CPU will only issue the following sequence of memory operations: + + a = LOAD *X, STORE *X = b + + And for: + + *X = c; d = *X; + + the CPU will only issue: + + STORE *X = c, d = LOAD *X + + (Loads and stores overlap if they are targetted at overlapping pieces of + memory). + +And there are a number of things that _must_ or _must_not_ be assumed: + + (*) It _must_not_ be assumed that independent loads and stores will be issued + in the order given. This means that for: + + X = *A; Y = *B; *D = Z; + + we may get any of the following sequences: + + X = LOAD *A, Y = LOAD *B, STORE *D = Z + X = LOAD *A, STORE *D = Z, Y = LOAD *B + Y = LOAD *B, X = LOAD *A, STORE *D = Z + Y = LOAD *B, STORE *D = Z, X = LOAD *A + STORE *D = Z, X = LOAD *A, Y = LOAD *B + STORE *D = Z, Y = LOAD *B, X = LOAD *A + + (*) It _must_ be assumed that overlapping memory accesses may be merged or + discarded. This means that for: + + X = *A; Y = *(A + 4); + + we may get any one of the following sequences: + + X = LOAD *A; Y = LOAD *(A + 4); + Y = LOAD *(A + 4); X = LOAD *A; + {X, Y} = LOAD {*A, *(A + 4) }; + + And for: + + *A = X; Y = *A; + + we may get either of: + + STORE *A = X; Y = LOAD *A; + STORE *A = Y; + + +========================= +WHAT ARE MEMORY BARRIERS? +========================= + +As can be seen above, independent memory operations are effectively performed +in random order, but this can be a problem for CPU-CPU interaction and for I/O. +What is required is some way of intervening to instruct the compiler and the +CPU to restrict the order. + +Memory barriers are such interventions. They impose a perceived partial +ordering between the memory operations specified on either side of the barrier. +They request that the sequence of memory events generated appears to other +parts of the system as if the barrier is effective on that CPU. + + +VARIETIES OF MEMORY BARRIER +--------------------------- + +Memory barriers come in four basic varieties: + + (1) Write (or store) memory barriers. + + A write memory barrier gives a guarantee that all the STORE operations + specified before the barrier will appear to happen before all the STORE + operations specified after the barrier with respect to the other + components of the system. + + A write barrier is a partial ordering on stores only; it is not required + to have any effect on loads. + + A CPU can be viewed as as commiting a sequence of store operations to the + memory system as time progresses. All stores before a write barrier will + occur in the sequence _before_ all the stores after the write barrier. + + [!] Note that write barriers should normally be paired with read or data + dependency barriers; see the "SMP barrier pairing" subsection. + + + (2) Data dependency barriers. + + A data dependency barrier is a weaker form of read barrier. In the case + where two loads are performed such that the second depends on the result + of the first (eg: the first load retrieves the address to which the second + load will be directed), a data dependency barrier would be required to + make sure that the target of the second load is updated before the address + obtained by the first load is accessed. + + A data dependency barrier is a partial ordering on interdependent loads + only; it is not required to have any effect on stores, independent loads + or overlapping loads. + + As mentioned in (1), the other CPUs in the system can be viewed as + committing sequences of stores to the memory system that the CPU being + considered can then perceive. A data dependency barrier issued by the CPU + under consideration guarantees that for any load preceding it, if that + load touches one of a sequence of stores from another CPU, then by the + time the barrier completes, the effects of all the stores prior to that + touched by the load will be perceptible to any loads issued after the data + dependency barrier. + + See the "Examples of memory barrier sequences" subsection for diagrams + showing the ordering constraints. + + [!] Note that the first load really has to have a _data_ dependency and + not a control dependency. If the address for the second load is dependent + on the first load, but the dependency is through a conditional rather than + actually loading the address itself, then it's a _control_ dependency and + a full read barrier or better is required. See the "Control dependencies" + subsection for more information. + + [!] Note that data dependency barriers should normally be paired with + write barriers; see the "SMP barrier pairing" subsection. + + + (3) Read (or load) memory barriers. + + A read barrier is a data dependency barrier plus a guarantee that all the + LOAD operations specified before the barrier will appear to happen before + all the LOAD operations specified after the barrier with respect to the + other components of the system. + + A read barrier is a partial ordering on loads only; it is not required to + have any effect on stores. + + Read memory barriers imply data dependency barriers, and so can substitute + for them. + + [!] Note that read barriers should normally be paired with write barriers; + see the "SMP barrier pairing" subsection. + + + (4) General memory barriers. + + A general memory barrier is a combination of both a read memory barrier + and a write memory barrier. It is a partial ordering over both loads and + stores. + + General memory barriers imply both read and write memory barriers, and so + can substitute for either. + + +And a couple of implicit varieties: + + (5) LOCK operations. + + This acts as a one-way permeable barrier. It guarantees that all memory + operations after the LOCK operation will appear to happen after the LOCK + operation with respect to the other components of the system. + + Memory operations that occur before a LOCK operation may appear to happen + after it completes. + + A LOCK operation should almost always be paired with an UNLOCK operation. + + + (6) UNLOCK operations. + + This also acts as a one-way permeable barrier. It guarantees that all + memory operations before the UNLOCK operation will appear to happen before + the UNLOCK operation with respect to the other components of the system. + + Memory operations that occur after an UNLOCK operation may appear to + happen before it completes. + + LOCK and UNLOCK operations are guaranteed to appear with respect to each + other strictly in the order specified. + + The use of LOCK and UNLOCK operations generally precludes the need for + other sorts of memory barrier (but note the exceptions mentioned in the + subsection "MMIO write barrier"). + + +Memory barriers are only required where there's a possibility of interaction +between two CPUs or between a CPU and a device. If it can be guaranteed that +there won't be any such interaction in any particular piece of code, then +memory barriers are unnecessary in that piece of code. + + +Note that these are the _minimum_ guarantees. Different architectures may give +more substantial guarantees, but they may _not_ be relied upon outside of arch +specific code. + + +WHAT MAY NOT BE ASSUMED ABOUT MEMORY BARRIERS? +---------------------------------------------- + +There are certain things that the Linux kernel memory barriers do not guarantee: + + (*) There is no guarantee that any of the memory accesses specified before a + memory barrier will be _complete_ by the completion of a memory barrier + instruction; the barrier can be considered to draw a line in that CPU's + access queue that accesses of the appropriate type may not cross. + + (*) There is no guarantee that issuing a memory barrier on one CPU will have + any direct effect on another CPU or any other hardware in the system. The + indirect effect will be the order in which the second CPU sees the effects + of the first CPU's accesses occur, but see the next point: + + (*) There is no guarantee that the a CPU will see the correct order of effects + from a second CPU's accesses, even _if_ the second CPU uses a memory + barrier, unless the first CPU _also_ uses a matching memory barrier (see + the subsection on "SMP Barrier Pairing"). + + (*) There is no guarantee that some intervening piece of off-the-CPU + hardware[*] will not reorder the memory accesses. CPU cache coherency + mechanisms should propagate the indirect effects of a memory barrier + between CPUs, but might not do so in order. + + [*] For information on bus mastering DMA and coherency please read: + + Documentation/pci.txt + Documentation/DMA-mapping.txt + Documentation/DMA-API.txt + + +DATA DEPENDENCY BARRIERS +------------------------ + +The usage requirements of data dependency barriers are a little subtle, and +it's not always obvious that they're needed. To illustrate, consider the +following sequence of events: + + CPU 1 CPU 2 + =============== =============== + { A == 1, B == 2, C = 3, P == &A, Q == &C } + B = 4; + + P = &B + Q = P; + D = *Q; + +There's a clear data dependency here, and it would seem that by the end of the +sequence, Q must be either &A or &B, and that: + + (Q == &A) implies (D == 1) + (Q == &B) implies (D == 4) + +But! CPU 2's perception of P may be updated _before_ its perception of B, thus +leading to the following situation: + + (Q == &B) and (D == 2) ???? + +Whilst this may seem like a failure of coherency or causality maintenance, it +isn't, and this behaviour can be observed on certain real CPUs (such as the DEC +Alpha). + +To deal with this, a data dependency barrier must be inserted between the +address load and the data load: + + CPU 1 CPU 2 + =============== =============== + { A == 1, B == 2, C = 3, P == &A, Q == &C } + B = 4; + + P = &B + Q = P; + + D = *Q; + +This enforces the occurrence of one of the two implications, and prevents the +third possibility from arising. + +[!] Note that this extremely counterintuitive situation arises most easily on +machines with split caches, so that, for example, one cache bank processes +even-numbered cache lines and the other bank processes odd-numbered cache +lines. The pointer P might be stored in an odd-numbered cache line, and the +variable B might be stored in an even-numbered cache line. Then, if the +even-numbered bank of the reading CPU's cache is extremely busy while the +odd-numbered bank is idle, one can see the new value of the pointer P (&B), +but the old value of the variable B (1). + + +Another example of where data dependency barriers might by required is where a +number is read from memory and then used to calculate the index for an array +access: + + CPU 1 CPU 2 + =============== =============== + { M[0] == 1, M[1] == 2, M[3] = 3, P == 0, Q == 3 } + M[1] = 4; + + P = 1 + Q = P; + + D = M[Q]; + + +The data dependency barrier is very important to the RCU system, for example. +See rcu_dereference() in include/linux/rcupdate.h. This permits the current +target of an RCU'd pointer to be replaced with a new modified target, without +the replacement target appearing to be incompletely initialised. + +See also the subsection on "Cache Coherency" for a more thorough example. + + +CONTROL DEPENDENCIES +-------------------- + +A control dependency requires a full read memory barrier, not simply a data +dependency barrier to make it work correctly. Consider the following bit of +code: + + q = &a; + if (p) + q = &b; + + x = *q; + +This will not have the desired effect because there is no actual data +dependency, but rather a control dependency that the CPU may short-circuit by +attempting to predict the outcome in advance. In such a case what's actually +required is: + + q = &a; + if (p) + q = &b; + + x = *q; + + +SMP BARRIER PAIRING +------------------- + +When dealing with CPU-CPU interactions, certain types of memory barrier should +always be paired. A lack of appropriate pairing is almost certainly an error. + +A write barrier should always be paired with a data dependency barrier or read +barrier, though a general barrier would also be viable. Similarly a read +barrier or a data dependency barrier should always be paired with at least an +write barrier, though, again, a general barrier is viable: + + CPU 1 CPU 2 + =============== =============== + a = 1; + + b = 2; x = a; + + y = b; + +Or: + + CPU 1 CPU 2 + =============== =============================== + a = 1; + + b = &a; x = b; + + y = *x; + +Basically, the read barrier always has to be there, even though it can be of +the "weaker" type. + + +EXAMPLES OF MEMORY BARRIER SEQUENCES +------------------------------------ + +Firstly, write barriers act as a partial orderings on store operations. +Consider the following sequence of events: + + CPU 1 + ======================= + STORE A = 1 + STORE B = 2 + STORE C = 3 + + STORE D = 4 + STORE E = 5 + +This sequence of events is committed to the memory coherence system in an order +that the rest of the system might perceive as the unordered set of { STORE A, +STORE B, STORE C } all occuring before the unordered set of { STORE D, STORE E +}: + + +-------+ : : + | | +------+ + | |------>| C=3 | } /\ + | | : +------+ }----- \ -----> Events perceptible + | | : | A=1 | } \/ to rest of system + | | : +------+ } + | CPU 1 | : | B=2 | } + | | +------+ } + | | wwwwwwwwwwwwwwww } <--- At this point the write barrier + | | +------+ } requires all stores prior to the + | | : | E=5 | } barrier to be committed before + | | : +------+ } further stores may be take place. + | |------>| D=4 | } + | | +------+ + +-------+ : : + | + | Sequence in which stores committed to memory system + | by CPU 1 + V + + +Secondly, data dependency barriers act as a partial orderings on data-dependent +loads. Consider the following sequence of events: + + CPU 1 CPU 2 + ======================= ======================= + { B = 7; X = 9; Y = 8; C = &Y } + STORE A = 1 + STORE B = 2 + + STORE C = &B LOAD X + STORE D = 4 LOAD C (gets &B) + LOAD *C (reads B) + +Without intervention, CPU 2 may perceive the events on CPU 1 in some +effectively random order, despite the write barrier issued by CPU 1: + + +-------+ : : : : + | | +------+ +-------+ | Sequence of update + | |------>| B=2 |----- --->| Y->8 | | of perception on + | | : +------+ \ +-------+ | CPU 2 + | CPU 1 | : | A=1 | \ --->| C->&Y | V + | | +------+ | +-------+ + | | wwwwwwwwwwwwwwww | : : + | | +------+ | : : + | | : | C=&B |--- | : : +-------+ + | | : +------+ \ | +-------+ | | + | |------>| D=4 | ----------->| C->&B |------>| | + | | +------+ | +-------+ | | + +-------+ : : | : : | | + | : : | | + | : : | CPU 2 | + | +-------+ | | + Apparently incorrect ---> | | B->7 |------>| | + perception of B (!) | +-------+ | | + | : : | | + | +-------+ | | + The load of X holds ---> \ | X->9 |------>| | + up the maintenance \ +-------+ | | + of coherence of B ----->| B->2 | +-------+ + +-------+ + : : + + +In the above example, CPU 2 perceives that B is 7, despite the load of *C +(which would be B) coming after the the LOAD of C. + +If, however, a data dependency barrier were to be placed between the load of C +and the load of *C (ie: B) on CPU 2: + + CPU 1 CPU 2 + ======================= ======================= + { B = 7; X = 9; Y = 8; C = &Y } + STORE A = 1 + STORE B = 2 + + STORE C = &B LOAD X + STORE D = 4 LOAD C (gets &B) + + LOAD *C (reads B) + +then the following will occur: + + +-------+ : : : : + | | +------+ +-------+ + | |------>| B=2 |----- --->| Y->8 | + | | : +------+ \ +-------+ + | CPU 1 | : | A=1 | \ --->| C->&Y | + | | +------+ | +-------+ + | | wwwwwwwwwwwwwwww | : : + | | +------+ | : : + | | : | C=&B |--- | : : +-------+ + | | : +------+ \ | +-------+ | | + | |------>| D=4 | ----------->| C->&B |------>| | + | | +------+ | +-------+ | | + +-------+ : : | : : | | + | : : | | + | : : | CPU 2 | + | +-------+ | | + \ | X->9 |------>| | + \ +-------+ | | + ----->| B->2 | | | + +-------+ | | + Makes sure all effects ---> ddddddddddddddddd | | + prior to the store of C +-------+ | | + are perceptible to | B->2 |------>| | + successive loads +-------+ | | + : : +-------+ + + +And thirdly, a read barrier acts as a partial order on loads. Consider the +following sequence of events: + + CPU 1 CPU 2 + ======================= ======================= + STORE A=1 + STORE B=2 + STORE C=3 + + STORE D=4 + STORE E=5 + LOAD A + LOAD B + LOAD C + LOAD D + LOAD E + +Without intervention, CPU 2 may then choose to perceive the events on CPU 1 in +some effectively random order, despite the write barrier issued by CPU 1: + + +-------+ : : + | | +------+ + | |------>| C=3 | } + | | : +------+ } + | | : | A=1 | } + | | : +------+ } + | CPU 1 | : | B=2 | }--- + | | +------+ } \ + | | wwwwwwwwwwwww} \ + | | +------+ } \ : : +-------+ + | | : | E=5 | } \ +-------+ | | + | | : +------+ } \ { | C->3 |------>| | + | |------>| D=4 | } \ { +-------+ : | | + | | +------+ \ { | E->5 | : | | + +-------+ : : \ { +-------+ : | | + Transfer -->{ | A->1 | : | CPU 2 | + from CPU 1 { +-------+ : | | + to CPU 2 { | D->4 | : | | + { +-------+ : | | + { | B->2 |------>| | + +-------+ | | + : : +-------+ + + +If, however, a read barrier were to be placed between the load of C and the +load of D on CPU 2, then the partial ordering imposed by CPU 1 will be +perceived correctly by CPU 2. + + +-------+ : : + | | +------+ + | |------>| C=3 | } + | | : +------+ } + | | : | A=1 | }--- + | | : +------+ } \ + | CPU 1 | : | B=2 | } \ + | | +------+ \ + | | wwwwwwwwwwwwwwww \ + | | +------+ \ : : +-------+ + | | : | E=5 | } \ +-------+ | | + | | : +------+ }--- \ { | C->3 |------>| | + | |------>| D=4 | } \ \ { +-------+ : | | + | | +------+ \ -->{ | B->2 | : | | + +-------+ : : \ { +-------+ : | | + \ { | A->1 | : | CPU 2 | + \ +-------+ | | + At this point the read ----> \ rrrrrrrrrrrrrrrrr | | + barrier causes all effects \ +-------+ | | + prior to the storage of C \ { | E->5 | : | | + to be perceptible to CPU 2 -->{ +-------+ : | | + { | D->4 |------>| | + +-------+ | | + : : +-------+ + + +======================== +EXPLICIT KERNEL BARRIERS +======================== + +The Linux kernel has a variety of different barriers that act at different +levels: + + (*) Compiler barrier. + + (*) CPU memory barriers. + + (*) MMIO write barrier. + + +COMPILER BARRIER +---------------- + +The Linux kernel has an explicit compiler barrier function that prevents the +compiler from moving the memory accesses either side of it to the other side: + + barrier(); + +This a general barrier - lesser varieties of compiler barrier do not exist. + +The compiler barrier has no direct effect on the CPU, which may then reorder +things however it wishes. + + +CPU MEMORY BARRIERS +------------------- + +The Linux kernel has eight basic CPU memory barriers: + + TYPE MANDATORY SMP CONDITIONAL + =============== ======================= =========================== + GENERAL mb() smp_mb() + WRITE wmb() smp_wmb() + READ rmb() smp_rmb() + DATA DEPENDENCY read_barrier_depends() smp_read_barrier_depends() + + +All CPU memory barriers unconditionally imply compiler barriers. + +SMP memory barriers are reduced to compiler barriers on uniprocessor compiled +systems because it is assumed that a CPU will be appear to be self-consistent, +and will order overlapping accesses correctly with respect to itself. + +[!] Note that SMP memory barriers _must_ be used to control the ordering of +references to shared memory on SMP systems, though the use of locking instead +is sufficient. + +Mandatory barriers should not be used to control SMP effects, since mandatory +barriers unnecessarily impose overhead on UP systems. They may, however, be +used to control MMIO effects on accesses through relaxed memory I/O windows. +These are required even on non-SMP systems as they affect the order in which +memory operations appear to a device by prohibiting both the compiler and the +CPU from reordering them. + + +There are some more advanced barrier functions: + + (*) set_mb(var, value) + (*) set_wmb(var, value) + + These assign the value to the variable and then insert at least a write + barrier after it, depending on the function. They aren't guaranteed to + insert anything more than a compiler barrier in a UP compilation. + + + (*) smp_mb__before_atomic_dec(); + (*) smp_mb__after_atomic_dec(); + (*) smp_mb__before_atomic_inc(); + (*) smp_mb__after_atomic_inc(); + + These are for use with atomic add, subtract, increment and decrement + functions that don't return a value, especially when used for reference + counting. These functions do not imply memory barriers. + + As an example, consider a piece of code that marks an object as being dead + and then decrements the object's reference count: + + obj->dead = 1; + smp_mb__before_atomic_dec(); + atomic_dec(&obj->ref_count); + + This makes sure that the death mark on the object is perceived to be set + *before* the reference counter is decremented. + + See Documentation/atomic_ops.txt for more information. See the "Atomic + operations" subsection for information on where to use these. + + + (*) smp_mb__before_clear_bit(void); + (*) smp_mb__after_clear_bit(void); + + These are for use similar to the atomic inc/dec barriers. These are + typically used for bitwise unlocking operations, so care must be taken as + there are no implicit memory barriers here either. + + Consider implementing an unlock operation of some nature by clearing a + locking bit. The clear_bit() would then need to be barriered like this: + + smp_mb__before_clear_bit(); + clear_bit( ... ); + + This prevents memory operations before the clear leaking to after it. See + the subsection on "Locking Functions" with reference to UNLOCK operation + implications. + + See Documentation/atomic_ops.txt for more information. See the "Atomic + operations" subsection for information on where to use these. + + +MMIO WRITE BARRIER +------------------ + +The Linux kernel also has a special barrier for use with memory-mapped I/O +writes: + + mmiowb(); + +This is a variation on the mandatory write barrier that causes writes to weakly +ordered I/O regions to be partially ordered. Its effects may go beyond the +CPU->Hardware interface and actually affect the hardware at some level. + +See the subsection "Locks vs I/O accesses" for more information. + + +=============================== +IMPLICIT KERNEL MEMORY BARRIERS +=============================== + +Some of the other functions in the linux kernel imply memory barriers, amongst +which are locking, scheduling and memory allocation functions. + +This specification is a _minimum_ guarantee; any particular architecture may +provide more substantial guarantees, but these may not be relied upon outside +of arch specific code. + + +LOCKING FUNCTIONS +----------------- + +The Linux kernel has a number of locking constructs: + + (*) spin locks + (*) R/W spin locks + (*) mutexes + (*) semaphores + (*) R/W semaphores + (*) RCU + +In all cases there are variants on "LOCK" operations and "UNLOCK" operations +for each construct. These operations all imply certain barriers: + + (1) LOCK operation implication: + + Memory operations issued after the LOCK will be completed after the LOCK + operation has completed. + + Memory operations issued before the LOCK may be completed after the LOCK + operation has completed. + + (2) UNLOCK operation implication: + + Memory operations issued before the UNLOCK will be completed before the + UNLOCK operation has completed. + + Memory operations issued after the UNLOCK may be completed before the + UNLOCK operation has completed. + + (3) LOCK vs LOCK implication: + + All LOCK operations issued before another LOCK operation will be completed + before that LOCK operation. + + (4) LOCK vs UNLOCK implication: + + All LOCK operations issued before an UNLOCK operation will be completed + before the UNLOCK operation. + + All UNLOCK operations issued before a LOCK operation will be completed + before the LOCK operation. + + (5) Failed conditional LOCK implication: + + Certain variants of the LOCK operation may fail, either due to being + unable to get the lock immediately, or due to receiving an unblocked + signal whilst asleep waiting for the lock to become available. Failed + locks do not imply any sort of barrier. + +Therefore, from (1), (2) and (4) an UNLOCK followed by an unconditional LOCK is +equivalent to a full barrier, but a LOCK followed by an UNLOCK is not. + +[!] Note: one of the consequence of LOCKs and UNLOCKs being only one-way + barriers is that the effects instructions outside of a critical section may + seep into the inside of the critical section. + +Locks and semaphores may not provide any guarantee of ordering on UP compiled +systems, and so cannot be counted on in such a situation to actually achieve +anything at all - especially with respect to I/O accesses - unless combined +with interrupt disabling operations. + +See also the section on "Inter-CPU locking barrier effects". + + +As an example, consider the following: + + *A = a; + *B = b; + LOCK + *C = c; + *D = d; + UNLOCK + *E = e; + *F = f; + +The following sequence of events is acceptable: + + LOCK, {*F,*A}, *E, {*C,*D}, *B, UNLOCK + + [+] Note that {*F,*A} indicates a combined access. + +But none of the following are: + + {*F,*A}, *B, LOCK, *C, *D, UNLOCK, *E + *A, *B, *C, LOCK, *D, UNLOCK, *E, *F + *A, *B, LOCK, *C, UNLOCK, *D, *E, *F + *B, LOCK, *C, *D, UNLOCK, {*F,*A}, *E + + + +INTERRUPT DISABLING FUNCTIONS +----------------------------- + +Functions that disable interrupts (LOCK equivalent) and enable interrupts +(UNLOCK equivalent) will act as compiler barriers only. So if memory or I/O +barriers are required in such a situation, they must be provided from some +other means. + + +MISCELLANEOUS FUNCTIONS +----------------------- + +Other functions that imply barriers: + + (*) schedule() and similar imply full memory barriers. + + (*) Memory allocation and release functions imply full memory barriers. + + +================================= +INTER-CPU LOCKING BARRIER EFFECTS +================================= + +On SMP systems locking primitives give a more substantial form of barrier: one +that does affect memory access ordering on other CPUs, within the context of +conflict on any particular lock. + + +LOCKS VS MEMORY ACCESSES +------------------------ + +Consider the following: the system has a pair of spinlocks (N) and (Q), and +three CPUs; then should the following sequence of events occur: + + CPU 1 CPU 2 + =============================== =============================== + *A = a; *E = e; + LOCK M LOCK Q + *B = b; *F = f; + *C = c; *G = g; + UNLOCK M UNLOCK Q + *D = d; *H = h; + +Then there is no guarantee as to what order CPU #3 will see the accesses to *A +through *H occur in, other than the constraints imposed by the separate locks +on the separate CPUs. It might, for example, see: + + *E, LOCK M, LOCK Q, *G, *C, *F, *A, *B, UNLOCK Q, *D, *H, UNLOCK M + +But it won't see any of: + + *B, *C or *D preceding LOCK M + *A, *B or *C following UNLOCK M + *F, *G or *H preceding LOCK Q + *E, *F or *G following UNLOCK Q + + +However, if the following occurs: + + CPU 1 CPU 2 + =============================== =============================== + *A = a; + LOCK M [1] + *B = b; + *C = c; + UNLOCK M [1] + *D = d; *E = e; + LOCK M [2] + *F = f; + *G = g; + UNLOCK M [2] + *H = h; + +CPU #3 might see: + + *E, LOCK M [1], *C, *B, *A, UNLOCK M [1], + LOCK M [2], *H, *F, *G, UNLOCK M [2], *D + +But assuming CPU #1 gets the lock first, it won't see any of: + + *B, *C, *D, *F, *G or *H preceding LOCK M [1] + *A, *B or *C following UNLOCK M [1] + *F, *G or *H preceding LOCK M [2] + *A, *B, *C, *E, *F or *G following UNLOCK M [2] + + +LOCKS VS I/O ACCESSES +--------------------- + +Under certain circumstances (especially involving NUMA), I/O accesses within +two spinlocked sections on two different CPUs may be seen as interleaved by the +PCI bridge, because the PCI bridge does not necessarily participate in the +cache-coherence protocol, and is therefore incapable of issuing the required +read memory barriers. + +For example: + + CPU 1 CPU 2 + =============================== =============================== + spin_lock(Q) + writel(0, ADDR) + writel(1, DATA); + spin_unlock(Q); + spin_lock(Q); + writel(4, ADDR); + writel(5, DATA); + spin_unlock(Q); + +may be seen by the PCI bridge as follows: + + STORE *ADDR = 0, STORE *ADDR = 4, STORE *DATA = 1, STORE *DATA = 5 + +which would probably cause the hardware to malfunction. + + +What is necessary here is to intervene with an mmiowb() before dropping the +spinlock, for example: + + CPU 1 CPU 2 + =============================== =============================== + spin_lock(Q) + writel(0, ADDR) + writel(1, DATA); + mmiowb(); + spin_unlock(Q); + spin_lock(Q); + writel(4, ADDR); + writel(5, DATA); + mmiowb(); + spin_unlock(Q); + +this will ensure that the two stores issued on CPU #1 appear at the PCI bridge +before either of the stores issued on CPU #2. + + +Furthermore, following a store by a load to the same device obviates the need +for an mmiowb(), because the load forces the store to complete before the load +is performed: + + CPU 1 CPU 2 + =============================== =============================== + spin_lock(Q) + writel(0, ADDR) + a = readl(DATA); + spin_unlock(Q); + spin_lock(Q); + writel(4, ADDR); + b = readl(DATA); + spin_unlock(Q); + + +See Documentation/DocBook/deviceiobook.tmpl for more information. + + +================================= +WHERE ARE MEMORY BARRIERS NEEDED? +================================= + +Under normal operation, memory operation reordering is generally not going to +be a problem as a single-threaded linear piece of code will still appear to +work correctly, even if it's in an SMP kernel. There are, however, three +circumstances in which reordering definitely _could_ be a problem: + + (*) Interprocessor interaction. + + (*) Atomic operations. + + (*) Accessing devices (I/O). + + (*) Interrupts. + + +INTERPROCESSOR INTERACTION +-------------------------- + +When there's a system with more than one processor, more than one CPU in the +system may be working on the same data set at the same time. This can cause +synchronisation problems, and the usual way of dealing with them is to use +locks. Locks, however, are quite expensive, and so it may be preferable to +operate without the use of a lock if at all possible. In such a case +operations that affect both CPUs may have to be carefully ordered to prevent +a malfunction. + +Consider, for example, the R/W semaphore slow path. Here a waiting process is +queued on the semaphore, by virtue of it having a piece of its stack linked to +the semaphore's list of waiting processes: + + struct rw_semaphore { + ... + spinlock_t lock; + struct list_head waiters; + }; + + struct rwsem_waiter { + struct list_head list; + struct task_struct *task; + }; + +To wake up a particular waiter, the up_read() or up_write() functions have to: + + (1) read the next pointer from this waiter's record to know as to where the + next waiter record is; + + (4) read the pointer to the waiter's task structure; + + (3) clear the task pointer to tell the waiter it has been given the semaphore; + + (4) call wake_up_process() on the task; and + + (5) release the reference held on the waiter's task struct. + +In otherwords, it has to perform this sequence of events: + + LOAD waiter->list.next; + LOAD waiter->task; + STORE waiter->task; + CALL wakeup + RELEASE task + +and if any of these steps occur out of order, then the whole thing may +malfunction. + +Once it has queued itself and dropped the semaphore lock, the waiter does not +get the lock again; it instead just waits for its task pointer to be cleared +before proceeding. Since the record is on the waiter's stack, this means that +if the task pointer is cleared _before_ the next pointer in the list is read, +another CPU might start processing the waiter and might clobber the waiter's +stack before the up*() function has a chance to read the next pointer. + +Consider then what might happen to the above sequence of events: + + CPU 1 CPU 2 + =============================== =============================== + down_xxx() + Queue waiter + Sleep + up_yyy() + LOAD waiter->task; + STORE waiter->task; + Woken up by other event + + Resume processing + down_xxx() returns + call foo() + foo() clobbers *waiter + + LOAD waiter->list.next; + --- OOPS --- + +This could be dealt with using the semaphore lock, but then the down_xxx() +function has to needlessly get the spinlock again after being woken up. + +The way to deal with this is to insert a general SMP memory barrier: + + LOAD waiter->list.next; + LOAD waiter->task; + smp_mb(); + STORE waiter->task; + CALL wakeup + RELEASE task + +In this case, the barrier makes a guarantee that all memory accesses before the +barrier will appear to happen before all the memory accesses after the barrier +with respect to the other CPUs on the system. It does _not_ guarantee that all +the memory accesses before the barrier will be complete by the time the barrier +instruction itself is complete. + +On a UP system - where this wouldn't be a problem - the smp_mb() is just a +compiler barrier, thus making sure the compiler emits the instructions in the +right order without actually intervening in the CPU. Since there there's only +one CPU, that CPU's dependency ordering logic will take care of everything +else. + + +ATOMIC OPERATIONS +----------------- + +Whilst they are technically interprocessor interaction considerations, atomic +operations are noted specially as some of them imply full memory barriers and +some don't, but they're very heavily relied on as a group throughout the +kernel. + +Any atomic operation that modifies some state in memory and returns information +about the state (old or new) implies an SMP-conditional general memory barrier +(smp_mb()) on each side of the actual operation. These include: + + xchg(); + cmpxchg(); + atomic_cmpxchg(); + atomic_inc_return(); + atomic_dec_return(); + atomic_add_return(); + atomic_sub_return(); + atomic_inc_and_test(); + atomic_dec_and_test(); + atomic_sub_and_test(); + atomic_add_negative(); + atomic_add_unless(); + test_and_set_bit(); + test_and_clear_bit(); + test_and_change_bit(); + +These are used for such things as implementing LOCK-class and UNLOCK-class +operations and adjusting reference counters towards object destruction, and as +such the implicit memory barrier effects are necessary. + + +The following operation are potential problems as they do _not_ imply memory +barriers, but might be used for implementing such things as UNLOCK-class +operations: + + atomic_set(); + set_bit(); + clear_bit(); + change_bit(); + +With these the appropriate explicit memory barrier should be used if necessary +(smp_mb__before_clear_bit() for instance). + + +The following also do _not_ imply memory barriers, and so may require explicit +memory barriers under some circumstances (smp_mb__before_atomic_dec() for +instance)): + + atomic_add(); + atomic_sub(); + atomic_inc(); + atomic_dec(); + +If they're used for statistics generation, then they probably don't need memory +barriers, unless there's a coupling between statistical data. + +If they're used for reference counting on an object to control its lifetime, +they probably don't need memory barriers because either the reference count +will be adjusted inside a locked section, or the caller will already hold +sufficient references to make the lock, and thus a memory barrier unnecessary. + +If they're used for constructing a lock of some description, then they probably +do need memory barriers as a lock primitive generally has to do things in a +specific order. + + +Basically, each usage case has to be carefully considered as to whether memory +barriers are needed or not. + +[!] Note that special memory barrier primitives are available for these +situations because on some CPUs the atomic instructions used imply full memory +barriers, and so barrier instructions are superfluous in conjunction with them, +and in such cases the special barrier primitives will be no-ops. + +See Documentation/atomic_ops.txt for more information. + + +ACCESSING DEVICES +----------------- + +Many devices can be memory mapped, and so appear to the CPU as if they're just +a set of memory locations. To control such a device, the driver usually has to +make the right memory accesses in exactly the right order. + +However, having a clever CPU or a clever compiler creates a potential problem +in that the carefully sequenced accesses in the driver code won't reach the +device in the requisite order if the CPU or the compiler thinks it is more +efficient to reorder, combine or merge accesses - something that would cause +the device to malfunction. + +Inside of the Linux kernel, I/O should be done through the appropriate accessor +routines - such as inb() or writel() - which know how to make such accesses +appropriately sequential. Whilst this, for the most part, renders the explicit +use of memory barriers unnecessary, there are a couple of situations where they +might be needed: + + (1) On some systems, I/O stores are not strongly ordered across all CPUs, and + so for _all_ general drivers locks should be used and mmiowb() must be + issued prior to unlocking the critical section. + + (2) If the accessor functions are used to refer to an I/O memory window with + relaxed memory access properties, then _mandatory_ memory barriers are + required to enforce ordering. + +See Documentation/DocBook/deviceiobook.tmpl for more information. + + +INTERRUPTS +---------- + +A driver may be interrupted by its own interrupt service routine, and thus the +two parts of the driver may interfere with each other's attempts to control or +access the device. + +This may be alleviated - at least in part - by disabling local interrupts (a +form of locking), such that the critical operations are all contained within +the interrupt-disabled section in the driver. Whilst the driver's interrupt +routine is executing, the driver's core may not run on the same CPU, and its +interrupt is not permitted to happen again until the current interrupt has been +handled, thus the interrupt handler does not need to lock against that. + +However, consider a driver that was talking to an ethernet card that sports an +address register and a data register. If that driver's core talks to the card +under interrupt-disablement and then the driver's interrupt handler is invoked: + + LOCAL IRQ DISABLE + writew(ADDR, 3); + writew(DATA, y); + LOCAL IRQ ENABLE + + writew(ADDR, 4); + q = readw(DATA); + + +The store to the data register might happen after the second store to the +address register if ordering rules are sufficiently relaxed: + + STORE *ADDR = 3, STORE *ADDR = 4, STORE *DATA = y, q = LOAD *DATA + + +If ordering rules are relaxed, it must be assumed that accesses done inside an +interrupt disabled section may leak outside of it and may interleave with +accesses performed in an interrupt - and vice versa - unless implicit or +explicit barriers are used. + +Normally this won't be a problem because the I/O accesses done inside such +sections will include synchronous load operations on strictly ordered I/O +registers that form implicit I/O barriers. If this isn't sufficient then an +mmiowb() may need to be used explicitly. + + +A similar situation may occur between an interrupt routine and two routines +running on separate CPUs that communicate with each other. If such a case is +likely, then interrupt-disabling locks should be used to guarantee ordering. + + +========================== +KERNEL I/O BARRIER EFFECTS +========================== + +When accessing I/O memory, drivers should use the appropriate accessor +functions: + + (*) inX(), outX(): + + These are intended to talk to I/O space rather than memory space, but + that's primarily a CPU-specific concept. The i386 and x86_64 processors do + indeed have special I/O space access cycles and instructions, but many + CPUs don't have such a concept. + + The PCI bus, amongst others, defines an I/O space concept - which on such + CPUs as i386 and x86_64 cpus readily maps to the CPU's concept of I/O + space. However, it may also mapped as a virtual I/O space in the CPU's + memory map, particularly on those CPUs that don't support alternate + I/O spaces. + + Accesses to this space may be fully synchronous (as on i386), but + intermediary bridges (such as the PCI host bridge) may not fully honour + that. + + They are guaranteed to be fully ordered with respect to each other. + + They are not guaranteed to be fully ordered with respect to other types of + memory and I/O operation. + + (*) readX(), writeX(): + + Whether these are guaranteed to be fully ordered and uncombined with + respect to each other on the issuing CPU depends on the characteristics + defined for the memory window through which they're accessing. On later + i386 architecture machines, for example, this is controlled by way of the + MTRR registers. + + Ordinarily, these will be guaranteed to be fully ordered and uncombined,, + provided they're not accessing a prefetchable device. + + However, intermediary hardware (such as a PCI bridge) may indulge in + deferral if it so wishes; to flush a store, a load from the same location + is preferred[*], but a load from the same device or from configuration + space should suffice for PCI. + + [*] NOTE! attempting to load from the same location as was written to may + cause a malfunction - consider the 16550 Rx/Tx serial registers for + example. + + Used with prefetchable I/O memory, an mmiowb() barrier may be required to + force stores to be ordered. + + Please refer to the PCI specification for more information on interactions + between PCI transactions. + + (*) readX_relaxed() + + These are similar to readX(), but are not guaranteed to be ordered in any + way. Be aware that there is no I/O read barrier available. + + (*) ioreadX(), iowriteX() + + These will perform as appropriate for the type of access they're actually + doing, be it inX()/outX() or readX()/writeX(). + + +======================================== +ASSUMED MINIMUM EXECUTION ORDERING MODEL +======================================== + +It has to be assumed that the conceptual CPU is weakly-ordered but that it will +maintain the appearance of program causality with respect to itself. Some CPUs +(such as i386 or x86_64) are more constrained than others (such as powerpc or +frv), and so the most relaxed case (namely DEC Alpha) must be assumed outside +of arch-specific code. + +This means that it must be considered that the CPU will execute its instruction +stream in any order it feels like - or even in parallel - provided that if an +instruction in the stream depends on the an earlier instruction, then that +earlier instruction must be sufficiently complete[*] before the later +instruction may proceed; in other words: provided that the appearance of +causality is maintained. + + [*] Some instructions have more than one effect - such as changing the + condition codes, changing registers or changing memory - and different + instructions may depend on different effects. + +A CPU may also discard any instruction sequence that winds up having no +ultimate effect. For example, if two adjacent instructions both load an +immediate value into the same register, the first may be discarded. + + +Similarly, it has to be assumed that compiler might reorder the instruction +stream in any way it sees fit, again provided the appearance of causality is +maintained. + + +============================ +THE EFFECTS OF THE CPU CACHE +============================ + +The way cached memory operations are perceived across the system is affected to +a certain extent by the caches that lie between CPUs and memory, and by the +memory coherence system that maintains the consistency of state in the system. + +As far as the way a CPU interacts with another part of the system through the +caches goes, the memory system has to include the CPU's caches, and memory +barriers for the most part act at the interface between the CPU and its cache +(memory barriers logically act on the dotted line in the following diagram): + + <--- CPU ---> : <----------- Memory -----------> + : + +--------+ +--------+ : +--------+ +-----------+ + | | | | : | | | | +--------+ + | CPU | | Memory | : | CPU | | | | | + | Core |--->| Access |----->| Cache |<-->| | | | + | | | Queue | : | | | |--->| Memory | + | | | | : | | | | | | + +--------+ +--------+ : +--------+ | | | | + : | Cache | +--------+ + : | Coherency | + : | Mechanism | +--------+ + +--------+ +--------+ : +--------+ | | | | + | | | | : | | | | | | + | CPU | | Memory | : | CPU | | |--->| Device | + | Core |--->| Access |----->| Cache |<-->| | | | + | | | Queue | : | | | | | | + | | | | : | | | | +--------+ + +--------+ +--------+ : +--------+ +-----------+ + : + : + +Although any particular load or store may not actually appear outside of the +CPU that issued it since it may have been satisfied within the CPU's own cache, +it will still appear as if the full memory access had taken place as far as the +other CPUs are concerned since the cache coherency mechanisms will migrate the +cacheline over to the accessing CPU and propagate the effects upon conflict. + +The CPU core may execute instructions in any order it deems fit, provided the +expected program causality appears to be maintained. Some of the instructions +generate load and store operations which then go into the queue of memory +accesses to be performed. The core may place these in the queue in any order +it wishes, and continue execution until it is forced to wait for an instruction +to complete. + +What memory barriers are concerned with is controlling the order in which +accesses cross from the CPU side of things to the memory side of things, and +the order in which the effects are perceived to happen by the other observers +in the system. + +[!] Memory barriers are _not_ needed within a given CPU, as CPUs always see +their own loads and stores as if they had happened in program order. + +[!] MMIO or other device accesses may bypass the cache system. This depends on +the properties of the memory window through which devices are accessed and/or +the use of any special device communication instructions the CPU may have. + + +CACHE COHERENCY +--------------- + +Life isn't quite as simple as it may appear above, however: for while the +caches are expected to be coherent, there's no guarantee that that coherency +will be ordered. This means that whilst changes made on one CPU will +eventually become visible on all CPUs, there's no guarantee that they will +become apparent in the same order on those other CPUs. + + +Consider dealing with a system that has pair of CPUs (1 & 2), each of which has +a pair of parallel data caches (CPU 1 has A/B, and CPU 2 has C/D): + + : + : +--------+ + : +---------+ | | + +--------+ : +--->| Cache A |<------->| | + | | : | +---------+ | | + | CPU 1 |<---+ | | + | | : | +---------+ | | + +--------+ : +--->| Cache B |<------->| | + : +---------+ | | + : | Memory | + : +---------+ | System | + +--------+ : +--->| Cache C |<------->| | + | | : | +---------+ | | + | CPU 2 |<---+ | | + | | : | +---------+ | | + +--------+ : +--->| Cache D |<------->| | + : +---------+ | | + : +--------+ + : + +Imagine the system has the following properties: + + (*) an odd-numbered cache line may be in cache A, cache C or it may still be + resident in memory; + + (*) an even-numbered cache line may be in cache B, cache D or it may still be + resident in memory; + + (*) whilst the CPU core is interrogating one cache, the other cache may be + making use of the bus to access the rest of the system - perhaps to + displace a dirty cacheline or to do a speculative load; + + (*) each cache has a queue of operations that need to be applied to that cache + to maintain coherency with the rest of the system; + + (*) the coherency queue is not flushed by normal loads to lines already + present in the cache, even though the contents of the queue may + potentially effect those loads. + +Imagine, then, that two writes are made on the first CPU, with a write barrier +between them to guarantee that they will appear to reach that CPU's caches in +the requisite order: + + CPU 1 CPU 2 COMMENT + =============== =============== ======================================= + u == 0, v == 1 and p == &u, q == &u + v = 2; + smp_wmb(); Make sure change to v visible before + change to p + v is now in cache A exclusively + p = &v; + p is now in cache B exclusively + +The write memory barrier forces the other CPUs in the system to perceive that +the local CPU's caches have apparently been updated in the correct order. But +now imagine that the second CPU that wants to read those values: + + CPU 1 CPU 2 COMMENT + =============== =============== ======================================= + ... + q = p; + x = *q; + +The above pair of reads may then fail to happen in expected order, as the +cacheline holding p may get updated in one of the second CPU's caches whilst +the update to the cacheline holding v is delayed in the other of the second +CPU's caches by some other cache event: + + CPU 1 CPU 2 COMMENT + =============== =============== ======================================= + u == 0, v == 1 and p == &u, q == &u + v = 2; + smp_wmb(); + + + p = &b; q = p; + + + + x = *q; + Reads from v before v updated in cache + + + +Basically, whilst both cachelines will be updated on CPU 2 eventually, there's +no guarantee that, without intervention, the order of update will be the same +as that committed on CPU 1. + + +To intervene, we need to interpolate a data dependency barrier or a read +barrier between the loads. This will force the cache to commit its coherency +queue before processing any further requests: + + CPU 1 CPU 2 COMMENT + =============== =============== ======================================= + u == 0, v == 1 and p == &u, q == &u + v = 2; + smp_wmb(); + + + p = &b; q = p; + + + + smp_read_barrier_depends() + + + x = *q; + Reads from v after v updated in cache + + +This sort of problem can be encountered on DEC Alpha processors as they have a +split cache that improves performance by making better use of the data bus. +Whilst most CPUs do imply a data dependency barrier on the read when a memory +access depends on a read, not all do, so it may not be relied on. + +Other CPUs may also have split caches, but must coordinate between the various +cachelets for normal memory accesss. The semantics of the Alpha removes the +need for coordination in absence of memory barriers. + + +CACHE COHERENCY VS DMA +---------------------- + +Not all systems maintain cache coherency with respect to devices doing DMA. In +such cases, a device attempting DMA may obtain stale data from RAM because +dirty cache lines may be resident in the caches of various CPUs, and may not +have been written back to RAM yet. To deal with this, the appropriate part of +the kernel must flush the overlapping bits of cache on each CPU (and maybe +invalidate them as well). + +In addition, the data DMA'd to RAM by a device may be overwritten by dirty +cache lines being written back to RAM from a CPU's cache after the device has +installed its own data, or cache lines simply present in a CPUs cache may +simply obscure the fact that RAM has been updated, until at such time as the +cacheline is discarded from the CPU's cache and reloaded. To deal with this, +the appropriate part of the kernel must invalidate the overlapping bits of the +cache on each CPU. + +See Documentation/cachetlb.txt for more information on cache management. + + +CACHE COHERENCY VS MMIO +----------------------- + +Memory mapped I/O usually takes place through memory locations that are part of +a window in the CPU's memory space that have different properties assigned than +the usual RAM directed window. + +Amongst these properties is usually the fact that such accesses bypass the +caching entirely and go directly to the device buses. This means MMIO accesses +may, in effect, overtake accesses to cached memory that were emitted earlier. +A memory barrier isn't sufficient in such a case, but rather the cache must be +flushed between the cached memory write and the MMIO access if the two are in +any way dependent. + + +========================= +THE THINGS CPUS GET UP TO +========================= + +A programmer might take it for granted that the CPU will perform memory +operations in exactly the order specified, so that if a CPU is, for example, +given the following piece of code to execute: + + a = *A; + *B = b; + c = *C; + d = *D; + *E = e; + +They would then expect that the CPU will complete the memory operation for each +instruction before moving on to the next one, leading to a definite sequence of +operations as seen by external observers in the system: + + LOAD *A, STORE *B, LOAD *C, LOAD *D, STORE *E. + + +Reality is, of course, much messier. With many CPUs and compilers, the above +assumption doesn't hold because: + + (*) loads are more likely to need to be completed immediately to permit + execution progress, whereas stores can often be deferred without a + problem; + + (*) loads may be done speculatively, and the result discarded should it prove + to have been unnecessary; + + (*) loads may be done speculatively, leading to the result having being + fetched at the wrong time in the expected sequence of events; + + (*) the order of the memory accesses may be rearranged to promote better use + of the CPU buses and caches; + + (*) loads and stores may be combined to improve performance when talking to + memory or I/O hardware that can do batched accesses of adjacent locations, + thus cutting down on transaction setup costs (memory and PCI devices may + both be able to do this); and + + (*) the CPU's data cache may affect the ordering, and whilst cache-coherency + mechanisms may alleviate this - once the store has actually hit the cache + - there's no guarantee that the coherency management will be propagated in + order to other CPUs. + +So what another CPU, say, might actually observe from the above piece of code +is: + + LOAD *A, ..., LOAD {*C,*D}, STORE *E, STORE *B + + (Where "LOAD {*C,*D}" is a combined load) + + +However, it is guaranteed that a CPU will be self-consistent: it will see its +_own_ accesses appear to be correctly ordered, without the need for a memory +barrier. For instance with the following code: + + U = *A; + *A = V; + *A = W; + X = *A; + *A = Y; + Z = *A; + +and assuming no intervention by an external influence, it can be assumed that +the final result will appear to be: + + U == the original value of *A + X == W + Z == Y + *A == Y + +The code above may cause the CPU to generate the full sequence of memory +accesses: + + U=LOAD *A, STORE *A=V, STORE *A=W, X=LOAD *A, STORE *A=Y, Z=LOAD *A + +in that order, but, without intervention, the sequence may have almost any +combination of elements combined or discarded, provided the program's view of +the world remains consistent. + +The compiler may also combine, discard or defer elements of the sequence before +the CPU even sees them. + +For instance: + + *A = V; + *A = W; + +may be reduced to: + + *A = W; + +since, without a write barrier, it can be assumed that the effect of the +storage of V to *A is lost. Similarly: + + *A = Y; + Z = *A; + +may, without a memory barrier, be reduced to: + + *A = Y; + Z = Y; + +and the LOAD operation never appear outside of the CPU. + + +AND THEN THERE'S THE ALPHA +-------------------------- + +The DEC Alpha CPU is one of the most relaxed CPUs there is. Not only that, +some versions of the Alpha CPU have a split data cache, permitting them to have +two semantically related cache lines updating at separate times. This is where +the data dependency barrier really becomes necessary as this synchronises both +caches with the memory coherence system, thus making it seem like pointer +changes vs new data occur in the right order. + +The Alpha defines the Linux's kernel's memory barrier model. + +See the subsection on "Cache Coherency" above. + + +========== +REFERENCES +========== + +Alpha AXP Architecture Reference Manual, Second Edition (Sites & Witek, +Digital Press) + Chapter 5.2: Physical Address Space Characteristics + Chapter 5.4: Caches and Write Buffers + Chapter 5.5: Data Sharing + Chapter 5.6: Read/Write Ordering + +AMD64 Architecture Programmer's Manual Volume 2: System Programming + Chapter 7.1: Memory-Access Ordering + Chapter 7.4: Buffering and Combining Memory Writes + +IA-32 Intel Architecture Software Developer's Manual, Volume 3: +System Programming Guide + Chapter 7.1: Locked Atomic Operations + Chapter 7.2: Memory Ordering + Chapter 7.4: Serializing Instructions + +The SPARC Architecture Manual, Version 9 + Chapter 8: Memory Models + Appendix D: Formal Specification of the Memory Models + Appendix J: Programming with the Memory Models + +UltraSPARC Programmer Reference Manual + Chapter 5: Memory Accesses and Cacheability + Chapter 15: Sparc-V9 Memory Models + +UltraSPARC III Cu User's Manual + Chapter 9: Memory Models + +UltraSPARC IIIi Processor User's Manual + Chapter 8: Memory Models + +UltraSPARC Architecture 2005 + Chapter 9: Memory + Appendix D: Formal Specifications of the Memory Models + +UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005 + Chapter 8: Memory Models + Appendix F: Caches and Cache Coherency + +Solaris Internals, Core Kernel Architecture, p63-68: + Chapter 3.3: Hardware Considerations for Locks and + Synchronization + +Unix Systems for Modern Architectures, Symmetric Multiprocessing and Caching +for Kernel Programmers: + Chapter 13: Other Memory Models + +Intel Itanium Architecture Software Developer's Manual: Volume 1: + Section 2.6: Speculation + Section 4.4: Memory Access diff --git a/Documentation/mtrr.txt b/Documentation/mtrr.txt index b78af1c32996..c39ac395970e 100644 --- a/Documentation/mtrr.txt +++ b/Documentation/mtrr.txt @@ -138,19 +138,29 @@ Reading MTRRs from a C program using ioctl()'s: */ #include +#include #include #include #include #include #include #include -#define MTRR_NEED_STRINGS #include #define TRUE 1 #define FALSE 0 #define ERRSTRING strerror (errno) +static char *mtrr_strings[MTRR_NUM_TYPES] = +{ + "uncachable", /* 0 */ + "write-combining", /* 1 */ + "?", /* 2 */ + "?", /* 3 */ + "write-through", /* 4 */ + "write-protect", /* 5 */ + "write-back", /* 6 */ +}; int main () { @@ -232,13 +242,22 @@ Creating MTRRs from a C programme using ioctl()'s: #include #include #include -#define MTRR_NEED_STRINGS #include #define TRUE 1 #define FALSE 0 #define ERRSTRING strerror (errno) +static char *mtrr_strings[MTRR_NUM_TYPES] = +{ + "uncachable", /* 0 */ + "write-combining", /* 1 */ + "?", /* 2 */ + "?", /* 3 */ + "write-through", /* 4 */ + "write-protect", /* 5 */ + "write-back", /* 6 */ +}; int main (int argc, char **argv) { diff --git a/Documentation/networking/TODO b/Documentation/networking/TODO deleted file mode 100644 index 66d36ff14bae..000000000000 --- a/Documentation/networking/TODO +++ /dev/null @@ -1,18 +0,0 @@ -To-do items for network drivers -------------------------------- - -* Move ethernet crc routine to generic code - -* (for 2.5) Integrate Jamal Hadi Salim's netdev Rx polling API change - -* Audit all net drivers to make sure magic packet / wake-on-lan / - similar features are disabled in the driver by default. - -* Audit all net drivers to make sure the module always prints out a - version string when loaded as a module, but only prints a version - string when built into the kernel if a device is detected. - -* Add ETHTOOL_GDRVINFO ioctl support to all ethernet drivers. - -* dmfe PCI DMA is totally wrong and only works on x86 - diff --git a/Documentation/networking/bcm43xx.txt b/Documentation/networking/bcm43xx.txt new file mode 100644 index 000000000000..28541d2bee1e --- /dev/null +++ b/Documentation/networking/bcm43xx.txt @@ -0,0 +1,36 @@ + + BCM43xx Linux Driver Project + ============================ + +About this software +------------------- + +The goal of this project is to develop a linux driver for Broadcom +BCM43xx chips, based on the specification at +http://bcm-specs.sipsolutions.net/ + +The project page is http://bcm43xx.berlios.de/ + + +Requirements +------------ + +1) Linux Kernel 2.6.16 or later + http://www.kernel.org/ + + You may want to configure your kernel with: + + CONFIG_DEBUG_FS (optional): + -> Kernel hacking + -> Debug Filesystem + +2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211 + modules: + http://softmac.sipsolutions.net/ + +3) Firmware Files + + Please try fwcutter. Fwcutter can extract the firmware from various + binary driver files. It supports driver files from Windows, MacOS and + Linux. You can get fwcutter from http://bcm43xx.berlios.de/. + Also, fwcutter comes with a README file for further instructions. diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 4fc8e9874320..aaf99d5f0dad 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt @@ -254,7 +254,7 @@ and, the number of frames be * / -Suposse the following parameters, which apply for 2.6 kernel and an +Suppose the following parameters, which apply for 2.6 kernel and an i386 architecture: = 131072 bytes diff --git a/Documentation/networking/tuntap.txt b/Documentation/networking/tuntap.txt index ec3d109d787a..76750fb9151a 100644 --- a/Documentation/networking/tuntap.txt +++ b/Documentation/networking/tuntap.txt @@ -138,7 +138,7 @@ This means that you have to read/write IP packets when you are using tun and ethernet frames when using tap. 5. What is the difference between BPF and TUN/TAP driver? -BFP is an advanced packet filter. It can be attached to existing +BPF is an advanced packet filter. It can be attached to existing network interface. It does not provide a virtual network interface. A TUN/TAP driver does provide a virtual network interface and it is possible to attach BPF to this interface. diff --git a/Documentation/networking/xfrm_sync.txt b/Documentation/networking/xfrm_sync.txt new file mode 100644 index 000000000000..8be626f7c0b8 --- /dev/null +++ b/Documentation/networking/xfrm_sync.txt @@ -0,0 +1,166 @@ + +The sync patches work is based on initial patches from +Krisztian and others and additional patches +from Jamal . + +The end goal for syncing is to be able to insert attributes + generate +events so that the an SA can be safely moved from one machine to another +for HA purposes. +The idea is to synchronize the SA so that the takeover machine can do +the processing of the SA as accurate as possible if it has access to it. + +We already have the ability to generate SA add/del/upd events. +These patches add ability to sync and have accurate lifetime byte (to +ensure proper decay of SAs) and replay counters to avoid replay attacks +with as minimal loss at failover time. +This way a backup stays as closely uptodate as an active member. + +Because the above items change for every packet the SA receives, +it is possible for a lot of the events to be generated. +For this reason, we also add a nagle-like algorithm to restrict +the events. i.e we are going to set thresholds to say "let me +know if the replay sequence threshold is reached or 10 secs have passed" +These thresholds are set system-wide via sysctls or can be updated +per SA. + +The identified items that need to be synchronized are: +- the lifetime byte counter +note that: lifetime time limit is not important if you assume the failover +machine is known ahead of time since the decay of the time countdown +is not driven by packet arrival. +- the replay sequence for both inbound and outbound + +1) Message Structure +---------------------- + +nlmsghdr:aevent_id:optional-TLVs. + +The netlink message types are: + +XFRM_MSG_NEWAE and XFRM_MSG_GETAE. + +A XFRM_MSG_GETAE does not have TLVs. +A XFRM_MSG_NEWAE will have at least two TLVs (as is +discussed further below). + +aevent_id structure looks like: + + struct xfrm_aevent_id { + struct xfrm_usersa_id sa_id; + __u32 flags; + }; + +xfrm_usersa_id in this message layout identifies the SA. + +flags are used to indicate different things. The possible +flags are: + XFRM_AE_RTHR=1, /* replay threshold*/ + XFRM_AE_RVAL=2, /* replay value */ + XFRM_AE_LVAL=4, /* lifetime value */ + XFRM_AE_ETHR=8, /* expiry timer threshold */ + XFRM_AE_CR=16, /* Event cause is replay update */ + XFRM_AE_CE=32, /* Event cause is timer expiry */ + XFRM_AE_CU=64, /* Event cause is policy update */ + +How these flags are used is dependent on the direction of the +message (kernel<->user) as well the cause (config, query or event). +This is described below in the different messages. + +The pid will be set appropriately in netlink to recognize direction +(0 to the kernel and pid = processid that created the event +when going from kernel to user space) + +A program needs to subscribe to multicast group XFRMNLGRP_AEVENTS +to get notified of these events. + +2) TLVS reflect the different parameters: +----------------------------------------- + +a) byte value (XFRMA_LTIME_VAL) +This TLV carries the running/current counter for byte lifetime since +last event. + +b)replay value (XFRMA_REPLAY_VAL) +This TLV carries the running/current counter for replay sequence since +last event. + +c)replay threshold (XFRMA_REPLAY_THRESH) +This TLV carries the threshold being used by the kernel to trigger events +when the replay sequence is exceeded. + +d) expiry timer (XFRMA_ETIMER_THRESH) +This is a timer value in milliseconds which is used as the nagle +value to rate limit the events. + +3) Default configurations for the parameters: +---------------------------------------------- + +By default these events should be turned off unless there is +at least one listener registered to listen to the multicast +group XFRMNLGRP_AEVENTS. + +Programs installing SAs will need to specify the two thresholds, however, +in order to not change existing applications such as racoon +we also provide default threshold values for these different parameters +in case they are not specified. + +the two sysctls/proc entries are: +a) /proc/sys/net/core/sysctl_xfrm_aevent_etime +used to provide default values for the XFRMA_ETIMER_THRESH in incremental +units of time of 100ms. The default is 10 (1 second) + +b) /proc/sys/net/core/sysctl_xfrm_aevent_rseqth +used to provide default values for XFRMA_REPLAY_THRESH parameter +in incremental packet count. The default is two packets. + +4) Message types +---------------- + +a) XFRM_MSG_GETAE issued by user-->kernel. +XFRM_MSG_GETAE does not carry any TLVs. +The response is a XFRM_MSG_NEWAE which is formatted based on what +XFRM_MSG_GETAE queried for. +The response will always have XFRMA_LTIME_VAL and XFRMA_REPLAY_VAL TLVs. +*if XFRM_AE_RTHR flag is set, then XFRMA_REPLAY_THRESH is also retrieved +*if XFRM_AE_ETHR flag is set, then XFRMA_ETIMER_THRESH is also retrieved + +b) XFRM_MSG_NEWAE is issued by either user space to configure +or kernel to announce events or respond to a XFRM_MSG_GETAE. + +i) user --> kernel to configure a specific SA. +any of the values or threshold parameters can be updated by passing the +appropriate TLV. +A response is issued back to the sender in user space to indicate success +or failure. +In the case of success, additionally an event with +XFRM_MSG_NEWAE is also issued to any listeners as described in iii). + +ii) kernel->user direction as a response to XFRM_MSG_GETAE +The response will always have XFRMA_LTIME_VAL and XFRMA_REPLAY_VAL TLVs. +The threshold TLVs will be included if explicitly requested in +the XFRM_MSG_GETAE message. + +iii) kernel->user to report as event if someone sets any values or +thresholds for an SA using XFRM_MSG_NEWAE (as described in #i above). +In such a case XFRM_AE_CU flag is set to inform the user that +the change happened as a result of an update. +The message will always have XFRMA_LTIME_VAL and XFRMA_REPLAY_VAL TLVs. + +iv) kernel->user to report event when replay threshold or a timeout +is exceeded. +In such a case either XFRM_AE_CR (replay exceeded) or XFRM_AE_CE (timeout +happened) is set to inform the user what happened. +Note the two flags are mutually exclusive. +The message will always have XFRMA_LTIME_VAL and XFRMA_REPLAY_VAL TLVs. + +Exceptions to threshold settings +-------------------------------- + +If you have an SA that is getting hit by traffic in bursts such that +there is a period where the timer threshold expires with no packets +seen, then an odd behavior is seen as follows: +The first packet arrival after a timer expiry will trigger a timeout +aevent; i.e we dont wait for a timeout period or a packet threshold +to be reached. This is done for simplicity and efficiency reasons. + +-JHS diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt index 97420f08c786..4739c5c3face 100644 --- a/Documentation/pcmcia/driver-changes.txt +++ b/Documentation/pcmcia/driver-changes.txt @@ -1,5 +1,11 @@ This file details changes in 2.6 which affect PCMCIA card driver authors: +* New release helper (as of 2.6.17) + Instead of calling pcmcia_release_{configuration,io,irq,win}, all that's + necessary now is calling pcmcia_disable_device. As there is no valid + reason left to call pcmcia_release_io and pcmcia_release_irq, the + exports for them were removed. + * Unify detach and REMOVAL event code, as well as attach and INSERTION code (as of 2.6.16) void (*remove) (struct pcmcia_device *dev); diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt index ee551c6ea235..217e51768b87 100644 --- a/Documentation/powerpc/booting-without-of.txt +++ b/Documentation/powerpc/booting-without-of.txt @@ -719,6 +719,11 @@ address which can extend beyond that limit. - model : this is your board name/model - #address-cells : address representation for "root" devices - #size-cells: the size representation for "root" devices + - device_type : This property shouldn't be necessary. However, if + you decide to create a device_type for your root node, make sure it + is _not_ "chrp" unless your platform is a pSeries or PAPR compliant + one for 64-bit, or a CHRP-type machine for 32-bit as this will + matched by the kernel this way. Additionally, some recommended properties are: diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt index 331afd791cbb..ce767b90bb0d 100644 --- a/Documentation/scsi/scsi_eh.txt +++ b/Documentation/scsi/scsi_eh.txt @@ -19,9 +19,9 @@ TABLE OF CONTENTS [2-1-1] Overview [2-1-2] Flow of scmds through EH [2-1-3] Flow of control - [2-2] EH through hostt->eh_strategy_handler() - [2-2-1] Pre hostt->eh_strategy_handler() SCSI midlayer conditions - [2-2-2] Post hostt->eh_strategy_handler() SCSI midlayer conditions + [2-2] EH through transportt->eh_strategy_handler() + [2-2-1] Pre transportt->eh_strategy_handler() SCSI midlayer conditions + [2-2-2] Post transportt->eh_strategy_handler() SCSI midlayer conditions [2-2-3] Things to consider @@ -413,9 +413,9 @@ scmd->allowed. layer of failure of the scmds. -[2-2] EH through hostt->eh_strategy_handler() +[2-2] EH through transportt->eh_strategy_handler() - hostt->eh_strategy_handler() is invoked in the place of + transportt->eh_strategy_handler() is invoked in the place of scsi_unjam_host() and it is responsible for whole recovery process. On completion, the handler should have made lower layers forget about all failed scmds and either ready for new commands or offline. Also, @@ -424,7 +424,7 @@ SCSI midlayer. IOW, of the steps described in [2-1-2], all steps except for #1 must be implemented by eh_strategy_handler(). -[2-2-1] Pre hostt->eh_strategy_handler() SCSI midlayer conditions +[2-2-1] Pre transportt->eh_strategy_handler() SCSI midlayer conditions The following conditions are true on entry to the handler. @@ -437,7 +437,7 @@ except for #1 must be implemented by eh_strategy_handler(). - shost->host_failed == shost->host_busy -[2-2-2] Post hostt->eh_strategy_handler() SCSI midlayer conditions +[2-2-2] Post transportt->eh_strategy_handler() SCSI midlayer conditions The following conditions must be true on exit from the handler. diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index 8bbae3e1abdf..75a535a975c3 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -804,7 +804,6 @@ Summary: eh_bus_reset_handler - issue SCSI bus reset eh_device_reset_handler - issue SCSI device reset eh_host_reset_handler - reset host (host bus adapter) - eh_strategy_handler - driver supplied alternate to scsi_unjam_host() info - supply information about given host ioctl - driver can respond to ioctls proc_info - supports /proc/scsi/{driver_name}/{host_no} @@ -969,24 +968,6 @@ Details: int eh_host_reset_handler(struct scsi_cmnd * scp) -/** - * eh_strategy_handler - driver supplied alternate to scsi_unjam_host() - * @shp: host on which error has occurred - * - * Returns TRUE if host unjammed, else FALSE. - * - * Locks: none - * - * Calling context: kernel thread - * - * Notes: Invoked from scsi_eh thread. LLD supplied alternate to - * scsi_unjam_host() found in scsi_error.c - * - * Optionally defined in: LLD - **/ - int eh_strategy_handler(struct Scsi_Host * shp) - - /** * info - supply information about given host: driver name plus data * to distinguish given host diff --git a/Documentation/serial/driver b/Documentation/serial/driver index 42ef9970bc86..df82116a9f26 100644 --- a/Documentation/serial/driver +++ b/Documentation/serial/driver @@ -3,14 +3,11 @@ -------------------- - $Id: driver,v 1.10 2002/07/22 15:27:30 rmk Exp $ - - This document is meant as a brief overview of some aspects of the new serial driver. It is not complete, any questions you have should be directed to -The reference implementation is contained within serial_amba.c. +The reference implementation is contained within amba_pl011.c. @@ -31,6 +28,11 @@ The serial core provides a few helper functions. This includes identifing the correct port structure (via uart_get_console) and decoding command line arguments (uart_parse_options). +There is also a helper function (uart_write_console) which performs a +character by character write, translating newlines to CRLF sequences. +Driver writers are recommended to use this function rather than implementing +their own version. + Locking ------- @@ -86,6 +88,7 @@ hardware. - TIOCM_DTR DTR signal. - TIOCM_OUT1 OUT1 signal. - TIOCM_OUT2 OUT2 signal. + - TIOCM_LOOP Set the port into loopback mode. If the appropriate bit is set, the signal should be driven active. If the bit is clear, the signal should be driven inactive. @@ -141,6 +144,10 @@ hardware. enable_ms(port) Enable the modem status interrupts. + This method may be called multiple times. Modem status + interrupts should be disabled when the shutdown method is + called. + Locking: port->lock taken. Interrupts: locally disabled. This call must not sleep @@ -160,6 +167,8 @@ hardware. state. Enable the port for reception. It should not activate RTS nor DTR; this will be done via a separate call to set_mctrl. + This method will only be called when the port is initially opened. + Locking: port_sem taken. Interrupts: globally disabled. @@ -169,6 +178,11 @@ hardware. RTS nor DTR; this will have already been done via a separate call to set_mctrl. + Drivers must not access port->info once this call has completed. + + This method will only be called when there are no more users of + this port. + Locking: port_sem taken. Interrupts: caller dependent. diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 1def6049784c..0ee2c7dfc482 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -120,6 +120,34 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. enable - enable card - Default: enabled, for PCI and ISA PnP cards + Module snd-adlib + ---------------- + + Module for AdLib FM cards. + + port - port # for OPL chip + + This module supports multiple cards. It does not support autoprobe, so + the port must be specified. For actual AdLib FM cards it will be 0x388. + Note that this card does not have PCM support and no mixer; only FM + synthesis. + + Make sure you have "sbiload" from the alsa-tools package available and, + after loading the module, find out the assigned ALSA sequencer port + number through "sbiload -l". Example output: + + Port Client name Port name + 64:0 OPL2 FM synth OPL2 FM Port + + Load the std.sb and drums.sb patches also supplied by sbiload: + + sbiload -p 64:0 std.sb drums.sb + + If you use this driver to drive an OPL3, you can use std.o3 and drums.o3 + instead. To have the card produce sound, use aplaymidi from alsa-utils: + + aplaymidi -p 64:0 foo.mid + Module snd-ad1816a ------------------ @@ -190,6 +218,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The power-management is supported. + Module snd-als300 + ----------------- + + Module for Avance Logic ALS300 and ALS300+ + + This module supports multiple cards. + + The power-management is supported. + Module snd-als4000 ------------------ @@ -701,6 +738,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. uniwill 3-jack F1734 2-jack lg LG laptop (m1 express dual) + lg-lw LG LW20 laptop test for testing/debugging purpose, almost all controls can be adjusted. Appearing only when compiled with $CONFIG_SND_DEBUG=y @@ -1013,6 +1051,23 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The power-management is supported. + Module snd-miro + --------------- + + Module for Miro soundcards: miroSOUND PCM 1 pro, + miroSOUND PCM 12, + miroSOUND PCM 20 Radio. + + port - Port # (0x530,0x604,0xe80,0xf40) + irq - IRQ # (5,7,9,10,11) + dma1 - 1st dma # (0,1,3) + dma2 - 2nd dma # (0,1) + mpu_port - MPU-401 port # (0x300,0x310,0x320,0x330) + mpu_irq - MPU-401 irq # (5,7,9,10) + fm_port - FM Port # (0x388) + wss - enable WSS mode + ide - enable onboard ide support + Module snd-mixart ----------------- @@ -1202,6 +1257,20 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The power-management is supported. + Module snd-riptide + ------------------ + + Module for Conexant Riptide chip + + joystick_port - Joystick port # (default: 0x200) + mpu_port - MPU401 port # (default: 0x330) + opl3_port - OPL3 port # (default: 0x388) + + This module supports multiple cards. + The driver requires the firmware loader support on kernel. + You need to install the firmware file "riptide.hex" to the standard + firmware path (e.g. /lib/firmware). + Module snd-rme32 ---------------- diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 6feef9e82b63..68eeebc17ff4 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -1123,8 +1123,8 @@ if ((err = pci_enable_device(pci)) < 0) return err; /* check PCI availability (28bit DMA) */ - if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || - pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { + if (pci_set_dma_mask(pci, DMA_28BIT_MASK) < 0 || + pci_set_consistent_dma_mask(pci, DMA_28BIT_MASK) < 0) { printk(KERN_ERR "error to set 28bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; @@ -1216,7 +1216,7 @@ The allocation of PCI resources is done in the probe() function, and usually an extra xxx_create() function is written for this - purpose. + purpose. @@ -1225,7 +1225,7 @@ allocating resources. Also, you need to set the proper PCI DMA mask to limit the accessed i/o range. In some cases, you might need to call pci_set_master() function, - too. + too. @@ -1236,8 +1236,8 @@ Now assume that this PCI device has an I/O port with 8 bytes and an interrupt. Then struct mychip will have the - following fields: + following fields: diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 8c7195455963..bca50903233f 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -52,7 +52,7 @@ 51 -> ProVideo PV952 [1540:9524] 52 -> AverMedia AverTV/305 [1461:2108] 53 -> ASUS TV-FM 7135 [1043:4845] - 54 -> LifeView FlyTV Platinum FM [5168:0214,1489:0214] + 54 -> LifeView FlyTV Platinum FM / Gold [5168:0214,1489:0214,5168:0304] 55 -> LifeView FlyDVB-T DUO [5168:0306] 56 -> Avermedia AVerTV 307 [1461:a70a] 57 -> Avermedia AVerTV GO 007 FM [1461:f31f] @@ -84,7 +84,7 @@ 83 -> Terratec Cinergy 250 PCI TV [153b:1160] 84 -> LifeView FlyDVB Trio [5168:0319] 85 -> AverTV DVB-T 777 [1461:2c05] - 86 -> LifeView FlyDVB-T [5168:0301] + 86 -> LifeView FlyDVB-T / Genius VideoWonder DVB-T [5168:0301,1489:0301] 87 -> ADS Instant TV Duo Cardbus PTV331 [0331:1421] 88 -> Tevion/KWorld DVB-T 220RF [17de:7201] 89 -> ELSA EX-VISION 700TV [1048:226c] @@ -92,3 +92,4 @@ 91 -> AVerMedia A169 B [1461:7360] 92 -> AVerMedia A169 B1 [1461:6360] 93 -> Medion 7134 Bridge #2 [16be:0005] + 94 -> LifeView FlyDVB-T Hybrid Cardbus [5168:3306,5168:3502] diff --git a/Documentation/usb/et61x251.txt b/Documentation/video4linux/et61x251.txt similarity index 100% rename from Documentation/usb/et61x251.txt rename to Documentation/video4linux/et61x251.txt diff --git a/Documentation/usb/ibmcam.txt b/Documentation/video4linux/ibmcam.txt similarity index 99% rename from Documentation/usb/ibmcam.txt rename to Documentation/video4linux/ibmcam.txt index c25003644131..4a40a2e99451 100644 --- a/Documentation/usb/ibmcam.txt +++ b/Documentation/video4linux/ibmcam.txt @@ -122,7 +122,7 @@ WHAT YOU NEED: - A Linux box with USB support (2.3/2.4; 2.2 w/backport may work) - A Video4Linux compatible frame grabber program such as xawtv. - + HOW TO COMPILE THE DRIVER: You need to compile the driver only if you are a developer diff --git a/Documentation/usb/ov511.txt b/Documentation/video4linux/ov511.txt similarity index 99% rename from Documentation/usb/ov511.txt rename to Documentation/video4linux/ov511.txt index a7fc0432bff1..142741e3c578 100644 --- a/Documentation/usb/ov511.txt +++ b/Documentation/video4linux/ov511.txt @@ -9,7 +9,7 @@ INTRODUCTION: This is a driver for the OV511, a USB-only chip used in many "webcam" devices. Any camera using the OV511/OV511+ and the OV6620/OV7610/20/20AE should work. -Video capture devices that use the Philips SAA7111A decoder also work. It +Video capture devices that use the Philips SAA7111A decoder also work. It supports streaming and capture of color or monochrome video via the Video4Linux API. Most V4L apps are compatible with it. Most resolutions with a width and height that are a multiple of 8 are supported. @@ -52,15 +52,15 @@ from it: chmod 666 /dev/video chmod 666 /dev/video0 (if necessary) - + Now you are ready to run a video app! Both vidcat and xawtv work well for me at 640x480. - + [Using vidcat:] vidcat -s 640x480 -p c > test.jpg xview test.jpg - + [Using xawtv:] From the main xawtv directory: @@ -70,7 +70,7 @@ From the main xawtv directory: make make install -Now you should be able to run xawtv. Right click for the options dialog. +Now you should be able to run xawtv. Right click for the options dialog. MODULE PARAMETERS: @@ -286,4 +286,3 @@ Randy Dunlap, and others. Big thanks to them for their pioneering work on that and the USB stack. Thanks to Bret Wallach for getting camera reg IO, ISOC, and image capture working. Thanks to Orion Sky Lawlor, Kevin Moore, and Claudio Matsuoka for their work as well. - diff --git a/Documentation/usb/se401.txt b/Documentation/video4linux/se401.txt similarity index 100% rename from Documentation/usb/se401.txt rename to Documentation/video4linux/se401.txt diff --git a/Documentation/usb/sn9c102.txt b/Documentation/video4linux/sn9c102.txt similarity index 98% rename from Documentation/usb/sn9c102.txt rename to Documentation/video4linux/sn9c102.txt index b957beae5607..142920bc011f 100644 --- a/Documentation/usb/sn9c102.txt +++ b/Documentation/video4linux/sn9c102.txt @@ -174,7 +174,7 @@ Module parameters are listed below: ------------------------------------------------------------------------------- Name: video_nr Type: short array (min = 0, max = 64) -Syntax: <-1|n[,...]> +Syntax: <-1|n[,...]> Description: Specify V4L2 minor mode number: -1 = use next available n = use minor number n @@ -187,7 +187,7 @@ Default: -1 ------------------------------------------------------------------------------- Name: force_munmap Type: bool array (min = 0, max = 64) -Syntax: <0|1[,...]> +Syntax: <0|1[,...]> Description: Force the application to unmap previously mapped buffer memory before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not all the applications support this feature. This parameter is @@ -206,7 +206,7 @@ Default: 2 ------------------------------------------------------------------------------- Name: debug Type: ushort -Syntax: +Syntax: Description: Debugging information level, from 0 to 3: 0 = none (use carefully) 1 = critical errors @@ -267,7 +267,7 @@ The sysfs interface also provides the "frame_header" entry, which exports the frame header of the most recent requested and captured video frame. The header is always 18-bytes long and is appended to every video frame by the SN9C10x controllers. As an example, this additional information can be used by the user -application for implementing auto-exposure features via software. +application for implementing auto-exposure features via software. The following table describes the frame header: @@ -441,7 +441,7 @@ blue pixels in one video frame. Each pixel is associated with a 8-bit long value and is disposed in memory according to the pattern shown below: B[0] G[1] B[2] G[3] ... B[m-2] G[m-1] -G[m] R[m+1] G[m+2] R[m+2] ... G[2m-2] R[2m-1] +G[m] R[m+1] G[m+2] R[m+2] ... G[2m-2] R[2m-1] ... ... B[(n-1)(m-2)] G[(n-1)(m-1)] ... G[n(m-2)] R[n(m-1)] @@ -472,12 +472,12 @@ The pixel reference value is calculated as follows: The algorithm purely describes the conversion from compressed Bayer code used in the SN9C10x chips to uncompressed Bayer. Additional steps are required to convert this to a color image (i.e. a color interpolation algorithm). - + The following Huffman codes have been found: -0: +0 (relative to reference pixel value) +0: +0 (relative to reference pixel value) 100: +4 101: -4? -1110xxxx: set absolute value to xxxx.0000 +1110xxxx: set absolute value to xxxx.0000 1101: +11 1111: -11 11001: +20 diff --git a/Documentation/usb/stv680.txt b/Documentation/video4linux/stv680.txt similarity index 82% rename from Documentation/usb/stv680.txt rename to Documentation/video4linux/stv680.txt index 6448041e7a37..4f8946f32f51 100644 --- a/Documentation/usb/stv680.txt +++ b/Documentation/video4linux/stv680.txt @@ -5,15 +5,15 @@ Copyright, 2001, Kevin Sisson INTRODUCTION: -STMicroelectronics produces the STV0680B chip, which comes in two -types, -001 and -003. The -003 version allows the recording and downloading -of sound clips from the camera, and allows a flash attachment. Otherwise, -it uses the same commands as the -001 version. Both versions support a -variety of SDRAM sizes and sensors, allowing for a maximum of 26 VGA or 20 -CIF pictures. The STV0680 supports either a serial or a usb interface, and +STMicroelectronics produces the STV0680B chip, which comes in two +types, -001 and -003. The -003 version allows the recording and downloading +of sound clips from the camera, and allows a flash attachment. Otherwise, +it uses the same commands as the -001 version. Both versions support a +variety of SDRAM sizes and sensors, allowing for a maximum of 26 VGA or 20 +CIF pictures. The STV0680 supports either a serial or a usb interface, and video is possible through the usb interface. -The following cameras are known to work with this driver, although any +The following cameras are known to work with this driver, although any camera with Vendor/Product codes of 0553/0202 should work: Aiptek Pencam (various models) @@ -34,15 +34,15 @@ http://www.linux-usb.org MODULE OPTIONS: When the driver is compiled as a module, you can set a "swapRGB=1" -option, if necessary, for those applications that require it -(such as xawtv). However, the driver should detect and set this +option, if necessary, for those applications that require it +(such as xawtv). However, the driver should detect and set this automatically, so this option should not normally be used. KNOWN PROBLEMS: -The driver seems to work better with the usb-ohci than the usb-uhci host -controller driver. +The driver seems to work better with the usb-ohci than the usb-uhci host +controller driver. HELP: @@ -50,6 +50,4 @@ The latest info on this driver can be found at: http://personal.clt.bellsouth.net/~kjsisson or at http://stv0680-usb.sourceforge.net -Any questions to me can be send to: kjsisson@bellsouth.net - - +Any questions to me can be send to: kjsisson@bellsouth.net \ No newline at end of file diff --git a/Documentation/usb/w9968cf.txt b/Documentation/video4linux/w9968cf.txt similarity index 97% rename from Documentation/usb/w9968cf.txt rename to Documentation/video4linux/w9968cf.txt index 9d46cd0b19e3..3b704f2aae6d 100644 --- a/Documentation/usb/w9968cf.txt +++ b/Documentation/video4linux/w9968cf.txt @@ -1,5 +1,5 @@ - W996[87]CF JPEG USB Dual Mode Camera Chip + W996[87]CF JPEG USB Dual Mode Camera Chip Driver for Linux 2.6 (basic version) ========================================= @@ -115,7 +115,7 @@ additional testing and full support, would be much appreciated. ====================== For it to work properly, the driver needs kernel support for Video4Linux, USB and I2C, and the "ovcamchip" module for the image sensor. Make sure you are not -actually using any external "ovcamchip" module, given that the W996[87]CF +actually using any external "ovcamchip" module, given that the W996[87]CF driver depends on the version of the module present in the official kernels. The following options of the kernel configuration file must be enabled and @@ -197,16 +197,16 @@ Note: The kernel must be compiled with the CONFIG_KMOD option enabled for the 'ovcamchip' module to be loaded and for this parameter to be present. ------------------------------------------------------------------------------- -Name: simcams -Type: int -Syntax: +Name: simcams +Type: int +Syntax: Description: Number of cameras allowed to stream simultaneously. n may vary from 0 to 32. Default: 32 ------------------------------------------------------------------------------- Name: video_nr Type: int array (min = 0, max = 32) -Syntax: <-1|n[,...]> +Syntax: <-1|n[,...]> Description: Specify V4L minor mode number. -1 = use next available n = use minor number n @@ -219,7 +219,7 @@ Default: -1 ------------------------------------------------------------------------------- Name: packet_size Type: int array (min = 0, max = 32) -Syntax: +Syntax: Description: Specify the maximum data payload size in bytes for alternate settings, for each device. n is scaled between 63 and 1023. Default: 1023 @@ -234,7 +234,7 @@ Default: 2 ------------------------------------------------------------------------------- Name: double_buffer Type: bool array (min = 0, max = 32) -Syntax: <0|1[,...]> +Syntax: <0|1[,...]> Description: Hardware double buffering: 0 disabled, 1 enabled. It should be enabled if you want smooth video output: if you obtain out of sync. video, disable it, or try to @@ -243,13 +243,13 @@ Default: 1 for every device. ------------------------------------------------------------------------------- Name: clamping Type: bool array (min = 0, max = 32) -Syntax: <0|1[,...]> +Syntax: <0|1[,...]> Description: Video data clamping: 0 disabled, 1 enabled. Default: 0 for every device. ------------------------------------------------------------------------------- Name: filter_type Type: int array (min = 0, max = 32) -Syntax: <0|1|2[,...]> +Syntax: <0|1|2[,...]> Description: Video filter type. 0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter. The filter is used to reduce noise and aliasing artifacts @@ -258,13 +258,13 @@ Default: 0 for every device. ------------------------------------------------------------------------------- Name: largeview Type: bool array (min = 0, max = 32) -Syntax: <0|1[,...]> +Syntax: <0|1[,...]> Description: Large view: 0 disabled, 1 enabled. Default: 1 for every device. ------------------------------------------------------------------------------- Name: upscaling Type: bool array (min = 0, max = 32) -Syntax: <0|1[,...]> +Syntax: <0|1[,...]> Description: Software scaling (for non-compressed video only): 0 disabled, 1 enabled. Disable it if you have a slow CPU or you don't have enough @@ -341,8 +341,8 @@ Default: 50 for every device. ------------------------------------------------------------------------------- Name: bandingfilter Type: bool array (min = 0, max = 32) -Syntax: <0|1[,...]> -Description: Banding filter to reduce effects of fluorescent +Syntax: <0|1[,...]> +Description: Banding filter to reduce effects of fluorescent lighting: 0 disabled, 1 enabled. This filter tries to reduce the pattern of horizontal @@ -374,7 +374,7 @@ Default: 0 for every device. ------------------------------------------------------------------------------- Name: monochrome Type: bool array (min = 0, max = 32) -Syntax: <0|1[,...]> +Syntax: <0|1[,...]> Description: The image sensor is monochrome: 0 = no, 1 = yes Default: 0 for every device. @@ -400,19 +400,19 @@ Default: 32768 for every device. ------------------------------------------------------------------------------- Name: contrast Type: long array (min = 0, max = 32) -Syntax: +Syntax: Description: Set picture contrast (0-65535). Default: 50000 for every device. ------------------------------------------------------------------------------- Name: whiteness Type: long array (min = 0, max = 32) -Syntax: +Syntax: Description: Set picture whiteness (0-65535). Default: 32768 for every device. ------------------------------------------------------------------------------- Name: debug Type: int -Syntax: +Syntax: Description: Debugging information level, from 0 to 6: 0 = none (use carefully) 1 = critical errors diff --git a/Documentation/usb/zc0301.txt b/Documentation/video4linux/zc0301.txt similarity index 100% rename from Documentation/usb/zc0301.txt rename to Documentation/video4linux/zc0301.txt diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index 1ad9af1ca4d0..2803f63c1a27 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -27,7 +27,7 @@ number of free hugetlb pages at any time. It also displays information about the configured hugepage size - this is needed for generating the proper alignment and size of the arguments to the above system calls. -The output of "cat /proc/meminfo" will have output like: +The output of "cat /proc/meminfo" will have lines like: ..... HugePages_Total: xxx @@ -42,11 +42,11 @@ pages in the kernel. Super user can dynamically request more (or free some pre-configured) hugepages. The allocation (or deallocation) of hugetlb pages is possible only if there are enough physically contiguous free pages in system (freeing of hugepages is -possible only if there are enough hugetlb pages free that can be transfered +possible only if there are enough hugetlb pages free that can be transferred back to regular memory pool). -Pages that are used as hugetlb pages are reserved inside the kernel and can -not be used for other purposes. +Pages that are used as hugetlb pages are reserved inside the kernel and cannot +be used for other purposes. Once the kernel with Hugetlb page support is built and running, a user can use either the mmap system call or shared memory system calls to start using @@ -60,7 +60,7 @@ Use the following command to dynamically allocate/deallocate hugepages: This command will try to configure 20 hugepages in the system. The success or failure of allocation depends on the amount of physically contiguous memory that is preset in system at this time. System administrators may want -to put this command in one of the local rc init file. This will enable the +to put this command in one of the local rc init files. This will enable the kernel to request huge pages early in the boot process (when the possibility of getting physical contiguous pages is still very high). @@ -78,8 +78,8 @@ the uid and gid of the current process are taken. The mode option sets the mode of root of file system to value & 0777. This value is given in octal. By default the value 0755 is picked. The size option sets the maximum value of memory (huge pages) allowed for that filesystem (/mnt/huge). The size is -rounded down to HPAGE_SIZE. The option nr_inode sets the maximum number of -inodes that /mnt/huge can use. If the size or nr_inode options are not +rounded down to HPAGE_SIZE. The option nr_inodes sets the maximum number of +inodes that /mnt/huge can use. If the size or nr_inodes options are not provided on command line then no limits are set. For size and nr_inodes options, you can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For example, size=2K has the same meaning as size=2048. An example is given at @@ -88,7 +88,7 @@ the end of this document. read and write system calls are not supported on files that reside on hugetlb file systems. -A regular chown, chgrp and chmod commands (with right permissions) could be +Regular chown, chgrp, and chmod commands (with right permissions) could be used to change the file attributes on hugetlbfs. Also, it is important to note that no such mount command is required if the @@ -96,8 +96,8 @@ applications are going to use only shmat/shmget system calls. Users who wish to use hugetlb page via shared memory segment should be a member of a supplementary group and system admin needs to configure that gid into /proc/sys/vm/hugetlb_shm_group. It is possible for same or different -applications to use any combination of mmaps and shm* calls. Though the -mount of filesystem will be required for using mmaps. +applications to use any combination of mmaps and shm* calls, though the +mount of filesystem will be required for using mmap calls. ******************************************************************* diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt index 1921353259ae..f2cd6ef53ff3 100644 --- a/Documentation/x86_64/boot-options.txt +++ b/Documentation/x86_64/boot-options.txt @@ -151,6 +151,11 @@ NUMA numa=fake=X Fake X nodes and ignore NUMA setup of the actual machine. + numa=hotadd=percent + Only allow hotadd memory to preallocate page structures upto + percent of already available memory. + numa=hotadd=0 will disable hotadd memory. + ACPI acpi=off Don't enable ACPI diff --git a/Kbuild b/Kbuild index 95d6a00bace0..2d4f95e4b89f 100644 --- a/Kbuild +++ b/Kbuild @@ -18,7 +18,7 @@ define sed-y "/^->/{s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; s:->::; p;}" endef # Override default regexp for specific architectures -sed-$(CONFIG_MIPS) := "/^@@@/s///p" +sed-$(CONFIG_MIPS) := "/^@@@/{s/^@@@//; s/ \#.*\$$//; p;}" quiet_cmd_offsets = GEN $@ define cmd_offsets diff --git a/MAINTAINERS b/MAINTAINERS index e5b051f0e27e..6d3c401ccdb6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1451,6 +1451,12 @@ P: Juanjo Ciarlante M: jjciarla@raiz.uncu.edu.ar S: Maintained +IPATH DRIVER: +P: Bryan O'Sullivan +M: support@pathscale.com +L: openib-general@openib.org +S: Supported + IPX NETWORK LAYER P: Arnaldo Carvalho de Melo M: acme@conectiva.com.br @@ -1550,9 +1556,7 @@ S: Maintained KEXEC P: Eric Biederman -P: Randy Dunlap M: ebiederm@xmission.com -M: rdunlap@xenotime.net W: http://www.xmission.com/~ebiederm/files/kexec/ L: linux-kernel@vger.kernel.org L: fastboot@osdl.org @@ -1885,6 +1889,7 @@ NETWORKING [GENERAL] P: Networking Team M: netdev@vger.kernel.org L: netdev@vger.kernel.org +W: http://linux-net.osdl.org/ S: Maintained NETWORKING [IPv4/IPv6] @@ -3053,13 +3058,6 @@ M: khali@linux-fr.org L: lm-sensors@lm-sensors.org S: Odd Fixes -WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) -P: Nenad Corbic -M: ncorbic@sangoma.com -M: dm@sangoma.com -W: http://www.sangoma.com -S: Supported - WATCHDOG DEVICE DRIVERS P: Wim Van Sebroeck M: wim@iguana.be diff --git a/Makefile b/Makefile index af6210d48836..fc8e08c419f0 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 -SUBLEVEL = 16 -EXTRAVERSION = +SUBLEVEL = 17 +EXTRAVERSION =-rc1 NAME=Sliding Snow Leopard # *DOCUMENTATION* @@ -1112,7 +1112,6 @@ modules_install: _emodinst_ _emodinst_post install-dir := $(if $(INSTALL_MOD_DIR),$(INSTALL_MOD_DIR),extra) PHONY += _emodinst_ _emodinst_: - $(Q)rm -rf $(MODLIB)/$(install-dir) $(Q)mkdir -p $(MODLIB)/$(install-dir) $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst @@ -1275,40 +1274,43 @@ kernelversion: # Single targets # --------------------------------------------------------------------------- -# The directory part is taken from first prerequisite, so this -# works even with external modules -%.s: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(dir $<) $(dir $<)$(notdir $@) -%.i: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(dir $<) $(dir $<)$(notdir $@) -%.o: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(dir $<) $(dir $<)$(notdir $@) -%.lst: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(dir $<) $(dir $<)$(notdir $@) -%.s: %.S prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(dir $<) $(dir $<)$(notdir $@) -%.o: %.S prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(dir $<) $(dir $<)$(notdir $@) +# Single targets are compatible with: +# - build whith mixed source and output +# - build with separate output dir 'make O=...' +# - external modules +# +# target-dir => where to store outputfile +# build-dir => directory in kernel source tree to use -# For external modules we shall include any directory of the target, -# but usual case there is no directory part. -# make M=`pwd` module.o => $(dir $@)=./ -# make M=`pwd` foo/module.o => $(dir $@)=foo/ -# make M=`pwd` / => $(dir $@)=/ - ifeq ($(KBUILD_EXTMOD),) - target-dir = $(@D) + build-dir = $(patsubst %/,%,$(dir $@)) + target-dir = $(dir $@) else zap-slash=$(filter-out .,$(patsubst %/,%,$(dir $@))) - target-dir = $(KBUILD_EXTMOD)$(if $(zap-slash),/$(zap-slash)) + build-dir = $(KBUILD_EXTMOD)$(if $(zap-slash),/$(zap-slash)) + target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@)) endif -/ %/: scripts prepare FORCE +%.s: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.i: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.o: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.lst: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.s: %.S prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.o: %.S prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) + +# Modules +/ %/: prepare scripts FORCE $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ - $(build)=$(target-dir) -%.ko: scripts FORCE + $(build)=$(build-dir) +%.ko: prepare scripts FORCE $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ - $(build)=$(target-dir) $(@:.ko=.o) + $(build)=$(build-dir) $(@:.ko=.o) $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost # FIXME Should go into a make.lib or something diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig index 9bef61b30367..8290b69da202 100644 --- a/arch/alpha/Kconfig +++ b/arch/alpha/Kconfig @@ -549,6 +549,11 @@ config NUMA Access). This option is for configuring high-end multiprocessor server machines. If in doubt, say N. +config NODES_SHIFT + int + default "7" + depends on NEED_MULTIPLE_NODES + # LARGE_VMALLOC is racy, if you *really* need it then fix it first config ALPHA_LARGE_VMALLOC bool diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c index 1898ea79d0e2..c645c5e14786 100644 --- a/arch/alpha/kernel/alpha_ksyms.c +++ b/arch/alpha/kernel/alpha_ksyms.c @@ -76,7 +76,6 @@ EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(memcmp); @@ -216,8 +215,6 @@ EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(get_wchan); - #ifdef CONFIG_ALPHA_IRONGATE EXPORT_SYMBOL(irongate_ioremap); EXPORT_SYMBOL(irongate_iounmap); diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c index 44866cb26a80..7f6a98455e74 100644 --- a/arch/alpha/kernel/core_marvel.c +++ b/arch/alpha/kernel/core_marvel.c @@ -435,7 +435,7 @@ marvel_specify_io7(char *str) str = pchar; } while(*str); - return 0; + return 1; } __setup("io7=", marvel_specify_io7); diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index dd8769670596..558b83368559 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -24,10 +24,12 @@ #include /* CONFIG_ALPHA_LCA etc */ #include #include +#include #include #include #include #include +#include #include #include #include @@ -470,6 +472,22 @@ page_is_ram(unsigned long pfn) return 0; } +static int __init +register_cpus(void) +{ + int i; + + for_each_possible_cpu(i) { + struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + register_cpu(p, i, NULL); + } + return 0; +} + +arch_initcall(register_cpus); + void __init setup_arch(char **cmdline_p) { @@ -1478,3 +1496,20 @@ alpha_panic_event(struct notifier_block *this, unsigned long event, void *ptr) #endif return NOTIFY_DONE; } + +static __init int add_pcspkr(void) +{ + struct platform_device *pd; + int ret; + + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} +device_initcall(add_pcspkr); diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index 02c2db08114a..185255416e85 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -439,7 +439,7 @@ setup_smp(void) if ((cpu->flags & 0x1cc) == 0x1cc) { smp_num_probed++; /* Assume here that "whami" == index */ - cpu_set(i, cpu_possible_map); + cpu_set(i, cpu_present_mask); cpu->pal_revision = boot_cpu_palrev; } @@ -450,9 +450,8 @@ setup_smp(void) } } else { smp_num_probed = 1; - cpu_set(boot_cpuid, cpu_possible_map); + cpu_set(boot_cpuid, cpu_present_mask); } - cpu_present_mask = cpumask_of_cpu(boot_cpuid); printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n", smp_num_probed, cpu_possible_map.bits[0]); @@ -488,9 +487,8 @@ void __devinit smp_prepare_boot_cpu(void) { /* - * Mark the boot cpu (current cpu) as both present and online + * Mark the boot cpu (current cpu) as online */ - cpu_set(smp_processor_id(), cpu_present_mask); cpu_set(smp_processor_id(), cpu_online_map); } diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ba46d779ede7..1dbf6ddb300d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -77,6 +77,14 @@ config FIQ config ARCH_MTD_XIP bool +config VECTORS_BASE + hex + default 0xffff0000 if MMU + default DRAM_BASE if REMAP_VECTORS_TO_RAM + default 0x00000000 + help + The base address of exception vectors. + source "init/Kconfig" menu "System Type" @@ -504,6 +512,12 @@ config ARCH_DISCONTIGMEM_ENABLE or have huge holes in the physical address space for other reasons. See for more. +config NODES_SHIFT + int + default "4" if ARCH_LH7A40X + default "2" + depends on NEED_MULTIPLE_NODES + source "mm/Kconfig" config LEDS @@ -839,6 +853,8 @@ source "drivers/misc/Kconfig" source "drivers/mfd/Kconfig" +source "drivers/leds/Kconfig" + source "drivers/media/Kconfig" source "drivers/video/Kconfig" diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu new file mode 100644 index 000000000000..e1574be2ded6 --- /dev/null +++ b/arch/arm/Kconfig-nommu @@ -0,0 +1,44 @@ +# +# Kconfig for uClinux(non-paged MM) depend configurations +# Hyok S. Choi +# + +config SET_MEM_PARAM + bool "Set flash/sdram size and base addr" + help + Say Y to manually set the base addresses and sizes. + otherwise, the default values are assigned. + +config DRAM_BASE + hex '(S)DRAM Base Address' if SET_MEM_PARAM + default 0x00800000 + +config DRAM_SIZE + hex '(S)DRAM SIZE' if SET_MEM_PARAM + default 0x00800000 + +config FLASH_MEM_BASE + hex 'FLASH Base Address' if SET_MEM_PARAM + default 0x00400000 + +config FLASH_SIZE + hex 'FLASH Size' if SET_MEM_PARAM + default 0x00400000 + +config REMAP_VECTORS_TO_RAM + bool 'Install vectors to the begining of RAM' if DRAM_BASE + depends on DRAM_BASE + help + The kernel needs to change the hardware exception vectors. + In nommu mode, the hardware exception vectors are normally + placed at address 0x00000000. However, this region may be + occupied by read-only memory depending on H/W design. + + If the region contains read-write memory, say 'n' here. + + If your CPU provides a remap facility which allows the exception + vectors to be mapped to writable memory, say 'n' here. + + Otherwise, say 'y' here. In this case, the kernel will require + external support to redirect the hardware exception vectors to + the writable versions located at DRAM_BASE. diff --git a/arch/arm/Makefile b/arch/arm/Makefile index ce3e804ea0f3..95a96275f88a 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -20,6 +20,11 @@ GZFLAGS :=-9 # Select a platform tht is kept up-to-date KBUILD_DEFCONFIG := versatile_defconfig +# defines filename extension depending memory manement type. +ifeq ($(CONFIG_MMU),) +MMUEXT := -nommu +endif + ifeq ($(CONFIG_FRAME_POINTER),y) CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog endif @@ -73,7 +78,7 @@ AFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) -msoft-float CHECKFLAGS += -D__arm__ #Default value -head-y := arch/arm/kernel/head.o arch/arm/kernel/init_task.o +head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task.o textofs-y := 0x00008000 machine-$(CONFIG_ARCH_RPC) := rpc @@ -133,7 +138,7 @@ else MACHINE := endif -export TEXT_OFFSET GZFLAGS +export TEXT_OFFSET GZFLAGS MMUEXT # Do we have FASTFPE? FASTFPE :=arch/arm/fastfpe diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 491c7e4c9ac6..b56f5e691d65 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -2,6 +2,7 @@ * linux/arch/arm/boot/compressed/head.S * * Copyright (C) 1996-2002 Russell King + * Copyright (C) 2004 Hyok S. Choi (MPU support) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -320,6 +321,62 @@ params: ldr r0, =params_phys cache_on: mov r3, #8 @ cache_on function b call_cache_fn +/* + * Initialize the highest priority protection region, PR7 + * to cover all 32bit address and cacheable and bufferable. + */ +__armv4_mpu_cache_on: + mov r0, #0x3f @ 4G, the whole + mcr p15, 0, r0, c6, c7, 0 @ PR7 Area Setting + mcr p15, 0, r0, c6, c7, 1 + + mov r0, #0x80 @ PR7 + mcr p15, 0, r0, c2, c0, 0 @ D-cache on + mcr p15, 0, r0, c2, c0, 1 @ I-cache on + mcr p15, 0, r0, c3, c0, 0 @ write-buffer on + + mov r0, #0xc000 + mcr p15, 0, r0, c5, c0, 1 @ I-access permission + mcr p15, 0, r0, c5, c0, 0 @ D-access permission + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c7, c5, 0 @ flush(inval) I-Cache + mcr p15, 0, r0, c7, c6, 0 @ flush(inval) D-Cache + mrc p15, 0, r0, c1, c0, 0 @ read control reg + @ ...I .... ..D. WC.M + orr r0, r0, #0x002d @ .... .... ..1. 11.1 + orr r0, r0, #0x1000 @ ...1 .... .... .... + + mcr p15, 0, r0, c1, c0, 0 @ write control reg + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ flush(inval) I-Cache + mcr p15, 0, r0, c7, c6, 0 @ flush(inval) D-Cache + mov pc, lr + +__armv3_mpu_cache_on: + mov r0, #0x3f @ 4G, the whole + mcr p15, 0, r0, c6, c7, 0 @ PR7 Area Setting + + mov r0, #0x80 @ PR7 + mcr p15, 0, r0, c2, c0, 0 @ cache on + mcr p15, 0, r0, c3, c0, 0 @ write-buffer on + + mov r0, #0xc000 + mcr p15, 0, r0, c5, c0, 0 @ access permission + + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mrc p15, 0, r0, c1, c0, 0 @ read control reg + @ .... .... .... WC.M + orr r0, r0, #0x000d @ .... .... .... 11.1 + mov r0, #0 + mcr p15, 0, r0, c1, c0, 0 @ write control reg + + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mov pc, lr + __setup_mmu: sub r3, r4, #16384 @ Page directory size bic r3, r3, #0xff @ Align the pointer bic r3, r3, #0x3f00 @@ -496,6 +553,18 @@ proc_types: b __armv4_mmu_cache_off mov pc, lr + .word 0x41007400 @ ARM74x + .word 0xff00ff00 + b __armv3_mpu_cache_on + b __armv3_mpu_cache_off + b __armv3_mpu_cache_flush + + .word 0x41009400 @ ARM94x + .word 0xff00ff00 + b __armv4_mpu_cache_on + b __armv4_mpu_cache_off + b __armv4_mpu_cache_flush + .word 0x00007000 @ ARM7 IDs .word 0x0000f000 mov pc, lr @@ -562,6 +631,24 @@ proc_types: cache_off: mov r3, #12 @ cache_off function b call_cache_fn +__armv4_mpu_cache_off: + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0 @ turn MPU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c7, c6, 0 @ flush D-Cache + mcr p15, 0, r0, c7, c5, 0 @ flush I-Cache + mov pc, lr + +__armv3_mpu_cache_off: + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0, 0 @ turn MPU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mov pc, lr + __armv4_mmu_cache_off: mrc p15, 0, r0, c1, c0 bic r0, r0, #0x000d @@ -601,6 +688,24 @@ cache_clean_flush: mov r3, #16 b call_cache_fn +__armv4_mpu_cache_flush: + mov r2, #1 + mov r3, #0 + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache + mov r1, #7 << 5 @ 8 segments +1: orr r3, r1, #63 << 26 @ 64 entries +2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index + subs r3, r3, #1 << 26 + bcs 2b @ entries 63 to 0 + subs r1, r1, #1 << 5 + bcs 1b @ segments 7 to 0 + + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + + __armv6_mmu_cache_flush: mov r1, #0 mcr p15, 0, r1, c7, c14, 0 @ clean+invalidate D @@ -638,6 +743,7 @@ no_cache_id: mov pc, lr __armv3_mmu_cache_flush: +__armv3_mpu_cache_flush: mov r1, #0 mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 mov pc, lr diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in index eed616113e47..153a07e7222b 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.in +++ b/arch/arm/boot/compressed/vmlinux.lds.in @@ -18,6 +18,7 @@ SECTIONS _start = .; *(.start) *(.text) + *(.text.*) *(.fixup) *(.gnu.warning) *(.rodata) diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c index 978d32e82d39..3cd8c9ee4510 100644 --- a/arch/arm/common/sharpsl_pm.c +++ b/arch/arm/common/sharpsl_pm.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,7 @@ static void sharpsl_battery_thread(void *private_); struct sharpsl_pm_status sharpsl_pm; DECLARE_WORK(toggle_charger, sharpsl_charge_toggle, NULL); DECLARE_WORK(sharpsl_bat, sharpsl_battery_thread, NULL); +DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger); static int get_percentage(int voltage) @@ -190,10 +192,10 @@ void sharpsl_pm_led(int val) dev_err(sharpsl_pm.dev, "Charging Error!\n"); } else if (val == SHARPSL_LED_ON) { dev_dbg(sharpsl_pm.dev, "Charge LED On\n"); - + led_trigger_event(sharpsl_charge_led_trigger, LED_FULL); } else { dev_dbg(sharpsl_pm.dev, "Charge LED Off\n"); - + led_trigger_event(sharpsl_charge_led_trigger, LED_OFF); } } @@ -786,6 +788,8 @@ static int __init sharpsl_pm_probe(struct platform_device *pdev) init_timer(&sharpsl_pm.chrg_full_timer); sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer; + led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger); + sharpsl_pm.machinfo->init(); device_create_file(&pdev->dev, &dev_attr_battery_percentage); @@ -807,6 +811,8 @@ static int sharpsl_pm_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &dev_attr_battery_percentage); device_remove_file(&pdev->dev, &dev_attr_battery_voltage); + led_trigger_unregister_simple(sharpsl_charge_led_trigger); + sharpsl_pm.machinfo->exit(); del_timer_sync(&sharpsl_pm.chrg_full_timer); diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig index 1fe73d198888..9e1c1cceb735 100644 --- a/arch/arm/configs/at91rm9200dk_defconfig +++ b/arch/arm/configs/at91rm9200dk_defconfig @@ -379,7 +379,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2 # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set CONFIG_MTD_AT91_DATAFLASH=y -CONFIG_MTD_AT91_DATAFLASH_CARD=y +# CONFIG_MTD_AT91_DATAFLASH_CARD is not set # # NAND Flash Device Drivers diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig index b7d934cdb1b7..6e0805a971d7 100644 --- a/arch/arm/configs/at91rm9200ek_defconfig +++ b/arch/arm/configs/at91rm9200ek_defconfig @@ -370,7 +370,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2 # CONFIG_MTD_DOC2001 is not set # CONFIG_MTD_DOC2001PLUS is not set CONFIG_MTD_AT91_DATAFLASH=y -CONFIG_MTD_AT91_DATAFLASH_CARD=y +# CONFIG_MTD_AT91_DATAFLASH_CARD is not set # # NAND Flash Device Drivers diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 1574941ebfe1..c49b5d4d7fca 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -100,23 +100,11 @@ EXPORT_SYMBOL(__raw_writesl); #endif /* string / mem functions */ -EXPORT_SYMBOL(strcpy); -EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(__memzero); @@ -190,8 +178,6 @@ EXPORT_SYMBOL(_find_next_bit_be); /* syscalls */ EXPORT_SYMBOL(sys_write); -EXPORT_SYMBOL(sys_read); EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_open); EXPORT_SYMBOL(sys_exit); EXPORT_SYMBOL(sys_wait4); diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 355914ffb192..ab8e600c18c8 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -666,7 +666,7 @@ __kuser_helper_start: * * #define __kernel_dmb() \ * asm volatile ( "mov r0, #0xffff0fff; mov lr, pc; sub pc, r0, #95" \ - * : : : "lr","cc" ) + * : : : "r0", "lr","cc" ) */ __kuser_memory_barrier: @ 0xffff0fa0 diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S new file mode 100644 index 000000000000..a52da0ddb43d --- /dev/null +++ b/arch/arm/kernel/head-common.S @@ -0,0 +1,217 @@ +/* + * linux/arch/arm/kernel/head-common.S + * + * Copyright (C) 1994-2002 Russell King + * Copyright (c) 2003 ARM Limited + * 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 version 2 as + * published by the Free Software Foundation. + * + */ + + .type __switch_data, %object +__switch_data: + .long __mmap_switched + .long __data_loc @ r4 + .long __data_start @ r5 + .long __bss_start @ r6 + .long _end @ r7 + .long processor_id @ r4 + .long __machine_arch_type @ r5 + .long cr_alignment @ r6 + .long init_thread_union + THREAD_START_SP @ sp + +/* + * The following fragment of code is executed with the MMU on in MMU mode, + * and uses absolute addresses; this is not position independent. + * + * r0 = cp#15 control register + * r1 = machine ID + * r9 = processor ID + */ + .type __mmap_switched, %function +__mmap_switched: + adr r3, __switch_data + 4 + + ldmia r3!, {r4, r5, r6, r7} + cmp r4, r5 @ Copy data segment if needed +1: cmpne r5, r6 + ldrne fp, [r4], #4 + strne fp, [r5], #4 + bne 1b + + mov fp, #0 @ Clear BSS (and zero fp) +1: cmp r6, r7 + strcc fp, [r6],#4 + bcc 1b + + ldmia r3, {r4, r5, r6, sp} + str r9, [r4] @ Save processor ID + str r1, [r5] @ Save machine type + bic r4, r0, #CR_A @ Clear 'A' bit + stmia r6, {r0, r4} @ Save control register values + b start_kernel + +/* + * Exception handling. Something went wrong and we can't proceed. We + * ought to tell the user, but since we don't have any guarantee that + * we're even running on the right architecture, we do virtually nothing. + * + * If CONFIG_DEBUG_LL is set we try to print out something about the error + * and hope for the best (useful if bootloader fails to pass a proper + * machine ID for example). + */ + + .type __error_p, %function +__error_p: +#ifdef CONFIG_DEBUG_LL + adr r0, str_p1 + bl printascii + b __error +str_p1: .asciz "\nError: unrecognized/unsupported processor variant.\n" + .align +#endif + + .type __error_a, %function +__error_a: +#ifdef CONFIG_DEBUG_LL + mov r4, r1 @ preserve machine ID + adr r0, str_a1 + bl printascii + mov r0, r4 + bl printhex8 + adr r0, str_a2 + bl printascii + adr r3, 3f + ldmia r3, {r4, r5, r6} @ get machine desc list + sub r4, r3, r4 @ get offset between virt&phys + add r5, r5, r4 @ convert virt addresses to + add r6, r6, r4 @ physical address space +1: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type + bl printhex8 + mov r0, #'\t' + bl printch + ldr r0, [r5, #MACHINFO_NAME] @ get machine name + add r0, r0, r4 + bl printascii + mov r0, #'\n' + bl printch + add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc + cmp r5, r6 + blo 1b + adr r0, str_a3 + bl printascii + b __error +str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x" +str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n" +str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n" + .align +#endif + + .type __error, %function +__error: +#ifdef CONFIG_ARCH_RPC +/* + * Turn the screen red on a error - RiscPC only. + */ + mov r0, #0x02000000 + mov r3, #0x11 + orr r3, r3, r3, lsl #8 + orr r3, r3, r3, lsl #16 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 + str r3, [r0], #4 +#endif +1: mov r0, r0 + b 1b + + +/* + * Read processor ID register (CP#15, CR0), and look up in the linker-built + * supported processor list. Note that we can't use the absolute addresses + * for the __proc_info lists since we aren't running with the MMU on + * (and therefore, we are not in the correct address space). We have to + * calculate the offset. + * + * r9 = cpuid + * Returns: + * r3, r4, r6 corrupted + * r5 = proc_info pointer in physical address space + * r9 = cpuid (preserved) + */ + .type __lookup_processor_type, %function +__lookup_processor_type: + adr r3, 3f + ldmda r3, {r5 - r7} + sub r3, r3, r7 @ get offset between virt&phys + add r5, r5, r3 @ convert virt addresses to + add r6, r6, r3 @ physical address space +1: ldmia r5, {r3, r4} @ value, mask + and r4, r4, r9 @ mask wanted bits + teq r3, r4 + beq 2f + add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) + cmp r5, r6 + blo 1b + mov r5, #0 @ unknown processor +2: mov pc, lr + +/* + * This provides a C-API version of the above function. + */ +ENTRY(lookup_processor_type) + stmfd sp!, {r4 - r7, r9, lr} + mov r9, r0 + bl __lookup_processor_type + mov r0, r5 + ldmfd sp!, {r4 - r7, r9, pc} + +/* + * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for + * more information about the __proc_info and __arch_info structures. + */ + .long __proc_info_begin + .long __proc_info_end +3: .long . + .long __arch_info_begin + .long __arch_info_end + +/* + * Lookup machine architecture in the linker-build list of architectures. + * Note that we can't use the absolute addresses for the __arch_info + * lists since we aren't running with the MMU on (and therefore, we are + * not in the correct address space). We have to calculate the offset. + * + * r1 = machine architecture number + * Returns: + * r3, r4, r6 corrupted + * r5 = mach_info pointer in physical address space + */ + .type __lookup_machine_type, %function +__lookup_machine_type: + adr r3, 3b + ldmia r3, {r4, r5, r6} + sub r3, r3, r4 @ get offset between virt&phys + add r5, r5, r3 @ convert virt addresses to + add r6, r6, r3 @ physical address space +1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type + teq r3, r1 @ matches loader number? + beq 2f @ found + add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc + cmp r5, r6 + blo 1b + mov r5, #0 @ unknown machine +2: mov pc, lr + +/* + * This provides a C-API version of the above function. + */ +ENTRY(lookup_machine_type) + stmfd sp!, {r4 - r6, lr} + mov r1, r0 + bl __lookup_machine_type + mov r0, r5 + ldmfd sp!, {r4 - r6, pc} diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S new file mode 100644 index 000000000000..b093ab8738b5 --- /dev/null +++ b/arch/arm/kernel/head-nommu.S @@ -0,0 +1,83 @@ +/* + * linux/arch/arm/kernel/head-nommu.S + * + * Copyright (C) 1994-2002 Russell King + * Copyright (C) 2003-2006 Hyok S. Choi + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Common kernel startup code (non-paged MM) + * for 32-bit CPUs which has a process ID register(CP15). + * + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define PROCINFO_INITFUNC 12 + +/* + * Kernel startup entry point. + * --------------------------- + * + * This is normally called from the decompressor code. The requirements + * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, + * r1 = machine nr. + * + * See linux/arch/arm/tools/mach-types for the complete list of machine + * numbers for r1. + * + */ + __INIT + .type stext, %function +ENTRY(stext) + msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC @ ensure svc mode + @ and irqs disabled + mrc p15, 0, r9, c0, c0 @ get processor id + bl __lookup_processor_type @ r5=procinfo r9=cpuid + movs r10, r5 @ invalid processor (r5=0)? + beq __error_p @ yes, error 'p' + bl __lookup_machine_type @ r5=machinfo + movs r8, r5 @ invalid machine (r5=0)? + beq __error_a @ yes, error 'a' + + ldr r13, __switch_data @ address to jump to after + @ the initialization is done + adr lr, __after_proc_init @ return (PIC) address + add pc, r10, #PROCINFO_INITFUNC + +/* + * Set the Control Register and Read the process ID. + */ + .type __after_proc_init, %function +__after_proc_init: + mrc p15, 0, r0, c1, c0, 0 @ read control reg +#ifdef CONFIG_ALIGNMENT_TRAP + orr r0, r0, #CR_A +#else + bic r0, r0, #CR_A +#endif +#ifdef CONFIG_CPU_DCACHE_DISABLE + bic r0, r0, #CR_C +#endif +#ifdef CONFIG_CPU_BPREDICT_DISABLE + bic r0, r0, #CR_Z +#endif +#ifdef CONFIG_CPU_ICACHE_DISABLE + bic r0, r0, #CR_I +#endif + mcr p15, 0, r0, c1, c0, 0 @ write control reg + + mov pc, r13 @ clear the BSS and jump + @ to start_kernel + +#include "head-common.S" diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 53b6901f70a6..04b66a9328ef 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -102,49 +102,6 @@ ENTRY(stext) adr lr, __enable_mmu @ return (PIC) address add pc, r10, #PROCINFO_INITFUNC - .type __switch_data, %object -__switch_data: - .long __mmap_switched - .long __data_loc @ r4 - .long __data_start @ r5 - .long __bss_start @ r6 - .long _end @ r7 - .long processor_id @ r4 - .long __machine_arch_type @ r5 - .long cr_alignment @ r6 - .long init_thread_union + THREAD_START_SP @ sp - -/* - * The following fragment of code is executed with the MMU on, and uses - * absolute addresses; this is not position independent. - * - * r0 = cp#15 control register - * r1 = machine ID - * r9 = processor ID - */ - .type __mmap_switched, %function -__mmap_switched: - adr r3, __switch_data + 4 - - ldmia r3!, {r4, r5, r6, r7} - cmp r4, r5 @ Copy data segment if needed -1: cmpne r5, r6 - ldrne fp, [r4], #4 - strne fp, [r5], #4 - bne 1b - - mov fp, #0 @ Clear BSS (and zero fp) -1: cmp r6, r7 - strcc fp, [r6],#4 - bcc 1b - - ldmia r3, {r4, r5, r6, sp} - str r9, [r4] @ Save processor ID - str r1, [r5] @ Save machine type - bic r4, r0, #CR_A @ Clear 'A' bit - stmia r6, {r0, r4} @ Save control register values - b start_kernel - #if defined(CONFIG_SMP) .type secondary_startup, #function ENTRY(secondary_startup) @@ -367,166 +324,4 @@ __create_page_tables: mov pc, lr .ltorg - - -/* - * Exception handling. Something went wrong and we can't proceed. We - * ought to tell the user, but since we don't have any guarantee that - * we're even running on the right architecture, we do virtually nothing. - * - * If CONFIG_DEBUG_LL is set we try to print out something about the error - * and hope for the best (useful if bootloader fails to pass a proper - * machine ID for example). - */ - - .type __error_p, %function -__error_p: -#ifdef CONFIG_DEBUG_LL - adr r0, str_p1 - bl printascii - b __error -str_p1: .asciz "\nError: unrecognized/unsupported processor variant.\n" - .align -#endif - - .type __error_a, %function -__error_a: -#ifdef CONFIG_DEBUG_LL - mov r4, r1 @ preserve machine ID - adr r0, str_a1 - bl printascii - mov r0, r4 - bl printhex8 - adr r0, str_a2 - bl printascii - adr r3, 3f - ldmia r3, {r4, r5, r6} @ get machine desc list - sub r4, r3, r4 @ get offset between virt&phys - add r5, r5, r4 @ convert virt addresses to - add r6, r6, r4 @ physical address space -1: ldr r0, [r5, #MACHINFO_TYPE] @ get machine type - bl printhex8 - mov r0, #'\t' - bl printch - ldr r0, [r5, #MACHINFO_NAME] @ get machine name - add r0, r0, r4 - bl printascii - mov r0, #'\n' - bl printch - add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc - cmp r5, r6 - blo 1b - adr r0, str_a3 - bl printascii - b __error -str_a1: .asciz "\nError: unrecognized/unsupported machine ID (r1 = 0x" -str_a2: .asciz ").\n\nAvailable machine support:\n\nID (hex)\tNAME\n" -str_a3: .asciz "\nPlease check your kernel config and/or bootloader.\n" - .align -#endif - - .type __error, %function -__error: -#ifdef CONFIG_ARCH_RPC -/* - * Turn the screen red on a error - RiscPC only. - */ - mov r0, #0x02000000 - mov r3, #0x11 - orr r3, r3, r3, lsl #8 - orr r3, r3, r3, lsl #16 - str r3, [r0], #4 - str r3, [r0], #4 - str r3, [r0], #4 - str r3, [r0], #4 -#endif -1: mov r0, r0 - b 1b - - -/* - * Read processor ID register (CP#15, CR0), and look up in the linker-built - * supported processor list. Note that we can't use the absolute addresses - * for the __proc_info lists since we aren't running with the MMU on - * (and therefore, we are not in the correct address space). We have to - * calculate the offset. - * - * r9 = cpuid - * Returns: - * r3, r4, r6 corrupted - * r5 = proc_info pointer in physical address space - * r9 = cpuid (preserved) - */ - .type __lookup_processor_type, %function -__lookup_processor_type: - adr r3, 3f - ldmda r3, {r5 - r7} - sub r3, r3, r7 @ get offset between virt&phys - add r5, r5, r3 @ convert virt addresses to - add r6, r6, r3 @ physical address space -1: ldmia r5, {r3, r4} @ value, mask - and r4, r4, r9 @ mask wanted bits - teq r3, r4 - beq 2f - add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list) - cmp r5, r6 - blo 1b - mov r5, #0 @ unknown processor -2: mov pc, lr - -/* - * This provides a C-API version of the above function. - */ -ENTRY(lookup_processor_type) - stmfd sp!, {r4 - r7, r9, lr} - mov r9, r0 - bl __lookup_processor_type - mov r0, r5 - ldmfd sp!, {r4 - r7, r9, pc} - -/* - * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for - * more information about the __proc_info and __arch_info structures. - */ - .long __proc_info_begin - .long __proc_info_end -3: .long . - .long __arch_info_begin - .long __arch_info_end - -/* - * Lookup machine architecture in the linker-build list of architectures. - * Note that we can't use the absolute addresses for the __arch_info - * lists since we aren't running with the MMU on (and therefore, we are - * not in the correct address space). We have to calculate the offset. - * - * r1 = machine architecture number - * Returns: - * r3, r4, r6 corrupted - * r5 = mach_info pointer in physical address space - */ - .type __lookup_machine_type, %function -__lookup_machine_type: - adr r3, 3b - ldmia r3, {r4, r5, r6} - sub r3, r3, r4 @ get offset between virt&phys - add r5, r5, r3 @ convert virt addresses to - add r6, r6, r3 @ physical address space -1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type - teq r3, r1 @ matches loader number? - beq 2f @ found - add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc - cmp r5, r6 - blo 1b - mov r5, #0 @ unknown machine -2: mov pc, lr - -/* - * This provides a C-API version of the above function. - */ -ENTRY(lookup_machine_type) - stmfd sp!, {r4 - r6, lr} - mov r1, r0 - bl __lookup_machine_type - mov r0, r5 - ldmfd sp!, {r4 - r6, pc} +#include "head-common.S" diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 489c069e5c3e..1ff75cee4b0d 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -474,4 +474,3 @@ unsigned long get_wchan(struct task_struct *p) } while (count ++ < 16); return 0; } -EXPORT_SYMBOL(get_wchan); diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index b7cd280bfd63..8cff73e668b3 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -252,6 +252,9 @@ static void __init dump_cpu_info(int cpu) dump_cache("cache", cpu, CACHE_ISIZE(info)); } } + + if (arch_is_coherent()) + printk("Cache coherency enabled\n"); } int cpu_architecture(void) @@ -319,6 +322,12 @@ static void __init setup_processor(void) sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); elf_hwcap = list->elf_hwcap; +#ifndef CONFIG_ARM_THUMB + elf_hwcap &= ~HWCAP_THUMB; +#endif +#ifndef CONFIG_VFP + elf_hwcap &= ~HWCAP_VFP; +#endif cpu_proc_init(); } diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h index 9991049c522d..27beece15502 100644 --- a/arch/arm/kernel/signal.h +++ b/arch/arm/kernel/signal.h @@ -7,6 +7,6 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#define KERN_SIGRETURN_CODE 0xffff0500 +#define KERN_SIGRETURN_CODE (CONFIG_VECTORS_BASE + 0x00000500) extern const unsigned long sigreturn_codes[7]; diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index d566d5f4574d..35230a060108 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -688,6 +688,7 @@ EXPORT_SYMBOL(abort); void __init trap_init(void) { + unsigned long vectors = CONFIG_VECTORS_BASE; extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; @@ -698,9 +699,9 @@ void __init trap_init(void) * into the vector page, mapped at 0xffff0000, and ensure these * are visible to the instruction stream. */ - memcpy((void *)0xffff0000, __vectors_start, __vectors_end - __vectors_start); - memcpy((void *)0xffff0200, __stubs_start, __stubs_end - __stubs_start); - memcpy((void *)0xffff1000 - kuser_sz, __kuser_helper_start, kuser_sz); + memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); + memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); + memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz); /* * Copy signal return handlers into the vector page, and @@ -709,6 +710,6 @@ void __init trap_init(void) memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes, sizeof(sigreturn_codes)); - flush_icache_range(0xffff0000, 0xffff0000 + PAGE_SIZE); + flush_icache_range(vectors, vectors + PAGE_SIZE); modify_domain(DOMAIN_USER, DOMAIN_CLIENT); } diff --git a/arch/arm/mach-at91rm9200/Makefile b/arch/arm/mach-at91rm9200/Makefile index 75e6ee318ded..ef88c4128edc 100644 --- a/arch/arm/mach-at91rm9200/Makefile +++ b/arch/arm/mach-at91rm9200/Makefile @@ -16,11 +16,12 @@ obj-$(CONFIG_MACH_CSB637) += board-csb637.o #obj-$(CONFIG_MACH_KB9200) += board-kb9202.o # LEDs support -#led-$(CONFIG_ARCH_AT91RM9200DK) += leds.o -#led-$(CONFIG_MACH_AT91RM9200EK) += leds.o -#led-$(CONFIG_MACH_CSB337) += leds.o -#led-$(CONFIG_MACH_CSB637) += leds.o +led-$(CONFIG_ARCH_AT91RM9200DK) += leds.o +led-$(CONFIG_MACH_AT91RM9200EK) += leds.o +led-$(CONFIG_MACH_CSB337) += leds.o +led-$(CONFIG_MACH_CSB637) += leds.o #led-$(CONFIG_MACH_KB9200) += leds.o +#led-$(CONFIG_MACH_KAFA) += leds.o obj-$(CONFIG_LEDS) += $(led-y) # VGA support diff --git a/arch/arm/mach-at91rm9200/board-csb337.c b/arch/arm/mach-at91rm9200/board-csb337.c index 54022e58d50d..f45104ceea8f 100644 --- a/arch/arm/mach-at91rm9200/board-csb337.c +++ b/arch/arm/mach-at91rm9200/board-csb337.c @@ -67,6 +67,9 @@ static void __init csb337_map_io(void) /* Initialize clocks: 3.6864 MHz crystal */ at91_clock_init(3686400); + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); + #ifdef CONFIG_SERIAL_AT91 at91_console_port = CSB337_SERIAL_CONSOLE; memcpy(at91_serial_map, serial, sizeof(serial)); diff --git a/arch/arm/mach-at91rm9200/board-csb637.c b/arch/arm/mach-at91rm9200/board-csb637.c index 8195f9d919ea..f2c2d6e79bc6 100644 --- a/arch/arm/mach-at91rm9200/board-csb637.c +++ b/arch/arm/mach-at91rm9200/board-csb637.c @@ -67,6 +67,9 @@ static void __init csb637_map_io(void) /* Initialize clocks: 3.6864 MHz crystal */ at91_clock_init(3686400); + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); + #ifdef CONFIG_SERIAL_AT91 at91_console_port = CSB637_SERIAL_CONSOLE; memcpy(at91_serial_map, serial, sizeof(serial)); diff --git a/arch/arm/mach-at91rm9200/board-dk.c b/arch/arm/mach-at91rm9200/board-dk.c index 8a783368366e..2d7200ed66ed 100644 --- a/arch/arm/mach-at91rm9200/board-dk.c +++ b/arch/arm/mach-at91rm9200/board-dk.c @@ -70,6 +70,9 @@ static void __init dk_map_io(void) /* Initialize clocks: 18.432 MHz crystal */ at91_clock_init(18432000); + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2); + #ifdef CONFIG_SERIAL_AT91 at91_console_port = DK_SERIAL_CONSOLE; memcpy(at91_serial_map, serial, sizeof(serial)); @@ -118,9 +121,14 @@ static void __init dk_board_init(void) at91_add_device_udc(&dk_udc_data); /* Compact Flash */ at91_add_device_cf(&dk_cf_data); +#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD + /* DataFlash card */ + at91_set_gpio_output(AT91_PIN_PB7, 0); +#else /* MMC */ - at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). default: MMC */ + at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ at91_add_device_mmc(&dk_mmc_data); +#endif /* VGA */ // dk_add_device_video(); } diff --git a/arch/arm/mach-at91rm9200/board-ek.c b/arch/arm/mach-at91rm9200/board-ek.c index fd0752eba897..80d90f5135a1 100644 --- a/arch/arm/mach-at91rm9200/board-ek.c +++ b/arch/arm/mach-at91rm9200/board-ek.c @@ -70,6 +70,9 @@ static void __init ek_map_io(void) /* Initialize clocks: 18.432 MHz crystal */ at91_clock_init(18432000); + /* Setup the LEDs */ + at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2); + #ifdef CONFIG_SERIAL_AT91 at91_console_port = EK_SERIAL_CONSOLE; memcpy(at91_serial_map, serial, sizeof(serial)); @@ -111,9 +114,14 @@ static void __init ek_board_init(void) at91_add_device_usbh(&ek_usbh_data); /* USB Device */ at91_add_device_udc(&ek_udc_data); +#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD + /* DataFlash card */ + at91_set_gpio_output(AT91_PIN_PB22, 0); +#else /* MMC */ - at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). default: MMC */ + at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */ at91_add_device_mmc(&ek_mmc_data); +#endif /* VGA */ // ek_add_device_video(); } diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c index 57eedd5beaf6..bfe47bd6e50c 100644 --- a/arch/arm/mach-at91rm9200/devices.c +++ b/arch/arm/mach-at91rm9200/devices.c @@ -28,10 +28,10 @@ static u64 ohci_dmamask = 0xffffffffUL; static struct at91_usbh_data usbh_data; -static struct resource at91rm9200_usbh_resource[] = { +static struct resource at91_usbh_resource[] = { [0] = { .start = AT91_UHP_BASE, - .end = AT91_UHP_BASE + SZ_1M -1, + .end = AT91_UHP_BASE + SZ_1M - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -49,8 +49,8 @@ static struct platform_device at91rm9200_usbh_device = { .coherent_dma_mask = 0xffffffff, .platform_data = &usbh_data, }, - .resource = at91rm9200_usbh_resource, - .num_resources = ARRAY_SIZE(at91rm9200_usbh_resource), + .resource = at91_usbh_resource, + .num_resources = ARRAY_SIZE(at91_usbh_resource), }; void __init at91_add_device_usbh(struct at91_usbh_data *data) @@ -121,6 +121,19 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {} static u64 eth_dmamask = 0xffffffffUL; static struct at91_eth_data eth_data; +static struct resource at91_eth_resources[] = { + [0] = { + .start = AT91_BASE_EMAC, + .end = AT91_BASE_EMAC + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AT91_ID_EMAC, + .end = AT91_ID_EMAC, + .flags = IORESOURCE_IRQ, + }, +}; + static struct platform_device at91rm9200_eth_device = { .name = "at91_ether", .id = -1, @@ -129,7 +142,8 @@ static struct platform_device at91rm9200_eth_device = { .coherent_dma_mask = 0xffffffff, .platform_data = ð_data, }, - .num_resources = 0, + .resource = at91_eth_resources, + .num_resources = ARRAY_SIZE(at91_eth_resources), }; void __init at91_add_device_eth(struct at91_eth_data *data) @@ -180,13 +194,23 @@ void __init at91_add_device_eth(struct at91_eth_data *data) {} #if defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE) static struct at91_cf_data cf_data; +static struct resource at91_cf_resources[] = { + [0] = { + .start = AT91_CF_BASE, + /* ties up CS4, CS5, and CS6 */ + .end = AT91_CF_BASE + (0x30000000 - 1), + .flags = IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT, + }, +}; + static struct platform_device at91rm9200_cf_device = { .name = "at91_cf", .id = -1, .dev = { .platform_data = &cf_data, }, - .num_resources = 0, + .resource = at91_cf_resources, + .num_resources = ARRAY_SIZE(at91_cf_resources), }; void __init at91_add_device_cf(struct at91_cf_data *data) @@ -224,15 +248,20 @@ static u64 mmc_dmamask = 0xffffffffUL; static struct at91_mmc_data mmc_data; static struct resource at91_mmc_resources[] = { - { + [0] = { .start = AT91_BASE_MCI, .end = AT91_BASE_MCI + SZ_16K - 1, .flags = IORESOURCE_MEM, - } + }, + [1] = { + .start = AT91_ID_MCI, + .end = AT91_ID_MCI, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device at91rm9200_mmc_device = { - .name = "at91rm9200_mci", + .name = "at91_mci", .id = -1, .dev = { .dma_mask = &mmc_dmamask, @@ -290,4 +319,123 @@ void __init at91_add_device_mmc(struct at91_mmc_data *data) void __init at91_add_device_mmc(struct at91_mmc_data *data) {} #endif +/* -------------------------------------------------------------------- + * NAND / SmartMedia + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE) +static struct at91_nand_data nand_data; + +static struct resource at91_nand_resources[] = { + { + .start = AT91_SMARTMEDIA_BASE, + .end = AT91_SMARTMEDIA_BASE + SZ_8M - 1, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device at91_nand_device = { + .name = "at91_nand", + .id = -1, + .dev = { + .platform_data = &nand_data, + }, + .resource = at91_nand_resources, + .num_resources = ARRAY_SIZE(at91_nand_resources), +}; + +void __init at91_add_device_nand(struct at91_nand_data *data) +{ + if (!data) + return; + + /* enable pin */ + if (data->enable_pin) + at91_set_gpio_output(data->enable_pin, 1); + + /* ready/busy pin */ + if (data->rdy_pin) + at91_set_gpio_input(data->rdy_pin, 1); + + /* card detect pin */ + if (data->det_pin) + at91_set_gpio_input(data->det_pin, 1); + + at91_set_A_periph(AT91_PIN_PC1, 0); /* SMOE */ + at91_set_A_periph(AT91_PIN_PC3, 0); /* SMWE */ + + nand_data = *data; + platform_device_register(&at91_nand_device); +} +#else +void __init at91_add_device_nand(struct at91_nand_data *data) {} +#endif + + +/* -------------------------------------------------------------------- + * TWI (i2c) + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE) +static struct platform_device at91rm9200_twi_device = { + .name = "at91_i2c", + .id = -1, + .num_resources = 0, +}; + +void __init at91_add_device_i2c(void) +{ + /* pins used for TWI interface */ + at91_set_A_periph(AT91_PIN_PA25, 0); /* TWD */ + at91_set_multi_drive(AT91_PIN_PA25, 1); + + at91_set_A_periph(AT91_PIN_PA26, 0); /* TWCK */ + at91_set_multi_drive(AT91_PIN_PA26, 1); + + platform_device_register(&at91rm9200_twi_device); +} +#else +void __init at91_add_device_i2c(void) {} +#endif + + +/* -------------------------------------------------------------------- + * RTC + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_AT91_RTC) || defined(CONFIG_AT91_RTC_MODULE) +static struct platform_device at91rm9200_rtc_device = { + .name = "at91_rtc", + .id = -1, + .num_resources = 0, +}; + +void __init at91_add_device_rtc(void) +{ + platform_device_register(&at91rm9200_rtc_device); +} +#else +void __init at91_add_device_rtc(void) {} +#endif + + +/* -------------------------------------------------------------------- + * LEDs + * -------------------------------------------------------------------- */ + +#if defined(CONFIG_LEDS) +u8 at91_leds_cpu; +u8 at91_leds_timer; + +void __init at91_init_leds(u8 cpu_led, u8 timer_led) +{ + at91_leds_cpu = cpu_led; + at91_leds_timer = timer_led; +} + +#else +void __init at91_init_leds(u8 cpu_led, u8 timer_led) {} +#endif + + /* -------------------------------------------------------------------- */ diff --git a/arch/arm/mach-at91rm9200/leds.c b/arch/arm/mach-at91rm9200/leds.c new file mode 100644 index 000000000000..28150e8905ba --- /dev/null +++ b/arch/arm/mach-at91rm9200/leds.c @@ -0,0 +1,100 @@ +/* + * LED driver for Atmel AT91-based boards. + * + * Copyright (C) SAN People (Pty) Ltd + * + * 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. +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include + + +static inline void at91_led_on(unsigned int led) +{ + at91_set_gpio_value(led, 0); +} + +static inline void at91_led_off(unsigned int led) +{ + at91_set_gpio_value(led, 1); +} + +static inline void at91_led_toggle(unsigned int led) +{ + unsigned long is_off = at91_get_gpio_value(led); + if (is_off) + at91_led_on(led); + else + at91_led_off(led); +} + + +/* + * Handle LED events. + */ +static void at91_leds_event(led_event_t evt) +{ + unsigned long flags; + + local_irq_save(flags); + + switch(evt) { + case led_start: /* System startup */ + at91_led_on(at91_leds_cpu); + break; + + case led_stop: /* System stop / suspend */ + at91_led_off(at91_leds_cpu); + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: /* Every 50 timer ticks */ + at91_led_toggle(at91_leds_timer); + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: /* Entering idle state */ + at91_led_off(at91_leds_cpu); + break; + + case led_idle_end: /* Exit idle state */ + at91_led_on(at91_leds_cpu); + break; +#endif + + default: + break; + } + + local_irq_restore(flags); +} + + +static int __init leds_init(void) +{ + if (!at91_leds_timer || !at91_leds_cpu) + return -ENODEV; + + /* Enable PIO to access the LEDs */ + at91_set_gpio_output(at91_leds_timer, 1); + at91_set_gpio_output(at91_leds_cpu, 1); + + leds_event = at91_leds_event; + + leds_event(led_start); + return 0; +} + +__initcall(leds_init); diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 2d892e4daa07..dcd417625389 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -424,6 +424,14 @@ static struct amba_device uart3_device = { .periphid = 0x00041010, }; + +static struct platform_device ep93xx_rtc_device = { + .name = "ep93xx-rtc", + .id = -1, + .num_resources = 0, +}; + + void __init ep93xx_init_devices(void) { unsigned int v; @@ -439,4 +447,6 @@ void __init ep93xx_init_devices(void) amba_device_register(&uart1_device, &iomem_resource); amba_device_register(&uart2_device, &iomem_resource); amba_device_register(&uart3_device, &iomem_resource); + + platform_device_register(&ep93xx_rtc_device); } diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c index 777e75daa8a5..9be01b0c3f48 100644 --- a/arch/arm/mach-ep93xx/ts72xx.c +++ b/arch/arm/mach-ep93xx/ts72xx.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -39,6 +41,16 @@ static struct map_desc ts72xx_io_desc[] __initdata = { .pfn = __phys_to_pfn(TS72XX_OPTIONS2_PHYS_BASE), .length = TS72XX_OPTIONS2_SIZE, .type = MT_DEVICE, + }, { + .virtual = TS72XX_RTC_INDEX_VIRT_BASE, + .pfn = __phys_to_pfn(TS72XX_RTC_INDEX_PHYS_BASE), + .length = TS72XX_RTC_INDEX_SIZE, + .type = MT_DEVICE, + }, { + .virtual = TS72XX_RTC_DATA_VIRT_BASE, + .pfn = __phys_to_pfn(TS72XX_RTC_DATA_PHYS_BASE), + .length = TS72XX_RTC_DATA_SIZE, + .type = MT_DEVICE, } }; @@ -99,11 +111,38 @@ static void __init ts72xx_map_io(void) } } +static unsigned char ts72xx_rtc_readb(unsigned long addr) +{ + __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE); + return __raw_readb(TS72XX_RTC_DATA_VIRT_BASE); +} + +static void ts72xx_rtc_writeb(unsigned char value, unsigned long addr) +{ + __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE); + __raw_writeb(value, TS72XX_RTC_DATA_VIRT_BASE); +} + +static struct m48t86_ops ts72xx_rtc_ops = { + .readb = ts72xx_rtc_readb, + .writeb = ts72xx_rtc_writeb, +}; + +static struct platform_device ts72xx_rtc_device = { + .name = "rtc-m48t86", + .id = -1, + .dev = { + .platform_data = &ts72xx_rtc_ops, + }, + .num_resources = 0, +}; + static void __init ts72xx_init_machine(void) { ep93xx_init_devices(); if (board_is_ts7200()) physmap_configure(TS72XX_NOR_PHYS_BASE, 0x01000000, 1, NULL); + platform_device_register(&ts72xx_rtc_device); } MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC") diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c index 71a59e196166..4ca51dcf13ac 100644 --- a/arch/arm/mach-imx/dma.c +++ b/arch/arm/mach-imx/dma.c @@ -7,11 +7,18 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * 03/03/2004 Sascha Hauer + * 2004-03-03 Sascha Hauer * initial version heavily inspired by * linux/arch/arm/mach-pxa/dma.c + * + * 2005-04-17 Pavel Pisa + * Changed to support scatter gather DMA + * by taking Russell's code from RiscPC + * */ +#undef DEBUG + #include #include #include @@ -22,69 +29,368 @@ #include #include #include +#include -static struct dma_channel { - char *name; - void (*irq_handler) (int, void *, struct pt_regs *); - void (*err_handler) (int, void *, struct pt_regs *); - void *data; -} dma_channels[11]; +struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; -/* set err_handler to NULL to have the standard info-only error handler */ -int -imx_request_dma(char *name, imx_dma_prio prio, - void (*irq_handler) (int, void *, struct pt_regs *), - void (*err_handler) (int, void *, struct pt_regs *), void *data) +/* + * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation + * @dma_ch: i.MX DMA channel number + * @lastcount: number of bytes transferred during last transfer + * + * Functions prepares DMA controller for next sg data chunk transfer. + * The @lastcount argument informs function about number of bytes transferred + * during last block. Zero value can be used for @lastcount to setup DMA + * for the first chunk. + */ +static inline int imx_dma_sg_next(imx_dmach_t dma_ch, unsigned int lastcount) { - unsigned long flags; - int i, found = 0; + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + unsigned int nextcount; + unsigned int nextaddr; - /* basic sanity checks */ - if (!name || !irq_handler) - return -EINVAL; + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __FUNCTION__, dma_ch); + return 0; + } - local_irq_save(flags); + imxdma->resbytes -= lastcount; - /* try grabbing a DMA channel with the requested priority */ - for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) { - if (!dma_channels[i].name) { - found = 1; - break; + if (!imxdma->sg) { + pr_debug("imxdma%d: no sg data\n", dma_ch); + return 0; + } + + imxdma->sgbc += lastcount; + if ((imxdma->sgbc >= imxdma->sg->length) || !imxdma->resbytes) { + if ((imxdma->sgcount <= 1) || !imxdma->resbytes) { + pr_debug("imxdma%d: sg transfer limit reached\n", + dma_ch); + imxdma->sgcount=0; + imxdma->sg = NULL; + return 0; + } else { + imxdma->sgcount--; + imxdma->sg++; + imxdma->sgbc = 0; } } + nextcount = imxdma->sg->length - imxdma->sgbc; + nextaddr = imxdma->sg->dma_address + imxdma->sgbc; - if (!found) { - /* requested prio group is full, try hier priorities */ - for (i = prio - 1; i >= 0; i--) { - if (!dma_channels[i].name) { - found = 1; - break; - } - } - } + if(imxdma->resbytes < nextcount) + nextcount = imxdma->resbytes; - if (found) { - DIMR &= ~(1 << i); - dma_channels[i].name = name; - dma_channels[i].irq_handler = irq_handler; - dma_channels[i].err_handler = err_handler; - dma_channels[i].data = data; - } else { - printk(KERN_WARNING "No more available DMA channels for %s\n", - name); - i = -ENODEV; - } + if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ) + DAR(dma_ch) = nextaddr; + else + SAR(dma_ch) = nextaddr; - local_irq_restore(flags); - return i; + CNTR(dma_ch) = nextcount; + pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, size 0x%08x\n", + dma_ch, DAR(dma_ch), SAR(dma_ch), CNTR(dma_ch)); + + return nextcount; } -void -imx_free_dma(int dma_ch) +/* + * imx_dma_setup_sg_base - scatter-gather DMA emulation + * @dma_ch: i.MX DMA channel number + * @sg: pointer to the scatter-gather list/vector + * @sgcount: scatter-gather list hungs count + * + * Functions sets up i.MX DMA state for emulated scatter-gather transfer + * and sets up channel registers to be ready for the first chunk + */ +static int +imx_dma_setup_sg_base(imx_dmach_t dma_ch, + struct scatterlist *sg, unsigned int sgcount) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + + imxdma->sg = sg; + imxdma->sgcount = sgcount; + imxdma->sgbc = 0; + return imx_dma_sg_next(dma_ch, 0); +} + +/** + * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from device transfer + * @dma_ch: i.MX DMA channel number + * @dma_address: the DMA/physical memory address of the linear data block + * to transfer + * @dma_length: length of the data block in bytes + * @dev_addr: physical device port address + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory + * or %DMA_MODE_WRITE from memory to the device + * + * The function setups DMA channel source and destination addresses for transfer + * specified by provided parameters. The scatter-gather emulation is disabled, + * because linear data block + * form the physical address range is transfered. + * Return value: if incorrect parameters are provided -%EINVAL. + * Zero indicates success. + */ +int +imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address, + unsigned int dma_length, unsigned int dev_addr, + dmamode_t dmamode) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + + imxdma->sg = NULL; + imxdma->sgcount = 0; + imxdma->dma_mode = dmamode; + imxdma->resbytes = dma_length; + + if (!dma_address) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n", + dma_ch); + return -EINVAL; + } + + if (!dma_length) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n", + dma_ch); + return -EINVAL; + } + + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { + pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for read\n", + dma_ch, (unsigned int)dma_address, dma_length, + dev_addr); + SAR(dma_ch) = dev_addr; + DAR(dma_ch) = (unsigned int)dma_address; + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { + pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for write\n", + dma_ch, (unsigned int)dma_address, dma_length, + dev_addr); + SAR(dma_ch) = (unsigned int)dma_address; + DAR(dma_ch) = dev_addr; + } else { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n", + dma_ch); + return -EINVAL; + } + + CNTR(dma_ch) = dma_length; + + return 0; +} + +/** + * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer + * @dma_ch: i.MX DMA channel number + * @sg: pointer to the scatter-gather list/vector + * @sgcount: scatter-gather list hungs count + * @dma_length: total length of the transfer request in bytes + * @dev_addr: physical device port address + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory + * or %DMA_MODE_WRITE from memory to the device + * + * The function setups DMA channel state and registers to be ready for transfer + * specified by provided parameters. The scatter-gather emulation is set up + * according to the parameters. + * + * The full preparation of the transfer requires setup of more register + * by the caller before imx_dma_enable() can be called. + * + * %BLR(dma_ch) holds transfer burst length in bytes, 0 means 64 bytes + * + * %RSSR(dma_ch) has to be set to the DMA request line source %DMA_REQ_xxx + * + * %CCR(dma_ch) has to specify transfer parameters, the next settings is typical + * for linear or simple scatter-gather transfers if %DMA_MODE_READ is specified + * + * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x + * + * The typical setup for %DMA_MODE_WRITE is specified by next options combination + * + * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x + * + * Be carefull there and do not mistakenly mix source and target device + * port sizes constants, they are really different: + * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32, + * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32 + * + * Return value: if incorrect parameters are provided -%EINVAL. + * Zero indicates success. + */ +int +imx_dma_setup_sg(imx_dmach_t dma_ch, + struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length, + unsigned int dev_addr, dmamode_t dmamode) +{ + int res; + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + + imxdma->sg = NULL; + imxdma->sgcount = 0; + imxdma->dma_mode = dmamode; + imxdma->resbytes = dma_length; + + if (!sg || !sgcount) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg epty sg list\n", + dma_ch); + return -EINVAL; + } + + if (!sg->length) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n", + dma_ch); + return -EINVAL; + } + + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { + pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for read\n", + dma_ch, sg, sgcount, dma_length, dev_addr); + SAR(dma_ch) = dev_addr; + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { + pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for write\n", + dma_ch, sg, sgcount, dma_length, dev_addr); + DAR(dma_ch) = dev_addr; + } else { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n", + dma_ch); + return -EINVAL; + } + + res = imx_dma_setup_sg_base(dma_ch, sg, sgcount); + if (res <= 0) { + printk(KERN_ERR "imxdma%d: no sg chunk ready\n", dma_ch); + return -EINVAL; + } + + return 0; +} + +/** + * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification handlers + * @dma_ch: i.MX DMA channel number + * @irq_handler: the pointer to the function called if the transfer + * ends successfully + * @err_handler: the pointer to the function called if the premature + * end caused by error occurs + * @data: user specified value to be passed to the handlers + */ +int +imx_dma_setup_handlers(imx_dmach_t dma_ch, + void (*irq_handler) (int, void *, struct pt_regs *), + void (*err_handler) (int, void *, struct pt_regs *), + void *data) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + unsigned long flags; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __FUNCTION__, dma_ch); + return -ENODEV; + } + + local_irq_save(flags); + DISR = (1 << dma_ch); + imxdma->irq_handler = irq_handler; + imxdma->err_handler = err_handler; + imxdma->data = data; + local_irq_restore(flags); + return 0; +} + +/** + * imx_dma_enable - function to start i.MX DMA channel operation + * @dma_ch: i.MX DMA channel number + * + * The channel has to be allocated by driver through imx_dma_request() + * or imx_dma_request_by_prio() function. + * The transfer parameters has to be set to the channel registers through + * call of the imx_dma_setup_single() or imx_dma_setup_sg() function + * and registers %BLR(dma_ch), %RSSR(dma_ch) and %CCR(dma_ch) has to + * be set prior this function call by the channel user. + */ +void imx_dma_enable(imx_dmach_t dma_ch) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + unsigned long flags; + + pr_debug("imxdma%d: imx_dma_enable\n", dma_ch); + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __FUNCTION__, dma_ch); + return; + } + + local_irq_save(flags); + DISR = (1 << dma_ch); + DIMR &= ~(1 << dma_ch); + CCR(dma_ch) |= CCR_CEN; + local_irq_restore(flags); +} + +/** + * imx_dma_disable - stop, finish i.MX DMA channel operatin + * @dma_ch: i.MX DMA channel number + */ +void imx_dma_disable(imx_dmach_t dma_ch) { unsigned long flags; - if (!dma_channels[dma_ch].name) { + pr_debug("imxdma%d: imx_dma_disable\n", dma_ch); + + local_irq_save(flags); + DIMR |= (1 << dma_ch); + CCR(dma_ch) &= ~CCR_CEN; + DISR = (1 << dma_ch); + local_irq_restore(flags); +} + +/** + * imx_dma_request - request/allocate specified channel number + * @dma_ch: i.MX DMA channel number + * @name: the driver/caller own non-%NULL identification + */ +int imx_dma_request(imx_dmach_t dma_ch, const char *name) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + unsigned long flags; + + /* basic sanity checks */ + if (!name) + return -EINVAL; + + if (dma_ch >= IMX_DMA_CHANNELS) { + printk(KERN_CRIT "%s: called for non-existed channel %d\n", + __FUNCTION__, dma_ch); + return -EINVAL; + } + + local_irq_save(flags); + if (imxdma->name) { + local_irq_restore(flags); + return -ENODEV; + } + + imxdma->name = name; + imxdma->irq_handler = NULL; + imxdma->err_handler = NULL; + imxdma->data = NULL; + imxdma->sg = NULL; + local_irq_restore(flags); + return 0; +} + +/** + * imx_dma_free - release previously acquired channel + * @dma_ch: i.MX DMA channel number + */ +void imx_dma_free(imx_dmach_t dma_ch) +{ + unsigned long flags; + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; + + if (!imxdma->name) { printk(KERN_CRIT "%s: trying to free channel %d which is already freed\n", __FUNCTION__, dma_ch); @@ -92,27 +398,84 @@ imx_free_dma(int dma_ch) } local_irq_save(flags); - DIMR &= ~(1 << dma_ch); - dma_channels[dma_ch].name = NULL; + /* Disable interrupts */ + DIMR |= (1 << dma_ch); + CCR(dma_ch) &= ~CCR_CEN; + imxdma->name = NULL; local_irq_restore(flags); } -static irqreturn_t -dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) +/** + * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority + * @dma_ch: i.MX DMA channel number + * @name: the driver/caller own non-%NULL identification + * @prio: one of the hardware distinguished priority level: + * %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW + * + * This function tries to find free channel in the specified priority group + * if the priority cannot be achieved it tries to look for free channel + * in the higher and then even lower priority groups. + * + * Return value: If there is no free channel to allocate, -%ENODEV is returned. + * Zero value indicates successful channel allocation. + */ +int +imx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name, + imx_dma_prio prio) +{ + int i; + int best; + + switch (prio) { + case (DMA_PRIO_HIGH): + best = 8; + break; + case (DMA_PRIO_MEDIUM): + best = 4; + break; + case (DMA_PRIO_LOW): + default: + best = 0; + break; + } + + for (i = best; i < IMX_DMA_CHANNELS; i++) { + if (!imx_dma_request(i, name)) { + *pdma_ch = i; + return 0; + } + } + + for (i = best - 1; i >= 0; i--) { + if (!imx_dma_request(i, name)) { + *pdma_ch = i; + return 0; + } + } + + printk(KERN_ERR "%s: no free DMA channel found\n", __FUNCTION__); + + return -ENODEV; +} + +static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) { int i, disr = DISR; - struct dma_channel *channel; + struct imx_dma_channel *channel; unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR; DISR = disr; - for (i = 0; i < 11; i++) { - channel = &dma_channels[i]; + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + channel = &imx_dma_channels[i]; - if ( (err_mask & 1<name && channel->err_handler) { + if ((err_mask & 1 << i) && channel->name + && channel->err_handler) { channel->err_handler(i, channel->data, regs); continue; } + imx_dma_channels[i].sg = NULL; + if (DBTOSR & (1 << i)) { printk(KERN_WARNING "Burst timeout on channel %d (%s)\n", @@ -141,17 +504,27 @@ dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static irqreturn_t -dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { int i, disr = DISR; + pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n", + disr); + DISR = disr; - for (i = 0; i < 11; i++) { + for (i = 0; i < IMX_DMA_CHANNELS; i++) { if (disr & (1 << i)) { - struct dma_channel *channel = &dma_channels[i]; - if (channel->name && channel->irq_handler) { - channel->irq_handler(i, channel->data, regs); + struct imx_dma_channel *channel = &imx_dma_channels[i]; + if (channel->name) { + if (imx_dma_sg_next(i, CNTR(i))) { + CCR(i) &= ~CCR_CEN; + mb(); + CCR(i) |= CCR_CEN; + } else { + if (channel->irq_handler) + channel->irq_handler(i, + channel->data, regs); + } } else { /* * IRQ for an unregistered DMA channel: @@ -165,10 +538,10 @@ dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -static int __init -imx_dma_init(void) +static int __init imx_dma_init(void) { int ret; + int i; /* reset DMA module */ DCR = DCR_DRST; @@ -189,15 +562,27 @@ imx_dma_init(void) DCR = DCR_DEN; /* clear all interrupts */ - DISR = 0x3ff; + DISR = (1 << IMX_DMA_CHANNELS) - 1; /* enable interrupts */ - DIMR = 0; + DIMR = (1 << IMX_DMA_CHANNELS) - 1; + + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + imx_dma_channels[i].sg = NULL; + imx_dma_channels[i].dma_num = i; + } return ret; } arch_initcall(imx_dma_init); -EXPORT_SYMBOL(imx_request_dma); -EXPORT_SYMBOL(imx_free_dma); +EXPORT_SYMBOL(imx_dma_setup_single); +EXPORT_SYMBOL(imx_dma_setup_sg); +EXPORT_SYMBOL(imx_dma_setup_handlers); +EXPORT_SYMBOL(imx_dma_enable); +EXPORT_SYMBOL(imx_dma_disable); +EXPORT_SYMBOL(imx_dma_request); +EXPORT_SYMBOL(imx_dma_free); +EXPORT_SYMBOL(imx_dma_request_by_prio); +EXPORT_SYMBOL(imx_dma_channels); diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index 37613ad68366..9d8331be2b58 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c @@ -33,6 +33,7 @@ #include #include +#include void imx_gpio_mode(int gpio_mode) { @@ -175,13 +176,25 @@ static struct resource imx_mmc_resources[] = { }, }; +static u64 imxmmmc_dmamask = 0xffffffffUL; + static struct platform_device imx_mmc_device = { .name = "imx-mmc", .id = 0, + .dev = { + .dma_mask = &imxmmmc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, .num_resources = ARRAY_SIZE(imx_mmc_resources), .resource = imx_mmc_resources, }; +void __init imx_set_mmc_info(struct imxmmc_platform_data *info) +{ + imx_mmc_device.dev.platform_data = info; +} +EXPORT_SYMBOL(imx_set_mmc_info); + static struct resource imx_uart1_resources[] = { [0] = { .start = 0x00206000, diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c index 8ab1b040288c..e34d0df90aed 100644 --- a/arch/arm/mach-imx/mx1ads.c +++ b/arch/arm/mach-imx/mx1ads.c @@ -25,6 +25,7 @@ #include #include +#include #include #include "generic.h" @@ -51,11 +52,28 @@ static struct platform_device *devices[] __initdata = { &cs89x0_device, }; +#ifdef CONFIG_MMC_IMX +static int mx1ads_mmc_card_present(void) +{ + /* MMC/SD Card Detect is PB 20 on MX1ADS V1.0.7 */ + return (SSR(1) & (1 << 20) ? 0 : 1); +} + +static struct imxmmc_platform_data mx1ads_mmc_info = { + .card_present = mx1ads_mmc_card_present, +}; +#endif + static void __init mx1ads_init(void) { #ifdef CONFIG_LEDS imx_gpio_mode(GPIO_PORTA | GPIO_OUT | 2); +#endif +#ifdef CONFIG_MMC_IMX + /* SD/MMC card detect */ + imx_gpio_mode(GPIO_PORTB | GPIO_GIUS | GPIO_IN | 20); + imx_set_mmc_info(&mx1ads_mmc_info); #endif platform_add_devices(devices, ARRAY_SIZE(devices)); } diff --git a/arch/arm/mach-ixp23xx/espresso.c b/arch/arm/mach-ixp23xx/espresso.c index 2327c9790416..bf688c128630 100644 --- a/arch/arm/mach-ixp23xx/espresso.c +++ b/arch/arm/mach-ixp23xx/espresso.c @@ -44,6 +44,15 @@ #include #include +static int __init espresso_pci_init(void) +{ + if (machine_is_espresso()) + ixp23xx_pci_slave_init(); + + return 0; +}; +subsys_initcall(espresso_pci_init); + static void __init espresso_init(void) { physmap_configure(0x90000000, 0x02000000, 2, NULL); diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c index 5330ad78c1bb..ac72f94c5b4d 100644 --- a/arch/arm/mach-ixp23xx/pci.c +++ b/arch/arm/mach-ixp23xx/pci.c @@ -201,7 +201,7 @@ int clear_master_aborts(void) return 0; } -void __init ixp23xx_pci_preinit(void) +static void __init ixp23xx_pci_common_init(void) { #ifdef __ARMEB__ *IXP23XX_PCI_CONTROL |= 0x20000; /* set I/O swapping */ @@ -219,7 +219,18 @@ void __init ixp23xx_pci_preinit(void) *IXP23XX_PCI_CPP_ADDR_BITS &= ~(1 << 1); } else { *IXP23XX_PCI_CPP_ADDR_BITS |= (1 << 1); + + /* + * Enable coherency on A2 silicon. + */ + if (arch_is_coherent()) + *IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_COH_OFF; } +} + +void __init ixp23xx_pci_preinit(void) +{ + ixp23xx_pci_common_init(); hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS, "PCI config cycle to non-existent device"); @@ -273,3 +284,8 @@ int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys) return 1; } + +void ixp23xx_pci_slave_init(void) +{ + ixp23xx_pci_common_init(); +} diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 86a0f0d14345..f8d716ccc1df 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -69,12 +69,6 @@ config MACH_VOICEBLUE Support for Voiceblue GSM/VoIP gateway. Say Y here if you have such a board. -config MACH_NETSTAR - bool "NetStar" - depends on ARCH_OMAP1 && ARCH_OMAP15XX - help - Support for NetStar PBX. Say Y here if you have such a board. - config MACH_OMAP_PALMTE bool "Palm Tungsten E" depends on ARCH_OMAP1 && ARCH_OMAP15XX @@ -85,6 +79,20 @@ config MACH_OMAP_PALMTE informations. Say Y here if you have such a PDA, say NO otherwise. +config MACH_NOKIA770 + bool "Nokia 770" + depends on ARCH_OMAP1 && ARCH_OMAP16XX + help + Support for the Nokia 770 Internet Tablet. Say Y here if you + have such a device. + +config MACH_AMS_DELTA + bool "Amstrad E3 (Delta)" + depends on ARCH_OMAP1 && ARCH_OMAP15XX + help + Support for the Amstrad E3 (codename Delta) videophone. Say Y here + if you have such a device. + config MACH_OMAP_GENERIC bool "Generic OMAP board" depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX) diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index b0b00156faae..9ea719550ad3 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -3,7 +3,13 @@ # # Common support -obj-y := io.o id.o clock.o irq.o time.o mux.o serial.o devices.o +obj-y := io.o id.o clock.o irq.o mux.o serial.o devices.o + +obj-$(CONFIG_OMAP_MPU_TIMER) += time.o + +# Power Management +obj-$(CONFIG_PM) += pm.o sleep.o + led-y := leds.o # Specific board support @@ -14,8 +20,9 @@ obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o -obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o +obj-$(CONFIG_MACH_NOKIA770) += board-nokia770.o +obj-$(CONFIG_MACH_AMS_DELTA) += board-ams-delta.o ifeq ($(CONFIG_ARCH_OMAP15XX),y) # Innovator-1510 FPGA diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c new file mode 100644 index 000000000000..6178f046f128 --- /dev/null +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -0,0 +1,116 @@ +/* + * linux/arch/arm/mach-omap1/board-ams-delta.c + * + * Modified from board-generic.c + * + * Board specific inits for the Amstrad E3 (codename Delta) videophone + * + * Copyright (C) 2006 Jonathan McDowell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static u8 ams_delta_latch1_reg; +static u16 ams_delta_latch2_reg; + +void ams_delta_latch1_write(u8 mask, u8 value) +{ + ams_delta_latch1_reg &= ~mask; + ams_delta_latch1_reg |= value; + *(volatile __u8 *) AMS_DELTA_LATCH1_VIRT = ams_delta_latch1_reg; +} + +void ams_delta_latch2_write(u16 mask, u16 value) +{ + ams_delta_latch2_reg &= ~mask; + ams_delta_latch2_reg |= value; + *(volatile __u16 *) AMS_DELTA_LATCH2_VIRT = ams_delta_latch2_reg; +} + +static void __init ams_delta_init_irq(void) +{ + omap1_init_common_hw(); + omap_init_irq(); + omap_gpio_init(); +} + +static struct map_desc ams_delta_io_desc[] __initdata = { + // AMS_DELTA_LATCH1 + { + .virtual = AMS_DELTA_LATCH1_VIRT, + .pfn = __phys_to_pfn(AMS_DELTA_LATCH1_PHYS), + .length = 0x01000000, + .type = MT_DEVICE + }, + // AMS_DELTA_LATCH2 + { + .virtual = AMS_DELTA_LATCH2_VIRT, + .pfn = __phys_to_pfn(AMS_DELTA_LATCH2_PHYS), + .length = 0x01000000, + .type = MT_DEVICE + }, + // AMS_DELTA_MODEM + { + .virtual = AMS_DELTA_MODEM_VIRT, + .pfn = __phys_to_pfn(AMS_DELTA_MODEM_PHYS), + .length = 0x01000000, + .type = MT_DEVICE + } +}; + +static struct omap_uart_config ams_delta_uart_config __initdata = { + .enabled_uarts = 1, +}; + +static struct omap_board_config_kernel ams_delta_config[] = { + { OMAP_TAG_UART, &ams_delta_uart_config }, +}; + +static void __init ams_delta_init(void) +{ + iotable_init(ams_delta_io_desc, ARRAY_SIZE(ams_delta_io_desc)); + + omap_board_config = ams_delta_config; + omap_board_config_size = ARRAY_SIZE(ams_delta_config); + omap_serial_init(); + + /* Clear latch2 (NAND, LCD, modem enable) */ + ams_delta_latch2_write(~0, 0); +} + +static void __init ams_delta_map_io(void) +{ + omap1_map_common_io(); +} + +MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)") + /* Maintainer: Jonathan McDowell */ + .phys_io = 0xfff00000, + .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc, + .boot_params = 0x10000100, + .map_io = ams_delta_map_io, + .init_irq = ams_delta_init_irq, + .init_machine = ams_delta_init, + .timer = &omap_timer, +MACHINE_END + +EXPORT_SYMBOL(ams_delta_latch1_write); +EXPORT_SYMBOL(ams_delta_latch2_write); diff --git a/arch/arm/mach-omap1/board-generic.c b/arch/arm/mach-omap1/board-generic.c index a177e78b2b87..33d01adab1ed 100644 --- a/arch/arm/mach-omap1/board-generic.c +++ b/arch/arm/mach-omap1/board-generic.c @@ -88,7 +88,7 @@ static struct omap_board_config_kernel generic_config[] = { static void __init omap_generic_init(void) { #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { generic_config[0].data = &generic1510_usb_config; } #endif diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c index 89f0cc74a519..cd3a06dfc0a8 100644 --- a/arch/arm/mach-omap1/board-h2.c +++ b/arch/arm/mach-omap1/board-h2.c @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include #include @@ -35,12 +37,55 @@ #include #include #include +#include #include +#include #include +#include +#include extern int omap_gpio_init(void); -static struct mtd_partition h2_partitions[] = { +static int h2_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_3), + KEY(0, 3, KEY_F10), + KEY(0, 4, KEY_F5), + KEY(0, 5, KEY_9), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_2), + KEY(1, 3, KEY_F9), + KEY(1, 4, KEY_F7), + KEY(1, 5, KEY_0), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_6), + KEY(2, 2, KEY_1), + KEY(2, 3, KEY_F2), + KEY(2, 4, KEY_F6), + KEY(2, 5, KEY_HOME), + KEY(3, 0, KEY_8), + KEY(3, 1, KEY_5), + KEY(3, 2, KEY_F12), + KEY(3, 3, KEY_F3), + KEY(3, 4, KEY_F8), + KEY(3, 5, KEY_END), + KEY(4, 0, KEY_7), + KEY(4, 1, KEY_4), + KEY(4, 2, KEY_F11), + KEY(4, 3, KEY_F1), + KEY(4, 4, KEY_F4), + KEY(4, 5, KEY_ESC), + KEY(5, 0, KEY_F13), + KEY(5, 1, KEY_F14), + KEY(5, 2, KEY_F15), + KEY(5, 3, KEY_F16), + KEY(5, 4, KEY_SLEEP), + 0 +}; + +static struct mtd_partition h2_nor_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { .name = "bootloader", @@ -71,26 +116,26 @@ static struct mtd_partition h2_partitions[] = { } }; -static struct flash_platform_data h2_flash_data = { +static struct flash_platform_data h2_nor_data = { .map_name = "cfi_probe", .width = 2, - .parts = h2_partitions, - .nr_parts = ARRAY_SIZE(h2_partitions), + .parts = h2_nor_partitions, + .nr_parts = ARRAY_SIZE(h2_nor_partitions), }; -static struct resource h2_flash_resource = { +static struct resource h2_nor_resource = { /* This is on CS3, wherever it's mapped */ .flags = IORESOURCE_MEM, }; -static struct platform_device h2_flash_device = { +static struct platform_device h2_nor_device = { .name = "omapflash", .id = 0, .dev = { - .platform_data = &h2_flash_data, + .platform_data = &h2_nor_data, }, .num_resources = 1, - .resource = &h2_flash_resource, + .resource = &h2_nor_resource, }; static struct resource h2_smc91x_resources[] = { @@ -113,9 +158,119 @@ static struct platform_device h2_smc91x_device = { .resource = h2_smc91x_resources, }; +static struct resource h2_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data h2_kp_data = { + .rows = 8, + .cols = 8, + .keymap = h2_keymap, + .rep = 1, +}; + +static struct platform_device h2_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &h2_kp_data, + }, + .num_resources = ARRAY_SIZE(h2_kp_resources), + .resource = h2_kp_resources, +}; + +#define H2_IRDA_FIRSEL_GPIO_PIN 17 + +#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE) +static int h2_transceiver_mode(struct device *dev, int state) +{ + if (state & IR_SIRMODE) + omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 0); + else /* MIR/FIR */ + omap_set_gpio_dataout(H2_IRDA_FIRSEL_GPIO_PIN, 1); + + return 0; +} +#endif + +static struct omap_irda_config h2_irda_data = { + .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE, + .rx_channel = OMAP_DMA_UART3_RX, + .tx_channel = OMAP_DMA_UART3_TX, + .dest_start = UART3_THR, + .src_start = UART3_RHR, + .tx_trigger = 0, + .rx_trigger = 0, +}; + +static struct resource h2_irda_resources[] = { + [0] = { + .start = INT_UART3, + .end = INT_UART3, + .flags = IORESOURCE_IRQ, + }, +}; +static struct platform_device h2_irda_device = { + .name = "omapirda", + .id = 0, + .dev = { + .platform_data = &h2_irda_data, + }, + .num_resources = ARRAY_SIZE(h2_irda_resources), + .resource = h2_irda_resources, +}; + +static struct platform_device h2_lcd_device = { + .name = "lcd_h2", + .id = -1, +}; + +static struct omap_mcbsp_reg_cfg mcbsp_regs = { + .spcr2 = FREE | FRST | GRST | XRST | XINTM(3), + .spcr1 = RINTM(3) | RRST, + .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) | + RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(1), + .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16), + .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) | + XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(1) | XFIG, + .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16), + .srgr1 = FWID(15), + .srgr2 = GSYNC | CLKSP | FSGM | FPER(31), + + .pcr0 = CLKXM | CLKRM | FSXP | FSRP | CLKXP | CLKRP, + //.pcr0 = CLKXP | CLKRP, /* mcbsp: slave */ +}; + +static struct omap_alsa_codec_config alsa_config = { + .name = "H2 TSC2101", + .mcbsp_regs_alsa = &mcbsp_regs, + .codec_configure_dev = NULL, // tsc2101_configure, + .codec_set_samplerate = NULL, // tsc2101_set_samplerate, + .codec_clock_setup = NULL, // tsc2101_clock_setup, + .codec_clock_on = NULL, // tsc2101_clock_on, + .codec_clock_off = NULL, // tsc2101_clock_off, + .get_default_samplerate = NULL, // tsc2101_get_default_samplerate, +}; + +static struct platform_device h2_mcbsp1_device = { + .name = "omap_alsa_mcbsp", + .id = 1, + .dev = { + .platform_data = &alsa_config, + }, +}; + static struct platform_device *h2_devices[] __initdata = { - &h2_flash_device, + &h2_nor_device, &h2_smc91x_device, + &h2_irda_device, + &h2_kp_device, + &h2_lcd_device, + &h2_mcbsp1_device, }; static void __init h2_init_smc91x(void) @@ -164,7 +319,6 @@ static struct omap_uart_config h2_uart_config __initdata = { }; static struct omap_lcd_config h2_lcd_config __initdata = { - .panel_name = "h2", .ctrl_name = "internal", }; @@ -177,16 +331,34 @@ static struct omap_board_config_kernel h2_config[] = { static void __init h2_init(void) { - /* NOTE: revC boards support NAND-boot, which can put NOR on CS2B - * and NAND (either 16bit or 8bit) on CS3. + /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped + * to address 0 by a dip switch), NAND on CS2B. The NAND driver will + * notice whether a NAND chip is enabled at probe time. + * + * FIXME revC boards (and H3) support NAND-boot, with a dip switch to + * put NOR on CS2B and NAND (which on H2 may be 16bit) on CS3. Try + * detecting that in code here, to avoid probing every possible flash + * configuration... */ - h2_flash_resource.end = h2_flash_resource.start = omap_cs3_phys(); - h2_flash_resource.end += SZ_32M - 1; + h2_nor_resource.end = h2_nor_resource.start = omap_cs3_phys(); + h2_nor_resource.end += SZ_32M - 1; + + omap_cfg_reg(L3_1610_FLASH_CS2B_OE); + omap_cfg_reg(M8_1610_FLASH_CS2B_WE); /* MMC: card detect and WP */ // omap_cfg_reg(U19_ARMIO1); /* CD */ omap_cfg_reg(BALLOUT_V8_ARMIO3); /* WP */ + /* Irda */ +#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE) + omap_writel(omap_readl(FUNC_MUX_CTRL_A) | 7, FUNC_MUX_CTRL_A); + if (!(omap_request_gpio(H2_IRDA_FIRSEL_GPIO_PIN))) { + omap_set_gpio_direction(H2_IRDA_FIRSEL_GPIO_PIN, 0); + h2_irda_data.transceiver_mode = h2_transceiver_mode; + } +#endif + platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices)); omap_board_config = h2_config; omap_board_config_size = ARRAY_SIZE(h2_config); diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c index d9f386265996..4b8d0ec73cb7 100644 --- a/arch/arm/mach-omap1/board-h3.c +++ b/arch/arm/mach-omap1/board-h3.c @@ -21,8 +21,11 @@ #include #include #include +#include #include +#include #include +#include #include #include @@ -33,15 +36,59 @@ #include #include +#include #include #include #include +#include #include +#include +#include #include extern int omap_gpio_init(void); -static struct mtd_partition h3_partitions[] = { +static int h3_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_3), + KEY(0, 3, KEY_F10), + KEY(0, 4, KEY_F5), + KEY(0, 5, KEY_9), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_2), + KEY(1, 3, KEY_F9), + KEY(1, 4, KEY_F7), + KEY(1, 5, KEY_0), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_6), + KEY(2, 2, KEY_1), + KEY(2, 3, KEY_F2), + KEY(2, 4, KEY_F6), + KEY(2, 5, KEY_HOME), + KEY(3, 0, KEY_8), + KEY(3, 1, KEY_5), + KEY(3, 2, KEY_F12), + KEY(3, 3, KEY_F3), + KEY(3, 4, KEY_F8), + KEY(3, 5, KEY_END), + KEY(4, 0, KEY_7), + KEY(4, 1, KEY_4), + KEY(4, 2, KEY_F11), + KEY(4, 3, KEY_F1), + KEY(4, 4, KEY_F4), + KEY(4, 5, KEY_ESC), + KEY(5, 0, KEY_F13), + KEY(5, 1, KEY_F14), + KEY(5, 2, KEY_F15), + KEY(5, 3, KEY_F16), + KEY(5, 4, KEY_SLEEP), + 0 +}; + + +static struct mtd_partition nor_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { .name = "bootloader", @@ -72,26 +119,80 @@ static struct mtd_partition h3_partitions[] = { } }; -static struct flash_platform_data h3_flash_data = { +static struct flash_platform_data nor_data = { .map_name = "cfi_probe", .width = 2, - .parts = h3_partitions, - .nr_parts = ARRAY_SIZE(h3_partitions), + .parts = nor_partitions, + .nr_parts = ARRAY_SIZE(nor_partitions), }; -static struct resource h3_flash_resource = { +static struct resource nor_resource = { /* This is on CS3, wherever it's mapped */ .flags = IORESOURCE_MEM, }; -static struct platform_device flash_device = { +static struct platform_device nor_device = { .name = "omapflash", .id = 0, .dev = { - .platform_data = &h3_flash_data, + .platform_data = &nor_data, }, .num_resources = 1, - .resource = &h3_flash_resource, + .resource = &nor_resource, +}; + +static struct mtd_partition nand_partitions[] = { +#if 0 + /* REVISIT: enable these partitions if you make NAND BOOT work */ + { + .name = "xloader", + .offset = 0, + .size = 64 * 1024, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "bootloader", + .offset = MTDPART_OFS_APPEND, + .size = 256 * 1024, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = 192 * 1024, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = 2 * SZ_1M, + }, +#endif + { + .name = "filesystem", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + }, +}; + +/* dip switches control NAND chip access: 8 bit, 16 bit, or neither */ +static struct nand_platform_data nand_data = { + .options = NAND_SAMSUNG_LP_OPTIONS, + .parts = nand_partitions, + .nr_parts = ARRAY_SIZE(nand_partitions), +}; + +static struct resource nand_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device nand_device = { + .name = "omapnand", + .id = 0, + .dev = { + .platform_data = &nand_data, + }, + .num_resources = 1, + .resource = &nand_resource, }; static struct resource smc91x_resources[] = { @@ -138,10 +239,136 @@ static struct platform_device intlat_device = { .resource = intlat_resources, }; +static struct resource h3_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data h3_kp_data = { + .rows = 8, + .cols = 8, + .keymap = h3_keymap, + .rep = 1, +}; + +static struct platform_device h3_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &h3_kp_data, + }, + .num_resources = ARRAY_SIZE(h3_kp_resources), + .resource = h3_kp_resources, +}; + + +/* Select between the IrDA and aGPS module + */ +static int h3_select_irda(struct device *dev, int state) +{ + unsigned char expa; + int err = 0; + + if ((err = read_gpio_expa(&expa, 0x26))) { + printk(KERN_ERR "Error reading from I/O EXPANDER \n"); + return err; + } + + /* 'P6' enable/disable IRDA_TX and IRDA_RX */ + if (state & IR_SEL) { /* IrDA */ + if ((err = write_gpio_expa(expa | 0x40, 0x26))) { + printk(KERN_ERR "Error writing to I/O EXPANDER \n"); + return err; + } + } else { + if ((err = write_gpio_expa(expa & ~0x40, 0x26))) { + printk(KERN_ERR "Error writing to I/O EXPANDER \n"); + return err; + } + } + return err; +} + +static void set_trans_mode(void *data) +{ + int *mode = data; + unsigned char expa; + int err = 0; + + if ((err = read_gpio_expa(&expa, 0x27)) != 0) { + printk(KERN_ERR "Error reading from I/O expander\n"); + } + + expa &= ~0x03; + + if (*mode & IR_SIRMODE) { + expa |= 0x01; + } else { /* MIR/FIR */ + expa |= 0x03; + } + + if ((err = write_gpio_expa(expa, 0x27)) != 0) { + printk(KERN_ERR "Error writing to I/O expander\n"); + } +} + +static int h3_transceiver_mode(struct device *dev, int mode) +{ + struct omap_irda_config *irda_config = dev->platform_data; + + cancel_delayed_work(&irda_config->gpio_expa); + PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode); + schedule_work(&irda_config->gpio_expa); + + return 0; +} + +static struct omap_irda_config h3_irda_data = { + .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE, + .transceiver_mode = h3_transceiver_mode, + .select_irda = h3_select_irda, + .rx_channel = OMAP_DMA_UART3_RX, + .tx_channel = OMAP_DMA_UART3_TX, + .dest_start = UART3_THR, + .src_start = UART3_RHR, + .tx_trigger = 0, + .rx_trigger = 0, +}; + +static struct resource h3_irda_resources[] = { + [0] = { + .start = INT_UART3, + .end = INT_UART3, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device h3_irda_device = { + .name = "omapirda", + .id = 0, + .dev = { + .platform_data = &h3_irda_data, + }, + .num_resources = ARRAY_SIZE(h3_irda_resources), + .resource = h3_irda_resources, +}; + +static struct platform_device h3_lcd_device = { + .name = "lcd_h3", + .id = -1, +}; + static struct platform_device *devices[] __initdata = { - &flash_device, + &nor_device, + &nand_device, &smc91x_device, &intlat_device, + &h3_irda_device, + &h3_kp_device, + &h3_lcd_device, }; static struct omap_usb_config h3_usb_config __initdata = { @@ -171,7 +398,6 @@ static struct omap_uart_config h3_uart_config __initdata = { }; static struct omap_lcd_config h3_lcd_config __initdata = { - .panel_name = "h3", .ctrl_name = "internal", }; @@ -182,11 +408,36 @@ static struct omap_board_config_kernel h3_config[] = { { OMAP_TAG_LCD, &h3_lcd_config }, }; +#define H3_NAND_RB_GPIO_PIN 10 + +static int nand_dev_ready(struct nand_platform_data *data) +{ + return omap_get_gpio_datain(H3_NAND_RB_GPIO_PIN); +} + static void __init h3_init(void) { - h3_flash_resource.end = h3_flash_resource.start = omap_cs3_phys(); - h3_flash_resource.end += OMAP_CS3_SIZE - 1; - (void) platform_add_devices(devices, ARRAY_SIZE(devices)); + /* Here we assume the NOR boot config: NOR on CS3 (possibly swapped + * to address 0 by a dip switch), NAND on CS2B. The NAND driver will + * notice whether a NAND chip is enabled at probe time. + * + * H3 support NAND-boot, with a dip switch to put NOR on CS2B and NAND + * (which on H2 may be 16bit) on CS3. Try detecting that in code here, + * to avoid probing every possible flash configuration... + */ + nor_resource.end = nor_resource.start = omap_cs3_phys(); + nor_resource.end += SZ_32M - 1; + + nand_resource.end = nand_resource.start = OMAP_CS2B_PHYS; + nand_resource.end += SZ_4K - 1; + if (!(omap_request_gpio(H3_NAND_RB_GPIO_PIN))) + nand_data.dev_ready = nand_dev_ready; + + /* GPIO10 Func_MUX_CTRL reg bit 29:27, Configure V2 to mode1 as GPIO */ + /* GPIO10 pullup/down register, Enable pullup on GPIO10 */ + omap_cfg_reg(V2_1710_GPIO10); + + platform_add_devices(devices, ARRAY_SIZE(devices)); omap_board_config = h3_config; omap_board_config_size = ARRAY_SIZE(h3_config); omap_serial_init(); diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c index a04e4332915e..e90c137a4cf3 100644 --- a/arch/arm/mach-omap1/board-innovator.c +++ b/arch/arm/mach-omap1/board-innovator.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -34,8 +35,22 @@ #include #include #include +#include #include +static int innovator_keymap[] = { + KEY(0, 0, KEY_F1), + KEY(0, 3, KEY_DOWN), + KEY(1, 1, KEY_F2), + KEY(1, 2, KEY_RIGHT), + KEY(2, 0, KEY_F3), + KEY(2, 1, KEY_F4), + KEY(2, 2, KEY_UP), + KEY(3, 2, KEY_ENTER), + KEY(3, 3, KEY_LEFT), + 0 +}; + static struct mtd_partition innovator_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { @@ -97,6 +112,31 @@ static struct platform_device innovator_flash_device = { .resource = &innovator_flash_resource, }; +static struct resource innovator_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data innovator_kp_data = { + .rows = 8, + .cols = 8, + .keymap = innovator_keymap, +}; + +static struct platform_device innovator_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &innovator_kp_data, + }, + .num_resources = ARRAY_SIZE(innovator_kp_resources), + .resource = innovator_kp_resources, +}; + + #ifdef CONFIG_ARCH_OMAP15XX /* Only FPGA needs to be mapped here. All others are done with ioremap */ @@ -129,9 +169,16 @@ static struct platform_device innovator1510_smc91x_device = { .resource = innovator1510_smc91x_resources, }; +static struct platform_device innovator1510_lcd_device = { + .name = "lcd_inn1510", + .id = -1, +}; + static struct platform_device *innovator1510_devices[] __initdata = { &innovator_flash_device, &innovator1510_smc91x_device, + &innovator_kp_device, + &innovator1510_lcd_device, }; #endif /* CONFIG_ARCH_OMAP15XX */ @@ -158,9 +205,16 @@ static struct platform_device innovator1610_smc91x_device = { .resource = innovator1610_smc91x_resources, }; +static struct platform_device innovator1610_lcd_device = { + .name = "inn1610_lcd", + .id = -1, +}; + static struct platform_device *innovator1610_devices[] __initdata = { &innovator_flash_device, &innovator1610_smc91x_device, + &innovator_kp_device, + &innovator1610_lcd_device, }; #endif /* CONFIG_ARCH_OMAP16XX */ @@ -206,7 +260,6 @@ static struct omap_usb_config innovator1510_usb_config __initdata = { }; static struct omap_lcd_config innovator1510_lcd_config __initdata = { - .panel_name = "inn1510", .ctrl_name = "internal", }; #endif @@ -228,7 +281,6 @@ static struct omap_usb_config h2_usb_config __initdata = { }; static struct omap_lcd_config innovator1610_lcd_config __initdata = { - .panel_name = "inn1610", .ctrl_name = "internal", }; #endif diff --git a/arch/arm/mach-omap1/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c deleted file mode 100644 index 7520e602d7a2..000000000000 --- a/arch/arm/mach-omap1/board-netstar.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Modified from board-generic.c - * - * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl - * - * Code for Netstar OMAP board. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -extern void __init omap_init_time(void); -extern int omap_gpio_init(void); - -static struct resource netstar_smc91x_resources[] = { - [0] = { - .start = OMAP_CS1_PHYS + 0x300, - .end = OMAP_CS1_PHYS + 0x300 + 16, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = OMAP_GPIO_IRQ(8), - .end = OMAP_GPIO_IRQ(8), - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device netstar_smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(netstar_smc91x_resources), - .resource = netstar_smc91x_resources, -}; - -static struct platform_device *netstar_devices[] __initdata = { - &netstar_smc91x_device, -}; - -static struct omap_uart_config netstar_uart_config __initdata = { - .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), -}; - -static struct omap_board_config_kernel netstar_config[] = { - { OMAP_TAG_UART, &netstar_uart_config }, -}; - -static void __init netstar_init_irq(void) -{ - omap1_init_common_hw(); - omap_init_irq(); - omap_gpio_init(); -} - -static void __init netstar_init(void) -{ - /* green LED */ - omap_request_gpio(4); - omap_set_gpio_direction(4, 0); - /* smc91x reset */ - omap_request_gpio(7); - omap_set_gpio_direction(7, 0); - omap_set_gpio_dataout(7, 1); - udelay(2); /* wait at least 100ns */ - omap_set_gpio_dataout(7, 0); - mdelay(50); /* 50ms until PHY ready */ - /* smc91x interrupt pin */ - omap_request_gpio(8); - - omap_request_gpio(12); - omap_request_gpio(13); - omap_request_gpio(14); - omap_request_gpio(15); - set_irq_type(OMAP_GPIO_IRQ(12), IRQT_FALLING); - set_irq_type(OMAP_GPIO_IRQ(13), IRQT_FALLING); - set_irq_type(OMAP_GPIO_IRQ(14), IRQT_FALLING); - set_irq_type(OMAP_GPIO_IRQ(15), IRQT_FALLING); - - platform_add_devices(netstar_devices, ARRAY_SIZE(netstar_devices)); - - /* Switch on green LED */ - omap_set_gpio_dataout(4, 0); - /* Switch off red LED */ - omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */ - omap_writeb(0x80, OMAP_LPG1_LCR); - - omap_board_config = netstar_config; - omap_board_config_size = ARRAY_SIZE(netstar_config); - omap_serial_init(); -} - -static void __init netstar_map_io(void) -{ - omap1_map_common_io(); -} - -#define MACHINE_PANICED 1 -#define MACHINE_REBOOTING 2 -#define MACHINE_REBOOT 4 -static unsigned long machine_state; - -static int panic_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - if (test_and_set_bit(MACHINE_PANICED, &machine_state)) - return NOTIFY_DONE; - - /* Switch off green LED */ - omap_set_gpio_dataout(4, 1); - /* Flash red LED */ - omap_writeb(0x78, OMAP_LPG1_LCR); - omap_writeb(0x01, OMAP_LPG1_PMR); /* Enable clock */ - - return NOTIFY_DONE; -} - -static struct notifier_block panic_block = { - .notifier_call = panic_event, -}; - -static int __init netstar_late_init(void) -{ - /* TODO: Setup front panel switch here */ - - /* Setup panic notifier */ - atomic_notifier_chain_register(&panic_notifier_list, &panic_block); - - return 0; -} - -postcore_initcall(netstar_late_init); - -MACHINE_START(NETSTAR, "NetStar OMAP5910") - /* Maintainer: Ladislav Michl */ - .phys_io = 0xfff00000, - .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc, - .boot_params = 0x10000100, - .map_io = netstar_map_io, - .init_irq = netstar_init_irq, - .init_machine = netstar_init, - .timer = &omap_timer, -MACHINE_END diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c new file mode 100644 index 000000000000..02b980d77b12 --- /dev/null +++ b/arch/arm/mach-omap1/board-nokia770.c @@ -0,0 +1,268 @@ +/* + * linux/arch/arm/mach-omap1/board-nokia770.c + * + * Modified from board-generic.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __init omap_nokia770_init_irq(void) +{ + /* On Nokia 770, the SleepX signal is masked with an + * MPUIO line by default. It has to be unmasked for it + * to become functional */ + + /* SleepX mask direction */ + omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008); + /* Unmask SleepX signal */ + omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004); + + omap1_init_common_hw(); + omap_init_irq(); +} + +static int nokia770_keymap[] = { + KEY(0, 1, GROUP_0 | KEY_UP), + KEY(0, 2, GROUP_1 | KEY_F5), + KEY(1, 0, GROUP_0 | KEY_LEFT), + KEY(1, 1, GROUP_0 | KEY_ENTER), + KEY(1, 2, GROUP_0 | KEY_RIGHT), + KEY(2, 0, GROUP_1 | KEY_ESC), + KEY(2, 1, GROUP_0 | KEY_DOWN), + KEY(2, 2, GROUP_1 | KEY_F4), + KEY(3, 0, GROUP_2 | KEY_F7), + KEY(3, 1, GROUP_2 | KEY_F8), + KEY(3, 2, GROUP_2 | KEY_F6), + 0 +}; + +static struct resource nokia770_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data nokia770_kp_data = { + .rows = 8, + .cols = 8, + .keymap = nokia770_keymap +}; + +static struct platform_device nokia770_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &nokia770_kp_data, + }, + .num_resources = ARRAY_SIZE(nokia770_kp_resources), + .resource = nokia770_kp_resources, +}; + +static struct platform_device *nokia770_devices[] __initdata = { + &nokia770_kp_device, +}; + +static struct ads7846_platform_data nokia770_ads7846_platform_data __initdata = { + .x_max = 0x0fff, + .y_max = 0x0fff, + .x_plate_ohms = 180, + .pressure_max = 255, + .debounce_max = 10, + .debounce_tol = 3, +}; + +static struct spi_board_info nokia770_spi_board_info[] __initdata = { + [0] = { + .modalias = "lcd_lph8923", + .bus_num = 2, + .chip_select = 3, + .max_speed_hz = 12000000, + }, + [1] = { + .modalias = "ads7846", + .bus_num = 2, + .chip_select = 0, + .max_speed_hz = 2500000, + .irq = OMAP_GPIO_IRQ(15), + .platform_data = &nokia770_ads7846_platform_data, + }, +}; + + +/* assume no Mini-AB port */ + +static struct omap_usb_config nokia770_usb_config __initdata = { + .otg = 1, + .register_host = 1, + .register_dev = 1, + .hmc_mode = 16, + .pins[0] = 6, +}; + +static struct omap_mmc_config nokia770_mmc_config __initdata = { + .mmc[0] = { + .enabled = 0, + .wire4 = 0, + .wp_pin = -1, + .power_pin = -1, + .switch_pin = -1, + }, + .mmc[1] = { + .enabled = 0, + .wire4 = 0, + .wp_pin = -1, + .power_pin = -1, + .switch_pin = -1, + }, +}; + +static struct omap_board_config_kernel nokia770_config[] = { + { OMAP_TAG_USB, NULL }, + { OMAP_TAG_MMC, &nokia770_mmc_config }, +}; + +/* + * audio power control + */ +#define HEADPHONE_GPIO 14 +#define AMPLIFIER_CTRL_GPIO 58 + +static struct clk *dspxor_ck; +static DECLARE_MUTEX(audio_pwr_sem); +/* + * audio_pwr_state + * +--+-------------------------+---------------------------------------+ + * |-1|down |power-up request -> 0 | + * +--+-------------------------+---------------------------------------+ + * | 0|up |power-down(1) request -> 1 | + * | | |power-down(2) request -> (ignore) | + * +--+-------------------------+---------------------------------------+ + * | 1|up, |power-up request -> 0 | + * | |received down(1) request |power-down(2) request -> -1 | + * +--+-------------------------+---------------------------------------+ + */ +static int audio_pwr_state = -1; + +/* + * audio_pwr_up / down should be called under audio_pwr_sem + */ +static void nokia770_audio_pwr_up(void) +{ + clk_enable(dspxor_ck); + + /* Turn on codec */ + tlv320aic23_power_up(); + + if (omap_get_gpio_datain(HEADPHONE_GPIO)) + /* HP not connected, turn on amplifier */ + omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 1); + else + /* HP connected, do not turn on amplifier */ + printk("HP connected\n"); +} + +static void codec_delayed_power_down(void *arg) +{ + down(&audio_pwr_sem); + if (audio_pwr_state == -1) + tlv320aic23_power_down(); + clk_disable(dspxor_ck); + up(&audio_pwr_sem); +} + +static DECLARE_WORK(codec_power_down_work, codec_delayed_power_down, NULL); + +static void nokia770_audio_pwr_down(void) +{ + /* Turn off amplifier */ + omap_set_gpio_dataout(AMPLIFIER_CTRL_GPIO, 0); + + /* Turn off codec: schedule delayed work */ + schedule_delayed_work(&codec_power_down_work, HZ / 20); /* 50ms */ +} + +void nokia770_audio_pwr_up_request(int stage) +{ + down(&audio_pwr_sem); + if (audio_pwr_state == -1) + nokia770_audio_pwr_up(); + /* force audio_pwr_state = 0, even if it was 1. */ + audio_pwr_state = 0; + up(&audio_pwr_sem); +} + +void nokia770_audio_pwr_down_request(int stage) +{ + down(&audio_pwr_sem); + switch (stage) { + case 1: + if (audio_pwr_state == 0) + audio_pwr_state = 1; + break; + case 2: + if (audio_pwr_state == 1) { + nokia770_audio_pwr_down(); + audio_pwr_state = -1; + } + break; + } + up(&audio_pwr_sem); +} + +static void __init omap_nokia770_init(void) +{ + nokia770_config[0].data = &nokia770_usb_config; + + platform_add_devices(nokia770_devices, ARRAY_SIZE(nokia770_devices)); + spi_register_board_info(nokia770_spi_board_info, + ARRAY_SIZE(nokia770_spi_board_info)); + omap_board_config = nokia770_config; + omap_board_config_size = ARRAY_SIZE(nokia770_config); + omap_serial_init(); + omap_dsp_audio_pwr_up_request = nokia770_audio_pwr_up_request; + omap_dsp_audio_pwr_down_request = nokia770_audio_pwr_down_request; + dspxor_ck = clk_get(0, "dspxor_ck"); +} + +static void __init omap_nokia770_map_io(void) +{ + omap1_map_common_io(); +} + +MACHINE_START(NOKIA770, "Nokia 770") + .phys_io = 0xfff00000, + .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc, + .boot_params = 0x10000100, + .map_io = omap_nokia770_map_io, + .init_irq = omap_nokia770_init_irq, + .init_machine = omap_nokia770_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c index 543fa136106d..1160093e8ef6 100644 --- a/arch/arm/mach-omap1/board-osk.c +++ b/arch/arm/mach-omap1/board-osk.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -44,7 +45,24 @@ #include #include #include +#include #include +#include +#include + +static int osk_keymap[] = { + KEY(0, 0, KEY_F1), + KEY(0, 3, KEY_UP), + KEY(1, 1, KEY_LEFTCTRL), + KEY(1, 2, KEY_LEFT), + KEY(2, 0, KEY_SPACE), + KEY(2, 1, KEY_ESC), + KEY(2, 2, KEY_DOWN), + KEY(3, 2, KEY_ENTER), + KEY(3, 3, KEY_RIGHT), + 0 +}; + static struct mtd_partition osk_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ @@ -133,9 +151,69 @@ static struct platform_device osk5912_cf_device = { .resource = osk5912_cf_resources, }; +#define DEFAULT_BITPERSAMPLE 16 + +static struct omap_mcbsp_reg_cfg mcbsp_regs = { + .spcr2 = FREE | FRST | GRST | XRST | XINTM(3), + .spcr1 = RINTM(3) | RRST, + .rcr2 = RPHASE | RFRLEN2(OMAP_MCBSP_WORD_8) | + RWDLEN2(OMAP_MCBSP_WORD_16) | RDATDLY(0), + .rcr1 = RFRLEN1(OMAP_MCBSP_WORD_8) | RWDLEN1(OMAP_MCBSP_WORD_16), + .xcr2 = XPHASE | XFRLEN2(OMAP_MCBSP_WORD_8) | + XWDLEN2(OMAP_MCBSP_WORD_16) | XDATDLY(0) | XFIG, + .xcr1 = XFRLEN1(OMAP_MCBSP_WORD_8) | XWDLEN1(OMAP_MCBSP_WORD_16), + .srgr1 = FWID(DEFAULT_BITPERSAMPLE - 1), + .srgr2 = GSYNC | CLKSP | FSGM | FPER(DEFAULT_BITPERSAMPLE * 2 - 1), + /*.pcr0 = FSXM | FSRM | CLKXM | CLKRM | CLKXP | CLKRP,*/ /* mcbsp: master */ + .pcr0 = CLKXP | CLKRP, /* mcbsp: slave */ +}; + +static struct omap_alsa_codec_config alsa_config = { + .name = "OSK AIC23", + .mcbsp_regs_alsa = &mcbsp_regs, + .codec_configure_dev = NULL, // aic23_configure, + .codec_set_samplerate = NULL, // aic23_set_samplerate, + .codec_clock_setup = NULL, // aic23_clock_setup, + .codec_clock_on = NULL, // aic23_clock_on, + .codec_clock_off = NULL, // aic23_clock_off, + .get_default_samplerate = NULL, // aic23_get_default_samplerate, +}; + static struct platform_device osk5912_mcbsp1_device = { - .name = "omap_mcbsp", - .id = 1, + .name = "omap_alsa_mcbsp", + .id = 1, + .dev = { + .platform_data = &alsa_config, + }, +}; + +static struct resource osk5912_kp_resources[] = { + [0] = { + .start = INT_KEYBOARD, + .end = INT_KEYBOARD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct omap_kp_platform_data osk_kp_data = { + .rows = 8, + .cols = 8, + .keymap = osk_keymap, +}; + +static struct platform_device osk5912_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &osk_kp_data, + }, + .num_resources = ARRAY_SIZE(osk5912_kp_resources), + .resource = osk5912_kp_resources, +}; + +static struct platform_device osk5912_lcd_device = { + .name = "lcd_osk", + .id = -1, }; static struct platform_device *osk5912_devices[] __initdata = { @@ -143,6 +221,8 @@ static struct platform_device *osk5912_devices[] __initdata = { &osk5912_smc91x_device, &osk5912_cf_device, &osk5912_mcbsp1_device, + &osk5912_kp_device, + &osk5912_lcd_device, }; static void __init osk_init_smc91x(void) @@ -197,7 +277,6 @@ static struct omap_uart_config osk_uart_config __initdata = { }; static struct omap_lcd_config osk_lcd_config __initdata = { - .panel_name = "osk", .ctrl_name = "internal", }; @@ -255,8 +334,18 @@ static void __init osk_mistral_init(void) static void __init osk_mistral_init(void) { } #endif +#define EMIFS_CS3_VAL (0x88013141) + static void __init osk_init(void) { + /* Workaround for wrong CS3 (NOR flash) timing + * There are some U-Boot versions out there which configure + * wrong CS3 memory timings. This mainly leads to CRC + * or similiar errors if you use NOR flash (e.g. with JFFS2) + */ + if (EMIFS_CCS(3) != EMIFS_CS3_VAL) + EMIFS_CCS(3) = EMIFS_CS3_VAL; + osk_flash_resource.end = osk_flash_resource.start = omap_cs3_phys(); osk_flash_resource.end += SZ_32M - 1; platform_add_devices(osk5912_devices, ARRAY_SIZE(osk5912_devices)); diff --git a/arch/arm/mach-omap1/board-palmte.c b/arch/arm/mach-omap1/board-palmte.c index e488f7236775..4bc8a62909b9 100644 --- a/arch/arm/mach-omap1/board-palmte.c +++ b/arch/arm/mach-omap1/board-palmte.c @@ -38,6 +38,15 @@ static void __init omap_generic_init_irq(void) omap_init_irq(); } +static struct platform_device palmte_lcd_device = { + .name = "lcd_palmte", + .id = -1, +}; + +static struct platform_device *devices[] __initdata = { + &palmte_lcd_device, +}; + static struct omap_usb_config palmte_usb_config __initdata = { .register_dev = 1, .hmc_mode = 0, @@ -55,7 +64,6 @@ static struct omap_mmc_config palmte_mmc_config __initdata = { }; static struct omap_lcd_config palmte_lcd_config __initdata = { - .panel_name = "palmte", .ctrl_name = "internal", }; @@ -69,6 +77,8 @@ static void __init omap_generic_init(void) { omap_board_config = palmte_config; omap_board_config_size = ARRAY_SIZE(palmte_config); + + platform_add_devices(devices, ARRAY_SIZE(devices)); } static void __init omap_generic_map_io(void) diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c index 3913a3cc0ce6..64b45d8ae357 100644 --- a/arch/arm/mach-omap1/board-perseus2.c +++ b/arch/arm/mach-omap1/board-perseus2.c @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include #include @@ -28,9 +30,44 @@ #include #include #include +#include #include #include +static int p2_keymap[] = { + KEY(0,0,KEY_UP), + KEY(0,1,KEY_RIGHT), + KEY(0,2,KEY_LEFT), + KEY(0,3,KEY_DOWN), + KEY(0,4,KEY_CENTER), + KEY(0,5,KEY_0_5), + KEY(1,0,KEY_SOFT2), + KEY(1,1,KEY_SEND), + KEY(1,2,KEY_END), + KEY(1,3,KEY_VOLUMEDOWN), + KEY(1,4,KEY_VOLUMEUP), + KEY(1,5,KEY_RECORD), + KEY(2,0,KEY_SOFT1), + KEY(2,1,KEY_3), + KEY(2,2,KEY_6), + KEY(2,3,KEY_9), + KEY(2,4,KEY_SHARP), + KEY(2,5,KEY_2_5), + KEY(3,0,KEY_BACK), + KEY(3,1,KEY_2), + KEY(3,2,KEY_5), + KEY(3,3,KEY_8), + KEY(3,4,KEY_0), + KEY(3,5,KEY_HEADSETHOOK), + KEY(4,0,KEY_HOME), + KEY(4,1,KEY_1), + KEY(4,2,KEY_4), + KEY(4,3,KEY_7), + KEY(4,4,KEY_STAR), + KEY(4,5,KEY_POWER), + 0 +}; + static struct resource smc91x_resources[] = { [0] = { .start = H2P2_DBG_FPGA_ETHR_START, /* Physical */ @@ -44,7 +81,7 @@ static struct resource smc91x_resources[] = { }, }; -static struct mtd_partition p2_partitions[] = { +static struct mtd_partition nor_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { .name = "bootloader", @@ -75,27 +112,47 @@ static struct mtd_partition p2_partitions[] = { }, }; -static struct flash_platform_data p2_flash_data = { +static struct flash_platform_data nor_data = { .map_name = "cfi_probe", .width = 2, - .parts = p2_partitions, - .nr_parts = ARRAY_SIZE(p2_partitions), + .parts = nor_partitions, + .nr_parts = ARRAY_SIZE(nor_partitions), }; -static struct resource p2_flash_resource = { +static struct resource nor_resource = { .start = OMAP_CS0_PHYS, .end = OMAP_CS0_PHYS + SZ_32M - 1, .flags = IORESOURCE_MEM, }; -static struct platform_device p2_flash_device = { +static struct platform_device nor_device = { .name = "omapflash", .id = 0, .dev = { - .platform_data = &p2_flash_data, + .platform_data = &nor_data, }, .num_resources = 1, - .resource = &p2_flash_resource, + .resource = &nor_resource, +}; + +static struct nand_platform_data nand_data = { + .options = NAND_SAMSUNG_LP_OPTIONS, +}; + +static struct resource nand_resource = { + .start = OMAP_CS3_PHYS, + .end = OMAP_CS3_PHYS + SZ_4K - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device nand_device = { + .name = "omapnand", + .id = 0, + .dev = { + .platform_data = &nand_data, + }, + .num_resources = 1, + .resource = &nand_resource, }; static struct platform_device smc91x_device = { @@ -105,17 +162,55 @@ static struct platform_device smc91x_device = { .resource = smc91x_resources, }; -static struct platform_device *devices[] __initdata = { - &p2_flash_device, - &smc91x_device, +static struct resource kp_resources[] = { + [0] = { + .start = INT_730_MPUIO_KEYPAD, + .end = INT_730_MPUIO_KEYPAD, + .flags = IORESOURCE_IRQ, + }, }; +static struct omap_kp_platform_data kp_data = { + .rows = 8, + .cols = 8, + .keymap = p2_keymap, +}; + +static struct platform_device kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &kp_data, + }, + .num_resources = ARRAY_SIZE(kp_resources), + .resource = kp_resources, +}; + +static struct platform_device lcd_device = { + .name = "lcd_p2", + .id = -1, +}; + +static struct platform_device *devices[] __initdata = { + &nor_device, + &nand_device, + &smc91x_device, + &kp_device, + &lcd_device, +}; + +#define P2_NAND_RB_GPIO_PIN 62 + +static int nand_dev_ready(struct nand_platform_data *data) +{ + return omap_get_gpio_datain(P2_NAND_RB_GPIO_PIN); +} + static struct omap_uart_config perseus2_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1)), }; static struct omap_lcd_config perseus2_lcd_config __initdata = { - .panel_name = "p2", .ctrl_name = "internal", }; @@ -126,7 +221,13 @@ static struct omap_board_config_kernel perseus2_config[] = { static void __init omap_perseus2_init(void) { - (void) platform_add_devices(devices, ARRAY_SIZE(devices)); + if (!(omap_request_gpio(P2_NAND_RB_GPIO_PIN))) + nand_data.dev_ready = nand_dev_ready; + + omap_cfg_reg(L3_1610_FLASH_CS2B_OE); + omap_cfg_reg(M8_1610_FLASH_CS2B_WE); + + platform_add_devices(devices, ARRAY_SIZE(devices)); omap_board_config = perseus2_config; omap_board_config_size = ARRAY_SIZE(perseus2_config); diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c index 52e4a9d69642..447a586eb334 100644 --- a/arch/arm/mach-omap1/board-voiceblue.c +++ b/arch/arm/mach-omap1/board-voiceblue.c @@ -155,9 +155,9 @@ static struct omap_uart_config voiceblue_uart_config __initdata = { }; static struct omap_board_config_kernel voiceblue_config[] = { - { OMAP_TAG_USB, &voiceblue_usb_config }, - { OMAP_TAG_MMC, &voiceblue_mmc_config }, - { OMAP_TAG_UART, &voiceblue_uart_config }, + { OMAP_TAG_USB, &voiceblue_usb_config }, + { OMAP_TAG_MMC, &voiceblue_mmc_config }, + { OMAP_TAG_UART, &voiceblue_uart_config }, }; static void __init voiceblue_init_irq(void) @@ -235,7 +235,7 @@ static struct notifier_block panic_block = { static int __init voiceblue_setup(void) { /* Setup panic notifier */ - atomic_notifier_chain_register(&panic_notifier_list, &panic_block); + notifier_chain_register(&panic_notifier_list, &panic_block); return 0; } diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c index 75110ba10424..619db18144ea 100644 --- a/arch/arm/mach-omap1/clock.c +++ b/arch/arm/mach-omap1/clock.c @@ -345,7 +345,7 @@ static unsigned calc_ext_dsor(unsigned long rate) */ for (dsor = 2; dsor < 96; ++dsor) { if ((dsor & 1) && dsor > 8) - continue; + continue; if (rate >= 96000000 / dsor) break; } @@ -687,6 +687,11 @@ int __init omap1_clk_init(void) clk_register(*clkp); continue; } + + if (((*clkp)->flags &CLOCK_IN_OMAP310) && cpu_is_omap310()) { + clk_register(*clkp); + continue; + } } info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config); @@ -784,7 +789,7 @@ int __init omap1_clk_init(void) clk_enable(&armxor_ck.clk); clk_enable(&armtim_ck.clk); /* This should be done by timer code */ - if (cpu_is_omap1510()) + if (cpu_is_omap15xx()) clk_enable(&arm_gpio_ck); return 0; diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h index 4f18d1b94449..b7c68819c4e7 100644 --- a/arch/arm/mach-omap1/clock.h +++ b/arch/arm/mach-omap1/clock.h @@ -151,7 +151,7 @@ static struct clk ck_ref = { .name = "ck_ref", .rate = 12000000, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | ALWAYS_ENABLED, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, }; @@ -160,7 +160,7 @@ static struct clk ck_dpll1 = { .name = "ck_dpll1", .parent = &ck_ref, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_PROPAGATES | ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | RATE_PROPAGATES | ALWAYS_ENABLED, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, }; @@ -183,7 +183,8 @@ static struct clk arm_ck = { .name = "arm_ck", .parent = &ck_dpll1, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_CKCTL | RATE_PROPAGATES | ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | RATE_CKCTL | RATE_PROPAGATES | + ALWAYS_ENABLED, .rate_offset = CKCTL_ARMDIV_OFFSET, .recalc = &omap1_ckctl_recalc, .enable = &omap1_clk_enable_generic, @@ -195,7 +196,8 @@ static struct arm_idlect1_clk armper_ck = { .name = "armper_ck", .parent = &ck_dpll1, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_CKCTL | CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | RATE_CKCTL | + CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_PERCK, .rate_offset = CKCTL_PERDIV_OFFSET, @@ -209,7 +211,7 @@ static struct arm_idlect1_clk armper_ck = { static struct clk arm_gpio_ck = { .name = "arm_gpio_ck", .parent = &ck_dpll1, - .flags = CLOCK_IN_OMAP1510, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_GPIOCK, .recalc = &followparent_recalc, @@ -222,7 +224,7 @@ static struct arm_idlect1_clk armxor_ck = { .name = "armxor_ck", .parent = &ck_ref, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_XORPCK, .recalc = &followparent_recalc, @@ -237,7 +239,7 @@ static struct arm_idlect1_clk armtim_ck = { .name = "armtim_ck", .parent = &ck_ref, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_TIMCK, .recalc = &followparent_recalc, @@ -252,7 +254,7 @@ static struct arm_idlect1_clk armwdt_ck = { .name = "armwdt_ck", .parent = &ck_ref, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_WDTCK, .recalc = &omap1_watchdog_recalc, @@ -344,9 +346,9 @@ static struct arm_idlect1_clk tc_ck = { .name = "tc_ck", .parent = &ck_dpll1, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IN_OMAP730 | RATE_CKCTL | - RATE_PROPAGATES | ALWAYS_ENABLED | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 | + RATE_CKCTL | RATE_PROPAGATES | + ALWAYS_ENABLED | CLOCK_IDLE_CONTROL, .rate_offset = CKCTL_TCDIV_OFFSET, .recalc = &omap1_ckctl_recalc, .enable = &omap1_clk_enable_generic, @@ -358,7 +360,8 @@ static struct arm_idlect1_clk tc_ck = { static struct clk arminth_ck1510 = { .name = "arminth_ck", .parent = &tc_ck.clk, - .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, .recalc = &followparent_recalc, /* Note: On 1510 the frequency follows TC_CK * @@ -372,7 +375,8 @@ static struct clk tipb_ck = { /* No-idle controlled by "tc_ck" */ .name = "tibp_ck", .parent = &tc_ck.clk, - .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + ALWAYS_ENABLED, .recalc = &followparent_recalc, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, @@ -417,7 +421,7 @@ static struct clk dma_ck = { .name = "dma_ck", .parent = &tc_ck.clk, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | ALWAYS_ENABLED, .recalc = &followparent_recalc, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, @@ -437,7 +441,7 @@ static struct arm_idlect1_clk api_ck = { .name = "api_ck", .parent = &tc_ck.clk, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - CLOCK_IDLE_CONTROL, + CLOCK_IN_OMAP310 | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_APICK, .recalc = &followparent_recalc, @@ -451,7 +455,8 @@ static struct arm_idlect1_clk lb_ck = { .clk = { .name = "lb_ck", .parent = &tc_ck.clk, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IDLE_CONTROL, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_LBCK, .recalc = &followparent_recalc, @@ -495,8 +500,8 @@ static struct arm_idlect1_clk lcd_ck_1510 = { .clk = { .name = "lcd_ck", .parent = &ck_dpll1, - .flags = CLOCK_IN_OMAP1510 | RATE_CKCTL | - CLOCK_IDLE_CONTROL, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + RATE_CKCTL | CLOCK_IDLE_CONTROL, .enable_reg = (void __iomem *)ARM_IDLECT2, .enable_bit = EN_LCDCK, .rate_offset = CKCTL_LCDDIV_OFFSET, @@ -512,8 +517,9 @@ static struct clk uart1_1510 = { /* Direct from ULPD, no real parent */ .parent = &armper_ck.clk, .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | - ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + ENABLE_REG_32BIT | ALWAYS_ENABLED | + CLOCK_NO_IDLE_PARENT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = 29, /* Chooses between 12MHz and 48MHz */ .set_rate = &omap1_set_uart_rate, @@ -544,8 +550,8 @@ static struct clk uart2_ck = { .parent = &armper_ck.clk, .rate = 12000000, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - ENABLE_REG_32BIT | ALWAYS_ENABLED | - CLOCK_NO_IDLE_PARENT, + CLOCK_IN_OMAP310 | ENABLE_REG_32BIT | + ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = 30, /* Chooses between 12MHz and 48MHz */ .set_rate = &omap1_set_uart_rate, @@ -559,8 +565,9 @@ static struct clk uart3_1510 = { /* Direct from ULPD, no real parent */ .parent = &armper_ck.clk, .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | - ALWAYS_ENABLED | CLOCK_NO_IDLE_PARENT, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | + ENABLE_REG_32BIT | ALWAYS_ENABLED | + CLOCK_NO_IDLE_PARENT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = 31, /* Chooses between 12MHz and 48MHz */ .set_rate = &omap1_set_uart_rate, @@ -590,7 +597,7 @@ static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */ /* Direct from ULPD, no parent */ .rate = 6000000, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_FIXED | ENABLE_REG_32BIT, + CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT, .enable_reg = (void __iomem *)ULPD_CLOCK_CTRL, .enable_bit = USB_MCLK_EN_BIT, .enable = &omap1_clk_enable_generic, @@ -601,7 +608,7 @@ static struct clk usb_hhc_ck1510 = { .name = "usb_hhc_ck", /* Direct from ULPD, no parent */ .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ - .flags = CLOCK_IN_OMAP1510 | + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = USB_HOST_HHC_UHOST_EN, @@ -637,7 +644,9 @@ static struct clk mclk_1510 = { .name = "mclk", /* Direct from ULPD, no parent. May be enabled by ext hardware. */ .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED, + .enable_reg = (void __iomem *)SOFT_REQ_REG, + .enable_bit = 6, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, }; @@ -659,7 +668,7 @@ static struct clk bclk_1510 = { .name = "bclk", /* Direct from ULPD, no parent. May be enabled by ext hardware. */ .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | RATE_FIXED, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | RATE_FIXED, .enable = &omap1_clk_enable_generic, .disable = &omap1_clk_disable_generic, }; @@ -678,12 +687,14 @@ static struct clk bclk_16xx = { }; static struct clk mmc1_ck = { - .name = "mmc1_ck", + .name = "mmc_ck", + .id = 1, /* Functional clock is direct from ULPD, interface clock is ARMPER */ .parent = &armper_ck.clk, .rate = 48000000, .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - RATE_FIXED | ENABLE_REG_32BIT | CLOCK_NO_IDLE_PARENT, + CLOCK_IN_OMAP310 | RATE_FIXED | ENABLE_REG_32BIT | + CLOCK_NO_IDLE_PARENT, .enable_reg = (void __iomem *)MOD_CONF_CTRL_0, .enable_bit = 23, .enable = &omap1_clk_enable_generic, @@ -691,7 +702,8 @@ static struct clk mmc1_ck = { }; static struct clk mmc2_ck = { - .name = "mmc2_ck", + .name = "mmc_ck", + .id = 2, /* Functional clock is direct from ULPD, interface clock is ARMPER */ .parent = &armper_ck.clk, .rate = 48000000, @@ -706,7 +718,7 @@ static struct clk mmc2_ck = { static struct clk virtual_ck_mpu = { .name = "mpu", .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | - VIRTUAL_CLOCK | ALWAYS_ENABLED, + CLOCK_IN_OMAP310 | VIRTUAL_CLOCK | ALWAYS_ENABLED, .parent = &arm_ck, /* Is smarter alias for */ .recalc = &followparent_recalc, .set_rate = &omap1_select_table_rate, @@ -715,6 +727,20 @@ static struct clk virtual_ck_mpu = { .disable = &omap1_clk_disable_generic, }; +/* virtual functional clock domain for I2C. Just for making sure that ARMXOR_CK +remains active during MPU idle whenever this is enabled */ +static struct clk i2c_fck = { + .name = "i2c_fck", + .id = 1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + VIRTUAL_CLOCK | CLOCK_NO_IDLE_PARENT | + ALWAYS_ENABLED, + .parent = &armxor_ck.clk, + .recalc = &followparent_recalc, + .enable = &omap1_clk_enable_generic, + .disable = &omap1_clk_disable_generic, +}; + static struct clk * onchip_clks[] = { /* non-ULPD clocks */ &ck_ref, @@ -763,6 +789,7 @@ static struct clk * onchip_clks[] = { &mmc2_ck, /* Virtual clocks */ &virtual_ck_mpu, + &i2c_fck, }; #endif diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c index ecbc47514adc..847329cafc5c 100644 --- a/arch/arm/mach-omap1/devices.c +++ b/arch/arm/mach-omap1/devices.c @@ -25,10 +25,6 @@ #include #include -extern void omap_nop_release(struct device *dev); - -/*-------------------------------------------------------------------------*/ - #if defined(CONFIG_OMAP1610_IR) || defined(CONFIG_OMAP161O_IR_MODULE) static u64 irda_dmamask = 0xffffffff; @@ -37,7 +33,6 @@ static struct platform_device omap1610ir_device = { .name = "omap1610-ir", .id = -1, .dev = { - .release = omap_nop_release, .dma_mask = &irda_dmamask, }, }; @@ -84,9 +79,6 @@ static struct resource rtc_resources[] = { static struct platform_device omap_rtc_device = { .name = "omap_rtc", .id = -1, - .dev = { - .release = omap_nop_release, - }, .num_resources = ARRAY_SIZE(rtc_resources), .resource = rtc_resources, }; @@ -99,6 +91,42 @@ static void omap_init_rtc(void) static inline void omap_init_rtc(void) {} #endif +#if defined(CONFIG_OMAP_STI) + +#define OMAP1_STI_BASE IO_ADDRESS(0xfffea000) +#define OMAP1_STI_CHANNEL_BASE (OMAP1_STI_BASE + 0x400) + +static struct resource sti_resources[] = { + { + .start = OMAP1_STI_BASE, + .end = OMAP1_STI_BASE + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = OMAP1_STI_CHANNEL_BASE, + .end = OMAP1_STI_CHANNEL_BASE + SZ_1K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_1610_STI, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device sti_device = { + .name = "sti", + .id = -1, + .num_resources = ARRAY_SIZE(sti_resources), + .resource = sti_resources, +}; + +static inline void omap_init_sti(void) +{ + platform_device_register(&sti_device); +} +#else +static inline void omap_init_sti(void) {} +#endif /*-------------------------------------------------------------------------*/ @@ -129,6 +157,7 @@ static int __init omap1_init_devices(void) */ omap_init_irda(); omap_init_rtc(); + omap_init_sti(); return 0; } diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c index 82d556be79c5..be3a2a4ee2b8 100644 --- a/arch/arm/mach-omap1/io.c +++ b/arch/arm/mach-omap1/io.c @@ -18,6 +18,7 @@ #include #include #include +#include extern int omap1_clk_init(void); extern void omap_check_revision(void); @@ -110,7 +111,7 @@ void __init omap1_map_common_io(void) } #endif #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc)); } #endif @@ -121,6 +122,7 @@ void __init omap1_map_common_io(void) #endif omap_sram_init(); + omapfb_reserve_mem(); } /* diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c index ed65a7d2e941..a0431c00fa81 100644 --- a/arch/arm/mach-omap1/irq.c +++ b/arch/arm/mach-omap1/irq.c @@ -60,7 +60,7 @@ struct omap_irq_bank { unsigned long wake_enable; }; -static unsigned int irq_bank_count = 0; +static unsigned int irq_bank_count; static struct omap_irq_bank *irq_banks; static inline unsigned int irq_bank_readl(int bank, int offset) @@ -142,28 +142,28 @@ static void omap_irq_set_cfg(int irq, int fiq, int priority, int trigger) #ifdef CONFIG_ARCH_OMAP730 static struct omap_irq_bank omap730_irq_banks[] = { - { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f }, - { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 }, + { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3f8e22f }, + { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb9c1f2 }, { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0x800040f3 }, }; #endif #ifdef CONFIG_ARCH_OMAP15XX static struct omap_irq_bank omap1510_irq_banks[] = { - { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff }, - { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed }, + { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3febfff }, + { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xffbfffed }, }; static struct omap_irq_bank omap310_irq_banks[] = { - { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 }, - { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 }, + { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3faefc3 }, + { .base_reg = OMAP_IH2_BASE, .trigger_map = 0x65b3c061 }, }; #endif #if defined(CONFIG_ARCH_OMAP16XX) static struct omap_irq_bank omap1610_irq_banks[] = { - { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f }, - { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd }, + { .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f }, + { .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd }, { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xffffb7ff }, { .base_reg = OMAP_IH2_BASE + 0x200, .trigger_map = 0xffffffff }, }; diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c index d4b8d624e742..10fe0b3efcac 100644 --- a/arch/arm/mach-omap1/mux.c +++ b/arch/arm/mach-omap1/mux.c @@ -35,16 +35,20 @@ #ifdef CONFIG_ARCH_OMAP730 struct pin_config __initdata_or_module omap730_pins[] = { -MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 0, 20, 1, NA, 0, 0) -MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 0, 24, 1, NA, 0, 0) -MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 0, 28, 1, NA, 0, 0) -MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 0, 1, NA, 0, 0) -MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 0, 4, 1, NA, 0, 0) -MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 0, 8, 1, NA, 0, 0) -MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 0, 12, 1, NA, 0, 0) -MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 0, 16, 1, NA, 0, 0) -MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 0, 20, 1, NA, 0, 0) -MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 0, 24, 1, NA, 0, 0) +MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 20, 1, 0) +MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 24, 1, 0) +MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 28, 1, 0) +MUX_CFG_730("F3_730_KBR3", 13, 1, 0, 0, 1, 0) +MUX_CFG_730("D2_730_KBR4", 13, 5, 0, 4, 1, 0) +MUX_CFG_730("C2_730_KBC0", 13, 9, 0, 8, 1, 0) +MUX_CFG_730("D3_730_KBC1", 13, 13, 0, 12, 1, 0) +MUX_CFG_730("E4_730_KBC2", 13, 17, 0, 16, 1, 0) +MUX_CFG_730("F4_730_KBC3", 13, 21, 0, 20, 1, 0) +MUX_CFG_730("E3_730_KBC4", 13, 25, 0, 24, 1, 0) + +MUX_CFG_730("AA17_730_USB_DM", 2, 21, 0, 20, 0, 0) +MUX_CFG_730("W16_730_USB_PU_EN", 2, 25, 0, 24, 0, 0) +MUX_CFG_730("W17_730_USB_VBUSI", 2, 29, 0, 28, 0, 0) }; #endif @@ -73,8 +77,8 @@ MUX_CFG("UART3_BCLK", A, 0, 0, 2, 6, 0, NA, 0, 0) MUX_CFG("Y15_1610_UART3_RTS", A, 0, 1, 2, 6, 0, NA, 0, 0) /* PWT & PWL, conflicts with UART3 */ -MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0) -MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0) +MUX_CFG("PWT", 6, 0, 2, 0, 30, 0, NA, 0, 0) +MUX_CFG("PWL", 6, 3, 1, 0, 31, 1, NA, 0, 0) /* USB internal master generic */ MUX_CFG("R18_USB_VBUS", 7, 9, 2, 1, 11, 0, NA, 0, 1) @@ -151,7 +155,7 @@ MUX_CFG("MCBSP3_CLKX", 9, 3, 1, 1, 29, 0, NA, 0, 1) /* Misc ballouts */ MUX_CFG("BALLOUT_V8_ARMIO3", B, 18, 0, 2, 25, 1, NA, 0, 1) -MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0) +MUX_CFG("N20_HDQ", 6, 18, 1, 1, 4, 0, 1, 4, 0) /* OMAP-1610 MMC2 */ MUX_CFG("W8_1610_MMC2_DAT0", B, 21, 6, 2, 23, 1, 2, 1, 1) diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c new file mode 100644 index 000000000000..ddf6b07dc9c7 --- /dev/null +++ b/arch/arm/mach-omap1/pm.c @@ -0,0 +1,770 @@ +/* + * linux/arch/arm/mach-omap1/pm.c + * + * OMAP Power Management Routines + * + * Original code for the SA11x0: + * Copyright (c) 2001 Cliff Brake + * + * Modified for the PXA250 by Nicolas Pitre: + * Copyright (c) 2002 Monta Vista Software, Inc. + * + * Modified for the OMAP1510 by David Singleton: + * Copyright (c) 2002 Monta Vista Software, Inc. + * + * Cleanup 2004 for OMAP1510/1610 by Dirk Behme + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE]; +static unsigned short dsp_sleep_save[DSP_SLEEP_SAVE_SIZE]; +static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE]; +static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE]; +static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE]; +static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE]; + +static unsigned short enable_dyn_sleep = 1; + +static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf) +{ + return sprintf(buf, "%hu\n", enable_dyn_sleep); +} + +static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys, + const char * buf, + size_t n) +{ + unsigned short value; + if (sscanf(buf, "%hu", &value) != 1 || + (value != 0 && value != 1)) { + printk(KERN_ERR "idle_sleep_store: Invalid value\n"); + return -EINVAL; + } + enable_dyn_sleep = value; + return n; +} + +static struct subsys_attribute sleep_while_idle_attr = { + .attr = { + .name = __stringify(sleep_while_idle), + .mode = 0644, + }, + .show = omap_pm_sleep_while_idle_show, + .store = omap_pm_sleep_while_idle_store, +}; + +extern struct subsystem power_subsys; +static void (*omap_sram_idle)(void) = NULL; +static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL; + +/* + * Let's power down on idle, but only if we are really + * idle, because once we start down the path of + * going idle we continue to do idle even if we get + * a clock tick interrupt . . + */ +void omap_pm_idle(void) +{ + extern __u32 arm_idlect1_mask; + __u32 use_idlect1 = arm_idlect1_mask; +#ifndef CONFIG_OMAP_MPU_TIMER + int do_sleep; +#endif + + local_irq_disable(); + local_fiq_disable(); + if (need_resched()) { + local_fiq_enable(); + local_irq_enable(); + return; + } + + /* + * Since an interrupt may set up a timer, we don't want to + * reprogram the hardware timer with interrupts enabled. + * Re-enable interrupts only after returning from idle. + */ + timer_dyn_reprogram(); + +#ifdef CONFIG_OMAP_MPU_TIMER +#warning Enable 32kHz OS timer in order to allow sleep states in idle + use_idlect1 = use_idlect1 & ~(1 << 9); +#else + + do_sleep = 0; + while (enable_dyn_sleep) { + +#ifdef CONFIG_CBUS_TAHVO_USB + extern int vbus_active; + /* Clock requirements? */ + if (vbus_active) + break; +#endif + do_sleep = 1; + break; + } + +#ifdef CONFIG_OMAP_DM_TIMER + use_idlect1 = omap_dm_timer_modify_idlect_mask(use_idlect1); +#endif + + if (omap_dma_running()) { + use_idlect1 &= ~(1 << 6); + if (omap_lcd_dma_ext_running()) + use_idlect1 &= ~(1 << 12); + } + + /* We should be able to remove the do_sleep variable and multiple + * tests above as soon as drivers, timer and DMA code have been fixed. + * Even the sleep block count should become obsolete. */ + if ((use_idlect1 != ~0) || !do_sleep) { + + __u32 saved_idlect1 = omap_readl(ARM_IDLECT1); + if (cpu_is_omap15xx()) + use_idlect1 &= OMAP1510_BIG_SLEEP_REQUEST; + else + use_idlect1 &= OMAP1610_IDLECT1_SLEEP_VAL; + omap_writel(use_idlect1, ARM_IDLECT1); + __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4"); + omap_writel(saved_idlect1, ARM_IDLECT1); + + local_fiq_enable(); + local_irq_enable(); + return; + } + omap_sram_suspend(omap_readl(ARM_IDLECT1), + omap_readl(ARM_IDLECT2)); +#endif + + local_fiq_enable(); + local_irq_enable(); +} + +/* + * Configuration of the wakeup event is board specific. For the + * moment we put it into this helper function. Later it may move + * to board specific files. + */ +static void omap_pm_wakeup_setup(void) +{ + u32 level1_wake = 0; + u32 level2_wake = OMAP_IRQ_BIT(INT_UART2); + + /* + * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade, + * and the L2 wakeup interrupts: keypad and UART2. Note that the + * drivers must still separately call omap_set_gpio_wakeup() to + * wake up to a GPIO interrupt. + */ + if (cpu_is_omap730()) + level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) | + OMAP_IRQ_BIT(INT_730_IH2_IRQ); + else if (cpu_is_omap15xx()) + level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | + OMAP_IRQ_BIT(INT_1510_IH2_IRQ); + else if (cpu_is_omap16xx()) + level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) | + OMAP_IRQ_BIT(INT_1610_IH2_IRQ); + + omap_writel(~level1_wake, OMAP_IH1_MIR); + + if (cpu_is_omap730()) { + omap_writel(~level2_wake, OMAP_IH2_0_MIR); + omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) | + OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)), + OMAP_IH2_1_MIR); + } else if (cpu_is_omap15xx()) { + level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); + omap_writel(~level2_wake, OMAP_IH2_MIR); + } else if (cpu_is_omap16xx()) { + level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD); + omap_writel(~level2_wake, OMAP_IH2_0_MIR); + + /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */ + omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), + OMAP_IH2_1_MIR); + omap_writel(~0x0, OMAP_IH2_2_MIR); + omap_writel(~0x0, OMAP_IH2_3_MIR); + } + + /* New IRQ agreement, recalculate in cascade order */ + omap_writel(1, OMAP_IH2_CONTROL); + omap_writel(1, OMAP_IH1_CONTROL); +} + +#define EN_DSPCK 13 /* ARM_CKCTL */ +#define EN_APICK 6 /* ARM_IDLECT2 */ +#define DSP_EN 1 /* ARM_RSTCT1 */ + +void omap_pm_suspend(void) +{ + unsigned long arg0 = 0, arg1 = 0; + + printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev); + + omap_serial_wake_trigger(1); + + if (machine_is_omap_osk()) { + /* Stop LED1 (D9) blink */ + tps65010_set_led(LED1, OFF); + } + + omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG); + + /* + * Step 1: turn off interrupts (FIXME: NOTE: already disabled) + */ + + local_irq_disable(); + local_fiq_disable(); + + /* + * Step 2: save registers + * + * The omap is a strange/beautiful device. The caches, memory + * and register state are preserved across power saves. + * We have to save and restore very little register state to + * idle the omap. + * + * Save interrupt, MPUI, ARM and UPLD control registers. + */ + + if (cpu_is_omap730()) { + MPUI730_SAVE(OMAP_IH1_MIR); + MPUI730_SAVE(OMAP_IH2_0_MIR); + MPUI730_SAVE(OMAP_IH2_1_MIR); + MPUI730_SAVE(MPUI_CTRL); + MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI730_SAVE(MPUI_DSP_API_CONFIG); + MPUI730_SAVE(EMIFS_CONFIG); + MPUI730_SAVE(EMIFF_SDRAM_CONFIG); + + } else if (cpu_is_omap15xx()) { + MPUI1510_SAVE(OMAP_IH1_MIR); + MPUI1510_SAVE(OMAP_IH2_MIR); + MPUI1510_SAVE(MPUI_CTRL); + MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI1510_SAVE(MPUI_DSP_API_CONFIG); + MPUI1510_SAVE(EMIFS_CONFIG); + MPUI1510_SAVE(EMIFF_SDRAM_CONFIG); + } else if (cpu_is_omap16xx()) { + MPUI1610_SAVE(OMAP_IH1_MIR); + MPUI1610_SAVE(OMAP_IH2_0_MIR); + MPUI1610_SAVE(OMAP_IH2_1_MIR); + MPUI1610_SAVE(OMAP_IH2_2_MIR); + MPUI1610_SAVE(OMAP_IH2_3_MIR); + MPUI1610_SAVE(MPUI_CTRL); + MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI1610_SAVE(MPUI_DSP_API_CONFIG); + MPUI1610_SAVE(EMIFS_CONFIG); + MPUI1610_SAVE(EMIFF_SDRAM_CONFIG); + } + + ARM_SAVE(ARM_CKCTL); + ARM_SAVE(ARM_IDLECT1); + ARM_SAVE(ARM_IDLECT2); + if (!(cpu_is_omap15xx())) + ARM_SAVE(ARM_IDLECT3); + ARM_SAVE(ARM_EWUPCT); + ARM_SAVE(ARM_RSTCT1); + ARM_SAVE(ARM_RSTCT2); + ARM_SAVE(ARM_SYSST); + ULPD_SAVE(ULPD_CLOCK_CTRL); + ULPD_SAVE(ULPD_STATUS_REQ); + + /* (Step 3 removed - we now allow deep sleep by default) */ + + /* + * Step 4: OMAP DSP Shutdown + */ + + /* stop DSP */ + omap_writew(omap_readw(ARM_RSTCT1) & ~(1 << DSP_EN), ARM_RSTCT1); + + /* shut down dsp_ck */ + omap_writew(omap_readw(ARM_CKCTL) & ~(1 << EN_DSPCK), ARM_CKCTL); + + /* temporarily enabling api_ck to access DSP registers */ + omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); + + /* save DSP registers */ + DSP_SAVE(DSP_IDLECT2); + + /* Stop all DSP domain clocks */ + __raw_writew(0, DSP_IDLECT2); + + /* + * Step 5: Wakeup Event Setup + */ + + omap_pm_wakeup_setup(); + + /* + * Step 6: ARM and Traffic controller shutdown + */ + + /* disable ARM watchdog */ + omap_writel(0x00F5, OMAP_WDT_TIMER_MODE); + omap_writel(0x00A0, OMAP_WDT_TIMER_MODE); + + /* + * Step 6b: ARM and Traffic controller shutdown + * + * Step 6 continues here. Prepare jump to power management + * assembly code in internal SRAM. + * + * Since the omap_cpu_suspend routine has been copied to + * SRAM, we'll do an indirect procedure call to it and pass the + * contents of arm_idlect1 and arm_idlect2 so it can restore + * them when it wakes up and it will return. + */ + + arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1]; + arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2]; + + /* + * Step 6c: ARM and Traffic controller shutdown + * + * Jump to assembly code. The processor will stay there + * until wake up. + */ + omap_sram_suspend(arg0, arg1); + + /* + * If we are here, processor is woken up! + */ + + /* + * Restore DSP clocks + */ + + /* again temporarily enabling api_ck to access DSP registers */ + omap_writew(omap_readw(ARM_IDLECT2) | 1 << EN_APICK, ARM_IDLECT2); + + /* Restore DSP domain clocks */ + DSP_RESTORE(DSP_IDLECT2); + + /* + * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did + */ + + if (!(cpu_is_omap15xx())) + ARM_RESTORE(ARM_IDLECT3); + ARM_RESTORE(ARM_CKCTL); + ARM_RESTORE(ARM_EWUPCT); + ARM_RESTORE(ARM_RSTCT1); + ARM_RESTORE(ARM_RSTCT2); + ARM_RESTORE(ARM_SYSST); + ULPD_RESTORE(ULPD_CLOCK_CTRL); + ULPD_RESTORE(ULPD_STATUS_REQ); + + if (cpu_is_omap730()) { + MPUI730_RESTORE(EMIFS_CONFIG); + MPUI730_RESTORE(EMIFF_SDRAM_CONFIG); + MPUI730_RESTORE(OMAP_IH1_MIR); + MPUI730_RESTORE(OMAP_IH2_0_MIR); + MPUI730_RESTORE(OMAP_IH2_1_MIR); + } else if (cpu_is_omap15xx()) { + MPUI1510_RESTORE(MPUI_CTRL); + MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG); + MPUI1510_RESTORE(MPUI_DSP_API_CONFIG); + MPUI1510_RESTORE(EMIFS_CONFIG); + MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG); + MPUI1510_RESTORE(OMAP_IH1_MIR); + MPUI1510_RESTORE(OMAP_IH2_MIR); + } else if (cpu_is_omap16xx()) { + MPUI1610_RESTORE(MPUI_CTRL); + MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG); + MPUI1610_RESTORE(MPUI_DSP_API_CONFIG); + MPUI1610_RESTORE(EMIFS_CONFIG); + MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG); + + MPUI1610_RESTORE(OMAP_IH1_MIR); + MPUI1610_RESTORE(OMAP_IH2_0_MIR); + MPUI1610_RESTORE(OMAP_IH2_1_MIR); + MPUI1610_RESTORE(OMAP_IH2_2_MIR); + MPUI1610_RESTORE(OMAP_IH2_3_MIR); + } + + omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG); + + /* + * Reenable interrupts + */ + + local_irq_enable(); + local_fiq_enable(); + + omap_serial_wake_trigger(0); + + printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev); + + if (machine_is_omap_osk()) { + /* Let LED1 (D9) blink again */ + tps65010_set_led(LED1, BLINK); + } +} + +#if defined(DEBUG) && defined(CONFIG_PROC_FS) +static int g_read_completed; + +/* + * Read system PM registers for debugging + */ +static int omap_pm_read_proc( + char *page_buffer, + char **my_first_byte, + off_t virtual_start, + int length, + int *eof, + void *data) +{ + int my_buffer_offset = 0; + char * const my_base = page_buffer; + + ARM_SAVE(ARM_CKCTL); + ARM_SAVE(ARM_IDLECT1); + ARM_SAVE(ARM_IDLECT2); + if (!(cpu_is_omap15xx())) + ARM_SAVE(ARM_IDLECT3); + ARM_SAVE(ARM_EWUPCT); + ARM_SAVE(ARM_RSTCT1); + ARM_SAVE(ARM_RSTCT2); + ARM_SAVE(ARM_SYSST); + + ULPD_SAVE(ULPD_IT_STATUS); + ULPD_SAVE(ULPD_CLOCK_CTRL); + ULPD_SAVE(ULPD_SOFT_REQ); + ULPD_SAVE(ULPD_STATUS_REQ); + ULPD_SAVE(ULPD_DPLL_CTRL); + ULPD_SAVE(ULPD_POWER_CTRL); + + if (cpu_is_omap730()) { + MPUI730_SAVE(MPUI_CTRL); + MPUI730_SAVE(MPUI_DSP_STATUS); + MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI730_SAVE(MPUI_DSP_API_CONFIG); + MPUI730_SAVE(EMIFF_SDRAM_CONFIG); + MPUI730_SAVE(EMIFS_CONFIG); + } else if (cpu_is_omap15xx()) { + MPUI1510_SAVE(MPUI_CTRL); + MPUI1510_SAVE(MPUI_DSP_STATUS); + MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI1510_SAVE(MPUI_DSP_API_CONFIG); + MPUI1510_SAVE(EMIFF_SDRAM_CONFIG); + MPUI1510_SAVE(EMIFS_CONFIG); + } else if (cpu_is_omap16xx()) { + MPUI1610_SAVE(MPUI_CTRL); + MPUI1610_SAVE(MPUI_DSP_STATUS); + MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG); + MPUI1610_SAVE(MPUI_DSP_API_CONFIG); + MPUI1610_SAVE(EMIFF_SDRAM_CONFIG); + MPUI1610_SAVE(EMIFS_CONFIG); + } + + if (virtual_start == 0) { + g_read_completed = 0; + + my_buffer_offset += sprintf(my_base + my_buffer_offset, + "ARM_CKCTL_REG: 0x%-8x \n" + "ARM_IDLECT1_REG: 0x%-8x \n" + "ARM_IDLECT2_REG: 0x%-8x \n" + "ARM_IDLECT3_REG: 0x%-8x \n" + "ARM_EWUPCT_REG: 0x%-8x \n" + "ARM_RSTCT1_REG: 0x%-8x \n" + "ARM_RSTCT2_REG: 0x%-8x \n" + "ARM_SYSST_REG: 0x%-8x \n" + "ULPD_IT_STATUS_REG: 0x%-4x \n" + "ULPD_CLOCK_CTRL_REG: 0x%-4x \n" + "ULPD_SOFT_REQ_REG: 0x%-4x \n" + "ULPD_DPLL_CTRL_REG: 0x%-4x \n" + "ULPD_STATUS_REQ_REG: 0x%-4x \n" + "ULPD_POWER_CTRL_REG: 0x%-4x \n", + ARM_SHOW(ARM_CKCTL), + ARM_SHOW(ARM_IDLECT1), + ARM_SHOW(ARM_IDLECT2), + ARM_SHOW(ARM_IDLECT3), + ARM_SHOW(ARM_EWUPCT), + ARM_SHOW(ARM_RSTCT1), + ARM_SHOW(ARM_RSTCT2), + ARM_SHOW(ARM_SYSST), + ULPD_SHOW(ULPD_IT_STATUS), + ULPD_SHOW(ULPD_CLOCK_CTRL), + ULPD_SHOW(ULPD_SOFT_REQ), + ULPD_SHOW(ULPD_DPLL_CTRL), + ULPD_SHOW(ULPD_STATUS_REQ), + ULPD_SHOW(ULPD_POWER_CTRL)); + + if (cpu_is_omap730()) { + my_buffer_offset += sprintf(my_base + my_buffer_offset, + "MPUI730_CTRL_REG 0x%-8x \n" + "MPUI730_DSP_STATUS_REG: 0x%-8x \n" + "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n" + "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n" + "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n" + "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n", + MPUI730_SHOW(MPUI_CTRL), + MPUI730_SHOW(MPUI_DSP_STATUS), + MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG), + MPUI730_SHOW(MPUI_DSP_API_CONFIG), + MPUI730_SHOW(EMIFF_SDRAM_CONFIG), + MPUI730_SHOW(EMIFS_CONFIG)); + } else if (cpu_is_omap15xx()) { + my_buffer_offset += sprintf(my_base + my_buffer_offset, + "MPUI1510_CTRL_REG 0x%-8x \n" + "MPUI1510_DSP_STATUS_REG: 0x%-8x \n" + "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n" + "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n" + "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n" + "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n", + MPUI1510_SHOW(MPUI_CTRL), + MPUI1510_SHOW(MPUI_DSP_STATUS), + MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG), + MPUI1510_SHOW(MPUI_DSP_API_CONFIG), + MPUI1510_SHOW(EMIFF_SDRAM_CONFIG), + MPUI1510_SHOW(EMIFS_CONFIG)); + } else if (cpu_is_omap16xx()) { + my_buffer_offset += sprintf(my_base + my_buffer_offset, + "MPUI1610_CTRL_REG 0x%-8x \n" + "MPUI1610_DSP_STATUS_REG: 0x%-8x \n" + "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n" + "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n" + "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n" + "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n", + MPUI1610_SHOW(MPUI_CTRL), + MPUI1610_SHOW(MPUI_DSP_STATUS), + MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG), + MPUI1610_SHOW(MPUI_DSP_API_CONFIG), + MPUI1610_SHOW(EMIFF_SDRAM_CONFIG), + MPUI1610_SHOW(EMIFS_CONFIG)); + } + + g_read_completed++; + } else if (g_read_completed >= 1) { + *eof = 1; + return 0; + } + g_read_completed++; + + *my_first_byte = page_buffer; + return my_buffer_offset; +} + +static void omap_pm_init_proc(void) +{ + struct proc_dir_entry *entry; + + entry = create_proc_read_entry("driver/omap_pm", + S_IWUSR | S_IRUGO, NULL, + omap_pm_read_proc, NULL); +} + +#endif /* DEBUG && CONFIG_PROC_FS */ + +static void (*saved_idle)(void) = NULL; + +/* + * omap_pm_prepare - Do preliminary suspend work. + * @state: suspend state we're entering. + * + */ +static int omap_pm_prepare(suspend_state_t state) +{ + int error = 0; + + /* We cannot sleep in idle until we have resumed */ + saved_idle = pm_idle; + pm_idle = NULL; + + switch (state) + { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + break; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return error; +} + + +/* + * omap_pm_enter - Actually enter a sleep state. + * @state: State we're entering. + * + */ + +static int omap_pm_enter(suspend_state_t state) +{ + switch (state) + { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + omap_pm_suspend(); + break; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return 0; +} + + +/** + * omap_pm_finish - Finish up suspend sequence. + * @state: State we're coming out of. + * + * This is called after we wake back up (or if entering the sleep state + * failed). + */ + +static int omap_pm_finish(suspend_state_t state) +{ + pm_idle = saved_idle; + return 0; +} + + +static irqreturn_t omap_wakeup_interrupt(int irq, void * dev, + struct pt_regs * regs) +{ + return IRQ_HANDLED; +} + +static struct irqaction omap_wakeup_irq = { + .name = "peripheral wakeup", + .flags = SA_INTERRUPT, + .handler = omap_wakeup_interrupt +}; + + + +static struct pm_ops omap_pm_ops ={ + .pm_disk_mode = 0, + .prepare = omap_pm_prepare, + .enter = omap_pm_enter, + .finish = omap_pm_finish, +}; + +static int __init omap_pm_init(void) +{ + printk("Power Management for TI OMAP.\n"); + + /* + * We copy the assembler sleep/wakeup routines to SRAM. + * These routines need to be in SRAM as that's the only + * memory the MPU can see when it wakes up. + */ + if (cpu_is_omap730()) { + omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend, + omap730_idle_loop_suspend_sz); + omap_sram_suspend = omap_sram_push(omap730_cpu_suspend, + omap730_cpu_suspend_sz); + } else if (cpu_is_omap15xx()) { + omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend, + omap1510_idle_loop_suspend_sz); + omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend, + omap1510_cpu_suspend_sz); + } else if (cpu_is_omap16xx()) { + omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend, + omap1610_idle_loop_suspend_sz); + omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend, + omap1610_cpu_suspend_sz); + } + + if (omap_sram_idle == NULL || omap_sram_suspend == NULL) { + printk(KERN_ERR "PM not initialized: Missing SRAM support\n"); + return -ENODEV; + } + + pm_idle = omap_pm_idle; + + if (cpu_is_omap730()) + setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq); + else if (cpu_is_omap16xx()) + setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq); + + /* Program new power ramp-up time + * (0 for most boards since we don't lower voltage when in deep sleep) + */ + omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3); + + /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */ + omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL); + + /* Configure IDLECT3 */ + if (cpu_is_omap730()) + omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3); + else if (cpu_is_omap16xx()) + omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3); + + pm_set_ops(&omap_pm_ops); + +#if defined(DEBUG) && defined(CONFIG_PROC_FS) + omap_pm_init_proc(); +#endif + + subsys_create_file(&power_subsys, &sleep_while_idle_attr); + + if (cpu_is_omap16xx()) { + /* configure LOW_PWR pin */ + omap_cfg_reg(T20_1610_LOW_PWR); + } + + return 0; +} +__initcall(omap_pm_init); diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c index e924e0c6a4ce..9b4cd698bec8 100644 --- a/arch/arm/mach-omap1/serial.c +++ b/arch/arm/mach-omap1/serial.c @@ -30,9 +30,9 @@ #include #endif -static struct clk * uart1_ck = NULL; -static struct clk * uart2_ck = NULL; -static struct clk * uart3_ck = NULL; +static struct clk * uart1_ck; +static struct clk * uart2_ck; +static struct clk * uart3_ck; static inline unsigned int omap_serial_in(struct plat_serial8250_port *up, int offset) diff --git a/arch/arm/plat-omap/sleep.S b/arch/arm/mach-omap1/sleep.S similarity index 93% rename from arch/arm/plat-omap/sleep.S rename to arch/arm/mach-omap1/sleep.S index 4cd7d292f854..e58295e2d3b2 100644 --- a/arch/arm/plat-omap/sleep.S +++ b/arch/arm/mach-omap1/sleep.S @@ -1,5 +1,5 @@ /* - * linux/arch/arm/plat-omap/sleep.S + * linux/arch/arm/mach-omap1/sleep.S * * Low-level OMAP730/1510/1610 sleep/wakeUp support * @@ -383,60 +383,133 @@ ENTRY(omap1610_cpu_suspend) mcr p15, 0, r0, c7, c10, 4 nop - @ load base address of Traffic Controller + @ Load base address of Traffic Controller mov r6, #TCMIF_ASM_BASE & 0xff000000 orr r6, r6, #TCMIF_ASM_BASE & 0x00ff0000 orr r6, r6, #TCMIF_ASM_BASE & 0x0000ff00 - @ prepare to put SDRAM into self-refresh manually + @ Prepare to put SDRAM into self-refresh manually ldr r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] orr r9, r7, #SELF_REFRESH_MODE & 0xff000000 orr r9, r9, #SELF_REFRESH_MODE & 0x000000ff str r9, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] - @ prepare to put EMIFS to Sleep + @ Prepare to put EMIFS to Sleep ldr r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] orr r9, r8, #IDLE_EMIFS_REQUEST & 0xff str r9, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - @ load base address of ARM_IDLECT1 and ARM_IDLECT2 + @ Load base address of ARM_IDLECT1 and ARM_IDLECT2 mov r4, #CLKGEN_REG_ASM_BASE & 0xff000000 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x00ff0000 orr r4, r4, #CLKGEN_REG_ASM_BASE & 0x0000ff00 - @ turn off clock domains - @ do not disable PERCK (0x04) + @ Turn off clock domains + @ Do not disable PERCK (0x04) mov r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff orr r5, r5, #OMAP1610_IDLECT2_SLEEP_VAL & 0xff00 strh r5, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] - @ request ARM idle + @ Request ARM idle mov r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff orr r3, r3, #OMAP1610_IDLECT1_SLEEP_VAL & 0xff00 strh r3, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] - @ disable instruction cache - mrc p15, 0, r9, c1, c0, 0 - bic r2, r9, #0x1000 - mcr p15, 0, r2, c1, c0, 0 - nop - /* * Let's wait for the next wake up event to wake us up. r0 can't be * used here because r0 holds ARM_IDLECT1 */ mov r2, #0 mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt + + @ Errata (HEL3SU467, section 1.4.4) specifies nop-instructions + @ according to this formula: + @ 2 + (4*DPLL_MULT)/DPLL_DIV/ARMDIV + @ Max DPLL_MULT = 18 + @ DPLL_DIV = 1 + @ ARMDIV = 1 + @ => 74 nop-instructions + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @10 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @20 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @30 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @40 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @50 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @60 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop @70 + nop + nop + nop + nop @74 /* * omap1610_cpu_suspend()'s resume point. * * It will just start executing here, so we'll restore stuff from the * stack. */ - @ re-enable Icache - mcr p15, 0, r9, c1, c0, 0 - - @ reset the ARM_IDLECT1 and ARM_IDLECT2. + @ Restore the ARM_IDLECT1 and ARM_IDLECT2. strh r1, [r4, #ARM_IDLECT2_ASM_OFFSET & 0xff] strh r0, [r4, #ARM_IDLECT1_ASM_OFFSET & 0xff] @@ -444,7 +517,7 @@ ENTRY(omap1610_cpu_suspend) str r7, [r6, #EMIFF_SDRAM_CONFIG_ASM_OFFSET & 0xff] str r8, [r6, #EMIFS_CONFIG_ASM_OFFSET & 0xff] - @ restore regs and return + @ Restore regs and return ldmfd sp!, {r0 - r12, pc} ENTRY(omap1610_cpu_suspend_sz) diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c index cdbf4d7620c6..a85fe6066bc4 100644 --- a/arch/arm/mach-omap1/time.c +++ b/arch/arm/mach-omap1/time.c @@ -51,8 +51,6 @@ struct sys_timer omap_timer; -#ifdef CONFIG_OMAP_MPU_TIMER - /* * --------------------------------------------------------------------------- * MPU timer @@ -222,195 +220,6 @@ unsigned long long sched_clock(void) return cycles_2_ns(ticks64); } -#endif /* CONFIG_OMAP_MPU_TIMER */ - -#ifdef CONFIG_OMAP_32K_TIMER - -#ifdef CONFIG_ARCH_OMAP15XX -#error OMAP 32KHz timer does not currently work on 15XX! -#endif - -/* - * --------------------------------------------------------------------------- - * 32KHz OS timer - * - * This currently works only on 16xx, as 1510 does not have the continuous - * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track - * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer - * on 1510 would be possible, but the timer would not be as accurate as - * with the 32KHz synchronized timer. - * --------------------------------------------------------------------------- - */ -#define OMAP_32K_TIMER_BASE 0xfffb9000 -#define OMAP_32K_TIMER_CR 0x08 -#define OMAP_32K_TIMER_TVR 0x00 -#define OMAP_32K_TIMER_TCR 0x04 - -#define OMAP_32K_TICKS_PER_HZ (32768 / HZ) - -/* - * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1 - * so with HZ = 100, TVR = 327.68. - */ -#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1) -#define TIMER_32K_SYNCHRONIZED 0xfffbc410 - -#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ - (((nr_jiffies) * (clock_rate)) / HZ) - -static inline void omap_32k_timer_write(int val, int reg) -{ - omap_writew(val, reg + OMAP_32K_TIMER_BASE); -} - -static inline unsigned long omap_32k_timer_read(int reg) -{ - return omap_readl(reg + OMAP_32K_TIMER_BASE) & 0xffffff; -} - -/* - * The 32KHz synchronized timer is an additional timer on 16xx. - * It is always running. - */ -static inline unsigned long omap_32k_sync_timer_read(void) -{ - return omap_readl(TIMER_32K_SYNCHRONIZED); -} - -static inline void omap_32k_timer_start(unsigned long load_val) -{ - omap_32k_timer_write(load_val, OMAP_32K_TIMER_TVR); - omap_32k_timer_write(0x0f, OMAP_32K_TIMER_CR); -} - -static inline void omap_32k_timer_stop(void) -{ - omap_32k_timer_write(0x0, OMAP_32K_TIMER_CR); -} - -/* - * Rounds down to nearest usec. Note that this will overflow for larger values. - */ -static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k) -{ - return (ticks_32k * 5*5*5*5*5*5) >> 9; -} - -/* - * Rounds down to nearest nsec. - */ -static inline unsigned long long -omap_32k_ticks_to_nsecs(unsigned long ticks_32k) -{ - return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9; -} - -static unsigned long omap_32k_last_tick = 0; - -/* - * Returns elapsed usecs since last 32k timer interrupt - */ -static unsigned long omap_32k_timer_gettimeoffset(void) -{ - unsigned long now = omap_32k_sync_timer_read(); - return omap_32k_ticks_to_usecs(now - omap_32k_last_tick); -} - -/* - * Returns current time from boot in nsecs. It's OK for this to wrap - * around for now, as it's just a relative time stamp. - */ -unsigned long long sched_clock(void) -{ - return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read()); -} - -/* - * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this - * function is also called from other interrupts to remove latency - * issues with dynamic tick. In the dynamic tick case, we need to lock - * with irqsave. - */ -static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, - struct pt_regs *regs) -{ - unsigned long flags; - unsigned long now; - - write_seqlock_irqsave(&xtime_lock, flags); - now = omap_32k_sync_timer_read(); - - while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) { - omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; - timer_tick(regs); - } - - /* Restart timer so we don't drift off due to modulo or dynamic tick. - * By default we program the next timer to be continuous to avoid - * latencies during high system load. During dynamic tick operation the - * continuous timer can be overridden from pm_idle to be longer. - */ - omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); - write_sequnlock_irqrestore(&xtime_lock, flags); - - return IRQ_HANDLED; -} - -#ifdef CONFIG_NO_IDLE_HZ -/* - * Programs the next timer interrupt needed. Called when dynamic tick is - * enabled, and to reprogram the ticks to skip from pm_idle. Note that - * we can keep the timer continuous, and don't need to set it to run in - * one-shot mode. This is because the timer will get reprogrammed again - * after next interrupt. - */ -void omap_32k_timer_reprogram(unsigned long next_tick) -{ - omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1); -} - -static struct irqaction omap_32k_timer_irq; -extern struct timer_update_handler timer_update; - -static int omap_32k_timer_enable_dyn_tick(void) -{ - /* No need to reprogram timer, just use the next interrupt */ - return 0; -} - -static int omap_32k_timer_disable_dyn_tick(void) -{ - omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); - return 0; -} - -static struct dyn_tick_timer omap_dyn_tick_timer = { - .enable = omap_32k_timer_enable_dyn_tick, - .disable = omap_32k_timer_disable_dyn_tick, - .reprogram = omap_32k_timer_reprogram, - .handler = omap_32k_timer_interrupt, -}; -#endif /* CONFIG_NO_IDLE_HZ */ - -static struct irqaction omap_32k_timer_irq = { - .name = "32KHz timer", - .flags = SA_INTERRUPT | SA_TIMER, - .handler = omap_32k_timer_interrupt, -}; - -static __init void omap_init_32k_timer(void) -{ - -#ifdef CONFIG_NO_IDLE_HZ - omap_timer.dyn_tick = &omap_dyn_tick_timer; -#endif - - setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); - omap_timer.offset = omap_32k_timer_gettimeoffset; - omap_32k_last_tick = omap_32k_sync_timer_read(); - omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); -} -#endif /* CONFIG_OMAP_32K_TIMER */ /* * --------------------------------------------------------------------------- @@ -419,13 +228,7 @@ static __init void omap_init_32k_timer(void) */ static void __init omap_timer_init(void) { -#if defined(CONFIG_OMAP_MPU_TIMER) omap_init_mpu_timer(); -#elif defined(CONFIG_OMAP_32K_TIMER) - omap_init_32k_timer(); -#else -#error No system timer selected in Kconfig! -#endif } struct sys_timer omap_timer = { diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 578880943cf2..537dd2e6d380 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -20,3 +20,6 @@ config MACH_OMAP_H4 bool "OMAP 2420 H4 board" depends on ARCH_OMAP2 && ARCH_OMAP24XX +config MACH_OMAP_APOLLON + bool "OMAP 2420 Apollon board" + depends on ARCH_OMAP2 && ARCH_OMAP24XX diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 42041166435c..111eaa64258f 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -3,11 +3,15 @@ # # Common support -obj-y := irq.o id.o io.o sram-fn.o clock.o mux.o devices.o serial.o +obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o serial.o obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o +# Power Management +obj-$(CONFIG_PM) += pm.o sleep.o + # Specific board support obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o +obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c new file mode 100644 index 000000000000..6c6ba172cdf6 --- /dev/null +++ b/arch/arm/mach-omap2/board-apollon.c @@ -0,0 +1,285 @@ +/* + * linux/arch/arm/mach-omap/omap2/board-apollon.c + * + * Copyright (C) 2005,2006 Samsung Electronics + * Author: Kyungmin Park + * + * Modified from mach-omap/omap2/board-h4.c + * + * Code for apollon OMAP2 board. Should work on many OMAP2 systems where + * the bootloader passes the board-specific data to the kernel. + * Do not put any board specific code to this file; create a new machine + * type if you need custom low-level initializations. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "prcm-regs.h" + +/* LED & Switch macros */ +#define LED0_GPIO13 13 +#define LED1_GPIO14 14 +#define LED2_GPIO15 15 +#define SW_ENTER_GPIO16 16 +#define SW_UP_GPIO17 17 +#define SW_DOWN_GPIO58 58 + +static struct mtd_partition apollon_partitions[] = { + { + .name = "X-Loader + U-Boot", + .offset = 0, + .size = SZ_128K, + .mask_flags = MTD_WRITEABLE, + }, + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = SZ_128K, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = SZ_16M, + }, + { + .name = "filesystem00", + .offset = MTDPART_OFS_APPEND, + .size = SZ_32M, + }, + { + .name = "filesystem01", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct flash_platform_data apollon_flash_data = { + .parts = apollon_partitions, + .nr_parts = ARRAY_SIZE(apollon_partitions), +}; + +static struct resource apollon_flash_resource = { + .start = APOLLON_CS0_BASE, + .end = APOLLON_CS0_BASE + SZ_128K, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device apollon_onenand_device = { + .name = "onenand", + .id = -1, + .dev = { + .platform_data = &apollon_flash_data, + }, + .num_resources = ARRAY_SIZE(&apollon_flash_resource), + .resource = &apollon_flash_resource, +}; + +static struct resource apollon_smc91x_resources[] = { + [0] = { + .start = APOLLON_ETHR_START, /* Physical */ + .end = APOLLON_ETHR_START + 0xf, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ), + .end = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device apollon_smc91x_device = { + .name = "smc91x", + .id = -1, + .num_resources = ARRAY_SIZE(apollon_smc91x_resources), + .resource = apollon_smc91x_resources, +}; + +static struct platform_device apollon_lcd_device = { + .name = "apollon_lcd", + .id = -1, +}; + +static struct platform_device *apollon_devices[] __initdata = { + &apollon_onenand_device, + &apollon_smc91x_device, + &apollon_lcd_device, +}; + +static inline void __init apollon_init_smc91x(void) +{ + /* Make sure CS1 timings are correct */ + GPMC_CONFIG1_1 = 0x00011203; + GPMC_CONFIG2_1 = 0x001f1f01; + GPMC_CONFIG3_1 = 0x00080803; + GPMC_CONFIG4_1 = 0x1c091c09; + GPMC_CONFIG5_1 = 0x041f1f1f; + GPMC_CONFIG6_1 = 0x000004c4; + GPMC_CONFIG7_1 = 0x00000f40 | (APOLLON_CS1_BASE >> 24); + udelay(100); + + omap_cfg_reg(W4__24XX_GPIO74); + if (omap_request_gpio(APOLLON_ETHR_GPIO_IRQ) < 0) { + printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", + APOLLON_ETHR_GPIO_IRQ); + return; + } + omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1); +} + +static void __init omap_apollon_init_irq(void) +{ + omap2_init_common_hw(); + omap_init_irq(); + omap_gpio_init(); + apollon_init_smc91x(); +} + +static struct omap_uart_config apollon_uart_config __initdata = { + .enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2), +}; + +static struct omap_mmc_config apollon_mmc_config __initdata = { + .mmc [0] = { + .enabled = 0, + .wire4 = 0, + .wp_pin = -1, + .power_pin = -1, + .switch_pin = -1, + }, +}; + +static struct omap_lcd_config apollon_lcd_config __initdata = { + .ctrl_name = "internal", +}; + +static struct omap_board_config_kernel apollon_config[] = { + { OMAP_TAG_UART, &apollon_uart_config }, + { OMAP_TAG_MMC, &apollon_mmc_config }, + { OMAP_TAG_LCD, &apollon_lcd_config }, +}; + +static void __init apollon_led_init(void) +{ + /* LED0 - AA10 */ + omap_cfg_reg(AA10_242X_GPIO13); + omap_request_gpio(LED0_GPIO13); + omap_set_gpio_direction(LED0_GPIO13, 0); + omap_set_gpio_dataout(LED0_GPIO13, 0); + /* LED1 - AA6 */ + omap_cfg_reg(AA6_242X_GPIO14); + omap_request_gpio(LED1_GPIO14); + omap_set_gpio_direction(LED1_GPIO14, 0); + omap_set_gpio_dataout(LED1_GPIO14, 0); + /* LED2 - AA4 */ + omap_cfg_reg(AA4_242X_GPIO15); + omap_request_gpio(LED2_GPIO15); + omap_set_gpio_direction(LED2_GPIO15, 0); + omap_set_gpio_dataout(LED2_GPIO15, 0); +} + +static irqreturn_t apollon_sw_interrupt(int irq, void *ignored, struct pt_regs *regs) +{ + static unsigned int led0, led1, led2; + + if (irq == OMAP_GPIO_IRQ(SW_ENTER_GPIO16)) + omap_set_gpio_dataout(LED0_GPIO13, led0 ^= 1); + else if (irq == OMAP_GPIO_IRQ(SW_UP_GPIO17)) + omap_set_gpio_dataout(LED1_GPIO14, led1 ^= 1); + else if (irq == OMAP_GPIO_IRQ(SW_DOWN_GPIO58)) + omap_set_gpio_dataout(LED2_GPIO15, led2 ^= 1); + + return IRQ_HANDLED; +} + +static void __init apollon_sw_init(void) +{ + /* Enter SW - Y11 */ + omap_cfg_reg(Y11_242X_GPIO16); + omap_request_gpio(SW_ENTER_GPIO16); + omap_set_gpio_direction(SW_ENTER_GPIO16, 1); + /* Up SW - AA12 */ + omap_cfg_reg(AA12_242X_GPIO17); + omap_request_gpio(SW_UP_GPIO17); + omap_set_gpio_direction(SW_UP_GPIO17, 1); + /* Down SW - AA8 */ + omap_cfg_reg(AA8_242X_GPIO58); + omap_request_gpio(SW_DOWN_GPIO58); + omap_set_gpio_direction(SW_DOWN_GPIO58, 1); + + set_irq_type(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), IRQT_RISING); + if (request_irq(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), &apollon_sw_interrupt, + SA_SHIRQ, "enter sw", + &apollon_sw_interrupt)) + return; + set_irq_type(OMAP_GPIO_IRQ(SW_UP_GPIO17), IRQT_RISING); + if (request_irq(OMAP_GPIO_IRQ(SW_UP_GPIO17), &apollon_sw_interrupt, + SA_SHIRQ, "up sw", + &apollon_sw_interrupt)) + return; + set_irq_type(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), IRQT_RISING); + if (request_irq(OMAP_GPIO_IRQ(SW_DOWN_GPIO58), &apollon_sw_interrupt, + SA_SHIRQ, "down sw", + &apollon_sw_interrupt)) + return; +} + +static void __init omap_apollon_init(void) +{ + apollon_led_init(); + apollon_sw_init(); + + /* REVISIT: where's the correct place */ + omap_cfg_reg(W19_24XX_SYS_NIRQ); + + /* + * Make sure the serial ports are muxed on at this point. + * You have to mux them off in device drivers later on + * if not needed. + */ + platform_add_devices(apollon_devices, ARRAY_SIZE(apollon_devices)); + omap_board_config = apollon_config; + omap_board_config_size = ARRAY_SIZE(apollon_config); + omap_serial_init(); +} + +static void __init omap_apollon_map_io(void) +{ + omap2_map_common_io(); +} + +MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon") + /* Maintainer: Kyungmin Park */ + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = omap_apollon_map_io, + .init_irq = omap_apollon_init_irq, + .init_machine = omap_apollon_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index a300d634d8a5..4933fce766c8 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -25,15 +27,57 @@ #include #include +#include #include #include +#include #include #include -#include +#include +#include +#include +#include "prcm-regs.h" #include #include +static unsigned int row_gpios[6] = { 88, 89, 124, 11, 6, 96 }; +static unsigned int col_gpios[7] = { 90, 91, 100, 36, 12, 97, 98 }; + +static int h4_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_A), + KEY(0, 3, KEY_B), + KEY(0, 4, KEY_C), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_E), + KEY(1, 3, KEY_F), + KEY(1, 4, KEY_G), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_I), + KEY(2, 2, KEY_J), + KEY(2, 3, KEY_K), + KEY(2, 4, KEY_3), + KEY(3, 0, KEY_M), + KEY(3, 1, KEY_N), + KEY(3, 2, KEY_O), + KEY(3, 3, KEY_P), + KEY(3, 4, KEY_Q), + KEY(4, 0, KEY_R), + KEY(4, 1, KEY_4), + KEY(4, 2, KEY_T), + KEY(4, 3, KEY_U), + KEY(4, 4, KEY_ENTER), + KEY(5, 0, KEY_V), + KEY(5, 1, KEY_W), + KEY(5, 2, KEY_L), + KEY(5, 3, KEY_S), + KEY(5, 4, KEY_ENTER), + 0 +}; + static struct mtd_partition h4_partitions[] = { /* bootloader (U-Boot, etc) in first sector */ { @@ -108,9 +152,123 @@ static struct platform_device h4_smc91x_device = { .resource = h4_smc91x_resources, }; +/* Select between the IrDA and aGPS module + */ +static int h4_select_irda(struct device *dev, int state) +{ + unsigned char expa; + int err = 0; + + if ((err = read_gpio_expa(&expa, 0x21))) { + printk(KERN_ERR "Error reading from I/O expander\n"); + return err; + } + + /* 'P6' enable/disable IRDA_TX and IRDA_RX */ + if (state & IR_SEL) { /* IrDa */ + if ((err = write_gpio_expa(expa | 0x01, 0x21))) { + printk(KERN_ERR "Error writing to I/O expander\n"); + return err; + } + } else { + if ((err = write_gpio_expa(expa & ~0x01, 0x21))) { + printk(KERN_ERR "Error writing to I/O expander\n"); + return err; + } + } + return err; +} + +static void set_trans_mode(void *data) +{ + int *mode = data; + unsigned char expa; + int err = 0; + + if ((err = read_gpio_expa(&expa, 0x20)) != 0) { + printk(KERN_ERR "Error reading from I/O expander\n"); + } + + expa &= ~0x01; + + if (!(*mode & IR_SIRMODE)) { /* MIR/FIR */ + expa |= 0x01; + } + + if ((err = write_gpio_expa(expa, 0x20)) != 0) { + printk(KERN_ERR "Error writing to I/O expander\n"); + } +} + +static int h4_transceiver_mode(struct device *dev, int mode) +{ + struct omap_irda_config *irda_config = dev->platform_data; + + cancel_delayed_work(&irda_config->gpio_expa); + PREPARE_WORK(&irda_config->gpio_expa, set_trans_mode, &mode); + schedule_work(&irda_config->gpio_expa); + + return 0; +} + +static struct omap_irda_config h4_irda_data = { + .transceiver_cap = IR_SIRMODE | IR_MIRMODE | IR_FIRMODE, + .transceiver_mode = h4_transceiver_mode, + .select_irda = h4_select_irda, + .rx_channel = OMAP24XX_DMA_UART3_RX, + .tx_channel = OMAP24XX_DMA_UART3_TX, + .dest_start = OMAP_UART3_BASE, + .src_start = OMAP_UART3_BASE, + .tx_trigger = OMAP24XX_DMA_UART3_TX, + .rx_trigger = OMAP24XX_DMA_UART3_RX, +}; + +static struct resource h4_irda_resources[] = { + [0] = { + .start = INT_24XX_UART3_IRQ, + .end = INT_24XX_UART3_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device h4_irda_device = { + .name = "omapirda", + .id = -1, + .dev = { + .platform_data = &h4_irda_data, + }, + .num_resources = 1, + .resource = h4_irda_resources, +}; + +static struct omap_kp_platform_data h4_kp_data = { + .rows = 6, + .cols = 7, + .keymap = h4_keymap, + .rep = 1, + .row_gpios = row_gpios, + .col_gpios = col_gpios, +}; + +static struct platform_device h4_kp_device = { + .name = "omap-keypad", + .id = -1, + .dev = { + .platform_data = &h4_kp_data, + }, +}; + +static struct platform_device h4_lcd_device = { + .name = "lcd_h4", + .id = -1, +}; + static struct platform_device *h4_devices[] __initdata = { &h4_smc91x_device, &h4_flash_device, + &h4_irda_device, + &h4_kp_device, + &h4_lcd_device, }; static inline void __init h4_init_smc91x(void) @@ -157,7 +315,6 @@ static struct omap_mmc_config h4_mmc_config __initdata = { }; static struct omap_lcd_config h4_lcd_config __initdata = { - .panel_name = "h4", .ctrl_name = "internal", }; @@ -174,6 +331,19 @@ static void __init omap_h4_init(void) * You have to mux them off in device drivers later on * if not needed. */ +#if defined(CONFIG_OMAP_IR) || defined(CONFIG_OMAP_IR_MODULE) + omap_cfg_reg(K15_24XX_UART3_TX); + omap_cfg_reg(K14_24XX_UART3_RX); +#endif + +#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE) + if (omap_has_menelaus()) { + row_gpios[5] = 0; + col_gpios[2] = 15; + col_gpios[6] = 18; + } +#endif + platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices)); omap_board_config = h4_config; omap_board_config_size = ARRAY_SIZE(h4_config); diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 180f675c9064..72eb4bf571ac 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -28,14 +28,14 @@ #include #include -#include +#include "prcm-regs.h" +#include "memory.h" #include "clock.h" //#define DOWN_VARIABLE_DPLL 1 /* Experimental */ static struct prcm_config *curr_prcm_set; -static struct memory_timings mem_timings; static u32 curr_perf_level = PRCM_FULL_SPEED; /*------------------------------------------------------------------------- @@ -54,11 +54,13 @@ static void omap2_sys_clk_recalc(struct clk * clk) static u32 omap2_get_dpll_rate(struct clk * tclk) { - int dpll_clk, dpll_mult, dpll_div, amult; + long long dpll_clk; + int dpll_mult, dpll_div, amult; dpll_mult = (CM_CLKSEL1_PLL >> 12) & 0x03ff; /* 10 bits */ dpll_div = (CM_CLKSEL1_PLL >> 8) & 0x0f; /* 4 bits */ - dpll_clk = (tclk->parent->rate * dpll_mult) / (dpll_div + 1); + dpll_clk = (long long)tclk->parent->rate * dpll_mult; + do_div(dpll_clk, dpll_div + 1); amult = CM_CLKSEL2_PLL & 0x3; dpll_clk *= amult; @@ -385,75 +387,23 @@ static u32 omap2_dll_force_needed(void) return 0; } -static void omap2_init_memory_params(u32 force_lock_to_unlock_mode) -{ - unsigned long dll_cnt; - u32 fast_dll = 0; - - mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */ - - /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others. - * In the case of 2422, its ok to use CS1 instead of CS0. - */ - -#if 0 /* FIXME: Enable after 24xx cpu detection works */ - ctype = get_cpu_type(); - if (cpu_is_omap2422()) - mem_timings.base_cs = 1; - else -#endif - mem_timings.base_cs = 0; - - if (mem_timings.m_type != M_DDR) - return; - - /* With DDR we need to determine the low frequency DLL value */ - if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL)) - mem_timings.dll_mode = M_UNLOCK; - else - mem_timings.dll_mode = M_LOCK; - - if (mem_timings.base_cs == 0) { - fast_dll = SDRC_DLLA_CTRL; - dll_cnt = SDRC_DLLA_STATUS & 0xff00; - } else { - fast_dll = SDRC_DLLB_CTRL; - dll_cnt = SDRC_DLLB_STATUS & 0xff00; - } - if (force_lock_to_unlock_mode) { - fast_dll &= ~0xff00; - fast_dll |= dll_cnt; /* Current lock mode */ - } - mem_timings.fast_dll_ctrl = fast_dll; - - /* No disruptions, DDR will be offline & C-ABI not followed */ - omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl, - mem_timings.fast_dll_ctrl, - mem_timings.base_cs, - force_lock_to_unlock_mode); - mem_timings.slow_dll_ctrl &= 0xff00; /* Keep lock value */ - - /* Turn status into unlock ctrl */ - mem_timings.slow_dll_ctrl |= - ((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2)); - - /* 90 degree phase for anything below 133Mhz */ - mem_timings.slow_dll_ctrl |= (1 << 1); -} - static u32 omap2_reprogram_sdrc(u32 level, u32 force) { + u32 slow_dll_ctrl, fast_dll_ctrl, m_type; u32 prev = curr_perf_level, flags; if ((curr_perf_level == level) && !force) return prev; + m_type = omap2_memory_get_type(); + slow_dll_ctrl = omap2_memory_get_slow_dll_ctrl(); + fast_dll_ctrl = omap2_memory_get_fast_dll_ctrl(); + if (level == PRCM_HALF_SPEED) { local_irq_save(flags); PRCM_VOLTSETUP = 0xffff; omap2_sram_reprogram_sdrc(PRCM_HALF_SPEED, - mem_timings.slow_dll_ctrl, - mem_timings.m_type); + slow_dll_ctrl, m_type); curr_perf_level = PRCM_HALF_SPEED; local_irq_restore(flags); } @@ -461,8 +411,7 @@ static u32 omap2_reprogram_sdrc(u32 level, u32 force) local_irq_save(flags); PRCM_VOLTSETUP = 0xffff; omap2_sram_reprogram_sdrc(PRCM_FULL_SPEED, - mem_timings.fast_dll_ctrl, - mem_timings.m_type); + fast_dll_ctrl, m_type); curr_perf_level = PRCM_FULL_SPEED; local_irq_restore(flags); } @@ -650,7 +599,7 @@ static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask, case 13: /* dss2 */ mask = 0x1; break; case 25: /* usb */ - mask = 0xf; break; + mask = 0x7; break; } } diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h index 6cab20b1d3c1..6c78d471fab7 100644 --- a/arch/arm/mach-omap2/clock.h +++ b/arch/arm/mach-omap2/clock.h @@ -33,20 +33,6 @@ static u32 omap2_clksel_get_divisor(struct clk *clk); #define RATE_IN_242X (1 << 0) #define RATE_IN_243X (1 << 1) -/* Memory timings */ -#define M_DDR 1 -#define M_LOCK_CTRL (1 << 2) -#define M_UNLOCK 0 -#define M_LOCK 1 - -struct memory_timings { - u32 m_type; /* ddr = 1, sdr = 0 */ - u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */ - u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */ - u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */ - u32 base_cs; /* base chip select to use for calculations */ -}; - /* Key dividers which make up a PRCM set. Ratio's for a PRCM are mandated. * xtal_speed, dpll_speed, mpu_speed, CM_CLKSEL_MPU,CM_CLKSEL_DSP * CM_CLKSEL_GFX, CM_CLKSEL1_CORE, CM_CLKSEL1_PLL CM_CLKSEL2_PLL, CM_CLKSEL_MDM @@ -731,6 +717,16 @@ static struct clk sys_clkout2 = { .recalc = &omap2_clksel_recalc, }; +static struct clk emul_ck = { + .name = "emul_ck", + .parent = &func_54m_ck, + .flags = CLOCK_IN_OMAP242X, + .enable_reg = (void __iomem *)&PRCM_CLKEMUL_CTRL, + .enable_bit = 0, + .recalc = &omap2_propagate_rate, + +}; + /* * MPU clock domain * Clocks: @@ -1702,7 +1698,8 @@ static struct clk hdq_fck = { }; static struct clk i2c2_ick = { - .name = "i2c2_ick", + .name = "i2c_ick", + .id = 2, .parent = &l4_ck, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, @@ -1711,7 +1708,8 @@ static struct clk i2c2_ick = { }; static struct clk i2c2_fck = { - .name = "i2c2_fck", + .name = "i2c_fck", + .id = 2, .parent = &func_12m_ck, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, @@ -1729,7 +1727,8 @@ static struct clk i2chs2_fck = { }; static struct clk i2c1_ick = { - .name = "i2c1_ick", + .name = "i2c_ick", + .id = 1, .parent = &l4_ck, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, .enable_reg = (void __iomem *)&CM_ICLKEN1_CORE, @@ -1738,7 +1737,8 @@ static struct clk i2c1_ick = { }; static struct clk i2c1_fck = { - .name = "i2c1_fck", + .name = "i2c_fck", + .id = 1, .parent = &func_12m_ck, .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X, .enable_reg = (void __iomem *)&CM_FCLKEN1_CORE, @@ -1971,6 +1971,7 @@ static struct clk *onchip_clks[] = { &wdt1_osc_ck, &sys_clkout, &sys_clkout2, + &emul_ck, /* mpu domain clocks */ &mpu_ck, /* dsp domain clocks */ diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 7181edb89352..fb7f91da1aad 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -25,10 +25,6 @@ #include #include -extern void omap_nop_release(struct device *dev); - -/*-------------------------------------------------------------------------*/ - #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE) #define OMAP2_I2C_BASE2 0x48072000 @@ -49,9 +45,6 @@ static struct resource i2c_resources2[] = { static struct platform_device omap_i2c_device2 = { .name = "i2c_omap", .id = 2, - .dev = { - .release = omap_nop_release, - }, .num_resources = ARRAY_SIZE(i2c_resources2), .resource = i2c_resources2, }; @@ -74,6 +67,44 @@ static void omap_init_i2c(void) {} #endif +#if defined(CONFIG_OMAP_STI) + +#define OMAP2_STI_BASE IO_ADDRESS(0x48068000) +#define OMAP2_STI_CHANNEL_BASE 0x54000000 +#define OMAP2_STI_IRQ 4 + +static struct resource sti_resources[] = { + { + .start = OMAP2_STI_BASE, + .end = OMAP2_STI_BASE + 0x7ff, + .flags = IORESOURCE_MEM, + }, + { + .start = OMAP2_STI_CHANNEL_BASE, + .end = OMAP2_STI_CHANNEL_BASE + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = OMAP2_STI_IRQ, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device sti_device = { + .name = "sti", + .id = -1, + .num_resources = ARRAY_SIZE(sti_resources), + .resource = sti_resources, +}; + +static inline void omap_init_sti(void) +{ + platform_device_register(&sti_device); +} +#else +static inline void omap_init_sti(void) {} +#endif + /*-------------------------------------------------------------------------*/ static int __init omap2_init_devices(void) @@ -82,6 +113,7 @@ static int __init omap2_init_devices(void) * in alphabetical order so they're easier to sort through. */ omap_init_i2c(); + omap_init_sti(); return 0; } diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 8ea67bf196a5..7d5711611f2f 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -16,9 +16,13 @@ #include #include -#include +#include #include + +#include + #include +#include extern void omap_sram_init(void); extern int omap2_clk_init(void); @@ -43,11 +47,24 @@ static struct map_desc omap2_io_desc[] __initdata = { } }; -void __init omap_map_common_io(void) +void __init omap2_map_common_io(void) { iotable_init(omap2_io_desc, ARRAY_SIZE(omap2_io_desc)); + + /* Normally devicemaps_init() would flush caches and tlb after + * mdesc->map_io(), but we must also do it here because of the CPU + * revision check below. + */ + local_flush_tlb_all(); + flush_cache_all(); + omap2_check_revision(); omap_sram_init(); + omapfb_reserve_mem(); +} + +void __init omap2_init_common_hw(void) +{ omap2_mux_init(); omap2_clk_init(); } diff --git a/arch/arm/mach-omap2/memory.c b/arch/arm/mach-omap2/memory.c new file mode 100644 index 000000000000..1d925d69fc35 --- /dev/null +++ b/arch/arm/mach-omap2/memory.c @@ -0,0 +1,102 @@ +/* + * linux/arch/arm/mach-omap2/memory.c + * + * Memory timing related functions for OMAP24XX + * + * Copyright (C) 2005 Texas Instruments Inc. + * Richard Woodruff + * + * Copyright (C) 2005 Nokia Corporation + * Tony Lindgren + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "prcm-regs.h" +#include "memory.h" + +static struct memory_timings mem_timings; + +u32 omap2_memory_get_slow_dll_ctrl(void) +{ + return mem_timings.slow_dll_ctrl; +} + +u32 omap2_memory_get_fast_dll_ctrl(void) +{ + return mem_timings.fast_dll_ctrl; +} + +u32 omap2_memory_get_type(void) +{ + return mem_timings.m_type; +} + +void omap2_init_memory_params(u32 force_lock_to_unlock_mode) +{ + unsigned long dll_cnt; + u32 fast_dll = 0; + + mem_timings.m_type = !((SDRC_MR_0 & 0x3) == 0x1); /* DDR = 1, SDR = 0 */ + + /* 2422 es2.05 and beyond has a single SIP DDR instead of 2 like others. + * In the case of 2422, its ok to use CS1 instead of CS0. + */ + if (cpu_is_omap2422()) + mem_timings.base_cs = 1; + else + mem_timings.base_cs = 0; + + if (mem_timings.m_type != M_DDR) + return; + + /* With DDR we need to determine the low frequency DLL value */ + if (((mem_timings.fast_dll_ctrl & (1 << 2)) == M_LOCK_CTRL)) + mem_timings.dll_mode = M_UNLOCK; + else + mem_timings.dll_mode = M_LOCK; + + if (mem_timings.base_cs == 0) { + fast_dll = SDRC_DLLA_CTRL; + dll_cnt = SDRC_DLLA_STATUS & 0xff00; + } else { + fast_dll = SDRC_DLLB_CTRL; + dll_cnt = SDRC_DLLB_STATUS & 0xff00; + } + if (force_lock_to_unlock_mode) { + fast_dll &= ~0xff00; + fast_dll |= dll_cnt; /* Current lock mode */ + } + /* set fast timings with DLL filter disabled */ + mem_timings.fast_dll_ctrl = (fast_dll | (3 << 8)); + + /* No disruptions, DDR will be offline & C-ABI not followed */ + omap2_sram_ddr_init(&mem_timings.slow_dll_ctrl, + mem_timings.fast_dll_ctrl, + mem_timings.base_cs, + force_lock_to_unlock_mode); + mem_timings.slow_dll_ctrl &= 0xff00; /* Keep lock value */ + + /* Turn status into unlock ctrl */ + mem_timings.slow_dll_ctrl |= + ((mem_timings.fast_dll_ctrl & 0xF) | (1 << 2)); + + /* 90 degree phase for anything below 133Mhz + disable DLL filter */ + mem_timings.slow_dll_ctrl |= ((1 << 1) | (3 << 8)); +} diff --git a/arch/arm/mach-omap2/memory.h b/arch/arm/mach-omap2/memory.h new file mode 100644 index 000000000000..d212eea83a05 --- /dev/null +++ b/arch/arm/mach-omap2/memory.h @@ -0,0 +1,34 @@ +/* + * linux/arch/arm/mach-omap2/memory.h + * + * Interface for memory timing related functions for OMAP24XX + * + * Copyright (C) 2005 Texas Instruments Inc. + * Richard Woodruff + * + * Copyright (C) 2005 Nokia Corporation + * Tony Lindgren + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* Memory timings */ +#define M_DDR 1 +#define M_LOCK_CTRL (1 << 2) +#define M_UNLOCK 0 +#define M_LOCK 1 + +struct memory_timings { + u32 m_type; /* ddr = 1, sdr = 0 */ + u32 dll_mode; /* use lock mode = 1, unlock mode = 0 */ + u32 slow_dll_ctrl; /* unlock mode, dll value for slow speed */ + u32 fast_dll_ctrl; /* unlock mode, dll value for fast speed */ + u32 base_cs; /* base chip select to use for calculations */ +}; + +extern void omap2_init_memory_params(u32 force_lock_to_unlock_mode); +extern u32 omap2_memory_get_slow_dll_ctrl(void); +extern u32 omap2_memory_get_fast_dll_ctrl(void); +extern u32 omap2_memory_get_type(void); diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index ea4654815dd1..1197dc38c20a 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -50,9 +50,54 @@ MUX_CFG_24XX("H19_24XX_I2C2_SDA", 0x114, 0, 0, 0, 1) /* Menelaus interrupt */ MUX_CFG_24XX("W19_24XX_SYS_NIRQ", 0x12c, 0, 1, 1, 1) +/* 24xx clocks */ +MUX_CFG_24XX("W14_24XX_SYS_CLKOUT", 0x137, 0, 1, 1, 1) + +/* 24xx McBSP */ +MUX_CFG_24XX("Y15_24XX_MCBSP2_CLKX", 0x124, 1, 1, 0, 1) +MUX_CFG_24XX("R14_24XX_MCBSP2_FSX", 0x125, 1, 1, 0, 1) +MUX_CFG_24XX("W15_24XX_MCBSP2_DR", 0x126, 1, 1, 0, 1) +MUX_CFG_24XX("V15_24XX_MCBSP2_DX", 0x127, 1, 1, 0, 1) + /* 24xx GPIO */ +MUX_CFG_24XX("M21_242X_GPIO11", 0x0c9, 3, 1, 1, 1) +MUX_CFG_24XX("AA10_242X_GPIO13", 0x0e5, 3, 0, 0, 1) +MUX_CFG_24XX("AA6_242X_GPIO14", 0x0e6, 3, 0, 0, 1) +MUX_CFG_24XX("AA4_242X_GPIO15", 0x0e7, 3, 0, 0, 1) +MUX_CFG_24XX("Y11_242X_GPIO16", 0x0e8, 3, 0, 0, 1) +MUX_CFG_24XX("AA12_242X_GPIO17", 0x0e9, 3, 0, 0, 1) +MUX_CFG_24XX("AA8_242X_GPIO58", 0x0ea, 3, 0, 0, 1) MUX_CFG_24XX("Y20_24XX_GPIO60", 0x12c, 3, 0, 0, 1) +MUX_CFG_24XX("W4__24XX_GPIO74", 0x0f2, 3, 0, 0, 1) MUX_CFG_24XX("M15_24XX_GPIO92", 0x10a, 3, 0, 0, 1) +MUX_CFG_24XX("V14_24XX_GPIO117", 0x128, 3, 1, 0, 1) + +/* TSC IRQ */ +MUX_CFG_24XX("P20_24XX_TSC_IRQ", 0x108, 0, 0, 0, 1) + +/* UART3 */ +MUX_CFG_24XX("K15_24XX_UART3_TX", 0x118, 0, 0, 0, 1) +MUX_CFG_24XX("K14_24XX_UART3_RX", 0x119, 0, 0, 0, 1) + +/* Keypad GPIO*/ +MUX_CFG_24XX("T19_24XX_KBR0", 0x106, 3, 1, 1, 1) +MUX_CFG_24XX("R19_24XX_KBR1", 0x107, 3, 1, 1, 1) +MUX_CFG_24XX("V18_24XX_KBR2", 0x139, 3, 1, 1, 1) +MUX_CFG_24XX("M21_24XX_KBR3", 0xc9, 3, 1, 1, 1) +MUX_CFG_24XX("E5__24XX_KBR4", 0x138, 3, 1, 1, 1) +MUX_CFG_24XX("M18_24XX_KBR5", 0x10e, 3, 1, 1, 1) +MUX_CFG_24XX("R20_24XX_KBC0", 0x108, 3, 0, 0, 1) +MUX_CFG_24XX("M14_24XX_KBC1", 0x109, 3, 0, 0, 1) +MUX_CFG_24XX("H19_24XX_KBC2", 0x114, 3, 0, 0, 1) +MUX_CFG_24XX("V17_24XX_KBC3", 0x135, 3, 0, 0, 1) +MUX_CFG_24XX("P21_24XX_KBC4", 0xca, 3, 0, 0, 1) +MUX_CFG_24XX("L14_24XX_KBC5", 0x10f, 3, 0, 0, 1) +MUX_CFG_24XX("N19_24XX_KBC6", 0x110, 3, 0, 0, 1) + +/* 24xx Menelaus Keypad GPIO */ +MUX_CFG_24XX("B3__24XX_KBR5", 0x30, 3, 1, 1, 1) +MUX_CFG_24XX("AA4_24XX_KBC2", 0xe7, 3, 0, 0, 1) +MUX_CFG_24XX("B13_24XX_KBC6", 0x110, 3, 0, 0, 1) }; diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c new file mode 100644 index 000000000000..562168fa2b16 --- /dev/null +++ b/arch/arm/mach-omap2/pm.c @@ -0,0 +1,149 @@ +/* + * linux/arch/arm/mach-omap2/pm.c + * + * OMAP2 Power Management Routines + * + * Copyright (C) 2006 Nokia Corporation + * Tony Lindgren + * + * Copyright (C) 2005 Texas Instruments, Inc. + * Richard Woodruff + * + * Based on pm.c for omap1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct clk *vclk; +static void (*omap2_sram_idle)(void); +static void (*omap2_sram_suspend)(int dllctrl, int cpu_rev); +static void (*saved_idle)(void); + +void omap2_pm_idle(void) +{ + local_irq_disable(); + local_fiq_disable(); + if (need_resched()) { + local_fiq_enable(); + local_irq_enable(); + return; + } + + /* + * Since an interrupt may set up a timer, we don't want to + * reprogram the hardware timer with interrupts enabled. + * Re-enable interrupts only after returning from idle. + */ + timer_dyn_reprogram(); + + omap2_sram_idle(); + local_fiq_enable(); + local_irq_enable(); +} + +static int omap2_pm_prepare(suspend_state_t state) +{ + int error = 0; + + /* We cannot sleep in idle until we have resumed */ + saved_idle = pm_idle; + pm_idle = NULL; + + switch (state) + { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + break; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return error; +} + +static int omap2_pm_enter(suspend_state_t state) +{ + switch (state) + { + case PM_SUSPEND_STANDBY: + case PM_SUSPEND_MEM: + /* FIXME: Add suspend */ + break; + + case PM_SUSPEND_DISK: + return -ENOTSUPP; + + default: + return -EINVAL; + } + + return 0; +} + +static int omap2_pm_finish(suspend_state_t state) +{ + pm_idle = saved_idle; + return 0; +} + +static struct pm_ops omap_pm_ops = { + .pm_disk_mode = 0, + .prepare = omap2_pm_prepare, + .enter = omap2_pm_enter, + .finish = omap2_pm_finish, +}; + +int __init omap2_pm_init(void) +{ + printk("Power Management for TI OMAP.\n"); + + vclk = clk_get(NULL, "virt_prcm_set"); + if (IS_ERR(vclk)) { + printk(KERN_ERR "Could not get PM vclk\n"); + return -ENODEV; + } + + /* + * We copy the assembler sleep/wakeup routines to SRAM. + * These routines need to be in SRAM as that's the only + * memory the MPU can see when it wakes up. + */ + omap2_sram_idle = omap_sram_push(omap24xx_idle_loop_suspend, + omap24xx_idle_loop_suspend_sz); + + omap2_sram_suspend = omap_sram_push(omap24xx_cpu_suspend, + omap24xx_cpu_suspend_sz); + + pm_set_ops(&omap_pm_ops); + pm_idle = omap2_pm_idle; + + return 0; +} + +__initcall(omap2_pm_init); diff --git a/arch/arm/mach-omap2/prcm.h b/arch/arm/mach-omap2/prcm-regs.h similarity index 70% rename from arch/arm/mach-omap2/prcm.h rename to arch/arm/mach-omap2/prcm-regs.h index 2eb89b936c83..22ac7be4f782 100644 --- a/arch/arm/mach-omap2/prcm.h +++ b/arch/arm/mach-omap2/prcm-regs.h @@ -1,5 +1,7 @@ /* - * prcm.h - Access definations for use in OMAP24XX clock and power management + * linux/arch/arm/mach-omap2/prcm-reg.h + * + * OMAP24XX Power Reset and Clock Management (PRCM) registers * * Copyright (C) 2005 Texas Instruments, Inc. * @@ -18,8 +20,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __ASM_ARM_ARCH_DPM_PRCM_H -#define __ASM_ARM_ARCH_DPM_PRCM_H +#ifndef __ARCH_ARM_MACH_OMAP2_PRCM_H +#define __ARCH_ARM_MACH_OMAP2_PRCM_H /* SET_PERFORMANCE_LEVEL PARAMETERS */ #define PRCM_HALF_SPEED 1 @@ -159,54 +161,63 @@ #define CM_FCLKEN_MDM PRCM_REG32(0xC00) #define CM_ICLKEN_MDM PRCM_REG32(0xC10) #define CM_IDLEST_MDM PRCM_REG32(0xC20) +#define CM_AUTOIDLE_MDM PRCM_REG32(0xC30) #define CM_CLKSEL_MDM PRCM_REG32(0xC40) +#define CM_CLKSTCTRL_MDM PRCM_REG32(0xC48) +#define RM_RSTCTRL_MDM PRCM_REG32(0xC50) +#define RM_RSTST_MDM PRCM_REG32(0xC58) +#define PM_WKEN_MDM PRCM_REG32(0xCA0) +#define PM_WKST_MDM PRCM_REG32(0xCB0) +#define PM_WKDEP_MDM PRCM_REG32(0xCC8) +#define PM_PWSTCTRL_MDM PRCM_REG32(0xCE0) +#define PM_PWSTST_MDM PRCM_REG32(0xCE4) -/* FIXME: Move to header for 2430 */ -#define DISP_BASE (OMAP24XX_L4_IO_BASE+0x50000) +#define OMAP24XX_L4_IO_BASE 0x48000000 + +#define DISP_BASE (OMAP24XX_L4_IO_BASE + 0x50000) #define DISP_REG32(offset) __REG32(DISP_BASE + (offset)) -#define GPMC_BASE (OMAP24XX_GPMC_BASE) -#define GPMC_REG32(offset) __REG32(GPMC_BASE + (offset)) +#define OMAP24XX_GPMC_BASE (L3_24XX_BASE + 0xa000) +#define GPMC_REG32(offset) __REG32(OMAP24XX_GPMC_BASE + (offset)) -#define GPT1_BASE (OMAP24XX_GPT1) +/* FIXME: Move these to timer code */ +#define GPT1_BASE (0x48028000) #define GPT1_REG32(offset) __REG32(GPT1_BASE + (offset)) /* Misc sysconfig */ #define DISPC_SYSCONFIG DISP_REG32(0x410) -#define SPI_BASE (OMAP24XX_L4_IO_BASE+0x98000) +#define SPI_BASE (OMAP24XX_L4_IO_BASE + 0x98000) #define MCSPI1_SYSCONFIG __REG32(SPI_BASE + 0x10) -#define MCSPI2_SYSCONFIG __REG32(SPI_BASE+0x2000 + 0x10) +#define MCSPI2_SYSCONFIG __REG32(SPI_BASE + 0x2000 + 0x10) +#define MCSPI3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0xb8010) -//#define DSP_MMU_SYSCONFIG 0x5A000010 -#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE+0x2C10) -//#define IVA_MMU_SYSCONFIG 0x5D000010 -//#define DSP_DMA_SYSCONFIG 0x00FCC02C -#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE+0x282C) -#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE+0x602C) +#define CAMERA_MMU_SYSCONFIG __REG32(DISP_BASE + 0x2C10) +#define CAMERA_DMA_SYSCONFIG __REG32(DISP_BASE + 0x282C) +#define SYSTEM_DMA_SYSCONFIG __REG32(DISP_BASE + 0x602C) #define GPMC_SYSCONFIG GPMC_REG32(0x010) -#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x94010) -#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6A054) -#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6C054) -#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE+0x6E054) -//#define IVA_SYSCONFIG 0x5C060010 -#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE+0x10) -#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE+0x10) -#define SSI_SYSCONFIG __REG32(DISP_BASE+0x8010) -//#define VLYNQ_SYSCONFIG 0x67FFFE10 +#define MAILBOXES_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x94010) +#define UART1_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6A054) +#define UART2_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6C054) +#define UART3_SYSCONFIG __REG32(OMAP24XX_L4_IO_BASE + 0x6E054) +#define SDRC_SYSCONFIG __REG32(OMAP24XX_SDRC_BASE + 0x10) +#define OMAP24XX_SMS_BASE (L3_24XX_BASE + 0x8000) +#define SMS_SYSCONFIG __REG32(OMAP24XX_SMS_BASE + 0x10) +#define SSI_SYSCONFIG __REG32(DISP_BASE + 0x8010) /* rkw - good cannidates for PM_ to start what nm was trying */ -#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE+0x2A000) -#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE+0x78000) -#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE+0x7A000) -#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE+0x7C000) -#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE+0x7E000) -#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE+0x80000) -#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE+0x82000) -#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE+0x84000) -#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE+0x86000) -#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE+0x88000) -#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE+0x8A000) +#define OMAP24XX_GPT2 (OMAP24XX_L4_IO_BASE + 0x2A000) +#define OMAP24XX_GPT3 (OMAP24XX_L4_IO_BASE + 0x78000) +#define OMAP24XX_GPT4 (OMAP24XX_L4_IO_BASE + 0x7A000) +#define OMAP24XX_GPT5 (OMAP24XX_L4_IO_BASE + 0x7C000) +#define OMAP24XX_GPT6 (OMAP24XX_L4_IO_BASE + 0x7E000) +#define OMAP24XX_GPT7 (OMAP24XX_L4_IO_BASE + 0x80000) +#define OMAP24XX_GPT8 (OMAP24XX_L4_IO_BASE + 0x82000) +#define OMAP24XX_GPT9 (OMAP24XX_L4_IO_BASE + 0x84000) +#define OMAP24XX_GPT10 (OMAP24XX_L4_IO_BASE + 0x86000) +#define OMAP24XX_GPT11 (OMAP24XX_L4_IO_BASE + 0x88000) +#define OMAP24XX_GPT12 (OMAP24XX_L4_IO_BASE + 0x8A000) +/* FIXME: Move these to timer code */ #define GPTIMER1_SYSCONFIG GPT1_REG32(0x010) #define GPTIMER2_SYSCONFIG __REG32(OMAP24XX_GPT2 + 0x10) #define GPTIMER3_SYSCONFIG __REG32(OMAP24XX_GPT3 + 0x10) @@ -220,12 +231,18 @@ #define GPTIMER11_SYSCONFIG __REG32(OMAP24XX_GPT11 + 0x10) #define GPTIMER12_SYSCONFIG __REG32(OMAP24XX_GPT12 + 0x10) -#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE+(0x2000*((X)-1))) +/* FIXME: Move these to gpio code */ +#define OMAP24XX_GPIO_BASE 0x48018000 +#define GPIOX_BASE(X) (OMAP24XX_GPIO_BASE + (0x2000 * ((X) - 1))) -#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1)+0x10)) -#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2)+0x10)) -#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3)+0x10)) -#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4)+0x10)) +#define GPIO1_SYSCONFIG __REG32((GPIOX_BASE(1) + 0x10)) +#define GPIO2_SYSCONFIG __REG32((GPIOX_BASE(2) + 0x10)) +#define GPIO3_SYSCONFIG __REG32((GPIOX_BASE(3) + 0x10)) +#define GPIO4_SYSCONFIG __REG32((GPIOX_BASE(4) + 0x10)) + +#if defined(CONFIG_ARCH_OMAP243X) +#define GPIO5_SYSCONFIG __REG32((OMAP24XX_GPIO5_BASE + 0x10)) +#endif /* GP TIMER 1 */ #define GPTIMER1_TISTAT GPT1_REG32(0x014) @@ -243,15 +260,15 @@ #define GPTIMER1_TCAR2 GPT1_REG32(0x044) /* rkw -- base fix up please... */ -#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE+0x78018) +#define GPTIMER3_TISR __REG32(OMAP24XX_L4_IO_BASE + 0x78018) /* SDRC */ -#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE+0x060) -#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE+0x064) -#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE+0x068) -#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE+0x06C) -#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE+0x070) -#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE+0x084) +#define SDRC_DLLA_CTRL __REG32(OMAP24XX_SDRC_BASE + 0x060) +#define SDRC_DLLA_STATUS __REG32(OMAP24XX_SDRC_BASE + 0x064) +#define SDRC_DLLB_CTRL __REG32(OMAP24XX_SDRC_BASE + 0x068) +#define SDRC_DLLB_STATUS __REG32(OMAP24XX_SDRC_BASE + 0x06C) +#define SDRC_POWER __REG32(OMAP24XX_SDRC_BASE + 0x070) +#define SDRC_MR_0 __REG32(OMAP24XX_SDRC_BASE + 0x084) /* GPIO 1 */ #define GPIO1_BASE GPIOX_BASE(1) @@ -278,6 +295,8 @@ #define GPIO2_DATAIN GPIO2_REG32(0x038) #define GPIO2_OE GPIO2_REG32(0x034) #define GPIO2_DATAOUT GPIO2_REG32(0x03C) +#define GPIO2_DEBOUNCENABLE GPIO2_REG32(0x050) +#define GPIO2_DEBOUNCINGTIME GPIO2_REG32(0x054) /* GPIO 3 */ #define GPIO3_BASE GPIOX_BASE(3) @@ -294,6 +313,8 @@ #define GPIO3_DATAOUT GPIO3_REG32(0x03C) #define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050) #define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054) +#define GPIO3_DEBOUNCENABLE GPIO3_REG32(0x050) +#define GPIO3_DEBOUNCINGTIME GPIO3_REG32(0x054) /* GPIO 4 */ #define GPIO4_BASE GPIOX_BASE(4) @@ -311,10 +332,26 @@ #define GPIO4_DEBOUNCENABLE GPIO4_REG32(0x050) #define GPIO4_DEBOUNCINGTIME GPIO4_REG32(0x054) +#if defined(CONFIG_ARCH_OMAP243X) +/* GPIO 5 */ +#define GPIO5_REG32(offset) __REG32((OMAP24XX_GPIO5_BASE + (offset))) +#define GPIO5_IRQENABLE1 GPIO5_REG32(0x01C) +#define GPIO5_IRQSTATUS1 GPIO5_REG32(0x018) +#define GPIO5_IRQENABLE2 GPIO5_REG32(0x02C) +#define GPIO5_IRQSTATUS2 GPIO5_REG32(0x028) +#define GPIO5_WAKEUPENABLE GPIO5_REG32(0x020) +#define GPIO5_RISINGDETECT GPIO5_REG32(0x048) +#define GPIO5_FALLINGDETECT GPIO5_REG32(0x04C) +#define GPIO5_DATAIN GPIO5_REG32(0x038) +#define GPIO5_OE GPIO5_REG32(0x034) +#define GPIO5_DATAOUT GPIO5_REG32(0x03C) +#define GPIO5_DEBOUNCENABLE GPIO5_REG32(0x050) +#define GPIO5_DEBOUNCINGTIME GPIO5_REG32(0x054) +#endif /* IO CONFIG */ -#define CONTROL_BASE (OMAP24XX_CTRL_BASE) -#define CONTROL_REG32(offset) __REG32(CONTROL_BASE + (offset)) +#define OMAP24XX_CTRL_BASE (L4_24XX_BASE) +#define CONTROL_REG32(offset) __REG32(OMAP24XX_CTRL_BASE + (offset)) #define CONTROL_PADCONF_SPI1_NCS2 CONTROL_REG32(0x104) #define CONTROL_PADCONF_SYS_XTALOUT CONTROL_REG32(0x134) @@ -322,15 +359,18 @@ #define CONTROL_PADCONF_MCBSP1_DX CONTROL_REG32(0x10C) #define CONTROL_PADCONF_GPMC_NCS4 CONTROL_REG32(0x090) #define CONTROL_PADCONF_DSS_D5 CONTROL_REG32(0x0B8) -#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC) +#define CONTROL_PADCONF_DSS_D9 CONTROL_REG32(0x0BC) /* 2420 */ #define CONTROL_PADCONF_DSS_D13 CONTROL_REG32(0x0C0) #define CONTROL_PADCONF_DSS_VSYNC CONTROL_REG32(0x0CC) +#define CONTROL_PADCONF_SYS_NIRQW0 CONTROL_REG32(0x0BC) /* 2430 */ +#define CONTROL_PADCONF_SSI1_FLAG_TX CONTROL_REG32(0x108) /* 2430 */ /* CONTROL */ #define CONTROL_DEVCONF CONTROL_REG32(0x274) +#define CONTROL_DEVCONF1 CONTROL_REG32(0x2E8) /* INTERRUPT CONTROLLER */ -#define INTC_BASE (OMAP24XX_L4_IO_BASE+0xfe000) +#define INTC_BASE ((L4_24XX_BASE) + 0xfe000) #define INTC_REG32(offset) __REG32(INTC_BASE + (offset)) #define INTC1_U_BASE INTC_REG32(0x000) @@ -348,10 +388,12 @@ #define INTC_ISR_CLEAR2 INTC_REG32(0x0D4) #define INTC_SIR_IRQ INTC_REG32(0x040) #define INTC_CONTROL INTC_REG32(0x048) -#define INTC_ILR11 INTC_REG32(0x12C) +#define INTC_ILR11 INTC_REG32(0x12C) /* PRCM on MPU PIC */ +#define INTC_ILR30 INTC_REG32(0x178) +#define INTC_ILR31 INTC_REG32(0x17C) #define INTC_ILR32 INTC_REG32(0x180) -#define INTC_ILR37 INTC_REG32(0x194) -#define INTC_SYSCONFIG INTC_REG32(0x010) +#define INTC_ILR37 INTC_REG32(0x194) /* GPIO4 on MPU PIC */ +#define INTC_SYSCONFIG INTC_REG32(0x010) /* GPT1 on MPU PIC */ /* RAM FIREWALL */ #define RAMFW_BASE (0x68005000) @@ -373,6 +415,24 @@ #define GPMC_CONFIG6_0 GPMC_REG32(0x074) #define GPMC_CONFIG7_0 GPMC_REG32(0x078) +/* GPMC CS1 */ +#define GPMC_CONFIG1_1 GPMC_REG32(0x090) +#define GPMC_CONFIG2_1 GPMC_REG32(0x094) +#define GPMC_CONFIG3_1 GPMC_REG32(0x098) +#define GPMC_CONFIG4_1 GPMC_REG32(0x09C) +#define GPMC_CONFIG5_1 GPMC_REG32(0x0a0) +#define GPMC_CONFIG6_1 GPMC_REG32(0x0a4) +#define GPMC_CONFIG7_1 GPMC_REG32(0x0a8) + +/* GPMC CS3 */ +#define GPMC_CONFIG1_3 GPMC_REG32(0x0F0) +#define GPMC_CONFIG2_3 GPMC_REG32(0x0F4) +#define GPMC_CONFIG3_3 GPMC_REG32(0x0F8) +#define GPMC_CONFIG4_3 GPMC_REG32(0x0FC) +#define GPMC_CONFIG5_3 GPMC_REG32(0x100) +#define GPMC_CONFIG6_3 GPMC_REG32(0x104) +#define GPMC_CONFIG7_3 GPMC_REG32(0x108) + /* DSS */ #define DSS_CONTROL DISP_REG32(0x040) #define DISPC_CONTROL DISP_REG32(0x440) @@ -405,11 +465,15 @@ #define DISPC_DATA_CYCLE2 DISP_REG32(0x5D8) #define DISPC_DATA_CYCLE3 DISP_REG32(0x5DC) -/* Wake up define for board */ -#define GPIO97 (1 << 1) -#define GPIO88 (1 << 24) +/* HSUSB Suspend */ +#define HSUSB_CTRL __REG8(0x480AC001) +#define USBOTG_POWER __REG32(0x480AC000) -#endif /* __ASSEMBLER__ */ +/* HS MMC */ +#define MMCHS1_SYSCONFIG __REG32(0x4809C010) +#define MMCHS2_SYSCONFIG __REG32(0x480b4010) + +#endif /* __ASSEMBLER__ */ #endif diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c new file mode 100644 index 000000000000..8893479dc7e0 --- /dev/null +++ b/arch/arm/mach-omap2/prcm.c @@ -0,0 +1,40 @@ +/* + * linux/arch/arm/mach-omap2/prcm.c + * + * OMAP 24xx Power Reset and Clock Management (PRCM) functions + * + * Copyright (C) 2005 Nokia Corporation + * + * Written by Tony Lindgren + * + * Some pieces of code Copyright (C) 2005 Texas Instruments, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include + +#include "prcm-regs.h" + +u32 omap_prcm_get_reset_sources(void) +{ + return RM_RSTST_WKUP & 0x7f; +} +EXPORT_SYMBOL(omap_prcm_get_reset_sources); + +/* Resets clock rates and reboots the system. Only called from system.h */ +void omap_prcm_arch_reset(char mode) +{ + u32 rate; + struct clk *vclk, *sclk; + + vclk = clk_get(NULL, "virt_prcm_set"); + sclk = clk_get(NULL, "sys_ck"); + rate = clk_get_rate(sclk); + clk_set_rate(vclk, rate); /* go to bypass for OMAP limitation */ + RM_RSTCTRL_WKUP |= 2; +} diff --git a/arch/arm/mach-omap2/sleep.S b/arch/arm/mach-omap2/sleep.S new file mode 100644 index 000000000000..00299cbeb911 --- /dev/null +++ b/arch/arm/mach-omap2/sleep.S @@ -0,0 +1,144 @@ +/* + * linux/arch/arm/mach-omap2/sleep.S + * + * (C) Copyright 2004 + * Texas Instruments, + * Richard Woodruff + * + * 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 + +#define A_32KSYNC_CR_V IO_ADDRESS(OMAP_TIMER32K_BASE+0x10) +#define A_PRCM_VOLTCTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x50) +#define A_PRCM_CLKCFG_CTRL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x80) +#define A_CM_CLKEN_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x500) +#define A_CM_IDLEST_CKGEN_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x520) +#define A_CM_CLKSEL1_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x540) +#define A_CM_CLKSEL2_PLL_V IO_ADDRESS(OMAP24XX_PRCM_BASE+0x544) + +#define A_SDRC_DLLA_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x60) +#define A_SDRC_POWER_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0x70) +#define A_SDRC_RFR_CTRL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA4) +#define A_SDRC0_V (0xC0000000) +#define A_SDRC_MANUAL_V IO_ADDRESS(OMAP24XX_SDRC_BASE+0xA8) + + .text + +/* + * Forces OMAP into idle state + * + * omap24xx_idle_loop_suspend() - This bit of code just executes the WFI + * for normal idles. + * + * Note: This code get's copied to internal SRAM at boot. When the OMAP + * wakes up it continues execution at the point it went to sleep. + */ +ENTRY(omap24xx_idle_loop_suspend) + stmfd sp!, {r0, lr} @ save registers on stack + mov r0, #0 @ clear for mcr setup + mcr p15, 0, r0, c7, c0, 4 @ wait for interrupt + ldmfd sp!, {r0, pc} @ restore regs and return + +ENTRY(omap24xx_idle_loop_suspend_sz) + .word . - omap24xx_idle_loop_suspend + +/* + * omap242x_cpu_suspend() - Forces OMAP into deep sleep state by completing + * SDRC shutdown then ARM shutdown. Upon wake MPU is back on so just restore + * SDRC. + * + * Input: + * R0 : DLL ctrl value pre-Sleep + * R1 : Processor+Revision + * 2420: 0x21 = 242xES1, 0x26 = 242xES2.2 + * 2430: 0x31 = 2430ES1, 0x32 = 2430ES2 + * + * The if the DPLL is going to AutoIdle. It seems like the DPLL may be back on + * when we get called, but the DLL probably isn't. We will wait a bit more in + * case the DPLL isn't quite there yet. The code will wait on DLL for DDR even + * if in unlocked mode. + * + * For less than 242x-ES2.2 upon wake from a sleep mode where the external + * oscillator was stopped, a timing bug exists where a non-stabilized 12MHz + * clock can pass into the PRCM can cause problems at DSP and IVA. + * To work around this the code will switch to the 32kHz source prior to sleep. + * Post sleep we will shift back to using the DPLL. Apparently, + * CM_IDLEST_CLKGEN does not reflect the full clock change so you need to wait + * 3x12MHz + 3x32kHz clocks for a full switch. + * + * The DLL load value is not kept in RETENTION or OFF. It needs to be restored + * at wake + */ +ENTRY(omap24xx_cpu_suspend) + stmfd sp!, {r0 - r12, lr} @ save registers on stack + mov r3, #0x0 @ clear for mrc call + mcr p15, 0, r3, c7, c10, 4 @ memory barrier, hope SDR/DDR finished + nop + nop + ldr r3, A_SDRC_POWER @ addr of sdrc power + ldr r4, [r3] @ value of sdrc power + orr r4, r4, #0x40 @ enable self refresh on idle req + mov r5, #0x2000 @ set delay (DPLL relock + DLL relock) + str r4, [r3] @ make it so + mov r2, #0 + nop + mcr p15, 0, r2, c7, c0, 4 @ wait for interrupt + nop +loop: + subs r5, r5, #0x1 @ awake, wait just a bit + bne loop + + /* The DPLL has on before we take the DDR out of self refresh */ + bic r4, r4, #0x40 @ now clear self refresh bit. + str r4, [r3] @ put vlaue back. + ldr r4, A_SDRC0 @ make a clock happen + ldr r4, [r4] + nop @ start auto refresh only after clk ok + movs r0, r0 @ see if DDR or SDR + ldrne r1, A_SDRC_DLLA_CTRL_S @ get addr of DLL ctrl + strne r0, [r1] @ rewrite DLLA to force DLL reload + addne r1, r1, #0x8 @ move to DLLB + strne r0, [r1] @ rewrite DLLB to force DLL reload + + mov r5, #0x1000 +loop2: + subs r5, r5, #0x1 + bne loop2 + /* resume*/ + ldmfd sp!, {r0 - r12, pc} @ restore regs and return + +A_SDRC_POWER: + .word A_SDRC_POWER_V +A_SDRC0: + .word A_SDRC0_V +A_CM_CLKSEL2_PLL_S: + .word A_CM_CLKSEL2_PLL_V +A_CM_CLKEN_PLL: + .word A_CM_CLKEN_PLL_V +A_SDRC_DLLA_CTRL_S: + .word A_SDRC_DLLA_CTRL_V +A_SDRC_MANUAL_S: + .word A_SDRC_MANUAL_V + +ENTRY(omap24xx_cpu_suspend_sz) + .word . - omap24xx_cpu_suspend + diff --git a/arch/arm/mach-omap2/sram-fn.S b/arch/arm/mach-omap2/sram-fn.S index 2a869e203342..d261e4ff4d9b 100644 --- a/arch/arm/mach-omap2/sram-fn.S +++ b/arch/arm/mach-omap2/sram-fn.S @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mach-omap1/sram.S + * linux/arch/arm/mach-omap2/sram.S * * Omap2 specific functions that need to be run in internal SRAM * @@ -28,7 +28,7 @@ #include #include -#include +#include "prcm-regs.h" #define TIMER_32KSYNCT_CR_V IO_ADDRESS(OMAP24XX_32KSYNCT_BASE + 0x010) diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 68923b1d2b62..d6d726036361 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -141,6 +141,8 @@ struct corgissp_machinfo corgi_ssp_machinfo = { */ static struct corgibl_machinfo corgi_bl_machinfo = { .max_intensity = 0x2f, + .default_intensity = 0x1f, + .limit_mask = 0x0b, .set_bl_intensity = corgi_bl_set_intensity, }; @@ -163,6 +165,14 @@ static struct platform_device corgikbd_device = { }; +/* + * Corgi LEDs + */ +static struct platform_device corgiled_device = { + .name = "corgi-led", + .id = -1, +}; + /* * Corgi Touch Screen Device */ @@ -297,6 +307,7 @@ static struct platform_device *devices[] __initdata = { &corgikbd_device, &corgibl_device, &corgits_device, + &corgiled_device, }; static void __init corgi_init(void) diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index b45560a8f6c4..a042473deedd 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -307,6 +307,10 @@ static void __init fixup_poodle(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { sharpsl_save_param(); + mi->nr_banks=1; + mi->bank[0].start = 0xa0000000; + mi->bank[0].node = 0; + mi->bank[0].size = (32*1024*1024); } MACHINE_START(POODLE, "SHARP Poodle") diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 0dbb079ecd25..19b372df544a 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -220,6 +220,8 @@ struct corgissp_machinfo spitz_ssp_machinfo = { * Spitz Backlight Device */ static struct corgibl_machinfo spitz_bl_machinfo = { + .default_intensity = 0x1f, + .limit_mask = 0x0b, .max_intensity = 0x2f, }; @@ -241,6 +243,14 @@ static struct platform_device spitzkbd_device = { }; +/* + * Spitz LEDs + */ +static struct platform_device spitzled_device = { + .name = "spitz-led", + .id = -1, +}; + /* * Spitz Touch Screen Device */ @@ -418,6 +428,7 @@ static struct platform_device *devices[] __initdata = { &spitzkbd_device, &spitzts_device, &spitzbl_device, + &spitzled_device, }; static void __init common_init(void) diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c index 66ec71756d0f..76c0e7f0a219 100644 --- a/arch/arm/mach-pxa/tosa.c +++ b/arch/arm/mach-pxa/tosa.c @@ -251,10 +251,19 @@ static struct platform_device tosakbd_device = { .id = -1, }; +/* + * Tosa LEDs + */ +static struct platform_device tosaled_device = { + .name = "tosa-led", + .id = -1, +}; + static struct platform_device *devices[] __initdata = { &tosascoop_device, &tosascoop_jc_device, &tosakbd_device, + &tosaled_device, }; static void __init tosa_init(void) diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index ed07c4149d82..ce7d81000695 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig @@ -50,9 +50,15 @@ config MACH_N30 . +config MACH_SMDK + bool + help + Common machine code for SMDK2410 and SMDK2440 + config ARCH_SMDK2410 bool "SMDK2410/A9M2410" select CPU_S3C2410 + select MACH_SMDK help Say Y here if you are using the SMDK2410 or the derived module A9M2410 @@ -60,6 +66,7 @@ config ARCH_SMDK2410 config ARCH_S3C2440 bool "SMDK2440" select CPU_S3C2440 + select MACH_SMDK help Say Y here if you are using the SMDK2440. diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 1b3b476e5637..3e5712db6b52 100644 --- a/arch/arm/mach-s3c2410/Makefile +++ b/arch/arm/mach-s3c2410/Makefile @@ -48,3 +48,5 @@ obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o obj-$(CONFIG_MACH_OTOM) += mach-otom.o obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o + +obj-$(CONFIG_MACH_SMDK) += common-smdk.o \ No newline at end of file diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c index fec02c92f95f..6de713ad319a 100644 --- a/arch/arm/mach-s3c2410/clock.c +++ b/arch/arm/mach-s3c2410/clock.c @@ -249,7 +249,7 @@ static int s3c24xx_upll_enable(struct clk *clk, int enable) /* if we started the UPLL, then allow to settle */ - if (enable && !(orig & S3C2410_CLKSLOW_UCLK_OFF)) + if (enable && (orig & S3C2410_CLKSLOW_UCLK_OFF)) udelay(200); return 0; @@ -367,6 +367,8 @@ static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) source = S3C2410_MISCCR_CLK0_UPLL; else if (parent == &clk_f) source = S3C2410_MISCCR_CLK0_FCLK; + else if (parent == &clk_h) + source = S3C2410_MISCCR_CLK0_HCLK; else if (parent == &clk_p) source = S3C2410_MISCCR_CLK0_PCLK; else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0) @@ -376,6 +378,8 @@ static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) else return -EINVAL; + clk->parent = parent; + if (clk == &s3c24xx_dclk0) mask = S3C2410_MISCCR_CLK0_MASK; else { diff --git a/arch/arm/mach-s3c2410/common-smdk.c b/arch/arm/mach-s3c2410/common-smdk.c new file mode 100644 index 000000000000..c940890f621f --- /dev/null +++ b/arch/arm/mach-s3c2410/common-smdk.c @@ -0,0 +1,135 @@ +/* linux/arch/arm/mach-s3c2410/common-smdk.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * Common code for SMDK2410 and SMDK2440 boards + * + * http://www.fluff.org/ben/smdk2440/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include "common-smdk.h" +#include "devs.h" +#include "pm.h" + +/* NAND parititon from 2.4.18-swl5 */ + +static struct mtd_partition smdk_default_nand_part[] = { + [0] = { + .name = "Boot Agent", + .size = SZ_16K, + .offset = 0, + }, + [1] = { + .name = "S3C2410 flash partition 1", + .offset = 0, + .size = SZ_2M, + }, + [2] = { + .name = "S3C2410 flash partition 2", + .offset = SZ_4M, + .size = SZ_4M, + }, + [3] = { + .name = "S3C2410 flash partition 3", + .offset = SZ_8M, + .size = SZ_2M, + }, + [4] = { + .name = "S3C2410 flash partition 4", + .offset = SZ_1M * 10, + .size = SZ_4M, + }, + [5] = { + .name = "S3C2410 flash partition 5", + .offset = SZ_1M * 14, + .size = SZ_1M * 10, + }, + [6] = { + .name = "S3C2410 flash partition 6", + .offset = SZ_1M * 24, + .size = SZ_1M * 24, + }, + [7] = { + .name = "S3C2410 flash partition 7", + .offset = SZ_1M * 48, + .size = SZ_16M, + } +}; + +static struct s3c2410_nand_set smdk_nand_sets[] = { + [0] = { + .name = "NAND", + .nr_chips = 1, + .nr_partitions = ARRAY_SIZE(smdk_default_nand_part), + .partitions = smdk_default_nand_part, + }, +}; + +/* choose a set of timings which should suit most 512Mbit + * chips and beyond. +*/ + +static struct s3c2410_platform_nand smdk_nand_info = { + .tacls = 20, + .twrph0 = 60, + .twrph1 = 20, + .nr_sets = ARRAY_SIZE(smdk_nand_sets), + .sets = smdk_nand_sets, +}; + +/* devices we initialise */ + +static struct platform_device __initdata *smdk_devs[] = { + &s3c_device_nand, +}; + +void __init smdk_machine_init(void) +{ + /* Configure the LEDs (even if we have no LED support)*/ + + s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP); + s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); + s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP); + s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP); + + s3c2410_gpio_setpin(S3C2410_GPF4, 1); + s3c2410_gpio_setpin(S3C2410_GPF5, 1); + s3c2410_gpio_setpin(S3C2410_GPF6, 1); + s3c2410_gpio_setpin(S3C2410_GPF7, 1); + + s3c_device_nand.dev.platform_data = &smdk_nand_info; + + platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs)); + + s3c2410_pm_init(); +} diff --git a/arch/arm/mach-s3c2410/common-smdk.h b/arch/arm/mach-s3c2410/common-smdk.h new file mode 100644 index 000000000000..0e3a3be330a3 --- /dev/null +++ b/arch/arm/mach-s3c2410/common-smdk.h @@ -0,0 +1,15 @@ +/* linux/arch/arm/mach-s3c2410/common-smdk.h + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * Common code for SMDK2410 and SMDK2440 boards + * + * http://www.fluff.org/ben/smdk2440/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +extern void smdk_machine_init(void); diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c index 3e327b8e46be..cc97fbf66291 100644 --- a/arch/arm/mach-s3c2410/mach-anubis.c +++ b/arch/arm/mach-s3c2410/mach-anubis.c @@ -232,8 +232,8 @@ static void anubis_nand_select(struct s3c2410_nand_set *set, int slot) static struct s3c2410_platform_nand anubis_nand_info = { .tacls = 25, - .twrph0 = 80, - .twrph1 = 80, + .twrph0 = 55, + .twrph1 = 40, .nr_sets = ARRAY_SIZE(anubis_nand_sets), .sets = anubis_nand_sets, .select_chip = anubis_nand_select, diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c index 0260ed5ab946..306afc1d7cd3 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2410/mach-rx3715.c @@ -32,6 +32,11 @@ #include #include +#include +#include +#include +#include + #include #include #include @@ -46,6 +51,7 @@ #include #include +#include #include #include "clock.h" @@ -170,12 +176,39 @@ static struct s3c2410fb_mach_info rx3715_lcdcfg __initdata = { }, }; +static struct mtd_partition rx3715_nand_part[] = { + [0] = { + .name = "Whole Flash", + .offset = 0, + .size = MTDPART_SIZ_FULL, + .mask_flags = MTD_WRITEABLE, + } +}; + +static struct s3c2410_nand_set rx3715_nand_sets[] = { + [0] = { + .name = "Internal", + .nr_chips = 1, + .nr_partitions = ARRAY_SIZE(rx3715_nand_part), + .partitions = rx3715_nand_part, + }, +}; + +static struct s3c2410_platform_nand rx3715_nand_info = { + .tacls = 25, + .twrph0 = 50, + .twrph1 = 15, + .nr_sets = ARRAY_SIZE(rx3715_nand_sets), + .sets = rx3715_nand_sets, +}; + static struct platform_device *rx3715_devices[] __initdata = { &s3c_device_usb, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c, &s3c_device_iis, + &s3c_device_nand, }; static struct s3c24xx_board rx3715_board __initdata = { @@ -185,6 +218,8 @@ static struct s3c24xx_board rx3715_board __initdata = { static void __init rx3715_map_io(void) { + s3c_device_nand.dev.platform_data = &rx3715_nand_info; + s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc)); s3c24xx_init_clocks(16934000); s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs)); diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index 1e76e1fdfcea..2db932d72c5a 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -28,7 +28,8 @@ * Ben Dooks * * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA - * 20-Sep-2005 BJD Added static to non-exported items + * 20-Sep-2005 BJD Added static to non-exported items + * 01-Apr-2006 BJD Moved init code to common smdk * ***********************************************************************/ @@ -54,6 +55,8 @@ #include "devs.h" #include "cpu.h" +#include "common-smdk.h" + static struct map_desc smdk2410_iodesc[] __initdata = { /* nothing here yet */ }; @@ -107,11 +110,6 @@ static void __init smdk2410_map_io(void) s3c24xx_set_board(&smdk2410_board); } -static void __init smdk2410_init_irq(void) -{ - s3c24xx_init_irq(); -} - MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch * to SMDK2410 */ /* Maintainer: Jonas Dietsche */ @@ -119,7 +117,8 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = smdk2410_map_io, - .init_irq = smdk2410_init_irq, + .init_irq = s3c24xx_init_irq, + .init_machine = smdk_machine_init, .timer = &s3c24xx_timer, MACHINE_END diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c index f4315721c3b8..5fffd1d51047 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2410/mach-smdk2440.c @@ -53,7 +53,8 @@ #include "clock.h" #include "devs.h" #include "cpu.h" -#include "pm.h" + +#include "common-smdk.h" static struct map_desc smdk2440_iodesc[] __initdata = { /* ISA IO Space map (memory space selected by A24) */ @@ -197,21 +198,9 @@ static void __init smdk2440_map_io(void) static void __init smdk2440_machine_init(void) { - /* Configure the LEDs (even if we have no LED support)*/ - - s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP); - s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP); - s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP); - s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP); - - s3c2410_gpio_setpin(S3C2410_GPF4, 0); - s3c2410_gpio_setpin(S3C2410_GPF5, 0); - s3c2410_gpio_setpin(S3C2410_GPF6, 0); - s3c2410_gpio_setpin(S3C2410_GPF7, 0); - s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg); - s3c2410_pm_init(); + smdk_machine_init(); } MACHINE_START(S3C2440, "SMDK2440") diff --git a/arch/arm/mach-s3c2410/s3c2440-clock.c b/arch/arm/mach-s3c2410/s3c2440-clock.c index 57a15974d4b5..d7a30ed6c327 100644 --- a/arch/arm/mach-s3c2410/s3c2440-clock.c +++ b/arch/arm/mach-s3c2410/s3c2440-clock.c @@ -139,7 +139,7 @@ static int s3c2440_clk_add(struct sys_device *sysdev) clkdivn = __raw_readl(S3C2410_CLKDIVN); clkdivn |= S3C2440_CLKDIVN_UCLK; - __raw_writel(camdivn, S3C2410_CLKDIVN); + __raw_writel(clkdivn, S3C2410_CLKDIVN); mutex_unlock(&clocks_mutex); } diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 102454082474..676b5c5b75bb 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -11,7 +11,8 @@ * published by the Free Software Foundation. * * ChangeLog: - * 03-06-2004 John Lenz + * 2006 Pavel Machek + * 03-06-2004 John Lenz * 06-04-2002 Chris Larson * 04-16-2001 Lineo Japan,Inc. ... */ @@ -87,12 +88,75 @@ static struct mcp_plat_data collie_mcp_data = { .sclk_rate = 11981000, }; +#ifdef CONFIG_SHARP_LOCOMO +/* + * low-level UART features. + */ +static struct locomo_dev *uart_dev = NULL; + +static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl) +{ + if (!uart_dev) return; + + if (mctrl & TIOCM_RTS) + locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 0); + else + locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 1); + + if (mctrl & TIOCM_DTR) + locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 0); + else + locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 1); +} + +static u_int collie_uart_get_mctrl(struct uart_port *port) +{ + int ret = TIOCM_CD; + unsigned int r; + if (!uart_dev) return ret; + + r = locomo_gpio_read_output(uart_dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR); + if (r & LOCOMO_GPIO_CTS) + ret |= TIOCM_CTS; + if (r & LOCOMO_GPIO_DSR) + ret |= TIOCM_DSR; + + return ret; +} static struct sa1100_port_fns collie_port_fns __initdata = { .set_mctrl = collie_uart_set_mctrl, .get_mctrl = collie_uart_get_mctrl, }; +static int collie_uart_probe(struct locomo_dev *dev) +{ + uart_dev = dev; + return 0; +} + +static int collie_uart_remove(struct locomo_dev *dev) +{ + uart_dev = NULL; + return 0; +} + +static struct locomo_driver collie_uart_driver = { + .drv = { + .name = "collie_uart", + }, + .devid = LOCOMO_DEVID_UART, + .probe = collie_uart_probe, + .remove = collie_uart_remove, +}; + +static int __init collie_uart_init(void) { + return locomo_driver_register(&collie_uart_driver); +} +device_initcall(collie_uart_init); + +#endif + static struct resource locomo_resources[] = { [0] = { @@ -218,6 +282,12 @@ static void __init collie_map_io(void) { sa1100_map_io(); iotable_init(collie_io_desc, ARRAY_SIZE(collie_io_desc)); + +#ifdef CONFIG_SHARP_LOCOMO + sa1100_register_uart_fns(&collie_port_fns); +#endif + sa1100_register_uart(0, 3); + sa1100_register_uart(1, 1); } MACHINE_START(COLLIE, "Sharp-Collie") diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S index 5c4055b62d97..54e3c5bb5186 100644 --- a/arch/arm/mm/cache-v4wb.S +++ b/arch/arm/mm/cache-v4wb.S @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include "proc-macros.S" @@ -46,6 +46,11 @@ */ #define CACHE_DLIMIT (CACHE_DSIZE * 4) + .data +flush_base: + .long FLUSH_BASE + .text + /* * flush_user_cache_all() * @@ -63,11 +68,21 @@ ENTRY(v4wb_flush_kern_cache_all) mov ip, #0 mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache __flush_whole_cache: - mov r0, #FLUSH_BASE - add r1, r0, #CACHE_DSIZE -1: ldr r2, [r0], #32 - cmp r0, r1 + ldr r3, =flush_base + ldr r1, [r3, #0] + eor r1, r1, #CACHE_DSIZE + str r1, [r3, #0] + add r2, r1, #CACHE_DSIZE +1: ldr r3, [r1], #32 + cmp r1, r2 blo 1b +#ifdef FLUSH_BASE_MINICACHE + add r2, r2, #FLUSH_BASE_MINICACHE - FLUSH_BASE + sub r1, r2, #512 @ only 512 bytes +1: ldr r3, [r1], #32 + cmp r1, r2 + blo 1b +#endif mcr p15, 0, ip, c7, c10, 4 @ drain write buffer mov pc, lr @@ -82,6 +97,7 @@ __flush_whole_cache: * - flags - vma_area_struct flags describing address space */ ENTRY(v4wb_flush_user_cache_range) + mov ip, #0 sub r3, r1, r0 @ calculate total size tst r2, #VM_EXEC @ executable region? mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c index 8a1bfcd50087..50e6b6bfb2e2 100644 --- a/arch/arm/mm/consistent.c +++ b/arch/arm/mm/consistent.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -272,6 +273,17 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) { + if (arch_is_coherent()) { + void *virt; + + virt = kmalloc(size, gfp); + if (!virt) + return NULL; + *handle = virt_to_dma(dev, virt); + + return virt; + } + return __dma_alloc(dev, size, handle, gfp, pgprot_noncached(pgprot_kernel)); } @@ -350,6 +362,11 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr WARN_ON(irqs_disabled()); + if (arch_is_coherent()) { + kfree(cpu_addr); + return; + } + size = PAGE_ALIGN(size); spin_lock_irqsave(&consistent_lock, flags); diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 88279124317a..9ea1f87a7079 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -455,14 +456,14 @@ static void __init devicemaps_init(struct machine_desc *mdesc) #ifdef FLUSH_BASE map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS); map.virtual = FLUSH_BASE; - map.length = PGDIR_SIZE; + map.length = SZ_1M; map.type = MT_CACHECLEAN; create_mapping(&map); #endif #ifdef FLUSH_BASE_MINICACHE - map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + PGDIR_SIZE); + map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + SZ_1M); map.virtual = FLUSH_BASE_MINICACHE; - map.length = PGDIR_SIZE; + map.length = SZ_1M; map.type = MT_MINICLEAN; create_mapping(&map); #endif diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c index 5e5d05bcad50..f14b2d0f3690 100644 --- a/arch/arm/mm/mm-armv.c +++ b/arch/arm/mm/mm-armv.c @@ -388,6 +388,17 @@ void __init build_mem_type_table(void) cp = &cache_policies[cachepolicy]; kern_pgprot = user_pgprot = cp->pte; + /* + * Enable CPU-specific coherency if supported. + * (Only available on XSC3 at the moment.) + */ + if (arch_is_coherent()) { + if (cpu_is_xsc3()) { + mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S; + mem_types[MT_MEMORY].prot_pte |= L_PTE_COHERENT; + } + } + /* * ARMv6 and above have extended page tables. */ diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S index c916a6cae404..a2dd5ae1077d 100644 --- a/arch/arm/mm/proc-sa110.S +++ b/arch/arm/mm/proc-sa110.S @@ -26,22 +26,7 @@ * the cache line size of the I and D cache */ #define DCACHELINESIZE 32 -#define FLUSH_OFFSET 32768 - .macro flush_110_dcache rd, ra, re - ldr \rd, =flush_base - ldr \ra, [\rd] - eor \ra, \ra, #FLUSH_OFFSET - str \ra, [\rd] - add \re, \ra, #16384 @ only necessary for 16k -1001: ldr \rd, [\ra], #DCACHELINESIZE - teq \re, \ra - bne 1001b - .endm - - .data -flush_base: - .long FLUSH_BASE .text /* @@ -145,13 +130,11 @@ ENTRY(cpu_sa110_dcache_clean_area) */ .align 5 ENTRY(cpu_sa110_switch_mm) - flush_110_dcache r3, ip, r1 - mov r1, #0 - mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache - mcr p15, 0, r1, c7, c10, 4 @ drain WB + str lr, [sp, #-4]! + bl v4wb_flush_kern_cache_all @ clears IP mcr p15, 0, r0, c2, c0, 0 @ load page table pointer - mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs - mov pc, lr + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + ldr pc, [sp], #4 /* * cpu_sa110_set_pte(ptep, pte) diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S index 41f21f2dd8ff..777ad99c1439 100644 --- a/arch/arm/mm/proc-sa1100.S +++ b/arch/arm/mm/proc-sa1100.S @@ -30,30 +30,6 @@ * the cache line size of the I and D cache */ #define DCACHELINESIZE 32 -#define FLUSH_OFFSET 32768 - - .macro flush_1100_dcache rd, ra, re - ldr \rd, =flush_base - ldr \ra, [\rd] - eor \ra, \ra, #FLUSH_OFFSET - str \ra, [\rd] - add \re, \ra, #8192 @ only necessary for 8k -1001: ldr \rd, [\ra], #DCACHELINESIZE - teq \re, \ra - bne 1001b -#ifdef FLUSH_BASE_MINICACHE - add \ra, \ra, #FLUSH_BASE_MINICACHE - FLUSH_BASE - add \re, \ra, #512 @ only 512 bytes -1002: ldr \rd, [\ra], #DCACHELINESIZE - teq \re, \ra - bne 1002b -#endif - .endm - - .data -flush_base: - .long FLUSH_BASE - .text __INIT @@ -79,9 +55,8 @@ ENTRY(cpu_sa1100_proc_fin) stmfd sp!, {lr} mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE msr cpsr_c, ip - flush_1100_dcache r0, r1, r2 @ clean caches - mov r0, #0 - mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching + bl v4wb_flush_kern_cache_all + mcr p15, 0, ip, c15, c2, 2 @ Disable clock switching mrc p15, 0, r0, c1, c0, 0 @ ctrl register bic r0, r0, #0x1000 @ ...i............ bic r0, r0, #0x000e @ ............wca. @@ -167,14 +142,12 @@ ENTRY(cpu_sa1100_dcache_clean_area) */ .align 5 ENTRY(cpu_sa1100_switch_mm) - flush_1100_dcache r3, ip, r1 - mov ip, #0 - mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + str lr, [sp, #-4]! + bl v4wb_flush_kern_cache_all @ clears IP mcr p15, 0, ip, c9, c0, 0 @ invalidate RB - mcr p15, 0, ip, c7, c10, 4 @ drain WB mcr p15, 0, r0, c2, c0, 0 @ load page table pointer mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs - mov pc, lr + ldr pc, [sp], #4 /* * cpu_sa1100_set_pte(ptep, pte) diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index f90513e9af0c..80873b36c3f7 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include "proc-macros.S" @@ -370,7 +371,7 @@ ENTRY(cpu_xsc3_switch_mm) ENTRY(cpu_xsc3_set_pte) str r1, [r0], #-2048 @ linux version - bic r2, r1, #0xff0 + bic r2, r1, #0xdf0 @ Keep C, B, coherency bits orr r2, r2, #PTE_TYPE_EXT @ extended page eor r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 0887bb2a2551..ec49495e651e 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -70,13 +70,13 @@ config OMAP_MPU_TIMER config OMAP_32K_TIMER bool "Use 32KHz timer" - depends on ARCH_OMAP16XX + depends on ARCH_OMAP16XX || ARCH_OMAP24XX help Select this option if you want to enable the OMAP 32KHz timer. This timer saves power compared to the OMAP_MPU_TIMER, and has support for no tick during idle. The 32KHz timer provides less intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is - currently only available for OMAP-16xx. + currently only available for OMAP16XX and 24XX. endchoice diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 9ccf1943fc94..2896b4546411 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -3,16 +3,16 @@ # # Common support -obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o +obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o obj-m := obj-n := obj- := +obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o + # OCPI interconnect support for 1710, 1610 and 5912 obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o -# Power Management -obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_CPU_FREQ) += cpu-omap.o obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 3c2bfc0efdaf..32ec04c58bcd 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -37,17 +38,38 @@ static struct clk_functions *arch_clock; * Standard clock functions defined in include/linux/clk.h *-------------------------------------------------------------------------*/ +/* + * Returns a clock. Note that we first try to use device id on the bus + * and clock name. If this fails, we try to use clock name only. + */ struct clk * clk_get(struct device *dev, const char *id) { struct clk *p, *clk = ERR_PTR(-ENOENT); + int idno; + + if (dev == NULL || dev->bus != &platform_bus_type) + idno = -1; + else + idno = to_platform_device(dev)->id; mutex_lock(&clocks_mutex); + + list_for_each_entry(p, &clocks, node) { + if (p->id == idno && + strcmp(id, p->name) == 0 && try_module_get(p->owner)) { + clk = p; + goto found; + } + } + list_for_each_entry(p, &clocks, node) { if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { clk = p; break; } } + +found: mutex_unlock(&clocks_mutex); return clk; @@ -59,6 +81,9 @@ int clk_enable(struct clk *clk) unsigned long flags; int ret = 0; + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_enable) ret = arch_clock->clk_enable(clk); @@ -72,6 +97,9 @@ void clk_disable(struct clk *clk) { unsigned long flags; + if (clk == NULL || IS_ERR(clk)) + return; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_disable) arch_clock->clk_disable(clk); @@ -84,6 +112,9 @@ int clk_get_usecount(struct clk *clk) unsigned long flags; int ret = 0; + if (clk == NULL || IS_ERR(clk)) + return 0; + spin_lock_irqsave(&clockfw_lock, flags); ret = clk->usecount; spin_unlock_irqrestore(&clockfw_lock, flags); @@ -97,6 +128,9 @@ unsigned long clk_get_rate(struct clk *clk) unsigned long flags; unsigned long ret = 0; + if (clk == NULL || IS_ERR(clk)) + return 0; + spin_lock_irqsave(&clockfw_lock, flags); ret = clk->rate; spin_unlock_irqrestore(&clockfw_lock, flags); @@ -121,6 +155,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate) unsigned long flags; long ret = 0; + if (clk == NULL || IS_ERR(clk)) + return ret; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_round_rate) ret = arch_clock->clk_round_rate(clk, rate); @@ -133,7 +170,10 @@ EXPORT_SYMBOL(clk_round_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { unsigned long flags; - int ret = 0; + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk)) + return ret; spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_set_rate) @@ -147,7 +187,10 @@ EXPORT_SYMBOL(clk_set_rate); int clk_set_parent(struct clk *clk, struct clk *parent) { unsigned long flags; - int ret = 0; + int ret = -EINVAL; + + if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent)) + return ret; spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_set_parent) @@ -163,6 +206,9 @@ struct clk *clk_get_parent(struct clk *clk) unsigned long flags; struct clk * ret = NULL; + if (clk == NULL || IS_ERR(clk)) + return ret; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_get_parent) ret = arch_clock->clk_get_parent(clk); @@ -199,6 +245,9 @@ __setup("mpurate=", omap_clk_setup); /* Used for clocks that always have same value as the parent clock */ void followparent_recalc(struct clk *clk) { + if (clk == NULL || IS_ERR(clk)) + return; + clk->rate = clk->parent->rate; } @@ -207,6 +256,9 @@ void propagate_rate(struct clk * tclk) { struct clk *clkp; + if (tclk == NULL || IS_ERR(tclk)) + return; + list_for_each_entry(clkp, &clocks, node) { if (likely(clkp->parent != tclk)) continue; @@ -217,6 +269,9 @@ void propagate_rate(struct clk * tclk) int clk_register(struct clk *clk) { + if (clk == NULL || IS_ERR(clk)) + return -EINVAL; + mutex_lock(&clocks_mutex); list_add(&clk->node, &clocks); if (clk->init) @@ -229,6 +284,9 @@ EXPORT_SYMBOL(clk_register); void clk_unregister(struct clk *clk) { + if (clk == NULL || IS_ERR(clk)) + return; + mutex_lock(&clocks_mutex); list_del(&clk->node); mutex_unlock(&clocks_mutex); @@ -239,6 +297,9 @@ void clk_deny_idle(struct clk *clk) { unsigned long flags; + if (clk == NULL || IS_ERR(clk)) + return; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_deny_idle) arch_clock->clk_deny_idle(clk); @@ -250,6 +311,9 @@ void clk_allow_idle(struct clk *clk) { unsigned long flags; + if (clk == NULL || IS_ERR(clk)) + return; + spin_lock_irqsave(&clockfw_lock, flags); if (arch_clock->clk_allow_idle) arch_clock->clk_allow_idle(clk); diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c index 9dcce904b608..5d5d6eb222dd 100644 --- a/arch/arm/plat-omap/devices.c +++ b/arch/arm/plat-omap/devices.c @@ -24,14 +24,7 @@ #include #include #include - - -void omap_nop_release(struct device *dev) -{ - /* Nothing */ -} - -/*-------------------------------------------------------------------------*/ +#include #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE) @@ -58,9 +51,6 @@ static struct resource i2c_resources1[] = { static struct platform_device omap_i2c_device1 = { .name = "i2c_omap", .id = 1, - .dev = { - .release = omap_nop_release, - }, .num_resources = ARRAY_SIZE(i2c_resources1), .resource = i2c_resources1, }; @@ -97,6 +87,62 @@ static void omap_init_i2c(void) static inline void omap_init_i2c(void) {} #endif +/*-------------------------------------------------------------------------*/ +#if defined(CONFIG_KEYBOARD_OMAP) || defined(CONFIG_KEYBOARD_OMAP_MODULE) + +static void omap_init_kp(void) +{ + if (machine_is_omap_h2() || machine_is_omap_h3()) { + omap_cfg_reg(F18_1610_KBC0); + omap_cfg_reg(D20_1610_KBC1); + omap_cfg_reg(D19_1610_KBC2); + omap_cfg_reg(E18_1610_KBC3); + omap_cfg_reg(C21_1610_KBC4); + + omap_cfg_reg(G18_1610_KBR0); + omap_cfg_reg(F19_1610_KBR1); + omap_cfg_reg(H14_1610_KBR2); + omap_cfg_reg(E20_1610_KBR3); + omap_cfg_reg(E19_1610_KBR4); + omap_cfg_reg(N19_1610_KBR5); + } else if (machine_is_omap_perseus2()) { + omap_cfg_reg(E2_730_KBR0); + omap_cfg_reg(J7_730_KBR1); + omap_cfg_reg(E1_730_KBR2); + omap_cfg_reg(F3_730_KBR3); + omap_cfg_reg(D2_730_KBR4); + + omap_cfg_reg(C2_730_KBC0); + omap_cfg_reg(D3_730_KBC1); + omap_cfg_reg(E4_730_KBC2); + omap_cfg_reg(F4_730_KBC3); + omap_cfg_reg(E3_730_KBC4); + } else if (machine_is_omap_h4()) { + omap_cfg_reg(T19_24XX_KBR0); + omap_cfg_reg(R19_24XX_KBR1); + omap_cfg_reg(V18_24XX_KBR2); + omap_cfg_reg(M21_24XX_KBR3); + omap_cfg_reg(E5__24XX_KBR4); + if (omap_has_menelaus()) { + omap_cfg_reg(B3__24XX_KBR5); + omap_cfg_reg(AA4_24XX_KBC2); + omap_cfg_reg(B13_24XX_KBC6); + } else { + omap_cfg_reg(M18_24XX_KBR5); + omap_cfg_reg(H19_24XX_KBC2); + omap_cfg_reg(N19_24XX_KBC6); + } + omap_cfg_reg(R20_24XX_KBC0); + omap_cfg_reg(M14_24XX_KBC1); + omap_cfg_reg(V17_24XX_KBC3); + omap_cfg_reg(P21_24XX_KBC4); + omap_cfg_reg(L14_24XX_KBC5); + } +} +#else +static inline void omap_init_kp(void) {} +#endif + /*-------------------------------------------------------------------------*/ #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) @@ -130,7 +176,6 @@ static struct platform_device mmc_omap_device1 = { .name = "mmci-omap", .id = 1, .dev = { - .release = omap_nop_release, .dma_mask = &mmc1_dmamask, .platform_data = &mmc1_conf, }, @@ -160,7 +205,6 @@ static struct platform_device mmc_omap_device2 = { .name = "mmci-omap", .id = 2, .dev = { - .release = omap_nop_release, .dma_mask = &mmc2_dmamask, .platform_data = &mmc2_conf, }, @@ -240,6 +284,52 @@ static void __init omap_init_mmc(void) static inline void omap_init_mmc(void) {} #endif +/*-------------------------------------------------------------------------*/ + +/* Numbering for the SPI-capable controllers when used for SPI: + * spi = 1 + * uwire = 2 + * mmc1..2 = 3..4 + * mcbsp1..3 = 5..7 + */ + +#if defined(CONFIG_SPI_OMAP_UWIRE) || defined(CONFIG_SPI_OMAP_UWIRE_MODULE) + +#define OMAP_UWIRE_BASE 0xfffb3000 + +static struct resource uwire_resources[] = { + { + .start = OMAP_UWIRE_BASE, + .end = OMAP_UWIRE_BASE + 0x20, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device omap_uwire_device = { + .name = "omap_uwire", + .id = -1, + .num_resources = ARRAY_SIZE(uwire_resources), + .resource = uwire_resources, +}; + +static void omap_init_uwire(void) +{ + /* FIXME define and use a boot tag; not all boards will be hooking + * up devices to the microwire controller, and multi-board configs + * mean that CONFIG_SPI_OMAP_UWIRE may be configured anyway... + */ + + /* board-specific code must configure chipselects (only a few + * are normally used) and SCLK/SDI/SDO (each has two choices). + */ + (void) platform_device_register(&omap_uwire_device); +} +#else +static inline void omap_init_uwire(void) {} +#endif + +/*-------------------------------------------------------------------------*/ + #if defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE) #ifdef CONFIG_ARCH_OMAP24XX @@ -259,9 +349,6 @@ static struct resource wdt_resources[] = { static struct platform_device omap_wdt_device = { .name = "omap_wdt", .id = -1, - .dev = { - .release = omap_nop_release, - }, .num_resources = ARRAY_SIZE(wdt_resources), .resource = wdt_resources, }; @@ -295,9 +382,6 @@ static struct resource rng_resources[] = { static struct platform_device omap_rng_device = { .name = "omap_rng", .id = -1, - .dev = { - .release = omap_nop_release, - }, .num_resources = ARRAY_SIZE(rng_resources), .resource = rng_resources, }; @@ -310,40 +394,6 @@ static void omap_init_rng(void) static inline void omap_init_rng(void) {} #endif -#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) - -static struct omap_lcd_config omap_fb_conf; - -static u64 omap_fb_dma_mask = ~(u32)0; - -static struct platform_device omap_fb_device = { - .name = "omapfb", - .id = -1, - .dev = { - .release = omap_nop_release, - .dma_mask = &omap_fb_dma_mask, - .coherent_dma_mask = ~(u32)0, - .platform_data = &omap_fb_conf, - }, - .num_resources = 0, -}; - -static inline void omap_init_fb(void) -{ - const struct omap_lcd_config *conf; - - conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); - if (conf != NULL) - omap_fb_conf = *conf; - platform_device_register(&omap_fb_device); -} - -#else - -static inline void omap_init_fb(void) {} - -#endif - /* * This gets called after board-specific INIT_MACHINE, and initializes most * on-chip peripherals accessible on this board (except for few like USB): @@ -369,9 +419,10 @@ static int __init omap_init_devices(void) /* please keep these calls, and their implementations above, * in alphabetical order so they're easier to sort through. */ - omap_init_fb(); omap_init_i2c(); + omap_init_kp(); omap_init_mmc(); + omap_init_uwire(); omap_init_wdt(); omap_init_rng(); diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c index a4e5ac77f6df..5dac4230360d 100644 --- a/arch/arm/plat-omap/dma.c +++ b/arch/arm/plat-omap/dma.c @@ -1258,6 +1258,11 @@ void omap_stop_lcd_dma(void) omap_writew(w, OMAP1610_DMA_LCD_CTRL); } +int omap_lcd_dma_ext_running(void) +{ + return lcd_dma.ext_ctrl && lcd_dma.active; +} + /*----------------------------------------------------------------------------*/ static int __init omap_init_dma(void) @@ -1389,6 +1394,7 @@ EXPORT_SYMBOL(omap_free_lcd_dma); EXPORT_SYMBOL(omap_enable_lcd_dma); EXPORT_SYMBOL(omap_setup_lcd_dma); EXPORT_SYMBOL(omap_stop_lcd_dma); +EXPORT_SYMBOL(omap_lcd_dma_ext_running); EXPORT_SYMBOL(omap_set_lcd_dma_b1); EXPORT_SYMBOL(omap_set_lcd_dma_single_transfer); EXPORT_SYMBOL(omap_set_lcd_dma_ext_controller); diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 38d7ebf87920..eba3cb52ad87 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -97,6 +97,32 @@ int omap_dm_timers_active(void) } +/** + * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR + * @inputmask: current value of idlect mask + */ +__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) +{ + int n; + + /* If ARMXOR cannot be idled this function call is unnecessary */ + if (!(inputmask & (1 << 1))) + return inputmask; + + /* If any active timer is using ARMXOR return modified mask */ + for (n = 0; dm_timers[n].base; ++n) + if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)& + OMAP_TIMER_CTRL_ST) { + if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0) + inputmask &= ~(1 << 1); + else + inputmask &= ~(1 << 2); + } + + return inputmask; +} + + void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { int n = (timer - dm_timers) << 1; diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c new file mode 100644 index 000000000000..305e9b990b71 --- /dev/null +++ b/arch/arm/plat-omap/fb.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE) + +static struct omapfb_platform_data omapfb_config; + +static u64 omap_fb_dma_mask = ~(u32)0; + +static struct platform_device omap_fb_device = { + .name = "omapfb", + .id = -1, + .dev = { + .dma_mask = &omap_fb_dma_mask, + .coherent_dma_mask = ~(u32)0, + .platform_data = &omapfb_config, + }, + .num_resources = 0, +}; + +/* called from map_io */ +void omapfb_reserve_mem(void) +{ + const struct omap_fbmem_config *fbmem_conf; + + omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start; + omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size; + + fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config); + + if (fbmem_conf != NULL) { + /* indicate that the bootloader already initialized the + * fb device, so we'll skip that part in the fb driver + */ + omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start; + omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size; + if (fbmem_conf->fb_sdram_size) { + pr_info("Reserving %u bytes SDRAM for frame buffer\n", + fbmem_conf->fb_sdram_size); + reserve_bootmem(fbmem_conf->fb_sdram_start, + fbmem_conf->fb_sdram_size); + } + } +} + +static inline int omap_init_fb(void) +{ + const struct omap_lcd_config *conf; + + conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); + if (conf == NULL) + return 0; + + omapfb_config.lcd = *conf; + + return platform_device_register(&omap_fb_device); +} + +arch_initcall(omap_init_fb); + +#else + +void omapfb_reserve_mem(void) {} + +#endif + + diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c index b4d5b9e4bfce..d3c8ea7eecfd 100644 --- a/arch/arm/plat-omap/gpio.c +++ b/arch/arm/plat-omap/gpio.c @@ -174,7 +174,7 @@ static int gpio_bank_count; static inline struct gpio_bank *get_gpio_bank(int gpio) { #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { if (OMAP_GPIO_IS_MPUIO(gpio)) return &gpio_bank[0]; return &gpio_bank[1]; @@ -223,7 +223,7 @@ static inline int gpio_valid(int gpio) return 0; } #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510() && gpio < 16) + if (cpu_is_omap15xx() && gpio < 16) return 0; #endif #if defined(CONFIG_ARCH_OMAP16XX) @@ -402,13 +402,13 @@ static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int tr u32 gpio_bit = 1 << gpio; MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, - trigger & IRQT_LOW); + trigger & __IRQT_LOWLVL); MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, - trigger & IRQT_HIGH); + trigger & __IRQT_HIGHLVL); MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit, - trigger & IRQT_RISING); + trigger & __IRQT_RISEDGE); MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, - trigger & IRQT_FALLING); + trigger & __IRQT_FALEDGE); /* FIXME: Possibly do 'set_irq_handler(j, do_level_IRQ)' if only level * triggering requested. */ } @@ -422,9 +422,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_MPUIO: reg += OMAP_MPUIO_GPIO_INT_EDGE; l = __raw_readl(reg); - if (trigger == IRQT_RISING) + if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; - else if (trigger == IRQT_FALLING) + else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; @@ -432,9 +432,9 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) case METHOD_GPIO_1510: reg += OMAP1510_GPIO_INT_CONTROL; l = __raw_readl(reg); - if (trigger == IRQT_RISING) + if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; - else if (trigger == IRQT_FALLING) + else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; @@ -446,20 +446,21 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger) reg += OMAP1610_GPIO_EDGE_CTRL1; gpio &= 0x07; /* We allow only edge triggering, i.e. two lowest bits */ - if (trigger & ~IRQT_BOTHEDGE) + if (trigger & (__IRQT_LOWLVL | __IRQT_HIGHLVL)) BUG(); - /* NOTE: knows __IRQT_{FAL,RIS}EDGE match OMAP hardware */ - trigger &= 0x03; l = __raw_readl(reg); l &= ~(3 << (gpio << 1)); - l |= trigger << (gpio << 1); + if (trigger & __IRQT_RISEDGE) + l |= 2 << (gpio << 1); + if (trigger & __IRQT_FALEDGE) + l |= 1 << (gpio << 1); break; case METHOD_GPIO_730: reg += OMAP730_GPIO_INT_CONTROL; l = __raw_readl(reg); - if (trigger == IRQT_RISING) + if (trigger & __IRQT_RISEDGE) l |= 1 << gpio; - else if (trigger == IRQT_FALLING) + else if (trigger & __IRQT_FALEDGE) l &= ~(1 << gpio); else goto bad; @@ -491,7 +492,9 @@ static int gpio_irq_type(unsigned irq, unsigned type) if (check_gpio(gpio) < 0) return -EINVAL; - if (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL|IRQT_PROBE)) + if (type & IRQT_PROBE) + return -EINVAL; + if (!cpu_is_omap24xx() && (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL))) return -EINVAL; bank = get_gpio_bank(gpio); @@ -755,13 +758,32 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, if (bank->method == METHOD_GPIO_24XX) isr_reg = bank->base + OMAP24XX_GPIO_IRQSTATUS1; #endif - while(1) { - isr = __raw_readl(isr_reg); - _enable_gpio_irqbank(bank, isr, 0); - _clear_gpio_irqbank(bank, isr); - _enable_gpio_irqbank(bank, isr, 1); - desc->chip->unmask(irq); + u32 isr_saved, level_mask = 0; + + isr_saved = isr = __raw_readl(isr_reg); + + if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO)) + isr &= 0x0000ffff; + + if (cpu_is_omap24xx()) + level_mask = + __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT0) | + __raw_readl(bank->base + + OMAP24XX_GPIO_LEVELDETECT1); + + /* clear edge sensitive interrupts before handler(s) are + called so that we don't miss any interrupt occurred while + executing them */ + _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 0); + _clear_gpio_irqbank(bank, isr_saved & ~level_mask); + _enable_gpio_irqbank(bank, isr_saved & ~level_mask, 1); + + /* if there is only edge sensitive GPIO pin interrupts + configured, we could unmask GPIO bank interrupt immediately */ + if (!level_mask) + desc->chip->unmask(irq); if (!isr) break; @@ -774,6 +796,20 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc, d = irq_desc + gpio_irq; desc_handle_irq(gpio_irq, d, regs); } + + if (cpu_is_omap24xx()) { + /* clear level sensitive interrupts after handler(s) */ + _enable_gpio_irqbank(bank, isr_saved & level_mask, 0); + _clear_gpio_irqbank(bank, isr_saved & level_mask); + _enable_gpio_irqbank(bank, isr_saved & level_mask, 1); + } + + /* if bank has any level sensitive GPIO pin interrupt + configured, we must unmask the bank interrupt only after + handler(s) are executed in order to avoid spurious bank + interrupt */ + if (level_mask) + desc->chip->unmask(irq); } } @@ -848,7 +884,7 @@ static int __init _omap_gpio_init(void) initialized = 1; - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { gpio_ick = clk_get(NULL, "arm_gpio_ck"); if (IS_ERR(gpio_ick)) printk("Could not get arm_gpio_ck\n"); @@ -869,7 +905,7 @@ static int __init _omap_gpio_init(void) } #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { printk(KERN_INFO "OMAP1510 GPIO hardware\n"); gpio_bank_count = 2; gpio_bank = gpio_bank_1510; diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 1cd2cace7e1b..196aac3ac329 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -34,7 +34,7 @@ #ifdef CONFIG_MCBSP_DEBUG #define DBG(x...) printk(x) #else -#define DBG(x...) do { } while (0) +#define DBG(x...) do { } while (0) #endif struct omap_mcbsp { @@ -44,6 +44,7 @@ struct omap_mcbsp { omap_mcbsp_word_length rx_word_length; omap_mcbsp_word_length tx_word_length; + omap_mcbsp_io_type_t io_type; /* IRQ or poll */ /* IRQ based TX/RX */ int rx_irq; int tx_irq; @@ -64,10 +65,19 @@ struct omap_mcbsp { }; static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT]; +#ifdef CONFIG_ARCH_OMAP1 static struct clk *mcbsp_dsp_ck = 0; static struct clk *mcbsp_api_ck = 0; static struct clk *mcbsp_dspxor_ck = 0; - +#endif +#ifdef CONFIG_ARCH_OMAP2 +static struct clk *mcbsp1_ick = 0; +static struct clk *mcbsp1_fck = 0; +static struct clk *mcbsp2_ick = 0; +static struct clk *mcbsp2_fck = 0; +static struct clk *sys_ck = 0; +static struct clk *sys_clkout = 0; +#endif static void omap_mcbsp_dump_reg(u8 id) { @@ -88,7 +98,6 @@ static void omap_mcbsp_dump_reg(u8 id) DBG("***********************\n"); } - static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id); @@ -109,7 +118,6 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_re return IRQ_HANDLED; } - static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data) { struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data); @@ -176,7 +184,7 @@ static int omap_mcbsp_check(unsigned int id) return 0; } - if (cpu_is_omap1510() || cpu_is_omap16xx()) { + if (cpu_is_omap15xx() || cpu_is_omap16xx() || cpu_is_omap24xx()) { if (id > OMAP_MAX_MCBSP_COUNT) { printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1); return -1; @@ -187,9 +195,10 @@ static int omap_mcbsp_check(unsigned int id) return -1; } +#ifdef CONFIG_ARCH_OMAP1 static void omap_mcbsp_dsp_request(void) { - if (cpu_is_omap1510() || cpu_is_omap16xx()) { + if (cpu_is_omap15xx() || cpu_is_omap16xx()) { clk_enable(mcbsp_dsp_ck); clk_enable(mcbsp_api_ck); @@ -207,12 +216,49 @@ static void omap_mcbsp_dsp_request(void) static void omap_mcbsp_dsp_free(void) { - if (cpu_is_omap1510() || cpu_is_omap16xx()) { + if (cpu_is_omap15xx() || cpu_is_omap16xx()) { clk_disable(mcbsp_dspxor_ck); clk_disable(mcbsp_dsp_ck); clk_disable(mcbsp_api_ck); } } +#endif + +#ifdef CONFIG_ARCH_OMAP2 +static void omap2_mcbsp2_mux_setup(void) +{ + omap_cfg_reg(Y15_24XX_MCBSP2_CLKX); + omap_cfg_reg(R14_24XX_MCBSP2_FSX); + omap_cfg_reg(W15_24XX_MCBSP2_DR); + omap_cfg_reg(V15_24XX_MCBSP2_DX); + omap_cfg_reg(V14_24XX_GPIO117); + omap_cfg_reg(W14_24XX_SYS_CLKOUT); +} +#endif + +/* + * We can choose between IRQ based or polled IO. + * This needs to be called before omap_mcbsp_request(). + */ +int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type) +{ + if (omap_mcbsp_check(id) < 0) + return -EINVAL; + + spin_lock(&mcbsp[id].lock); + + if (!mcbsp[id].free) { + printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1); + spin_unlock(&mcbsp[id].lock); + return -EINVAL; + } + + mcbsp[id].io_type = io_type; + + spin_unlock(&mcbsp[id].lock); + + return 0; +} int omap_mcbsp_request(unsigned int id) { @@ -221,12 +267,26 @@ int omap_mcbsp_request(unsigned int id) if (omap_mcbsp_check(id) < 0) return -EINVAL; +#ifdef CONFIG_ARCH_OMAP1 /* * On 1510, 1610 and 1710, McBSP1 and McBSP3 * are DSP public peripherals. */ if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) omap_mcbsp_dsp_request(); +#endif + +#ifdef CONFIG_ARCH_OMAP2 + if (cpu_is_omap24xx()) { + if (id == OMAP_MCBSP1) { + clk_enable(mcbsp1_ick); + clk_enable(mcbsp1_fck); + } else { + clk_enable(mcbsp2_ick); + clk_enable(mcbsp2_fck); + } + } +#endif spin_lock(&mcbsp[id].lock); if (!mcbsp[id].free) { @@ -238,30 +298,33 @@ int omap_mcbsp_request(unsigned int id) mcbsp[id].free = 0; spin_unlock(&mcbsp[id].lock); - /* We need to get IRQs here */ - err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0, - "McBSP", - (void *) (&mcbsp[id])); - if (err != 0) { - printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n", - mcbsp[id].tx_irq, mcbsp[id].id); - return err; + if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) { + /* We need to get IRQs here */ + err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n", + mcbsp[id].tx_irq, mcbsp[id].id); + return err; + } + + init_completion(&(mcbsp[id].tx_irq_completion)); + + + err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0, + "McBSP", + (void *) (&mcbsp[id])); + if (err != 0) { + printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n", + mcbsp[id].rx_irq, mcbsp[id].id); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + return err; + } + + init_completion(&(mcbsp[id].rx_irq_completion)); } - init_completion(&(mcbsp[id].tx_irq_completion)); - - - err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0, - "McBSP", - (void *) (&mcbsp[id])); - if (err != 0) { - printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n", - mcbsp[id].rx_irq, mcbsp[id].id); - free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); - return err; - } - - init_completion(&(mcbsp[id].rx_irq_completion)); return 0; } @@ -271,8 +334,24 @@ void omap_mcbsp_free(unsigned int id) if (omap_mcbsp_check(id) < 0) return; - if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) - omap_mcbsp_dsp_free(); +#ifdef CONFIG_ARCH_OMAP1 + if (cpu_class_is_omap1()) { + if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3) + omap_mcbsp_dsp_free(); + } +#endif + +#ifdef CONFIG_ARCH_OMAP2 + if (cpu_is_omap24xx()) { + if (id == OMAP_MCBSP1) { + clk_disable(mcbsp1_ick); + clk_disable(mcbsp1_fck); + } else { + clk_disable(mcbsp2_ick); + clk_disable(mcbsp2_fck); + } + } +#endif spin_lock(&mcbsp[id].lock); if (mcbsp[id].free) { @@ -284,9 +363,11 @@ void omap_mcbsp_free(unsigned int id) mcbsp[id].free = 1; spin_unlock(&mcbsp[id].lock); - /* Free IRQs */ - free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id])); - free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + if (mcbsp[id].io_type == OMAP_MCBSP_IRQ_IO) { + /* Free IRQs */ + free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id])); + free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id])); + } } /* @@ -461,6 +542,115 @@ u32 omap_mcbsp_recv_word(unsigned int id) } +int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) +{ + u32 io_base = mcbsp[id].io_base; + omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length; + omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length; + u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; + + if (tx_word_length != rx_word_length) + return -EINVAL; + + /* First we wait for the transmitter to be ready */ + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + while (!(spcr2 & XRDY)) { + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + if (attempts++ > 1000) { + /* We must reset the transmitter */ + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + udelay(10); + printk("McBSP transmitter not ready\n"); + return -EAGAIN; + } + } + + /* Now we can push the data */ + if (tx_word_length > OMAP_MCBSP_WORD_16) + OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); + OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); + + /* We wait for the receiver to be ready */ + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + while (!(spcr1 & RRDY)) { + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + if (attempts++ > 1000) { + /* We must reset the receiver */ + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + udelay(10); + printk("McBSP receiver not ready\n"); + return -EAGAIN; + } + } + + /* Receiver is ready, let's read the dummy data */ + if (rx_word_length > OMAP_MCBSP_WORD_16) + word_msb = OMAP_MCBSP_READ(io_base, DRR2); + word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + + return 0; +} + +int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word) +{ + u32 io_base = mcbsp[id].io_base, clock_word = 0; + omap_mcbsp_word_length tx_word_length = mcbsp[id].tx_word_length; + omap_mcbsp_word_length rx_word_length = mcbsp[id].rx_word_length; + u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; + + if (tx_word_length != rx_word_length) + return -EINVAL; + + /* First we wait for the transmitter to be ready */ + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + while (!(spcr2 & XRDY)) { + spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + if (attempts++ > 1000) { + /* We must reset the transmitter */ + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + udelay(10); + printk("McBSP transmitter not ready\n"); + return -EAGAIN; + } + } + + /* We first need to enable the bus clock */ + if (tx_word_length > OMAP_MCBSP_WORD_16) + OMAP_MCBSP_WRITE(io_base, DXR2, clock_word >> 16); + OMAP_MCBSP_WRITE(io_base, DXR1, clock_word & 0xffff); + + /* We wait for the receiver to be ready */ + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + while (!(spcr1 & RRDY)) { + spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + if (attempts++ > 1000) { + /* We must reset the receiver */ + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + udelay(10); + OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + udelay(10); + printk("McBSP receiver not ready\n"); + return -EAGAIN; + } + } + + /* Receiver is ready, there is something for us */ + if (rx_word_length > OMAP_MCBSP_WORD_16) + word_msb = OMAP_MCBSP_READ(io_base, DRR2); + word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + + word[0] = (word_lsb | (word_msb << 16)); + + return 0; +} + + /* * Simple DMA based buffer rx/tx routines. * Nothing fancy, just a single buffer tx/rx through DMA. @@ -471,6 +661,9 @@ u32 omap_mcbsp_recv_word(unsigned int id) int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) { int dma_tx_ch; + int src_port = 0; + int dest_port = 0; + int sync_dev = 0; if (omap_mcbsp_check(id) < 0) return -EINVAL; @@ -487,20 +680,27 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng init_completion(&(mcbsp[id].tx_dma_completion)); + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dest_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_is_omap24xx()) + sync_dev = mcbsp[id].dma_tx_sync; + omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch, OMAP_DMA_DATA_TYPE_S16, length >> 1, 1, OMAP_DMA_SYNC_ELEMENT, - 0, 0); + sync_dev, 0); omap_set_dma_dest_params(mcbsp[id].dma_tx_lch, - OMAP_DMA_PORT_TIPB, + src_port, OMAP_DMA_AMODE_CONSTANT, mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1, 0, 0); omap_set_dma_src_params(mcbsp[id].dma_tx_lch, - OMAP_DMA_PORT_EMIFF, + dest_port, OMAP_DMA_AMODE_POST_INC, buffer, 0, 0); @@ -514,6 +714,9 @@ int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length) { int dma_rx_ch; + int src_port = 0; + int dest_port = 0; + int sync_dev = 0; if (omap_mcbsp_check(id) < 0) return -EINVAL; @@ -530,20 +733,27 @@ int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int leng init_completion(&(mcbsp[id].rx_dma_completion)); + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dest_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_is_omap24xx()) + sync_dev = mcbsp[id].dma_rx_sync; + omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch, OMAP_DMA_DATA_TYPE_S16, length >> 1, 1, OMAP_DMA_SYNC_ELEMENT, - 0, 0); + sync_dev, 0); omap_set_dma_src_params(mcbsp[id].dma_rx_lch, - OMAP_DMA_PORT_TIPB, + src_port, OMAP_DMA_AMODE_CONSTANT, mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1, 0, 0); omap_set_dma_dest_params(mcbsp[id].dma_rx_lch, - OMAP_DMA_PORT_EMIFF, + dest_port, OMAP_DMA_AMODE_POST_INC, buffer, 0, 0); @@ -688,6 +898,23 @@ static const struct omap_mcbsp_info mcbsp_1610[] = { }; #endif +#if defined(CONFIG_ARCH_OMAP24XX) +static const struct omap_mcbsp_info mcbsp_24xx[] = { + [0] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP1_BASE), + .dma_rx_sync = OMAP24XX_DMA_MCBSP1_RX, + .dma_tx_sync = OMAP24XX_DMA_MCBSP1_TX, + .rx_irq = INT_24XX_MCBSP1_IRQ_RX, + .tx_irq = INT_24XX_MCBSP1_IRQ_TX, + }, + [1] = { .virt_base = IO_ADDRESS(OMAP24XX_MCBSP2_BASE), + .dma_rx_sync = OMAP24XX_DMA_MCBSP2_RX, + .dma_tx_sync = OMAP24XX_DMA_MCBSP2_TX, + .rx_irq = INT_24XX_MCBSP2_IRQ_RX, + .tx_irq = INT_24XX_MCBSP2_IRQ_TX, + }, +}; +#endif + static int __init omap_mcbsp_init(void) { int mcbsp_count = 0, i; @@ -695,6 +922,7 @@ static int __init omap_mcbsp_init(void) printk("Initializing OMAP McBSP system\n"); +#ifdef CONFIG_ARCH_OMAP1 mcbsp_dsp_ck = clk_get(0, "dsp_ck"); if (IS_ERR(mcbsp_dsp_ck)) { printk(KERN_ERR "mcbsp: could not acquire dsp_ck handle.\n"); @@ -710,6 +938,29 @@ static int __init omap_mcbsp_init(void) printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n"); return PTR_ERR(mcbsp_dspxor_ck); } +#endif +#ifdef CONFIG_ARCH_OMAP2 + mcbsp1_ick = clk_get(0, "mcbsp1_ick"); + if (IS_ERR(mcbsp1_ick)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp1_ick handle.\n"); + return PTR_ERR(mcbsp1_ick); + } + mcbsp1_fck = clk_get(0, "mcbsp1_fck"); + if (IS_ERR(mcbsp1_fck)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp1_fck handle.\n"); + return PTR_ERR(mcbsp1_fck); + } + mcbsp2_ick = clk_get(0, "mcbsp2_ick"); + if (IS_ERR(mcbsp2_ick)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp2_ick handle.\n"); + return PTR_ERR(mcbsp2_ick); + } + mcbsp2_fck = clk_get(0, "mcbsp2_fck"); + if (IS_ERR(mcbsp2_fck)) { + printk(KERN_ERR "mcbsp: could not acquire mcbsp2_fck handle.\n"); + return PTR_ERR(mcbsp2_fck); + } +#endif #ifdef CONFIG_ARCH_OMAP730 if (cpu_is_omap730()) { @@ -718,7 +969,7 @@ static int __init omap_mcbsp_init(void) } #endif #ifdef CONFIG_ARCH_OMAP15XX - if (cpu_is_omap1510()) { + if (cpu_is_omap15xx()) { mcbsp_info = mcbsp_1510; mcbsp_count = ARRAY_SIZE(mcbsp_1510); } @@ -728,6 +979,19 @@ static int __init omap_mcbsp_init(void) mcbsp_info = mcbsp_1610; mcbsp_count = ARRAY_SIZE(mcbsp_1610); } +#endif +#if defined(CONFIG_ARCH_OMAP24XX) + if (cpu_is_omap24xx()) { + mcbsp_info = mcbsp_24xx; + mcbsp_count = ARRAY_SIZE(mcbsp_24xx); + + /* REVISIT: where's the right place? */ + omap2_mcbsp2_mux_setup(); + sys_ck = clk_get(0, "sys_ck"); + sys_clkout = clk_get(0, "sys_clkout"); + clk_set_parent(sys_clkout, sys_ck); + clk_enable(sys_clkout); + } #endif for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) { if (i >= mcbsp_count) { @@ -741,6 +1005,7 @@ static int __init omap_mcbsp_init(void) mcbsp[i].dma_rx_lch = -1; mcbsp[i].io_base = mcbsp_info[i].virt_base; + mcbsp[i].io_type = OMAP_MCBSP_IRQ_IO; /* Default I/O is IRQ based */ mcbsp[i].tx_irq = mcbsp_info[i].tx_irq; mcbsp[i].rx_irq = mcbsp_info[i].rx_irq; mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync; @@ -751,11 +1016,11 @@ static int __init omap_mcbsp_init(void) return 0; } - arch_initcall(omap_mcbsp_init); EXPORT_SYMBOL(omap_mcbsp_config); EXPORT_SYMBOL(omap_mcbsp_request); +EXPORT_SYMBOL(omap_mcbsp_set_io_type); EXPORT_SYMBOL(omap_mcbsp_free); EXPORT_SYMBOL(omap_mcbsp_start); EXPORT_SYMBOL(omap_mcbsp_stop); @@ -763,4 +1028,6 @@ EXPORT_SYMBOL(omap_mcbsp_xmit_word); EXPORT_SYMBOL(omap_mcbsp_recv_word); EXPORT_SYMBOL(omap_mcbsp_xmit_buffer); EXPORT_SYMBOL(omap_mcbsp_recv_buffer); +EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll); +EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll); EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c index 5cc6775c789c..37792d43738b 100644 --- a/arch/arm/plat-omap/ocpi.c +++ b/arch/arm/plat-omap/ocpi.c @@ -62,9 +62,6 @@ int ocpi_enable(void) if (!cpu_is_omap16xx()) return -ENODEV; - /* Make sure there's clock for OCPI */ - clk_enable(ocpi_ck); - /* Enable access for OHCI in OCPI */ val = omap_readl(OCPI_PROT); val &= ~0xff; diff --git a/arch/arm/plat-omap/pm.c b/arch/arm/plat-omap/pm.c index 093efd786f21..1a24e2c10714 100644 --- a/arch/arm/plat-omap/pm.c +++ b/arch/arm/plat-omap/pm.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c index ee82763b02b8..b7bf09b1b412 100644 --- a/arch/arm/plat-omap/sram.c +++ b/arch/arm/plat-omap/sram.c @@ -16,24 +16,94 @@ #include #include -#include #include #include #include +#include + #include +#include #define OMAP1_SRAM_PA 0x20000000 #define OMAP1_SRAM_VA 0xd0000000 #define OMAP2_SRAM_PA 0x40200000 +#define OMAP2_SRAM_PUB_PA 0x4020f800 #define OMAP2_SRAM_VA 0xd0000000 +#define OMAP2_SRAM_PUB_VA 0xd0000800 +#if defined(CONFIG_ARCH_OMAP24XX) +#define SRAM_BOOTLOADER_SZ 0x00 +#else #define SRAM_BOOTLOADER_SZ 0x80 +#endif + +#define VA_REQINFOPERM0 IO_ADDRESS(0x68005048) +#define VA_READPERM0 IO_ADDRESS(0x68005050) +#define VA_WRITEPERM0 IO_ADDRESS(0x68005058) +#define VA_CONTROL_STAT IO_ADDRESS(0x480002F8) +#define GP_DEVICE 0x300 +#define TYPE_MASK 0x700 + +#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) static unsigned long omap_sram_base; static unsigned long omap_sram_size; static unsigned long omap_sram_ceil; +unsigned long omap_fb_sram_start; +unsigned long omap_fb_sram_size; + +/* Depending on the target RAMFS firewall setup, the public usable amount of + * SRAM varies. The default accessable size for all device types is 2k. A GP + * device allows ARM11 but not other initators for full size. This + * functionality seems ok until some nice security API happens. + */ +static int is_sram_locked(void) +{ + int type = 0; + + if (cpu_is_omap242x()) + type = __raw_readl(VA_CONTROL_STAT) & TYPE_MASK; + + if (type == GP_DEVICE) { + /* RAMFW: R/W access to all initators for all qualifier sets */ + if (cpu_is_omap242x()) { + __raw_writel(0xFF, VA_REQINFOPERM0); /* all q-vects */ + __raw_writel(0xCFDE, VA_READPERM0); /* all i-read */ + __raw_writel(0xCFDE, VA_WRITEPERM0); /* all i-write */ + } + return 0; + } else + return 1; /* assume locked with no PPA or security driver */ +} + +void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail, + unsigned long *start, unsigned long *size) +{ + const struct omap_fbmem_config *fbmem_conf; + + fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config); + if (fbmem_conf != NULL) { + *start = fbmem_conf->fb_sram_start; + *size = fbmem_conf->fb_sram_size; + } else { + *size = 0; + *start = 0; + } + + if (*size && ( + *start < start_avail || + *start + *size > start_avail + size_avail)) { + printk(KERN_ERR "invalid FB SRAM configuration\n"); + *start = start_avail; + *size = size_avail; + } + + if (*size) + pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size); +} + /* * The amount of SRAM depends on the core type. * Note that we cannot try to test for SRAM here because writes @@ -42,26 +112,45 @@ static unsigned long omap_sram_ceil; */ void __init omap_detect_sram(void) { - if (!cpu_is_omap24xx()) + unsigned long sram_start; + + if (cpu_is_omap24xx()) { + if (is_sram_locked()) { + omap_sram_base = OMAP2_SRAM_PUB_VA; + sram_start = OMAP2_SRAM_PUB_PA; + omap_sram_size = 0x800; /* 2K */ + } else { + omap_sram_base = OMAP2_SRAM_VA; + sram_start = OMAP2_SRAM_PA; + if (cpu_is_omap242x()) + omap_sram_size = 0xa0000; /* 640K */ + else if (cpu_is_omap243x()) + omap_sram_size = 0x10000; /* 64K */ + } + } else { omap_sram_base = OMAP1_SRAM_VA; - else - omap_sram_base = OMAP2_SRAM_VA; + sram_start = OMAP1_SRAM_PA; - if (cpu_is_omap730()) - omap_sram_size = 0x32000; /* 200K */ - else if (cpu_is_omap15xx()) - omap_sram_size = 0x30000; /* 192K */ - else if (cpu_is_omap1610() || cpu_is_omap1621() || cpu_is_omap1710()) - omap_sram_size = 0x4000; /* 16K */ - else if (cpu_is_omap1611()) - omap_sram_size = 0x3e800; /* 250K */ - else if (cpu_is_omap2420()) - omap_sram_size = 0xa0014; /* 640K */ - else { - printk(KERN_ERR "Could not detect SRAM size\n"); - omap_sram_size = 0x4000; + if (cpu_is_omap730()) + omap_sram_size = 0x32000; /* 200K */ + else if (cpu_is_omap15xx()) + omap_sram_size = 0x30000; /* 192K */ + else if (cpu_is_omap1610() || cpu_is_omap1621() || + cpu_is_omap1710()) + omap_sram_size = 0x4000; /* 16K */ + else if (cpu_is_omap1611()) + omap_sram_size = 0x3e800; /* 250K */ + else { + printk(KERN_ERR "Could not detect SRAM size\n"); + omap_sram_size = 0x4000; + } } - + get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ, + omap_sram_size - SRAM_BOOTLOADER_SZ, + &omap_fb_sram_start, &omap_fb_sram_size); + if (omap_fb_sram_size) + omap_sram_size -= sram_start + omap_sram_size - + omap_fb_sram_start; omap_sram_ceil = omap_sram_base + omap_sram_size; } @@ -80,12 +169,20 @@ static struct map_desc omap_sram_io_desc[] __initdata = { */ void __init omap_map_sram(void) { + unsigned long base; + if (omap_sram_size == 0) return; if (cpu_is_omap24xx()) { omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA; - omap_sram_io_desc[0].pfn = __phys_to_pfn(OMAP2_SRAM_PA); + + if (is_sram_locked()) + base = OMAP2_SRAM_PUB_PA; + else + base = OMAP2_SRAM_PA; + base = ROUND_DOWN(base, PAGE_SIZE); + omap_sram_io_desc[0].pfn = __phys_to_pfn(base); } omap_sram_io_desc[0].length = (omap_sram_size + PAGE_SIZE-1)/PAGE_SIZE; @@ -93,7 +190,8 @@ void __init omap_map_sram(void) iotable_init(omap_sram_io_desc, ARRAY_SIZE(omap_sram_io_desc)); printk(KERN_INFO "SRAM: Mapped pa 0x%08lx to va 0x%08lx size: 0x%lx\n", - omap_sram_io_desc[0].pfn, omap_sram_io_desc[0].virtual, + __pfn_to_phys(omap_sram_io_desc[0].pfn), + omap_sram_io_desc[0].virtual, omap_sram_io_desc[0].length); /* @@ -118,8 +216,9 @@ void * omap_sram_push(void * start, unsigned long size) printk(KERN_ERR "Not enough space in SRAM\n"); return NULL; } + omap_sram_ceil -= size; - omap_sram_ceil &= ~0x3; + omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *)); memcpy((void *)omap_sram_ceil, start, size); return (void *)omap_sram_ceil; diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c new file mode 100644 index 000000000000..b2a943bf11ef --- /dev/null +++ b/arch/arm/plat-omap/timer32k.c @@ -0,0 +1,325 @@ +/* + * linux/arch/arm/plat-omap/timer32k.c + * + * OMAP 32K Timer + * + * Copyright (C) 2004 - 2005 Nokia Corporation + * Partial timer rewrite and additional dynamic tick timer support by + * Tony Lindgen and + * Tuukka Tikkanen + * + * MPU timer code based on the older MPU timer code for OMAP + * Copyright (C) 2000 RidgeRun, Inc. + * Author: Greg Lonnon + * + * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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 +#include +#include +#include +#include + +struct sys_timer omap_timer; + +/* + * --------------------------------------------------------------------------- + * 32KHz OS timer + * + * This currently works only on 16xx, as 1510 does not have the continuous + * 32KHz synchronous timer. The 32KHz synchronous timer is used to keep track + * of time in addition to the 32KHz OS timer. Using only the 32KHz OS timer + * on 1510 would be possible, but the timer would not be as accurate as + * with the 32KHz synchronized timer. + * --------------------------------------------------------------------------- + */ + +#if defined(CONFIG_ARCH_OMAP16XX) +#define TIMER_32K_SYNCHRONIZED 0xfffbc410 +#elif defined(CONFIG_ARCH_OMAP24XX) +#define TIMER_32K_SYNCHRONIZED 0x48004010 +#else +#error OMAP 32KHz timer does not currently work on 15XX! +#endif + +/* 16xx specific defines */ +#define OMAP1_32K_TIMER_BASE 0xfffb9000 +#define OMAP1_32K_TIMER_CR 0x08 +#define OMAP1_32K_TIMER_TVR 0x00 +#define OMAP1_32K_TIMER_TCR 0x04 + +/* 24xx specific defines */ +#define OMAP2_GP_TIMER_BASE 0x48028000 +#define CM_CLKSEL_WKUP 0x48008440 +#define GP_TIMER_TIDR 0x00 +#define GP_TIMER_TISR 0x18 +#define GP_TIMER_TIER 0x1c +#define GP_TIMER_TCLR 0x24 +#define GP_TIMER_TCRR 0x28 +#define GP_TIMER_TLDR 0x2c +#define GP_TIMER_TTGR 0x30 +#define GP_TIMER_TSICR 0x40 + +#define OMAP_32K_TICKS_PER_HZ (32768 / HZ) + +/* + * TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1 + * so with HZ = 128, TVR = 255. + */ +#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1) + +#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ + (((nr_jiffies) * (clock_rate)) / HZ) + +static inline void omap_32k_timer_write(int val, int reg) +{ + if (cpu_class_is_omap1()) + omap_writew(val, OMAP1_32K_TIMER_BASE + reg); + + if (cpu_is_omap24xx()) + omap_writel(val, OMAP2_GP_TIMER_BASE + reg); +} + +static inline unsigned long omap_32k_timer_read(int reg) +{ + if (cpu_class_is_omap1()) + return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff; + + if (cpu_is_omap24xx()) + return omap_readl(OMAP2_GP_TIMER_BASE + reg); +} + +/* + * The 32KHz synchronized timer is an additional timer on 16xx. + * It is always running. + */ +static inline unsigned long omap_32k_sync_timer_read(void) +{ + return omap_readl(TIMER_32K_SYNCHRONIZED); +} + +static inline void omap_32k_timer_start(unsigned long load_val) +{ + if (cpu_class_is_omap1()) { + omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); + omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); + } + + if (cpu_is_omap24xx()) { + omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR); + omap_32k_timer_write((1 << 1), GP_TIMER_TIER); + omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR); + } +} + +static inline void omap_32k_timer_stop(void) +{ + if (cpu_class_is_omap1()) + omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR); + + if (cpu_is_omap24xx()) + omap_32k_timer_write(0x0, GP_TIMER_TCLR); +} + +/* + * Rounds down to nearest usec. Note that this will overflow for larger values. + */ +static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k) +{ + return (ticks_32k * 5*5*5*5*5*5) >> 9; +} + +/* + * Rounds down to nearest nsec. + */ +static inline unsigned long long +omap_32k_ticks_to_nsecs(unsigned long ticks_32k) +{ + return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9; +} + +static unsigned long omap_32k_last_tick = 0; + +/* + * Returns elapsed usecs since last 32k timer interrupt + */ +static unsigned long omap_32k_timer_gettimeoffset(void) +{ + unsigned long now = omap_32k_sync_timer_read(); + return omap_32k_ticks_to_usecs(now - omap_32k_last_tick); +} + +/* + * Returns current time from boot in nsecs. It's OK for this to wrap + * around for now, as it's just a relative time stamp. + */ +unsigned long long sched_clock(void) +{ + return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read()); +} + +/* + * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this + * function is also called from other interrupts to remove latency + * issues with dynamic tick. In the dynamic tick case, we need to lock + * with irqsave. + */ +static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, + struct pt_regs *regs) +{ + unsigned long flags; + unsigned long now; + + write_seqlock_irqsave(&xtime_lock, flags); + + if (cpu_is_omap24xx()) { + u32 status = omap_32k_timer_read(GP_TIMER_TISR); + omap_32k_timer_write(status, GP_TIMER_TISR); + } + + now = omap_32k_sync_timer_read(); + + while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) { + omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ; + timer_tick(regs); + } + + /* Restart timer so we don't drift off due to modulo or dynamic tick. + * By default we program the next timer to be continuous to avoid + * latencies during high system load. During dynamic tick operation the + * continuous timer can be overridden from pm_idle to be longer. + */ + omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); + write_sequnlock_irqrestore(&xtime_lock, flags); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_NO_IDLE_HZ +/* + * Programs the next timer interrupt needed. Called when dynamic tick is + * enabled, and to reprogram the ticks to skip from pm_idle. Note that + * we can keep the timer continuous, and don't need to set it to run in + * one-shot mode. This is because the timer will get reprogrammed again + * after next interrupt. + */ +void omap_32k_timer_reprogram(unsigned long next_tick) +{ + omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1); +} + +static struct irqaction omap_32k_timer_irq; +extern struct timer_update_handler timer_update; + +static int omap_32k_timer_enable_dyn_tick(void) +{ + /* No need to reprogram timer, just use the next interrupt */ + return 0; +} + +static int omap_32k_timer_disable_dyn_tick(void) +{ + omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); + return 0; +} + +static struct dyn_tick_timer omap_dyn_tick_timer = { + .enable = omap_32k_timer_enable_dyn_tick, + .disable = omap_32k_timer_disable_dyn_tick, + .reprogram = omap_32k_timer_reprogram, + .handler = omap_32k_timer_interrupt, +}; +#endif /* CONFIG_NO_IDLE_HZ */ + +static struct irqaction omap_32k_timer_irq = { + .name = "32KHz timer", + .flags = SA_INTERRUPT | SA_TIMER, + .handler = omap_32k_timer_interrupt, +}; + +static struct clk * gpt1_ick; +static struct clk * gpt1_fck; + +static __init void omap_init_32k_timer(void) +{ +#ifdef CONFIG_NO_IDLE_HZ + omap_timer.dyn_tick = &omap_dyn_tick_timer; +#endif + + if (cpu_class_is_omap1()) + setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); + if (cpu_is_omap24xx()) + setup_irq(37, &omap_32k_timer_irq); + omap_timer.offset = omap_32k_timer_gettimeoffset; + omap_32k_last_tick = omap_32k_sync_timer_read(); + + /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ + if (cpu_is_omap24xx()) { + omap_32k_timer_write(0, GP_TIMER_TCLR); + omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */ + + gpt1_ick = clk_get(NULL, "gpt1_ick"); + if (IS_ERR(gpt1_ick)) + printk(KERN_ERR "Could not get gpt1_ick\n"); + else + clk_enable(gpt1_ick); + + gpt1_fck = clk_get(NULL, "gpt1_fck"); + if (IS_ERR(gpt1_fck)) + printk(KERN_ERR "Could not get gpt1_fck\n"); + else + clk_enable(gpt1_fck); + + mdelay(100); /* Wait for clocks to stabilize */ + + omap_32k_timer_write(0x7, GP_TIMER_TISR); + } + + omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); +} + +/* + * --------------------------------------------------------------------------- + * Timer initialization + * --------------------------------------------------------------------------- + */ +static void __init omap_timer_init(void) +{ + omap_init_32k_timer(); +} + +struct sys_timer omap_timer = { + .init = omap_timer_init, + .offset = NULL, /* Initialized later */ +}; diff --git a/arch/arm/vfp/vfpdouble.c b/arch/arm/vfp/vfpdouble.c index 9b367a65cb4d..febd115dba28 100644 --- a/arch/arm/vfp/vfpdouble.c +++ b/arch/arm/vfp/vfpdouble.c @@ -588,6 +588,7 @@ static u32 vfp_double_ftosi(int sd, int unused, int dm, u32 fpscr) struct vfp_double vdm; u32 d, exceptions = 0; int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; vfp_double_unpack(&vdm, vfp_get_double(dm)); vfp_double_dump("VDM", &vdm); @@ -595,10 +596,14 @@ static u32 vfp_double_ftosi(int sd, int unused, int dm, u32 fpscr) /* * Do we have denormalised number? */ - if (vfp_double_type(&vdm) & VFP_DENORMAL) + tm = vfp_double_type(&vdm); + if (tm & VFP_DENORMAL) exceptions |= FPSCR_IDC; - if (vdm.exponent >= 1023 + 32) { + if (tm & VFP_NAN) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (vdm.exponent >= 1023 + 32) { d = 0x7fffffff; if (vdm.sign) d = ~d; @@ -1122,9 +1127,9 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr) { u32 op = inst & FOP_MASK; u32 exceptions = 0; - unsigned int dd = vfp_get_sd(inst); - unsigned int dn = vfp_get_sn(inst); - unsigned int dm = vfp_get_sm(inst); + unsigned int dd = vfp_get_dd(inst); + unsigned int dn = vfp_get_dn(inst); + unsigned int dm = vfp_get_dm(inst); unsigned int vecitr, veclen, vecstride; u32 (*fop)(int, int, s32, u32); @@ -1141,7 +1146,7 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr) pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, (veclen >> FPSCR_LENGTH_BIT) + 1); - fop = (op == FOP_EXT) ? fop_extfns[dn] : fop_fns[FOP_TO_IDX(op)]; + fop = (op == FOP_EXT) ? fop_extfns[FEXT_TO_IDX(inst)] : fop_fns[FOP_TO_IDX(op)]; if (!fop) goto invalid; @@ -1149,17 +1154,13 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr) u32 except; if (op == FOP_EXT) - pr_debug("VFP: itr%d (d%u.%u) = op[%u] (d%u.%u)\n", + pr_debug("VFP: itr%d (d%u) = op[%u] (d%u)\n", vecitr >> FPSCR_LENGTH_BIT, - dd >> 1, dd & 1, dn, - dm >> 1, dm & 1); + dd, dn, dm); else - pr_debug("VFP: itr%d (d%u.%u) = (d%u.%u) op[%u] (d%u.%u)\n", + pr_debug("VFP: itr%d (d%u) = (d%u) op[%u] (d%u)\n", vecitr >> FPSCR_LENGTH_BIT, - dd >> 1, dd & 1, - dn >> 1, dn & 1, - FOP_TO_IDX(op), - dm >> 1, dm & 1); + dd, dn, FOP_TO_IDX(op), dm); except = fop(dd, dn, dm, fpscr); pr_debug("VFP: itr%d: exceptions=%08x\n", diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index b7ed57e00cd4..a3f65b47aea9 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -189,11 +189,10 @@ vfp_put_float: .globl vfp_get_double vfp_get_double: - mov r0, r0, lsr #1 add pc, pc, r0, lsl #3 mov r0, r0 .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 - mrrc p10, 1, r0, r1, c\dr @ fmrrd r0, r1, d\dr + mrrc p11, 1, r0, r1, c\dr @ fmrrd r0, r1, d\dr mov pc, lr .endr @@ -204,10 +203,9 @@ vfp_get_double: .globl vfp_put_double vfp_put_double: - mov r0, r0, lsr #1 add pc, pc, r0, lsl #3 mov r0, r0 .irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 - mcrr p10, 1, r1, r2, c\dr @ fmrrd r1, r2, d\dr + mcrr p11, 1, r1, r2, c\dr @ fmdrr r1, r2, d\dr mov pc, lr .endr diff --git a/arch/arm/vfp/vfpsingle.c b/arch/arm/vfp/vfpsingle.c index 14dd696ddeb1..4ac27f193934 100644 --- a/arch/arm/vfp/vfpsingle.c +++ b/arch/arm/vfp/vfpsingle.c @@ -632,6 +632,7 @@ static u32 vfp_single_ftosi(int sd, int unused, s32 m, u32 fpscr) struct vfp_single vsm; u32 d, exceptions = 0; int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; vfp_single_unpack(&vsm, m); vfp_single_dump("VSM", &vsm); @@ -639,10 +640,14 @@ static u32 vfp_single_ftosi(int sd, int unused, s32 m, u32 fpscr) /* * Do we have a denormalised number? */ + tm = vfp_single_type(&vsm); if (vfp_single_type(&vsm) & VFP_DENORMAL) exceptions |= FPSCR_IDC; - if (vsm.exponent >= 127 + 32) { + if (tm & VFP_NAN) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (vsm.exponent >= 127 + 32) { /* * m >= 2^31-2^7: invalid */ @@ -1188,7 +1193,7 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr) pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, (veclen >> FPSCR_LENGTH_BIT) + 1); - fop = (op == FOP_EXT) ? fop_extfns[sn] : fop_fns[FOP_TO_IDX(op)]; + fop = (op == FOP_EXT) ? fop_extfns[FEXT_TO_IDX(inst)] : fop_fns[FOP_TO_IDX(op)]; if (!fop) goto invalid; diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c index 811a6376c624..9d66c27f2724 100644 --- a/arch/arm26/kernel/armksyms.c +++ b/arch/arm26/kernel/armksyms.c @@ -152,7 +152,6 @@ EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(memset); @@ -212,8 +211,6 @@ EXPORT_SYMBOL(sys_open); EXPORT_SYMBOL(sys_exit); EXPORT_SYMBOL(sys_wait4); -EXPORT_SYMBOL(get_wchan); - #ifdef CONFIG_PREEMPT EXPORT_SYMBOL(kernel_flag); #endif diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c index de39725da920..d57859053ce7 100644 --- a/arch/cris/kernel/crisksyms.c +++ b/arch/cris/kernel/crisksyms.c @@ -39,7 +39,6 @@ EXPORT_SYMBOL(loops_per_usec); /* String functions */ EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strchr); diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S index 1d21c8d34d8a..a9b59527a741 100644 --- a/arch/frv/kernel/entry.S +++ b/arch/frv/kernel/entry.S @@ -1170,12 +1170,6 @@ __syscall_badsys: # syscall vector table # ############################################################################### -#ifdef CONFIG_MMU -#define __MMU(X) X -#else -#define __MMU(X) sys_ni_syscall -#endif - .section .rodata ALIGN .globl sys_call_table @@ -1305,7 +1299,7 @@ sys_call_table: .long sys_newuname .long sys_ni_syscall /* old "cacheflush" */ .long sys_adjtimex - .long __MMU(sys_mprotect) /* 125 */ + .long sys_mprotect /* 125 */ .long sys_sigprocmask .long sys_ni_syscall /* old "create_module" */ .long sys_init_module @@ -1324,16 +1318,16 @@ sys_call_table: .long sys_getdents .long sys_select .long sys_flock - .long __MMU(sys_msync) + .long sys_msync .long sys_readv /* 145 */ .long sys_writev .long sys_getsid .long sys_fdatasync .long sys_sysctl - .long __MMU(sys_mlock) /* 150 */ - .long __MMU(sys_munlock) - .long __MMU(sys_mlockall) - .long __MMU(sys_munlockall) + .long sys_mlock /* 150 */ + .long sys_munlock + .long sys_mlockall + .long sys_munlockall .long sys_sched_setparam .long sys_sched_getparam /* 155 */ .long sys_sched_setscheduler @@ -1343,7 +1337,7 @@ sys_call_table: .long sys_sched_get_priority_min /* 160 */ .long sys_sched_rr_get_interval .long sys_nanosleep - .long __MMU(sys_mremap) + .long sys_mremap .long sys_setresuid16 .long sys_getresuid16 /* 165 */ .long sys_ni_syscall /* for vm86 */ @@ -1398,8 +1392,8 @@ sys_call_table: .long sys_setfsuid /* 215 */ .long sys_setfsgid .long sys_pivot_root - .long __MMU(sys_mincore) - .long __MMU(sys_madvise) + .long sys_mincore + .long sys_madvise .long sys_getdents64 /* 220 */ .long sys_fcntl64 .long sys_ni_syscall /* reserved for TUX */ @@ -1437,7 +1431,7 @@ sys_call_table: .long sys_epoll_create .long sys_epoll_ctl /* 255 */ .long sys_epoll_wait - .long __MMU(sys_remap_file_pages) + .long sys_remap_file_pages .long sys_set_tid_address .long sys_timer_create .long sys_timer_settime /* 260 */ diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c index aa6b7d0a2109..0f273a7aca5a 100644 --- a/arch/frv/kernel/frv_ksyms.c +++ b/arch/frv/kernel/frv_ksyms.c @@ -27,7 +27,6 @@ EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strchr); @@ -79,8 +78,6 @@ EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__outsl_ns); EXPORT_SYMBOL(__insl_ns); -EXPORT_SYMBOL(get_wchan); - #ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS EXPORT_SYMBOL(atomic_test_and_ANDNOT_mask); EXPORT_SYMBOL(atomic_test_and_OR_mask); diff --git a/arch/h8300/kernel/h8300_ksyms.c b/arch/h8300/kernel/h8300_ksyms.c index 69d6ad32d56c..f8d6dee84781 100644 --- a/arch/h8300/kernel/h8300_ksyms.c +++ b/arch/h8300/kernel/h8300_ksyms.c @@ -25,7 +25,6 @@ extern char h8300_debug_device[]; /* platform dependent support */ EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strchr); @@ -55,8 +54,6 @@ EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(get_wchan); - /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index f17bd1d2707e..18ec9fe6deb6 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -53,6 +53,35 @@ source "init/Kconfig" menu "Processor type and features" +config SMP + bool "Symmetric multi-processing support" + ---help--- + This enables support for systems with more than one CPU. If you have + a system with only one CPU, like most personal computers, say N. If + you have a system with more than one CPU, say Y. + + If you say N here, the kernel will run on single and multiprocessor + machines, but will use only one CPU of a multiprocessor machine. If + you say Y here, the kernel will run on many, but not all, + singleprocessor machines. On a singleprocessor machine, the kernel + will run faster if you say N here. + + Note that if you say Y here and choose architecture "586" or + "Pentium" under "Processor family", the kernel will not work on 486 + architectures. Similarly, multiprocessor kernels for the "PPro" + architecture may not work on all Pentium based boards. + + People using multiprocessor machines who say Y here should also say + Y to "Enhanced Real Time Clock Support", below. The "Advanced Power + Management" code will be disabled if you say Y here. + + See also the , + , + and the SMP-HOWTO available at + . + + If you don't know what to do here, say N. + choice prompt "Subarchitecture Type" default X86_PC @@ -178,35 +207,6 @@ config HPET_EMULATE_RTC depends on HPET_TIMER && RTC=y default y -config SMP - bool "Symmetric multi-processing support" - ---help--- - This enables support for systems with more than one CPU. If you have - a system with only one CPU, like most personal computers, say N. If - you have a system with more than one CPU, say Y. - - If you say N here, the kernel will run on single and multiprocessor - machines, but will use only one CPU of a multiprocessor machine. If - you say Y here, the kernel will run on many, but not all, - singleprocessor machines. On a singleprocessor machine, the kernel - will run faster if you say N here. - - Note that if you say Y here and choose architecture "586" or - "Pentium" under "Processor family", the kernel will not work on 486 - architectures. Similarly, multiprocessor kernels for the "PPro" - architecture may not work on all Pentium based boards. - - People using multiprocessor machines who say Y here should also say - Y to "Enhanced Real Time Clock Support", below. The "Advanced Power - Management" code will be disabled if you say Y here. - - See also the , - , - and the SMP-HOWTO available at - . - - If you don't know what to do here, say N. - config NR_CPUS int "Maximum number of CPUs (2-255)" range 2 255 @@ -522,6 +522,12 @@ config NUMA comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI" depends on X86_SUMMIT && (!HIGHMEM64G || !ACPI) +config NODES_SHIFT + int + default "4" if X86_NUMAQ + default "3" + depends on NEED_MULTIPLE_NODES + config HAVE_ARCH_BOOTMEM_NODE bool depends on NUMA @@ -757,15 +763,6 @@ config HOTPLUG_CPU Say N. -config DOUBLEFAULT - default y - bool "Enable doublefault exception handler" if EMBEDDED - help - This option allows trapping of rare doublefault exceptions that - would otherwise cause a system to silently reboot. Disabling this - option saves about 4k and might cause you much additional grey - hair. - endmenu diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu index 79603b3471f9..eb130482ba18 100644 --- a/arch/i386/Kconfig.cpu +++ b/arch/i386/Kconfig.cpu @@ -311,5 +311,5 @@ config X86_OOSTORE config X86_TSC bool - depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1) && !X86_NUMAQ + depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX) && !X86_NUMAQ default y diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug index 6e97df6979e8..c92191b1fb67 100644 --- a/arch/i386/Kconfig.debug +++ b/arch/i386/Kconfig.debug @@ -81,4 +81,13 @@ config X86_MPPARSE depends on X86_LOCAL_APIC && !X86_VISWS default y +config DOUBLEFAULT + default y + bool "Enable doublefault exception handler" if EMBEDDED + help + This option allows trapping of rare doublefault exceptions that + would otherwise cause a system to silently reboot. Disabling this + option saves about 4k and might cause you much additional grey + hair. + endmenu diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S index 0000a2674537..c9343c3a8082 100644 --- a/arch/i386/boot/video.S +++ b/arch/i386/boot/video.S @@ -97,6 +97,7 @@ #define PARAM_VESAPM_OFF 0x30 #define PARAM_LFB_PAGES 0x32 #define PARAM_VESA_ATTRIB 0x34 +#define PARAM_CAPABILITIES 0x36 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ #ifdef CONFIG_VIDEO_RETAIN @@ -233,6 +234,10 @@ mopar_gr: movw 18(%di), %ax movl %eax, %fs:(PARAM_LFB_SIZE) +# store mode capabilities + movl 10(%di), %eax + movl %eax, %fs:(PARAM_CAPABILITIES) + # switching the DAC to 8-bit is for <= 8 bpp only movw %fs:(PARAM_LFB_DEPTH), %ax cmpw $8, %ax diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 5b9ed21216cf..96fb8a020af2 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_i386.o \ - pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \ + pci-dma.o i386_ksyms.o i387.o bootflag.o \ quirks.o i8237.o topology.o alternative.o obj-y += cpu/ diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 033066176b3e..049a25583793 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c @@ -215,7 +215,7 @@ static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size) { struct acpi_table_madt *madt = NULL; - if (!phys_addr || !size) + if (!phys_addr || !size || !cpu_has_apic) return -EINVAL; madt = (struct acpi_table_madt *)__acpi_map_table(phys_addr, size); @@ -693,6 +693,9 @@ static int __init acpi_parse_madt_lapic_entries(void) { int count; + if (!cpu_has_apic) + return -ENODEV; + /* * Note that the LAPIC address is obtained from the MADT (32-bit value) * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). @@ -751,6 +754,9 @@ static int __init acpi_parse_madt_ioapic_entries(void) return -ENODEV; } + if (!cpu_has_apic) + return -ENODEV; + /* * if "noapic" boot option, don't look for IO-APICs */ @@ -1096,6 +1102,9 @@ int __init acpi_boot_table_init(void) dmi_check_system(acpi_dmi_table); #endif + if (!cpu_has_apic) + return -ENODEV; + /* * If acpi_disabled, bail out * One exception: acpi=ht continues far enough to enumerate LAPICs diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index eb5279d23b7f..254cee9f0b7b 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -62,6 +62,18 @@ int apic_verbosity; static void apic_pm_activate(void); +int modern_apic(void) +{ + unsigned int lvr, version; + /* AMD systems use old APIC versions, so check the CPU */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && + boot_cpu_data.x86 >= 0xf) + return 1; + lvr = apic_read(APIC_LVR); + version = GET_APIC_VERSION(lvr); + return version >= 0x14; +} + /* * 'what should we do if we get a hw irq event on an illegal vector'. * each architecture has to answer this themselves. @@ -119,10 +131,7 @@ void enable_NMI_through_LVT0 (void * dummy) int get_physical_broadcast(void) { - unsigned int lvr, version; - lvr = apic_read(APIC_LVR); - version = GET_APIC_VERSION(lvr); - if (!APIC_INTEGRATED(version) || version >= 0x14) + if (modern_apic()) return 0xff; else return 0xf; @@ -349,9 +358,9 @@ int __init verify_local_APIC(void) void __init sync_Arb_IDs(void) { - /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */ - unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR)); - if (ver >= 0x14) /* P4 or higher */ + /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 + And not needed on AMD */ + if (modern_apic()) return; /* * Wait for idle. @@ -415,6 +424,7 @@ void __init init_bsp_APIC(void) void __devinit setup_local_APIC(void) { unsigned long oldvalue, value, ver, maxlvt; + int i, j; /* Pound the ESR really hard over the head with a big hammer - mbligh */ if (esr_disable) { @@ -451,6 +461,25 @@ void __devinit setup_local_APIC(void) value &= ~APIC_TPRI_MASK; apic_write_around(APIC_TASKPRI, value); + /* + * After a crash, we no longer service the interrupts and a pending + * interrupt from previous kernel might still have ISR bit set. + * + * Most probably by now CPU has serviced that pending interrupt and + * it might not have done the ack_APIC_irq() because it thought, + * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it + * does not clear the ISR bit and cpu thinks it has already serivced + * the interrupt. Hence a vector might get locked. It was noticed + * for timer irq (vector 0x31). Issue an extra EOI to clear ISR. + */ + for (i = APIC_ISR_NR - 1; i >= 0; i--) { + value = apic_read(APIC_ISR + i*0x10); + for (j = 31; j >= 0; j--) { + if (value & (1<> 4) != 0xf; -} -#else -static int MP_valid_apicid(int apicid, int version) -{ - if (version >= 0x14) - return apicid < 0xff; - else - return apicid < 0xf; -} -#endif - static void __devinit MP_processor_info (struct mpc_config_processor *m) { int ver, apicid; @@ -190,12 +169,6 @@ static void __devinit MP_processor_info (struct mpc_config_processor *m) ver = m->mpc_apicver; - if (!MP_valid_apicid(apicid, ver)) { - printk(KERN_WARNING "Processor #%d INVALID. (Max ID: %d).\n", - m->mpc_apicid, MAX_APICS); - return; - } - /* * Validate version */ @@ -225,7 +198,14 @@ static void __devinit MP_processor_info (struct mpc_config_processor *m) cpu_set(num_processors, cpu_possible_map); num_processors++; - if (CPU_HOTPLUG_ENABLED || (num_processors > 8)) { + /* + * Would be preferable to switch to bigsmp when CONFIG_HOTPLUG_CPU=y + * but we need to work other dependencies like SMP_SUSPEND etc + * before this can be done without some confusion. + * if (CPU_HOTPLUG_ENABLED || num_processors > 8) + * - Ashok Raj + */ + if (num_processors > 8) { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_INTEL: if (!APIC_XAPIC(ver)) { @@ -249,6 +229,13 @@ static void __init MP_bus_info (struct mpc_config_bus *m) mpc_oem_bus_info(m, str, translation_table[mpc_record]); + if (m->mpc_busid >= MAX_MP_BUSSES) { + printk(KERN_WARNING "MP table busid value (%d) for bustype %s " + " is too large, max. supported is %d\n", + m->mpc_busid, str, MAX_MP_BUSSES - 1); + return; + } + if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) { diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 24b3e745478b..6259afea46d1 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -781,7 +781,6 @@ unsigned long get_wchan(struct task_struct *p) } while (count++ < 16); return 0; } -EXPORT_SYMBOL(get_wchan); /* * sys_alloc_thread_area: get a yet unused TLS descriptor index. diff --git a/arch/i386/kernel/reboot_fixups.c b/arch/i386/kernel/reboot_fixups.c index 10e21a4773dd..99aab41a05b0 100644 --- a/arch/i386/kernel/reboot_fixups.c +++ b/arch/i386/kernel/reboot_fixups.c @@ -51,7 +51,5 @@ void mach_reboot_fixups(void) cur->reboot_fixup(dev); } - - printk(KERN_WARNING "No reboot fixup found for your hardware\n"); } diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 8c08660b4e5d..80cb3b2d0997 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -962,6 +963,36 @@ efi_memory_present_wrapper(unsigned long start, unsigned long end, void *arg) return 0; } + /* + * This function checks if the entire range is mapped with type. + * + * Note: this function only works correct if the e820 table is sorted and + * not-overlapping, which is the case + */ +int __init +e820_all_mapped(unsigned long start, unsigned long end, unsigned type) +{ + int i; + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + if (type && ei->type != type) + continue; + /* is the region (part) in overlap with the current region ?*/ + if (ei->addr >= end || ei->addr + ei->size <= start) + continue; + /* if the region is at the beginning of we move + * start to the end of the region since it's ok until there + */ + if (ei->addr <= start) + start = ei->addr + ei->size; + /* if start is now at or beyond end, we're done, full + * coverage */ + if (start >= end) + return 1; /* we're done */ + } + return 0; +} + /* * Find the highest page frame number we have available */ @@ -1316,8 +1347,8 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat /* * Request address space for all standard resources * - * This is called just before pcibios_assign_resources(), which is also - * an fs_initcall, but is linked in later (in arch/i386/pci/i386.c). + * This is called just before pcibios_init(), which is also a + * subsys_initcall, but is linked in later (in arch/i386/pci/common.c). */ static int __init request_standard_resources(void) { @@ -1338,7 +1369,7 @@ static int __init request_standard_resources(void) return 0; } -fs_initcall(request_standard_resources); +subsys_initcall(request_standard_resources); static void __init register_memory(void) { @@ -1547,6 +1578,23 @@ void __init setup_arch(char **cmdline_p) #endif } +static __init int add_pcspkr(void) +{ + struct platform_device *pd; + int ret; + + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} +device_initcall(add_pcspkr); + #include "setup_arch_post.h" /* * Local Variables: diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index 326595f3fa4d..f48bef15b4f0 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S @@ -312,3 +312,6 @@ ENTRY(sys_call_table) .long sys_unshare /* 310 */ .long sys_set_robust_list .long sys_get_robust_list + .long sys_splice + .long sys_sync_file_range + .long sys_tee /* 315 */ diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 6b63a5aa1e46..2d22f5761b1d 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -365,6 +365,9 @@ void die(const char * str, struct pt_regs * regs, long err) if (++die.lock_owner_depth < 3) { int nl = 0; + unsigned long esp; + unsigned short ss; + handle_BUG(regs); printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); #ifdef CONFIG_PREEMPT @@ -387,8 +390,19 @@ void die(const char * str, struct pt_regs * regs, long err) printk("\n"); if (notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV) != - NOTIFY_STOP) + NOTIFY_STOP) { show_registers(regs); + /* Executive summary in case the oops scrolled away */ + esp = (unsigned long) (®s->esp); + savesegment(ss, ss); + if (user_mode(regs)) { + esp = regs->esp; + ss = regs->xss & 0xffff; + } + printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip); + print_symbol("%s", regs->eip); + printk(" SS:ESP %04x:%08lx\n", ss, esp); + } else regs = NULL; } else @@ -1193,6 +1207,6 @@ void __init trap_init(void) static int __init kstack_setup(char *s) { kstack_depth_to_print = simple_strtoul(s, NULL, 0); - return 0; + return 1; } __setup("kstack=", kstack_setup); diff --git a/arch/i386/kernel/vsyscall-sigreturn.S b/arch/i386/kernel/vsyscall-sigreturn.S index fadb5bc3c374..a92262f41659 100644 --- a/arch/i386/kernel/vsyscall-sigreturn.S +++ b/arch/i386/kernel/vsyscall-sigreturn.S @@ -44,7 +44,7 @@ __kernel_rt_sigreturn: .LSTARTCIEDLSI1: .long 0 /* CIE ID */ .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ + .string "zRS" /* NUL-terminated augmentation string */ .uleb128 1 /* Code alignment factor */ .sleb128 -4 /* Data alignment factor */ .byte 8 /* Return address register column */ diff --git a/arch/i386/mach-voyager/voyager_cat.c b/arch/i386/mach-voyager/voyager_cat.c index 23967fe658d3..3039539de51e 100644 --- a/arch/i386/mach-voyager/voyager_cat.c +++ b/arch/i386/mach-voyager/voyager_cat.c @@ -106,9 +106,15 @@ voyager_module_t *voyager_cat_list; /* the I/O port assignments for the VIC and QIC */ static struct resource vic_res = { - "Voyager Interrupt Controller", 0xFC00, 0xFC6F }; + .name = "Voyager Interrupt Controller", + .start = 0xFC00, + .end = 0xFC6F +}; static struct resource qic_res = { - "Quad Interrupt Controller", 0xFC70, 0xFCFF }; + .name = "Quad Interrupt Controller", + .start = 0xFC70, + .end = 0xFCFF +}; /* This function is used to pack a data bit stream inside a message. * It writes num_bits of the data buffer in msg starting at start_bit. diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index 9f66ac582a8b..ae6534ad8161 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -651,6 +651,7 @@ void __init mem_init(void) * Specifically, in the case of x86, we will always add * memory to the highmem for now. */ +#ifdef CONFIG_HOTPLUG_MEMORY #ifndef CONFIG_NEED_MULTIPLE_NODES int add_memory(u64 start, u64 size) { @@ -667,6 +668,7 @@ int remove_memory(u64 start, u64 size) return -EINVAL; } #endif +#endif kmem_cache_t *pgd_cache; kmem_cache_t *pmd_cache; diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c index 99012b93bd12..5d81fb510375 100644 --- a/arch/i386/pci/direct.c +++ b/arch/i386/pci/direct.c @@ -4,6 +4,7 @@ #include #include +#include #include "pci.h" /* @@ -18,8 +19,10 @@ int pci_conf1_read(unsigned int seg, unsigned int bus, { unsigned long flags; - if (!value || (bus > 255) || (devfn > 255) || (reg > 255)) + if ((bus > 255) || (devfn > 255) || (reg > 255)) { + *value = -1; return -EINVAL; + } spin_lock_irqsave(&pci_config_lock, flags); @@ -91,8 +94,10 @@ static int pci_conf2_read(unsigned int seg, unsigned int bus, unsigned long flags; int dev, fn; - if (!value || (bus > 255) || (devfn > 255) || (reg > 255)) + if ((bus > 255) || (devfn > 255) || (reg > 255)) { + *value = -1; return -EINVAL; + } dev = PCI_SLOT(devfn); fn = PCI_FUNC(devfn); @@ -188,6 +193,10 @@ static int __init pci_sanity_check(struct pci_raw_ops *o) if (pci_probe & PCI_NO_CHECKS) return 1; + /* Assume Type 1 works for newer systems. + This handles machines that don't have anything on PCI Bus 0. */ + if (dmi_get_year(DMI_BIOS_DATE) >= 2001) + return 1; for (devfn = 0; devfn < 0x100; devfn++) { if (o->read(0, 0, devfn, PCI_CLASS_DEVICE, 2, &x)) diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 3ca59cad05f3..73235443fda7 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c @@ -588,7 +588,10 @@ static __init int via_router_probe(struct irq_router *r, case PCI_DEVICE_ID_VIA_82C596: case PCI_DEVICE_ID_VIA_82C686: case PCI_DEVICE_ID_VIA_8231: + case PCI_DEVICE_ID_VIA_8233A: case PCI_DEVICE_ID_VIA_8235: + case PCI_DEVICE_ID_VIA_8237: + case PCI_DEVICE_ID_VIA_8237_SATA: /* FIXME: add new ones for 8233/5 */ r->name = "VIA"; r->get = pirq_via_get; diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c index 613789071f30..6b1ea0c9a570 100644 --- a/arch/i386/pci/mmconfig.c +++ b/arch/i386/pci/mmconfig.c @@ -12,14 +12,20 @@ #include #include #include +#include #include "pci.h" +#define MMCONFIG_APER_SIZE (256*1024*1024) + +/* Assume systems with more busses have correct MCFG */ +#define MAX_CHECK_BUS 16 + #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) /* The base address of the last MMCONFIG device accessed */ static u32 mmcfg_last_accessed_device; -static DECLARE_BITMAP(fallback_slots, 32); +static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32); /* * Functions for accessing PCI configuration space with MMCONFIG accesses @@ -29,8 +35,8 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) int cfg_num = -1; struct acpi_table_mcfg_config *cfg; - if (seg == 0 && bus == 0 && - test_bit(PCI_SLOT(devfn), fallback_slots)) + if (seg == 0 && bus < MAX_CHECK_BUS && + test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots)) return 0; while (1) { @@ -74,8 +80,10 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, unsigned long flags; u32 base; - if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) + if ((bus > 255) || (devfn > 255) || (reg > 4095)) { + *value = -1; return -EINVAL; + } base = get_base_addr(seg, bus, devfn); if (!base) @@ -146,29 +154,34 @@ static struct pci_raw_ops pci_mmcfg = { Normally this can be expressed in the MCFG by not listing them and assigning suitable _SEGs, but this isn't implemented in some BIOS. Instead try to discover all devices on bus 0 that are unreachable using MM - and fallback for them. - We only do this for bus 0/seg 0 */ + and fallback for them. */ static __init void unreachable_devices(void) { - int i; + int i, k; unsigned long flags; - for (i = 0; i < 32; i++) { - u32 val1; - u32 addr; + for (k = 0; k < MAX_CHECK_BUS; k++) { + for (i = 0; i < 32; i++) { + u32 val1; + u32 addr; - pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1); - if (val1 == 0xffffffff) - continue; + pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1); + if (val1 == 0xffffffff) + continue; - /* Locking probably not needed, but safer */ - spin_lock_irqsave(&pci_config_lock, flags); - addr = get_base_addr(0, 0, PCI_DEVFN(i, 0)); - if (addr != 0) - pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0)); - if (addr == 0 || readl((u32 __iomem *)mmcfg_virt_addr) != val1) - set_bit(i, fallback_slots); - spin_unlock_irqrestore(&pci_config_lock, flags); + /* Locking probably not needed, but safer */ + spin_lock_irqsave(&pci_config_lock, flags); + addr = get_base_addr(0, k, PCI_DEVFN(i, 0)); + if (addr != 0) + pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0)); + if (addr == 0 || + readl((u32 __iomem *)mmcfg_virt_addr) != val1) { + set_bit(i, fallback_slots); + printk(KERN_NOTICE + "PCI: No mmconfig possible on %x:%x\n", k, i); + } + spin_unlock_irqrestore(&pci_config_lock, flags); + } } } @@ -183,6 +196,14 @@ void __init pci_mmcfg_init(void) (pci_mmcfg_config[0].base_address == 0)) return; + if (!e820_all_mapped(pci_mmcfg_config[0].base_address, + pci_mmcfg_config[0].base_address + MMCONFIG_APER_SIZE, + E820_RESERVED)) { + printk(KERN_ERR "PCI: BIOS Bug: MCFG area is not E820-reserved\n"); + printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); + return; + } + printk(KERN_INFO "PCI: Using MMCONFIG\n"); raw_pci_ops = &pci_mmcfg; pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index edffe25a477a..9f40eeff0b5c 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -260,15 +260,6 @@ config NR_CPUS than 64 will cause the use of a CPU mask array, causing a small performance hit. -config IA64_NR_NODES - int "Maximum number of NODEs (256-1024)" if (IA64_SGI_SN2 || IA64_GENERIC) - range 256 1024 - depends on IA64_SGI_SN2 || IA64_GENERIC - default "256" - help - This option specifies the maximum number of nodes in your SSI system. - If in doubt, use the default. - config HOTPLUG_CPU bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" depends on SMP && EXPERIMENTAL @@ -352,6 +343,16 @@ config NUMA Access). This option is for configuring high-end multiprocessor server systems. If in doubt, say N. +config NODES_SHIFT + int "Max num nodes shift(3-10)" + range 3 10 + default "8" + depends on NEED_MULTIPLE_NODES + help + This option specifies the maximum number of nodes in your SSI system. + MAX_NUMNODES will be 2^(This value). + If in doubt, use the default. + # VIRTUAL_MEM_MAP and FLAT_NODE_MEM_MAP are functionally equivalent. # VIRTUAL_MEM_MAP has been retained for historical reasons. config VIRTUAL_MEM_MAP diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 59e871dae742..09a0dbc17fb6 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile @@ -7,7 +7,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \ - unwind.o mca.o mca_asm.o topology.o dmi_scan.o + unwind.o mca.o mca_asm.o topology.o obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o @@ -30,7 +30,6 @@ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o mca_recovery-y += mca_drv.o mca_drv_asm.o -dmi_scan-y += ../../i386/kernel/dmi_scan.o # The gate DSO image is built using a special linker script. targets += gate.so gate-syms.o diff --git a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c index 4a5574ff007b..fff82929d225 100644 --- a/arch/ia64/kernel/acpi-ext.c +++ b/arch/ia64/kernel/acpi-ext.c @@ -1,105 +1,104 @@ /* - * arch/ia64/kernel/acpi-ext.c + * (c) Copyright 2003, 2006 Hewlett-Packard Development Company, L.P. + * Alex Williamson + * Bjorn Helgaas * - * Copyright (C) 2003 Hewlett-Packard - * Copyright (C) Alex Williamson - * Copyright (C) Bjorn Helgaas - * - * Vendor specific extensions to ACPI. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include #include #include #include -#include #include -struct acpi_vendor_descriptor { - u8 guid_id; - efi_guid_t guid; +/* + * Device CSRs that do not appear in PCI config space should be described + * via ACPI. This would normally be done with Address Space Descriptors + * marked as "consumer-only," but old versions of Windows and Linux ignore + * the producer/consumer flag, so HP invented a vendor-defined resource to + * describe the location and size of CSR space. + */ + +struct acpi_vendor_uuid hp_ccsr_uuid = { + .subtype = 2, + .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a, + 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad }, }; -struct acpi_vendor_info { - struct acpi_vendor_descriptor *descriptor; - u8 *data; - u32 length; -}; - -acpi_status -acpi_vendor_resource_match(struct acpi_resource *resource, void *context) -{ - struct acpi_vendor_info *info = (struct acpi_vendor_info *)context; - struct acpi_resource_vendor *vendor; - struct acpi_vendor_descriptor *descriptor; - u32 byte_length; - - if (resource->type != ACPI_RESOURCE_TYPE_VENDOR) - return AE_OK; - - vendor = (struct acpi_resource_vendor *)&resource->data; - descriptor = (struct acpi_vendor_descriptor *)vendor->byte_data; - if (vendor->byte_length <= sizeof(*info->descriptor) || - descriptor->guid_id != info->descriptor->guid_id || - efi_guidcmp(descriptor->guid, info->descriptor->guid)) - return AE_OK; - - byte_length = vendor->byte_length - sizeof(struct acpi_vendor_descriptor); - info->data = acpi_os_allocate(byte_length); - if (!info->data) - return AE_NO_MEMORY; - - memcpy(info->data, - vendor->byte_data + sizeof(struct acpi_vendor_descriptor), - byte_length); - info->length = byte_length; - return AE_CTRL_TERMINATE; -} - -acpi_status -acpi_find_vendor_resource(acpi_handle obj, struct acpi_vendor_descriptor * id, - u8 ** data, u32 * byte_length) -{ - struct acpi_vendor_info info; - - info.descriptor = id; - info.data = NULL; - - acpi_walk_resources(obj, METHOD_NAME__CRS, acpi_vendor_resource_match, - &info); - if (!info.data) - return AE_NOT_FOUND; - - *data = info.data; - *byte_length = info.length; - return AE_OK; -} - -struct acpi_vendor_descriptor hp_ccsr_descriptor = { - .guid_id = 2, - .guid = - EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, 0xf6, 0x4a, 0x24, 0xd2, 0x01, - 0x37, 0x0e, 0xad) -}; - -acpi_status hp_acpi_csr_space(acpi_handle obj, u64 * csr_base, u64 * csr_length) +static acpi_status hp_ccsr_locate(acpi_handle obj, u64 *base, u64 *length) { acpi_status status; - u8 *data; - u32 length; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_resource *resource; + struct acpi_resource_vendor_typed *vendor; - status = - acpi_find_vendor_resource(obj, &hp_ccsr_descriptor, &data, &length); + status = acpi_get_vendor_resource(obj, METHOD_NAME__CRS, &hp_ccsr_uuid, + &buffer); - if (ACPI_FAILURE(status) || length != 16) + resource = buffer.pointer; + vendor = &resource->data.vendor_typed; + + if (ACPI_FAILURE(status) || vendor->byte_length < 16) { + status = AE_NOT_FOUND; + goto exit; + } + + memcpy(base, vendor->byte_data, sizeof(*base)); + memcpy(length, vendor->byte_data + 8, sizeof(*length)); + + exit: + acpi_os_free(buffer.pointer); + return status; +} + +struct csr_space { + u64 base; + u64 length; +}; + +static acpi_status find_csr_space(struct acpi_resource *resource, void *data) +{ + struct csr_space *space = data; + struct acpi_resource_address64 addr; + acpi_status status; + + status = acpi_resource_to_address64(resource, &addr); + if (ACPI_SUCCESS(status) && + addr.resource_type == ACPI_MEMORY_RANGE && + addr.address_length && + addr.producer_consumer == ACPI_CONSUMER) { + space->base = addr.minimum; + space->length = addr.address_length; + return AE_CTRL_TERMINATE; + } + return AE_OK; /* keep looking */ +} + +static acpi_status hp_crs_locate(acpi_handle obj, u64 *base, u64 *length) +{ + struct csr_space space = { 0, 0 }; + + acpi_walk_resources(obj, METHOD_NAME__CRS, find_csr_space, &space); + if (!space.length) return AE_NOT_FOUND; - memcpy(csr_base, data, sizeof(*csr_base)); - memcpy(csr_length, data + 8, sizeof(*csr_length)); - acpi_os_free(data); - + *base = space.base; + *length = space.length; return AE_OK; } +acpi_status hp_acpi_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length) +{ + acpi_status status; + + status = hp_ccsr_locate(obj, csr_base, csr_length); + if (ACPI_SUCCESS(status)) + return status; + + return hp_crs_locate(obj, csr_base, csr_length); +} EXPORT_SYMBOL(hp_acpi_csr_space); diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 0e3eda99e549..e30798811216 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1605,5 +1605,10 @@ sys_call_table: data8 sys_ni_syscall // reserved for pselect data8 sys_ni_syscall // 1295 reserved for ppoll data8 sys_unshare + data8 sys_splice + data8 sys_set_robust_list + data8 sys_get_robust_list + data8 sys_sync_file_range // 1300 + data8 sys_tee .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls diff --git a/arch/ia64/kernel/gate.lds.S b/arch/ia64/kernel/gate.lds.S index e1e4aba9ecd0..7c99e6ec3daf 100644 --- a/arch/ia64/kernel/gate.lds.S +++ b/arch/ia64/kernel/gate.lds.S @@ -59,6 +59,7 @@ SECTIONS *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) *(__ex_table) + *(__mca_table) } } diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 8832c553230a..7956eb9058fc 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -9,54 +9,65 @@ * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999,2000 Walt Drummond * - * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O APIC code. - * In particular, we now have separate handlers for edge - * and level triggered interrupts. - * 00/10/27 Asit Mallick, Goutham Rao IRQ vector allocation - * PCI to vector mapping, shared PCI interrupts. - * 00/10/27 D. Mosberger Document things a bit more to make them more understandable. - * Clean up much of the old IOSAPIC cruft. - * 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts and fixes for - * ACPI S5(SoftOff) support. + * 00/04/19 D. Mosberger Rewritten to mirror more closely the x86 I/O + * APIC code. In particular, we now have separate + * handlers for edge and level triggered + * interrupts. + * 00/10/27 Asit Mallick, Goutham Rao IRQ vector + * allocation PCI to vector mapping, shared PCI + * interrupts. + * 00/10/27 D. Mosberger Document things a bit more to make them more + * understandable. Clean up much of the old + * IOSAPIC cruft. + * 01/07/27 J.I. Lee PCI irq routing, Platform/Legacy interrupts + * and fixes for ACPI S5(SoftOff) support. * 02/01/23 J.I. Lee iosapic pgm fixes for PCI irq routing from _PRT - * 02/01/07 E. Focht Redirectable interrupt vectors in - * iosapic_set_affinity(), initializations for - * /proc/irq/#/smp_affinity + * 02/01/07 E. Focht Redirectable interrupt + * vectors in iosapic_set_affinity(), + * initializations for /proc/irq/#/smp_affinity * 02/04/02 P. Diefenbaugh Cleaned up ACPI PCI IRQ routing. * 02/04/18 J.I. Lee bug fix in iosapic_init_pci_irq - * 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to IOSAPIC mapping - * error + * 02/04/30 J.I. Lee bug fix in find_iosapic to fix ACPI PCI IRQ to + * IOSAPIC mapping error * 02/07/29 T. Kochi Allocate interrupt vectors dynamically - * 02/08/04 T. Kochi Cleaned up terminology (irq, global system interrupt, vector, etc.) - * 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's pci_irq code. + * 02/08/04 T. Kochi Cleaned up terminology (irq, global system + * interrupt, vector, etc.) + * 02/09/20 D. Mosberger Simplified by taking advantage of ACPI's + * pci_irq code. * 03/02/19 B. Helgaas Make pcat_compat system-wide, not per-IOSAPIC. - * Remove iosapic_address & gsi_base from external interfaces. - * Rationalize __init/__devinit attributes. + * Remove iosapic_address & gsi_base from + * external interfaces. Rationalize + * __init/__devinit attributes. * 04/12/04 Ashok Raj Intel Corporation 2004 - * Updated to work with irq migration necessary for CPU Hotplug + * Updated to work with irq migration necessary + * for CPU Hotplug */ /* - * Here is what the interrupt logic between a PCI device and the kernel looks like: + * Here is what the interrupt logic between a PCI device and the kernel looks + * like: * - * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The - * device is uniquely identified by its bus--, and slot-number (the function - * number does not matter here because all functions share the same interrupt - * lines). + * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, + * INTD). The device is uniquely identified by its bus-, and slot-number + * (the function number does not matter here because all functions share + * the same interrupt lines). * - * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC controller. - * Multiple interrupt lines may have to share the same IOSAPIC pin (if they're level - * triggered and use the same polarity). Each interrupt line has a unique Global - * System Interrupt (GSI) number which can be calculated as the sum of the controller's - * base GSI number and the IOSAPIC pin number to which the line connects. + * (2) The motherboard routes the interrupt line to a pin on a IOSAPIC + * controller. Multiple interrupt lines may have to share the same + * IOSAPIC pin (if they're level triggered and use the same polarity). + * Each interrupt line has a unique Global System Interrupt (GSI) number + * which can be calculated as the sum of the controller's base GSI number + * and the IOSAPIC pin number to which the line connects. * - * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the IOSAPIC pin - * into the IA-64 interrupt vector. This interrupt vector is then sent to the CPU. + * (3) The IOSAPIC uses an internal routing table entries (RTEs) to map the + * IOSAPIC pin into the IA-64 interrupt vector. This interrupt vector is then + * sent to the CPU. * - * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is used as - * architecture-independent interrupt handling mechanism in Linux. As an - * IRQ is a number, we have to have IA-64 interrupt vector number <-> IRQ number - * mapping. On smaller systems, we use one-to-one mapping between IA-64 vector and - * IRQ. A platform can implement platform_irq_to_vector(irq) and + * (4) The kernel recognizes an interrupt as an IRQ. The IRQ interface is + * used as architecture-independent interrupt handling mechanism in Linux. + * As an IRQ is a number, we have to have + * IA-64 interrupt vector number <-> IRQ number mapping. On smaller + * systems, we use one-to-one mapping between IA-64 vector and IRQ. A + * platform can implement platform_irq_to_vector(irq) and * platform_local_vector_to_irq(vector) APIs to differentiate the mapping. * Please see also include/asm-ia64/hw_irq.h for those APIs. * @@ -64,9 +75,9 @@ * * PCI pin -> global system interrupt (GSI) -> IA-64 vector <-> IRQ * - * Note: The term "IRQ" is loosely used everywhere in Linux kernel to describe interrupts. - * Now we use "IRQ" only for Linux IRQ's. ISA IRQ (isa_irq) is the only exception in this - * source code. + * Note: The term "IRQ" is loosely used everywhere in Linux kernel to + * describeinterrupts. Now we use "IRQ" only for Linux IRQ's. ISA IRQ + * (isa_irq) is the only exception in this source code. */ #include @@ -90,7 +101,6 @@ #include #include - #undef DEBUG_INTERRUPT_ROUTING #ifdef DEBUG_INTERRUPT_ROUTING @@ -99,36 +109,46 @@ #define DBG(fmt...) #endif -#define NR_PREALLOCATE_RTE_ENTRIES (PAGE_SIZE / sizeof(struct iosapic_rte_info)) +#define NR_PREALLOCATE_RTE_ENTRIES \ + (PAGE_SIZE / sizeof(struct iosapic_rte_info)) #define RTE_PREALLOCATED (1) static DEFINE_SPINLOCK(iosapic_lock); -/* These tables map IA-64 vectors to the IOSAPIC pin that generates this vector. */ +/* + * These tables map IA-64 vectors to the IOSAPIC pin that generates this + * vector. + */ struct iosapic_rte_info { - struct list_head rte_list; /* node in list of RTEs sharing the same vector */ + struct list_head rte_list; /* node in list of RTEs sharing the + * same vector */ char __iomem *addr; /* base address of IOSAPIC */ - unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ + unsigned int gsi_base; /* first GSI assigned to this + * IOSAPIC */ char rte_index; /* IOSAPIC RTE index */ int refcnt; /* reference counter */ unsigned int flags; /* flags */ } ____cacheline_aligned; static struct iosapic_intr_info { - struct list_head rtes; /* RTEs using this vector (empty => not an IOSAPIC interrupt) */ + struct list_head rtes; /* RTEs using this vector (empty => + * not an IOSAPIC interrupt) */ int count; /* # of RTEs that shares this vector */ - u32 low32; /* current value of low word of Redirection table entry */ + u32 low32; /* current value of low word of + * Redirection table entry */ unsigned int dest; /* destination CPU physical ID */ unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ - unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ + unsigned char polarity: 1; /* interrupt polarity + * (see iosapic.h) */ unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ } iosapic_intr_info[IA64_NUM_VECTORS]; static struct iosapic { char __iomem *addr; /* base address of IOSAPIC */ - unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ - unsigned short num_rte; /* number of RTE in this IOSAPIC */ + unsigned int gsi_base; /* first GSI assigned to this + * IOSAPIC */ + unsigned short num_rte; /* # of RTEs on this IOSAPIC */ int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ #ifdef CONFIG_NUMA unsigned short node; /* numa node association via pxm */ @@ -149,7 +169,8 @@ find_iosapic (unsigned int gsi) int i; for (i = 0; i < NR_IOSAPICS; i++) { - if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) + if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < + iosapic_lists[i].num_rte) return i; } @@ -162,7 +183,8 @@ _gsi_to_vector (unsigned int gsi) struct iosapic_intr_info *info; struct iosapic_rte_info *rte; - for (info = iosapic_intr_info; info < iosapic_intr_info + IA64_NUM_VECTORS; ++info) + for (info = iosapic_intr_info; info < + iosapic_intr_info + IA64_NUM_VECTORS; ++info) list_for_each_entry(rte, &info->rtes, rte_list) if (rte->gsi_base + rte->rte_index == gsi) return info - iosapic_intr_info; @@ -185,8 +207,8 @@ gsi_to_irq (unsigned int gsi) unsigned long flags; int irq; /* - * XXX fix me: this assumes an identity mapping vetween IA-64 vector and Linux irq - * numbers... + * XXX fix me: this assumes an identity mapping between IA-64 vector + * and Linux irq numbers... */ spin_lock_irqsave(&iosapic_lock, flags); { @@ -197,7 +219,8 @@ gsi_to_irq (unsigned int gsi) return irq; } -static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, unsigned int vec) +static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi, + unsigned int vec) { struct iosapic_rte_info *rte; @@ -237,7 +260,9 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) for (irq = 0; irq < NR_IRQS; ++irq) if (irq_to_vector(irq) == vector) { - set_irq_affinity_info(irq, (int)(dest & 0xffff), redir); + set_irq_affinity_info(irq, + (int)(dest & 0xffff), + redir); break; } } @@ -259,7 +284,7 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask) } static void -nop (unsigned int vector) +nop (unsigned int irq) { /* do nothing... */ } @@ -281,7 +306,8 @@ mask_irq (unsigned int irq) { /* set only the mask bit */ low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK; - list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { + list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, + rte_list) { addr = rte->addr; rte_index = rte->rte_index; iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); @@ -306,7 +332,8 @@ unmask_irq (unsigned int irq) spin_lock_irqsave(&iosapic_lock, flags); { low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK; - list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { + list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, + rte_list) { addr = rte->addr; rte_index = rte->rte_index; iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); @@ -346,21 +373,25 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask) spin_lock_irqsave(&iosapic_lock, flags); { - low32 = iosapic_intr_info[vec].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT); + low32 = iosapic_intr_info[vec].low32 & + ~(7 << IOSAPIC_DELIVERY_SHIFT); if (redir) /* change delivery mode to lowest priority */ - low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT); + low32 |= (IOSAPIC_LOWEST_PRIORITY << + IOSAPIC_DELIVERY_SHIFT); else /* change delivery mode to fixed */ low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); iosapic_intr_info[vec].low32 = low32; iosapic_intr_info[vec].dest = dest; - list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list) { + list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, + rte_list) { addr = rte->addr; rte_index = rte->rte_index; - iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); + iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), + high32); iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); } } @@ -433,7 +464,8 @@ iosapic_ack_edge_irq (unsigned int irq) * interrupt for real. This prevents IRQ storms from unhandled * devices. */ - if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == (IRQ_PENDING|IRQ_DISABLED)) + if ((idesc->status & (IRQ_PENDING|IRQ_DISABLED)) == + (IRQ_PENDING|IRQ_DISABLED)) mask_irq(irq); } @@ -467,7 +499,8 @@ iosapic_version (char __iomem *addr) return iosapic_read(addr, IOSAPIC_VERSION); } -static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long pol) +static int iosapic_find_sharable_vector (unsigned long trigger, + unsigned long pol) { int i, vector = -1, min_count = -1; struct iosapic_intr_info *info; @@ -482,7 +515,8 @@ static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long po for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) { info = &iosapic_intr_info[i]; if (info->trigger == trigger && info->polarity == pol && - (info->dmode == IOSAPIC_FIXED || info->dmode == IOSAPIC_LOWEST_PRIORITY)) { + (info->dmode == IOSAPIC_FIXED || info->dmode == + IOSAPIC_LOWEST_PRIORITY)) { if (min_count == -1 || info->count < min_count) { vector = i; min_count = info->count; @@ -506,12 +540,15 @@ iosapic_reassign_vector (int vector) new_vector = assign_irq_vector(AUTO_ASSIGN); if (new_vector < 0) panic("%s: out of interrupt vectors!\n", __FUNCTION__); - printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector); + printk(KERN_INFO "Reassigning vector %d to %d\n", + vector, new_vector); memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector], sizeof(struct iosapic_intr_info)); INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes); - list_move(iosapic_intr_info[vector].rtes.next, &iosapic_intr_info[new_vector].rtes); - memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); + list_move(iosapic_intr_info[vector].rtes.next, + &iosapic_intr_info[new_vector].rtes); + memset(&iosapic_intr_info[vector], 0, + sizeof(struct iosapic_intr_info)); iosapic_intr_info[vector].low32 = IOSAPIC_MASK; INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); } @@ -524,7 +561,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void) int preallocated = 0; if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) { - rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * NR_PREALLOCATE_RTE_ENTRIES); + rte = alloc_bootmem(sizeof(struct iosapic_rte_info) * + NR_PREALLOCATE_RTE_ENTRIES); if (!rte) return NULL; for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++) @@ -532,7 +570,8 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void) } if (!list_empty(&free_rte_list)) { - rte = list_entry(free_rte_list.next, struct iosapic_rte_info, rte_list); + rte = list_entry(free_rte_list.next, struct iosapic_rte_info, + rte_list); list_del(&rte->rte_list); preallocated++; } else { @@ -575,7 +614,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, index = find_iosapic(gsi); if (index < 0) { - printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi); + printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", + __FUNCTION__, gsi); return -ENODEV; } @@ -586,7 +626,8 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, if (!rte) { rte = iosapic_alloc_rte(); if (!rte) { - printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__); + printk(KERN_WARNING "%s: cannot allocate memory\n", + __FUNCTION__); return -ENOMEM; } @@ -602,7 +643,9 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, else if (vector_is_shared(vector)) { struct iosapic_intr_info *info = &iosapic_intr_info[vector]; if (info->trigger != trigger || info->polarity != polarity) { - printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__); + printk (KERN_WARNING + "%s: cannot override the interrupt\n", + __FUNCTION__); return -EINVAL; } } @@ -619,8 +662,10 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, idesc = irq_descp(vector); if (idesc->handler != irq_type) { if (idesc->handler != &no_irq_type) - printk(KERN_WARNING "%s: changing vector %d from %s to %s\n", - __FUNCTION__, vector, idesc->handler->typename, irq_type->typename); + printk(KERN_WARNING + "%s: changing vector %d from %s to %s\n", + __FUNCTION__, vector, + idesc->handler->typename, irq_type->typename); idesc->handler = irq_type; } return 0; @@ -681,7 +726,7 @@ get_target_cpu (unsigned int gsi, int vector) if (!num_cpus) goto skip_numa_setup; - /* Use vector assigment to distribute across cpus in node */ + /* Use vector assignment to distribute across cpus in node */ cpu_index = vector % num_cpus; for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++) @@ -703,7 +748,7 @@ skip_numa_setup: } while (!cpu_online(cpu)); return cpu_physical_id(cpu); -#else +#else /* CONFIG_SMP */ return cpu_physical_id(smp_processor_id()); #endif } @@ -755,7 +800,8 @@ again: if (list_empty(&iosapic_intr_info[vector].rtes)) free_irq_vector(vector); spin_unlock(&iosapic_lock); - spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); + spin_unlock_irqrestore(&irq_descp(vector)->lock, + flags); goto again; } @@ -764,7 +810,8 @@ again: polarity, trigger); if (err < 0) { spin_unlock(&iosapic_lock); - spin_unlock_irqrestore(&irq_descp(vector)->lock, flags); + spin_unlock_irqrestore(&irq_descp(vector)->lock, + flags); return err; } @@ -806,7 +853,8 @@ iosapic_unregister_intr (unsigned int gsi) */ irq = gsi_to_irq(gsi); if (irq < 0) { - printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); + printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", + gsi); WARN_ON(1); return; } @@ -817,7 +865,9 @@ iosapic_unregister_intr (unsigned int gsi) spin_lock(&iosapic_lock); { if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) { - printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi); + printk(KERN_ERR + "iosapic_unregister_intr(%u) unbalanced\n", + gsi); WARN_ON(1); goto out; } @@ -827,7 +877,8 @@ iosapic_unregister_intr (unsigned int gsi) /* Mask the interrupt */ low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK; - iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), low32); + iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index), + low32); /* Remove the rte entry from the list */ list_del(&rte->rte_list); @@ -840,7 +891,9 @@ iosapic_unregister_intr (unsigned int gsi) trigger = iosapic_intr_info[vector].trigger; polarity = iosapic_intr_info[vector].polarity; dest = iosapic_intr_info[vector].dest; - printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n", + printk(KERN_INFO + "GSI %u (%s, %s) -> CPU %d (0x%04x)" + " vector %d unregistered\n", gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), cpu_logical_id(dest), dest, vector); @@ -853,12 +906,15 @@ iosapic_unregister_intr (unsigned int gsi) idesc->handler = &no_irq_type; /* Clear the interrupt information */ - memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info)); + memset(&iosapic_intr_info[vector], 0, + sizeof(struct iosapic_intr_info)); iosapic_intr_info[vector].low32 |= IOSAPIC_MASK; INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); if (idesc->action) { - printk(KERN_ERR "interrupt handlers still exist on IRQ %u\n", irq); + printk(KERN_ERR + "interrupt handlers still exist on" + "IRQ %u\n", irq); WARN_ON(1); } @@ -873,7 +929,6 @@ iosapic_unregister_intr (unsigned int gsi) /* * ACPI calls this when it finds an entry for a platform interrupt. - * Note that the irq_base and IOSAPIC address must be set in iosapic_init(). */ int __init iosapic_register_platform_intr (u32 int_type, unsigned int gsi, @@ -907,13 +962,16 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi, mask = 1; break; default: - printk(KERN_ERR "iosapic_register_platform_irq(): invalid int type 0x%x\n", int_type); + printk(KERN_ERR "%s: invalid int type 0x%x\n", __FUNCTION__, + int_type); return -1; } register_intr(gsi, vector, delivery, polarity, trigger); - printk(KERN_INFO "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n", + printk(KERN_INFO + "PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)" + " vector %d\n", int_type < ARRAY_SIZE(name) ? name[int_type] : "unknown", int_type, gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"), (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), @@ -923,10 +981,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi, return vector; } - /* * ACPI calls this when it finds an entry for a legacy ISA IRQ override. - * Note that the gsi_base and IOSAPIC address must be set in iosapic_init(). */ void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, @@ -955,16 +1011,19 @@ iosapic_system_init (int system_pcat_compat) for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) { iosapic_intr_info[vector].low32 = IOSAPIC_MASK; - INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); /* mark as unused */ + /* mark as unused */ + INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes); } pcat_compat = system_pcat_compat; if (pcat_compat) { /* - * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support - * enabled. + * Disable the compatibility mode interrupts (8259 style), + * needs IN/OUT support enabled. */ - printk(KERN_INFO "%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__); + printk(KERN_INFO + "%s: Disabling PC-AT compatible 8259 interrupts\n", + __FUNCTION__); outb(0xff, 0xA1); outb(0xff, 0x21); } @@ -1004,10 +1063,7 @@ iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver) base = iosapic_lists[index].gsi_base; end = base + iosapic_lists[index].num_rte - 1; - if (gsi_base < base && gsi_end < base) - continue;/* OK */ - - if (gsi_base > end && gsi_end > end) + if (gsi_end < base || end < gsi_base) continue; /* OK */ return -EBUSY; @@ -1053,12 +1109,14 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) if ((gsi_base == 0) && pcat_compat) { /* - * Map the legacy ISA devices into the IOSAPIC data. Some of these may - * get reprogrammed later on with data from the ACPI Interrupt Source - * Override table. + * Map the legacy ISA devices into the IOSAPIC data. Some of + * these may get reprogrammed later on with data from the ACPI + * Interrupt Source Override table. */ for (isa_irq = 0; isa_irq < 16; ++isa_irq) - iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); + iosapic_override_isa_irq(isa_irq, isa_irq, + IOSAPIC_POL_HIGH, + IOSAPIC_EDGE); } return 0; } @@ -1081,7 +1139,8 @@ iosapic_remove (unsigned int gsi_base) if (iosapic_lists[index].rtes_inuse) { err = -EBUSY; - printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", + printk(KERN_WARNING + "%s: IOSAPIC for GSI base %u is busy\n", __FUNCTION__, gsi_base); goto out; } diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 8963171788d5..6a0880639bc9 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -581,10 +581,12 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs) { unsigned long flags; int cpu = smp_processor_id(); + struct ia64_mca_notify_die nd = + { .sos = NULL, .monarch_cpu = &monarch_cpu }; /* Mask all interrupts */ local_irq_save(flags); - if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, 0, 0, 0) + if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -594,7 +596,7 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs) */ ia64_sal_mc_rendez(); - if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, 0, 0, 0) + if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -602,7 +604,7 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs) while (monarch_cpu != -1) cpu_relax(); /* spin until monarch leaves */ - if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, 0, 0, 0) + if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -961,7 +963,7 @@ no_mod: */ static void -ia64_wait_for_slaves(int monarch) +ia64_wait_for_slaves(int monarch, const char *type) { int c, wait = 0, missing = 0; for_each_online_cpu(c) { @@ -987,7 +989,7 @@ ia64_wait_for_slaves(int monarch) } if (!missing) goto all_in; - printk(KERN_INFO "OS MCA slave did not rendezvous on cpu"); + printk(KERN_INFO "OS %s slave did not rendezvous on cpu", type); for_each_online_cpu(c) { if (c == monarch) continue; @@ -998,7 +1000,7 @@ ia64_wait_for_slaves(int monarch) return; all_in: - printk(KERN_INFO "All OS MCA slaves have reached rendezvous\n"); + printk(KERN_INFO "All OS %s slaves have reached rendezvous\n", type); return; } @@ -1023,6 +1025,8 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, &sos->proc_state_param; int recover, cpu = smp_processor_id(); task_t *previous_current; + struct ia64_mca_notify_die nd = + { .sos = sos, .monarch_cpu = &monarch_cpu }; oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ console_loglevel = 15; /* make sure printks make it to console */ @@ -1031,10 +1035,10 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA"); monarch_cpu = cpu; - if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, 0, 0, 0) + if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); - ia64_wait_for_slaves(cpu); + ia64_wait_for_slaves(cpu, "MCA"); /* Wakeup all the processors which are spinning in the rendezvous loop. * They will leave SAL, then spin in the OS with interrupts disabled @@ -1043,7 +1047,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, * spinning in SAL does not work. */ ia64_mca_wakeup_all(); - if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, 0, 0, 0) + if (notify_die(DIE_MCA_MONARCH_PROCESS, "MCA", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -1064,7 +1068,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw, ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); sos->os_status = IA64_MCA_CORRECTED; } - if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, 0, 0, recover) + if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -1351,10 +1355,14 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, static atomic_t monarchs; task_t *previous_current; int cpu = smp_processor_id(); + struct ia64_mca_notify_die nd = + { .sos = sos, .monarch_cpu = &monarch_cpu }; oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */ console_loglevel = 15; /* make sure printks make it to console */ + (void) notify_die(DIE_INIT_ENTER, "INIT", regs, (long)&nd, 0, 0); + printk(KERN_INFO "Entered OS INIT handler. PSP=%lx cpu=%d monarch=%ld\n", sos->proc_state_param, cpu, sos->monarch); salinfo_log_wakeup(SAL_INFO_TYPE_INIT, NULL, 0, 0); @@ -1390,15 +1398,15 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_INIT; while (monarch_cpu == -1) cpu_relax(); /* spin until monarch enters */ - if (notify_die(DIE_INIT_SLAVE_ENTER, "INIT", regs, 0, 0, 0) + if (notify_die(DIE_INIT_SLAVE_ENTER, "INIT", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); - if (notify_die(DIE_INIT_SLAVE_PROCESS, "INIT", regs, 0, 0, 0) + if (notify_die(DIE_INIT_SLAVE_PROCESS, "INIT", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); while (monarch_cpu != -1) cpu_relax(); /* spin until monarch leaves */ - if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, 0, 0, 0) + if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); printk("Slave on cpu %d returning to normal service.\n", cpu); @@ -1409,7 +1417,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, } monarch_cpu = cpu; - if (notify_die(DIE_INIT_MONARCH_ENTER, "INIT", regs, 0, 0, 0) + if (notify_die(DIE_INIT_MONARCH_ENTER, "INIT", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); @@ -1421,15 +1429,15 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw, */ printk("Delaying for 5 seconds...\n"); udelay(5*1000000); - ia64_wait_for_slaves(cpu); + ia64_wait_for_slaves(cpu, "INIT"); /* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through * to default_monarch_init_process() above and just print all the * tasks. */ - if (notify_die(DIE_INIT_MONARCH_PROCESS, "INIT", regs, 0, 0, 0) + if (notify_die(DIE_INIT_MONARCH_PROCESS, "INIT", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); - if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, 0, 0, 0) + if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, (long)&nd, 0, 0) == NOTIFY_STOP) ia64_mca_spin(__FUNCTION__); printk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu); @@ -1631,6 +1639,7 @@ ia64_mca_init(void) printk(KERN_INFO "Increasing MCA rendezvous timeout from " "%ld to %ld milliseconds\n", timeout, isrv.v0); timeout = isrv.v0; + (void) notify_die(DIE_MCA_NEW_TIMEOUT, "MCA", NULL, timeout, 0, 0); continue; } printk(KERN_ERR "Failed to register rendezvous interrupt " diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index 60a464bfd9e2..6dff024cd62b 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -827,7 +827,7 @@ ia64_state_restore: ld8 r9=[temp2],16 // sal_gp ;; ld8 r22=[temp1],16 // pal_min_state, virtual - ld8 r21=[temp2],16 // prev_IA64_KR_CURRENT + ld8 r13=[temp2],16 // prev_IA64_KR_CURRENT ;; ld8 r16=[temp1],16 // prev_IA64_KR_CURRENT_STACK ld8 r20=[temp2],16 // prev_task @@ -848,7 +848,7 @@ ia64_state_restore: mov cr.iim=temp3 mov cr.iha=temp4 dep r22=0,r22,62,1 // pal_min_state, physical, uncached - mov IA64_KR(CURRENT)=r21 + mov IA64_KR(CURRENT)=r13 ld8 r8=[temp1] // os_status ld8 r10=[temp2] // context @@ -856,7 +856,7 @@ ia64_state_restore: * avoid any dependencies on the algorithm in ia64_switch_to(), just * purge any existing CURRENT_STACK mapping and insert the new one. * - * r16 contains prev_IA64_KR_CURRENT_STACK, r21 contains + * r16 contains prev_IA64_KR_CURRENT_STACK, r13 contains * prev_IA64_KR_CURRENT, these values may have been changed by the C * code. Do not use r8, r9, r10, r22, they contain values ready for * the return to SAL. @@ -873,7 +873,7 @@ ia64_state_restore: ;; srlz.d - extr.u r19=r21,61,3 // r21 = prev_IA64_KR_CURRENT + extr.u r19=r13,61,3 // r13 = prev_IA64_KR_CURRENT shl r20=r16,IA64_GRANULE_SHIFT // r16 = prev_IA64_KR_CURRENT_STACK movl r21=PAGE_KERNEL // page properties ;; @@ -883,7 +883,7 @@ ia64_state_restore: (p6) br.spnt 1f // the dreaded cpu 0 idle task in region 5:( ;; mov cr.itir=r18 - mov cr.ifa=r21 + mov cr.ifa=r13 mov r20=IA64_TR_CURRENT_STACK ;; itr.d dtr[r20]=r21 diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 7a2f0a798d12..3a30cfc9574f 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -947,7 +947,7 @@ void percpu_modcopy (void *pcpudst, const void *src, unsigned long size) { unsigned int i; - for_each_cpu(i) { + for_each_possible_cpu(i) { memcpy(pcpudst + __per_cpu_offset[i], src, size); } } diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c index 89faa603c6be..6386f63c413e 100644 --- a/arch/ia64/kernel/palinfo.c +++ b/arch/ia64/kernel/palinfo.c @@ -240,7 +240,7 @@ cache_info(char *page) } p += sprintf(p, "%s Cache level %lu:\n" - "\tSize : %lu bytes\n" + "\tSize : %u bytes\n" "\tAttributes : ", cache_types[j+cci.pcci_unified], i+1, cci.pcci_cache_size); @@ -648,9 +648,9 @@ frequency_info(char *page) if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0; p += sprintf(p, - "Processor/Clock ratio : %ld/%ld\n" - "Bus/Clock ratio : %ld/%ld\n" - "ITC/Clock ratio : %ld/%ld\n", + "Processor/Clock ratio : %d/%d\n" + "Bus/Clock ratio : %d/%d\n" + "ITC/Clock ratio : %d/%d\n", proc.num, proc.den, bus.num, bus.den, itc.num, itc.den); return p - page; diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index ac167436e936..49958904045b 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -188,7 +188,7 @@ ia64_init_itm (void) itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; - printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " + printk(KERN_DEBUG "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%u/%u, " "ITC freq=%lu.%03luMHz", smp_processor_id(), platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c index 3b6fd798c4d6..b47476d655f1 100644 --- a/arch/ia64/kernel/topology.c +++ b/arch/ia64/kernel/topology.c @@ -9,6 +9,8 @@ * 2002/08/07 Erich Focht * Populate cpu entries in sysfs for non-numa systems as well * Intel Corporation - Ashok Raj + * 02/27/2006 Zhang, Yanmin + * Populate cpu cache entries in sysfs for cpu cache info */ #include @@ -19,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -101,3 +104,367 @@ out: } subsys_initcall(topology_init); + + +/* + * Export cpu cache information through sysfs + */ + +/* + * A bunch of string array to get pretty printing + */ +static const char *cache_types[] = { + "", /* not used */ + "Instruction", + "Data", + "Unified" /* unified */ +}; + +static const char *cache_mattrib[]={ + "WriteThrough", + "WriteBack", + "", /* reserved */ + "" /* reserved */ +}; + +struct cache_info { + pal_cache_config_info_t cci; + cpumask_t shared_cpu_map; + int level; + int type; + struct kobject kobj; +}; + +struct cpu_cache_info { + struct cache_info *cache_leaves; + int num_cache_leaves; + struct kobject kobj; +}; + +static struct cpu_cache_info all_cpu_cache_info[NR_CPUS]; +#define LEAF_KOBJECT_PTR(x,y) (&all_cpu_cache_info[x].cache_leaves[y]) + +#ifdef CONFIG_SMP +static void cache_shared_cpu_map_setup( unsigned int cpu, + struct cache_info * this_leaf) +{ + pal_cache_shared_info_t csi; + int num_shared, i = 0; + unsigned int j; + + if (cpu_data(cpu)->threads_per_core <= 1 && + cpu_data(cpu)->cores_per_socket <= 1) { + cpu_set(cpu, this_leaf->shared_cpu_map); + return; + } + + if (ia64_pal_cache_shared_info(this_leaf->level, + this_leaf->type, + 0, + &csi) != PAL_STATUS_SUCCESS) + return; + + num_shared = (int) csi.num_shared; + do { + for_each_cpu(j) + if (cpu_data(cpu)->socket_id == cpu_data(j)->socket_id + && cpu_data(j)->core_id == csi.log1_cid + && cpu_data(j)->thread_id == csi.log1_tid) + cpu_set(j, this_leaf->shared_cpu_map); + + i++; + } while (i < num_shared && + ia64_pal_cache_shared_info(this_leaf->level, + this_leaf->type, + i, + &csi) == PAL_STATUS_SUCCESS); +} +#else +static void cache_shared_cpu_map_setup(unsigned int cpu, + struct cache_info * this_leaf) +{ + cpu_set(cpu, this_leaf->shared_cpu_map); + return; +} +#endif + +static ssize_t show_coherency_line_size(struct cache_info *this_leaf, + char *buf) +{ + return sprintf(buf, "%u\n", 1 << this_leaf->cci.pcci_line_size); +} + +static ssize_t show_ways_of_associativity(struct cache_info *this_leaf, + char *buf) +{ + return sprintf(buf, "%u\n", this_leaf->cci.pcci_assoc); +} + +static ssize_t show_attributes(struct cache_info *this_leaf, char *buf) +{ + return sprintf(buf, + "%s\n", + cache_mattrib[this_leaf->cci.pcci_cache_attr]); +} + +static ssize_t show_size(struct cache_info *this_leaf, char *buf) +{ + return sprintf(buf, "%uK\n", this_leaf->cci.pcci_cache_size / 1024); +} + +static ssize_t show_number_of_sets(struct cache_info *this_leaf, char *buf) +{ + unsigned number_of_sets = this_leaf->cci.pcci_cache_size; + number_of_sets /= this_leaf->cci.pcci_assoc; + number_of_sets /= 1 << this_leaf->cci.pcci_line_size; + + return sprintf(buf, "%u\n", number_of_sets); +} + +static ssize_t show_shared_cpu_map(struct cache_info *this_leaf, char *buf) +{ + ssize_t len; + cpumask_t shared_cpu_map; + + cpus_and(shared_cpu_map, this_leaf->shared_cpu_map, cpu_online_map); + len = cpumask_scnprintf(buf, NR_CPUS+1, shared_cpu_map); + len += sprintf(buf+len, "\n"); + return len; +} + +static ssize_t show_type(struct cache_info *this_leaf, char *buf) +{ + int type = this_leaf->type + this_leaf->cci.pcci_unified; + return sprintf(buf, "%s\n", cache_types[type]); +} + +static ssize_t show_level(struct cache_info *this_leaf, char *buf) +{ + return sprintf(buf, "%u\n", this_leaf->level); +} + +struct cache_attr { + struct attribute attr; + ssize_t (*show)(struct cache_info *, char *); + ssize_t (*store)(struct cache_info *, const char *, size_t count); +}; + +#ifdef define_one_ro + #undef define_one_ro +#endif +#define define_one_ro(_name) \ + static struct cache_attr _name = \ +__ATTR(_name, 0444, show_##_name, NULL) + +define_one_ro(level); +define_one_ro(type); +define_one_ro(coherency_line_size); +define_one_ro(ways_of_associativity); +define_one_ro(size); +define_one_ro(number_of_sets); +define_one_ro(shared_cpu_map); +define_one_ro(attributes); + +static struct attribute * cache_default_attrs[] = { + &type.attr, + &level.attr, + &coherency_line_size.attr, + &ways_of_associativity.attr, + &attributes.attr, + &size.attr, + &number_of_sets.attr, + &shared_cpu_map.attr, + NULL +}; + +#define to_object(k) container_of(k, struct cache_info, kobj) +#define to_attr(a) container_of(a, struct cache_attr, attr) + +static ssize_t cache_show(struct kobject * kobj, struct attribute * attr, char * buf) +{ + struct cache_attr *fattr = to_attr(attr); + struct cache_info *this_leaf = to_object(kobj); + ssize_t ret; + + ret = fattr->show ? fattr->show(this_leaf, buf) : 0; + return ret; +} + +static struct sysfs_ops cache_sysfs_ops = { + .show = cache_show +}; + +static struct kobj_type cache_ktype = { + .sysfs_ops = &cache_sysfs_ops, + .default_attrs = cache_default_attrs, +}; + +static struct kobj_type cache_ktype_percpu_entry = { + .sysfs_ops = &cache_sysfs_ops, +}; + +static void __cpuinit cpu_cache_sysfs_exit(unsigned int cpu) +{ + if (all_cpu_cache_info[cpu].cache_leaves) { + kfree(all_cpu_cache_info[cpu].cache_leaves); + all_cpu_cache_info[cpu].cache_leaves = NULL; + } + all_cpu_cache_info[cpu].num_cache_leaves = 0; + memset(&all_cpu_cache_info[cpu].kobj, 0, sizeof(struct kobject)); + + return; +} + +static int __cpuinit cpu_cache_sysfs_init(unsigned int cpu) +{ + u64 i, levels, unique_caches; + pal_cache_config_info_t cci; + int j; + s64 status; + struct cache_info *this_cache; + int num_cache_leaves = 0; + + if ((status = ia64_pal_cache_summary(&levels, &unique_caches)) != 0) { + printk(KERN_ERR "ia64_pal_cache_summary=%ld\n", status); + return -1; + } + + this_cache=kzalloc(sizeof(struct cache_info)*unique_caches, + GFP_KERNEL); + if (this_cache == NULL) + return -ENOMEM; + + for (i=0; i < levels; i++) { + for (j=2; j >0 ; j--) { + if ((status=ia64_pal_cache_config_info(i,j, &cci)) != + PAL_STATUS_SUCCESS) + continue; + + this_cache[num_cache_leaves].cci = cci; + this_cache[num_cache_leaves].level = i + 1; + this_cache[num_cache_leaves].type = j; + + cache_shared_cpu_map_setup(cpu, + &this_cache[num_cache_leaves]); + num_cache_leaves ++; + } + } + + all_cpu_cache_info[cpu].cache_leaves = this_cache; + all_cpu_cache_info[cpu].num_cache_leaves = num_cache_leaves; + + memset(&all_cpu_cache_info[cpu].kobj, 0, sizeof(struct kobject)); + + return 0; +} + +/* Add cache interface for CPU device */ +static int __cpuinit cache_add_dev(struct sys_device * sys_dev) +{ + unsigned int cpu = sys_dev->id; + unsigned long i, j; + struct cache_info *this_object; + int retval = 0; + cpumask_t oldmask; + + if (all_cpu_cache_info[cpu].kobj.parent) + return 0; + + oldmask = current->cpus_allowed; + retval = set_cpus_allowed(current, cpumask_of_cpu(cpu)); + if (unlikely(retval)) + return retval; + + retval = cpu_cache_sysfs_init(cpu); + set_cpus_allowed(current, oldmask); + if (unlikely(retval < 0)) + return retval; + + all_cpu_cache_info[cpu].kobj.parent = &sys_dev->kobj; + kobject_set_name(&all_cpu_cache_info[cpu].kobj, "%s", "cache"); + all_cpu_cache_info[cpu].kobj.ktype = &cache_ktype_percpu_entry; + retval = kobject_register(&all_cpu_cache_info[cpu].kobj); + + for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) { + this_object = LEAF_KOBJECT_PTR(cpu,i); + this_object->kobj.parent = &all_cpu_cache_info[cpu].kobj; + kobject_set_name(&(this_object->kobj), "index%1lu", i); + this_object->kobj.ktype = &cache_ktype; + retval = kobject_register(&(this_object->kobj)); + if (unlikely(retval)) { + for (j = 0; j < i; j++) { + kobject_unregister( + &(LEAF_KOBJECT_PTR(cpu,j)->kobj)); + } + kobject_unregister(&all_cpu_cache_info[cpu].kobj); + cpu_cache_sysfs_exit(cpu); + break; + } + } + return retval; +} + +/* Remove cache interface for CPU device */ +static int __cpuinit cache_remove_dev(struct sys_device * sys_dev) +{ + unsigned int cpu = sys_dev->id; + unsigned long i; + + for (i = 0; i < all_cpu_cache_info[cpu].num_cache_leaves; i++) + kobject_unregister(&(LEAF_KOBJECT_PTR(cpu,i)->kobj)); + + if (all_cpu_cache_info[cpu].kobj.parent) { + kobject_unregister(&all_cpu_cache_info[cpu].kobj); + memset(&all_cpu_cache_info[cpu].kobj, + 0, + sizeof(struct kobject)); + } + + cpu_cache_sysfs_exit(cpu); + + return 0; +} + +/* + * When a cpu is hot-plugged, do a check and initiate + * cache kobject if necessary + */ +static int __cpuinit cache_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + struct sys_device *sys_dev; + + sys_dev = get_cpu_sysdev(cpu); + switch (action) { + case CPU_ONLINE: + cache_add_dev(sys_dev); + break; + case CPU_DEAD: + cache_remove_dev(sys_dev); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block cache_cpu_notifier = +{ + .notifier_call = cache_cpu_callback +}; + +static int __cpuinit cache_sysfs_init(void) +{ + int i; + + for_each_online_cpu(i) { + cache_cpu_callback(&cache_cpu_notifier, CPU_ONLINE, + (void *)(long)i); + } + + register_cpu_notifier(&cache_cpu_notifier); + + return 0; +} + +device_initcall(cache_sysfs_init); + diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S index 0b9e56dd7f05..783600fe52b2 100644 --- a/arch/ia64/kernel/vmlinux.lds.S +++ b/arch/ia64/kernel/vmlinux.lds.S @@ -70,6 +70,15 @@ SECTIONS __stop___ex_table = .; } + /* MCA table */ + . = ALIGN(16); + __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET) + { + __start___mca_table = .; + *(__mca_table) + __stop___mca_table = .; + } + /* Global data */ _data = .; @@ -130,15 +139,6 @@ SECTIONS __initcall_end = .; } - /* MCA table */ - . = ALIGN(16); - __mca_table : AT(ADDR(__mca_table) - LOAD_OFFSET) - { - __start___mca_table = .; - *(__mca_table) - __stop___mca_table = .; - } - .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET) { __start___vtop_patchlist = .; diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c index ec9eeb89975d..b6bcc9fa3603 100644 --- a/arch/ia64/mm/discontig.c +++ b/arch/ia64/mm/discontig.c @@ -519,6 +519,68 @@ void __cpuinit *per_cpu_init(void) } #endif /* CONFIG_SMP */ +#ifdef CONFIG_VIRTUAL_MEM_MAP +static inline int find_next_valid_pfn_for_pgdat(pg_data_t *pgdat, int i) +{ + unsigned long end_address, hole_next_pfn; + unsigned long stop_address; + + end_address = (unsigned long) &vmem_map[pgdat->node_start_pfn + i]; + end_address = PAGE_ALIGN(end_address); + + stop_address = (unsigned long) &vmem_map[ + pgdat->node_start_pfn + pgdat->node_spanned_pages]; + + do { + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_offset_k(end_address); + if (pgd_none(*pgd)) { + end_address += PGDIR_SIZE; + continue; + } + + pud = pud_offset(pgd, end_address); + if (pud_none(*pud)) { + end_address += PUD_SIZE; + continue; + } + + pmd = pmd_offset(pud, end_address); + if (pmd_none(*pmd)) { + end_address += PMD_SIZE; + continue; + } + + pte = pte_offset_kernel(pmd, end_address); +retry_pte: + if (pte_none(*pte)) { + end_address += PAGE_SIZE; + pte++; + if ((end_address < stop_address) && + (end_address != ALIGN(end_address, 1UL << PMD_SHIFT))) + goto retry_pte; + continue; + } + /* Found next valid vmem_map page */ + break; + } while (end_address < stop_address); + + end_address = min(end_address, stop_address); + end_address = end_address - (unsigned long) vmem_map + sizeof(struct page) - 1; + hole_next_pfn = end_address / sizeof(struct page); + return hole_next_pfn - pgdat->node_start_pfn; +} +#else +static inline int find_next_valid_pfn_for_pgdat(pg_data_t *pgdat, int i) +{ + return i + 1; +} +#endif + /** * show_mem - give short summary of memory stats * @@ -547,8 +609,10 @@ void show_mem(void) struct page *page; if (pfn_valid(pgdat->node_start_pfn + i)) page = pfn_to_page(pgdat->node_start_pfn + i); - else + else { + i = find_next_valid_pfn_for_pgdat(pgdat, i) - 1; continue; + } if (PageReserved(page)) reserved++; else if (PageSwapCache(page)) diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index af7eb087dca7..d98ec49570b8 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c @@ -60,6 +60,9 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re struct siginfo si; unsigned long mask; + /* mmap_sem is performance critical.... */ + prefetchw(&mm->mmap_sem); + /* * If we're in an interrupt or have no user context, we must not take the fault.. */ diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 2ef1151cde90..cafa8776a53d 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -109,6 +109,7 @@ lazy_mmu_prot_update (pte_t pte) { unsigned long addr; struct page *page; + unsigned long order; if (!pte_exec(pte)) return; /* not an executable page... */ @@ -119,7 +120,12 @@ lazy_mmu_prot_update (pte_t pte) if (test_bit(PG_arch_1, &page->flags)) return; /* i-cache is already coherent with d-cache */ - flush_icache_range(addr, addr + PAGE_SIZE); + if (PageCompound(page)) { + order = (unsigned long) (page[1].lru.prev); + flush_icache_range(addr, addr + (1UL << order << PAGE_SHIFT)); + } + else + flush_icache_range(addr, addr + PAGE_SIZE); set_bit(PG_arch_1, &page->flags); /* mark page as clean */ } diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c index 62328621f99c..643ccc6960ce 100644 --- a/arch/ia64/mm/ioremap.c +++ b/arch/ia64/mm/ioremap.c @@ -21,12 +21,12 @@ __ioremap (unsigned long offset, unsigned long size) void __iomem * ioremap (unsigned long offset, unsigned long size) { - if (efi_mem_attribute_range(offset, size, EFI_MEMORY_UC)) - return __ioremap(offset, size); - if (efi_mem_attribute_range(offset, size, EFI_MEMORY_WB)) return phys_to_virt(offset); + if (efi_mem_attribute_range(offset, size, EFI_MEMORY_UC)) + return __ioremap(offset, size); + /* * Someday this should check ACPI resources so we * can do the right thing for hot-plugged regions. diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c index 6a4eec9113e8..4dbbca0b5e9c 100644 --- a/arch/ia64/mm/tlb.c +++ b/arch/ia64/mm/tlb.c @@ -156,17 +156,19 @@ flush_tlb_range (struct vm_area_struct *vma, unsigned long start, nbits = purge.max_bits; start &= ~((1UL << nbits) - 1); -# ifdef CONFIG_SMP - platform_global_tlb_purge(mm, start, end, nbits); -# else preempt_disable(); +#ifdef CONFIG_SMP + if (mm != current->active_mm || cpus_weight(mm->cpu_vm_mask) != 1) { + platform_global_tlb_purge(mm, start, end, nbits); + preempt_enable(); + return; + } +#endif do { ia64_ptcl(start, (nbits<<2)); start += (1UL << nbits); } while (start < end); preempt_enable(); -# endif - ia64_srlz_i(); /* srlz.i implies srlz.d */ } EXPORT_SYMBOL(flush_tlb_range); diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index 70db21f3df21..d917afa30b27 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -110,7 +110,11 @@ static int sn_hwperf_geoid_to_cnode(char *location) if (sn_hwperf_location_to_bpos(location, &rack, &bay, &slot, &slab)) return -1; - for_each_node(cnode) { + /* + * FIXME: replace with cleaner for_each_XXX macro which addresses + * both compute and IO nodes once ACPI3.0 is available. + */ + for (cnode = 0; cnode < num_cnodes; cnode++) { geoid = cnodeid_get_geoid(cnode); module_id = geo_module(geoid); this_rack = MODULE_GET_RACK(module_id); @@ -605,7 +609,7 @@ static int sn_hwperf_op_cpu(struct sn_hwperf_op_info *op_info) op_info->a->arg &= SN_HWPERF_ARG_OBJID_MASK; if (cpu != SN_HWPERF_ARG_ANY_CPU) { - if (cpu >= num_online_cpus() || !cpu_online(cpu)) { + if (cpu >= NR_CPUS || !cpu_online(cpu)) { r = -EINVAL; goto out; } diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c index d0abddd9ffe6..8255a9be4632 100644 --- a/arch/ia64/sn/kernel/xpc_channel.c +++ b/arch/ia64/sn/kernel/xpc_channel.c @@ -1831,7 +1831,7 @@ xpc_initiate_allocate(partid_t partid, int ch_number, u32 flags, void **payload) { struct xpc_partition *part = &xpc_partitions[partid]; enum xpc_retval ret = xpcUnknownReason; - struct xpc_msg *msg; + struct xpc_msg *msg = NULL; DBUG_ON(partid <= 0 || partid >= XP_MAX_PARTITIONS); diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 05c864c6c2d9..41fd490af3b4 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -285,6 +285,11 @@ config NUMA depends on SMP && BROKEN default n +config NODES_SHIFT + int + default "1" + depends on NEED_MULTIPLE_NODES + # turning this on wastes a bunch of space. # Summit needs it only when NUMA is on config BOOT_IOREMAP diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c index be8b711367ec..c50330fa83b9 100644 --- a/arch/m32r/kernel/m32r_ksyms.c +++ b/arch/m32r/kernel/m32r_ksyms.c @@ -23,9 +23,6 @@ EXPORT_SYMBOL(boot_cpu_data); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); -EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(__down); EXPORT_SYMBOL(__down_interruptible); @@ -38,13 +35,6 @@ EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(__const_udelay); -EXPORT_SYMBOL(__get_user_1); -EXPORT_SYMBOL(__get_user_2); -EXPORT_SYMBOL(__get_user_4); - -EXPORT_SYMBOL(strpbrk); -EXPORT_SYMBOL(strstr); - EXPORT_SYMBOL(strncpy_from_user); EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(clear_user); @@ -59,11 +49,8 @@ extern void *dcache_dummy; EXPORT_SYMBOL(dcache_dummy); #endif EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(cpu_online_map); -EXPORT_SYMBOL(cpu_callout_map); /* Global SMP stuff */ -EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(smp_call_function); /* TLB flushing */ @@ -83,27 +70,11 @@ EXPORT_SYMBOL(__lshrdi3); EXPORT_SYMBOL(__muldi3); /* memory and string operations */ -EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(memcpy); -/* EXPORT_SYMBOL(memcpy_fromio); // not implement yet */ -/* EXPORT_SYMBOL(memcpy_toio); // not implement yet */ EXPORT_SYMBOL(memset); -/* EXPORT_SYMBOL(memset_io); // not implement yet */ -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(clear_page); - -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strncmp); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strncpy); EXPORT_SYMBOL(_inb); EXPORT_SYMBOL(_inw); diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c index 0d78942b4c76..3cd3c2988a48 100644 --- a/arch/m32r/kernel/setup.c +++ b/arch/m32r/kernel/setup.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -219,8 +220,6 @@ static unsigned long __init setup_memory(void) extern unsigned long setup_memory(void); #endif /* CONFIG_DISCONTIGMEM */ -#define M32R_PCC_PCATCR 0x00ef7014 /* will move to m32r.h */ - void __init setup_arch(char **cmdline_p) { ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV); @@ -269,15 +268,14 @@ void __init setup_arch(char **cmdline_p) paging_init(); } -static struct cpu cpu[NR_CPUS]; +static struct cpu cpu_devices[NR_CPUS]; static int __init topology_init(void) { - int cpu_id; + int i; - for (cpu_id = 0; cpu_id < NR_CPUS; cpu_id++) - if (cpu_possible(cpu_id)) - register_cpu(&cpu[cpu_id], cpu_id, NULL); + for_each_present_cpu(i) + register_cpu(&cpu_devices[i], i, NULL); return 0; } diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c index d7ec16e7fb25..840b4348bf0c 100644 --- a/arch/m32r/kernel/smpboot.c +++ b/arch/m32r/kernel/smpboot.c @@ -39,8 +39,10 @@ * Martin J. Bligh : Added support for multi-quad systems */ +#include #include #include +#include #include #include #include @@ -72,11 +74,15 @@ physid_mask_t phys_cpu_present_map; /* Bitmask of currently online CPUs */ cpumask_t cpu_online_map; +EXPORT_SYMBOL(cpu_online_map); cpumask_t cpu_bootout_map; cpumask_t cpu_bootin_map; -cpumask_t cpu_callout_map; static cpumask_t cpu_callin_map; +cpumask_t cpu_callout_map; +EXPORT_SYMBOL(cpu_callout_map); +cpumask_t cpu_possible_map = CPU_MASK_ALL; +EXPORT_SYMBOL(cpu_possible_map); /* Per CPU bogomips and other parameters */ struct cpuinfo_m32r cpu_data[NR_CPUS] __cacheline_aligned; @@ -110,7 +116,6 @@ static unsigned int calibration_result; void smp_prepare_boot_cpu(void); void smp_prepare_cpus(unsigned int); -static void smp_tune_scheduling(void); static void init_ipi_lock(void); static void do_boot_cpu(int); int __cpu_up(unsigned int); @@ -177,6 +182,9 @@ void __init smp_prepare_cpus(unsigned int max_cpus) } for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++) physid_set(phys_id, phys_cpu_present_map); +#ifndef CONFIG_HOTPLUG_CPU + cpu_present_map = cpu_possible_map; +#endif show_mp_info(nr_cpu); @@ -186,7 +194,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) * Setup boot CPU information */ smp_store_cpu_info(0); /* Final full version of the data */ - smp_tune_scheduling(); /* * If SMP should be disabled, then really disable it! @@ -230,11 +237,6 @@ smp_done: Dprintk("Boot done.\n"); } -static void __init smp_tune_scheduling(void) -{ - /* Nothing to do. */ -} - /* * init_ipi_lock : Initialize IPI locks. */ @@ -629,4 +631,3 @@ static void __init unmap_cpu_to_physid(int cpu_id, int phys_id) physid_2_cpu[phys_id] = -1; cpu_2_physid[cpu_id] = -1; } - diff --git a/arch/m32r/lib/Makefile b/arch/m32r/lib/Makefile index e632d10c7d78..d16b4e40d1ae 100644 --- a/arch/m32r/lib/Makefile +++ b/arch/m32r/lib/Makefile @@ -2,6 +2,6 @@ # Makefile for M32R-specific library files.. # -lib-y := checksum.o ashxdi3.o memset.o memcpy.o getuser.o \ - putuser.o delay.o strlen.o usercopy.o csum_partial_copy.o +lib-y := checksum.o ashxdi3.o memset.o memcpy.o \ + delay.o strlen.o usercopy.o csum_partial_copy.o diff --git a/arch/m32r/lib/getuser.S b/arch/m32r/lib/getuser.S deleted file mode 100644 index 58a0db055c5c..000000000000 --- a/arch/m32r/lib/getuser.S +++ /dev/null @@ -1,88 +0,0 @@ -/* - * __get_user functions. - * - * (C) Copyright 2001 Hirokazu Takata - * - * These functions have a non-standard call interface - * to make them more efficient, especially as they - * return an error value in addition to the "real" - * return value. - */ - -#include - -/* - * __get_user_X - * - * Inputs: r0 contains the address - * - * Outputs: r0 is error code (0 or -EFAULT) - * r1 contains zero-extended value - * - * These functions should not modify any other registers, - * as they get called from within inline assembly. - */ - -#ifdef CONFIG_ISA_DUAL_ISSUE - - .text - .balign 4 - .globl __get_user_1 -__get_user_1: -1: ldub r1, @r0 || ldi r0, #0 - jmp r14 - - .balign 4 - .globl __get_user_2 -__get_user_2: -2: lduh r1, @r0 || ldi r0, #0 - jmp r14 - - .balign 4 - .globl __get_user_4 -__get_user_4: -3: ld r1, @r0 || ldi r0, #0 - jmp r14 - -bad_get_user: - ldi r1, #0 || ldi r0, #-14 - jmp r14 - -#else /* not CONFIG_ISA_DUAL_ISSUE */ - - .text - .balign 4 - .globl __get_user_1 -__get_user_1: -1: ldub r1, @r0 - ldi r0, #0 - jmp r14 - - .balign 4 - .globl __get_user_2 -__get_user_2: -2: lduh r1, @r0 - ldi r0, #0 - jmp r14 - - .balign 4 - .globl __get_user_4 -__get_user_4: -3: ld r1, @r0 - ldi r0, #0 - jmp r14 - -bad_get_user: - ldi r1, #0 - ldi r0, #-14 - jmp r14 - -#endif /* not CONFIG_ISA_DUAL_ISSUE */ - -.section __ex_table,"a" - .long 1b,bad_get_user - .long 2b,bad_get_user - .long 3b,bad_get_user -.previous - - .end diff --git a/arch/m32r/lib/putuser.S b/arch/m32r/lib/putuser.S deleted file mode 100644 index 218154cc3890..000000000000 --- a/arch/m32r/lib/putuser.S +++ /dev/null @@ -1,84 +0,0 @@ -/* - * __put_user functions. - * - * (C) Copyright 1998 Linus Torvalds - * (C) Copyright 2001 Hirokazu Takata - * - * These functions have a non-standard call interface - * to make them more efficient. - */ - -#include - -/* - * __put_user_X - * - * Inputs: r0 contains the address - * r1 contains the value - * - * Outputs: r0 is error code (0 or -EFAULT) - * r1 is corrupted (will contain "current_task"). - * - * These functions should not modify any other registers, - * as they get called from within inline assembly. - */ - -#ifdef CONFIG_ISA_DUAL_ISSUE - - .text - .balign 4 - .globl __put_user_1 -__put_user_1: -1: stb r1, @r0 || ldi r0, #0 - jmp r14 - - .balign 4 - .globl __put_user_2 -__put_user_2: -2: sth r1, @r0 || ldi r0, #0 - jmp r14 - - .balign 4 - .globl __put_user_4 -__put_user_4: -3: st r1, @r0 || ldi r0, #0 - jmp r14 - -bad_put_user: - ldi r0, #-14 || jmp r14 - -#else /* not CONFIG_ISA_DUAL_ISSUE */ - - .text - .balign 4 - .globl __put_user_1 -__put_user_1: -1: stb r1, @r0 - ldi r0, #0 - jmp r14 - - .balign 4 - .globl __put_user_2 -__put_user_2: -2: sth r1, @r0 - ldi r0, #0 - jmp r14 - - .balign 4 - .globl __put_user_4 -__put_user_4: -3: st r1, @r0 - ldi r0, #0 - jmp r14 - -bad_put_user: - ldi r0, #-14 - jmp r14 - -#endif /* not CONFIG_ISA_DUAL_ISSUE */ - -.section __ex_table,"a" - .long 1b,bad_put_user - .long 2b,bad_put_user - .long 3b,bad_put_user -.previous diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c index 3d7f2000b714..5b7952ea2bae 100644 --- a/arch/m68k/kernel/m68k_ksyms.c +++ b/arch/m68k/kernel/m68k_ksyms.c @@ -57,7 +57,6 @@ EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(kernel_thread); @@ -79,4 +78,3 @@ EXPORT_SYMBOL(__down_failed_interruptible); EXPORT_SYMBOL(__down_failed_trylock); EXPORT_SYMBOL(__up_wakeup); -EXPORT_SYMBOL(get_wchan); diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c index d844c755945a..4320d5dcc9cb 100644 --- a/arch/m68knommu/kernel/m68k_ksyms.c +++ b/arch/m68knommu/kernel/m68k_ksyms.c @@ -26,7 +26,6 @@ EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strchr); @@ -57,8 +56,6 @@ EXPORT_SYMBOL(__down_failed_interruptible); EXPORT_SYMBOL(__down_failed_trylock); EXPORT_SYMBOL(__up_wakeup); -EXPORT_SYMBOL(get_wchan); - /* * libgcc functions - functions that are used internally by the * compiler... (prototypes are not correct though, but that diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 5080ea1799a4..7aec60d40420 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -233,6 +233,7 @@ config MACH_JAZZ select ARC32 select ARCH_MAY_HAVE_PC_FDC select GENERIC_ISA_DMA + select I8253 select I8259 select ISA select SYS_HAS_CPU_R4X00 @@ -530,6 +531,7 @@ config QEMU select DMA_COHERENT select GENERIC_ISA_DMA select HAVE_STD_PC_SERIAL_PORT + select I8253 select I8259 select ISA select SWAP_IO_SPACE @@ -714,6 +716,7 @@ config SNI_RM200_PCI select HAVE_STD_PC_SERIAL_PORT select HW_HAS_EISA select HW_HAS_PCI + select I8253 select I8259 select ISA select SYS_HAS_CPU_R4X00 @@ -1587,6 +1590,11 @@ config ARCH_FLATMEM_ENABLE def_bool y depends on !NUMA +config NODES_SHIFT + int + default "6" + depends on NEED_MULTIPLE_NODES + source "mm/Kconfig" config SMP @@ -1721,6 +1729,9 @@ config MMU bool default y +config I8253 + bool + source "drivers/pcmcia/Kconfig" source "drivers/pci/hotplug/Kconfig" diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index f36c4f20ee8a..309d54cceda3 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -59,6 +59,8 @@ obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_64BIT) += cpu-bugs64.o +obj-$(CONFIG_I8253) += i8253.o + CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c new file mode 100644 index 000000000000..475df6904219 --- /dev/null +++ b/arch/mips/kernel/i8253.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2006 IBM Corporation + * + * Implements device information for i8253 timer chip + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation + */ + +#include + +static __init int add_pcspkr(void) +{ + struct platform_device *pd; + int ret; + + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} +device_initcall(add_pcspkr); diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index 86e42c633f73..e042f9d2ba31 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -39,7 +39,6 @@ EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strncmp); #endif EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strrchr); diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index a8f435d82940..c66db5e5ab62 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -419,4 +419,3 @@ unsigned long get_wchan(struct task_struct *p) return pc; } -EXPORT_SYMBOL(get_wchan); diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 6b3c50964ca9..19f911c5dd58 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -177,14 +177,15 @@ config ARCH_DISCONTIGMEM_DEFAULT def_bool y depends on ARCH_DISCONTIGMEM_ENABLE +config NODES_SHIFT + int + default "3" + depends on NEED_MULTIPLE_NODES + +source "kernel/Kconfig.preempt" source "kernel/Kconfig.hz" source "mm/Kconfig" -config PREEMPT - bool -# bool "Preemptible Kernel" - default n - config COMPAT def_bool y depends on 64BIT diff --git a/arch/parisc/configs/712_defconfig b/arch/parisc/configs/712_defconfig index 3e013f55df64..41fd0696bbe7 100644 --- a/arch/parisc/configs/712_defconfig +++ b/arch/parisc/configs/712_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.14-rc5-pa1 -# Fri Oct 21 23:04:34 2005 +# Linux kernel version: 2.6.16-pa6 +# Sun Mar 26 19:59:51 2006 # CONFIG_PARISC=y CONFIG_MMU=y @@ -10,14 +10,11 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_ARCH_MAY_HAVE_PC_FDC=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y -# CONFIG_CLEAN_COMPILE is not set -CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -32,17 +29,18 @@ CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -51,8 +49,10 @@ CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -65,6 +65,23 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y +# +# Block layer +# + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + # # Processor type and features # @@ -75,6 +92,10 @@ CONFIG_PA7100LC=y # CONFIG_PA8X00 is not set CONFIG_PA11=y # CONFIG_SMP is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set # CONFIG_HZ_100 is not set CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set @@ -86,7 +107,7 @@ CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set -# CONFIG_PREEMPT is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 # CONFIG_HPUX is not set # @@ -130,6 +151,7 @@ CONFIG_NET=y # # Networking options # +# CONFIG_NETDEBUG is not set CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y @@ -165,7 +187,12 @@ CONFIG_TCP_CONG_BIC=y # CONFIG_IPV6 is not set CONFIG_NETFILTER=y # CONFIG_NETFILTER_DEBUG is not set + +# +# Core Netfilter Configuration +# # CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_XTABLES is not set # # IP: Netfilter Configuration @@ -182,64 +209,6 @@ CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_AMANDA=m # CONFIG_IP_NF_PPTP is not set CONFIG_IP_NF_QUEUE=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_LIMIT=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_MAC=m -CONFIG_IP_NF_MATCH_PKTTYPE=m -CONFIG_IP_NF_MATCH_MARK=m -CONFIG_IP_NF_MATCH_MULTIPORT=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_LENGTH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_TCPMSS=m -CONFIG_IP_NF_MATCH_HELPER=m -CONFIG_IP_NF_MATCH_STATE=m -CONFIG_IP_NF_MATCH_CONNTRACK=m -CONFIG_IP_NF_MATCH_OWNER=m -# CONFIG_IP_NF_MATCH_ADDRTYPE is not set -# CONFIG_IP_NF_MATCH_REALM is not set -CONFIG_IP_NF_MATCH_SCTP=m -# CONFIG_IP_NF_MATCH_DCCP is not set -CONFIG_IP_NF_MATCH_COMMENT=m -CONFIG_IP_NF_MATCH_CONNMARK=m -CONFIG_IP_NF_MATCH_HASHLIMIT=m -# CONFIG_IP_NF_MATCH_STRING is not set -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m -# CONFIG_IP_NF_TARGET_NFQUEUE is not set -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_IP_NF_NAT_SNMP_BASIC=m -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m -CONFIG_IP_NF_NAT_TFTP=m -CONFIG_IP_NF_NAT_AMANDA=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_DSCP=m -CONFIG_IP_NF_TARGET_MARK=m -CONFIG_IP_NF_TARGET_CLASSIFY=m -# CONFIG_IP_NF_TARGET_TTL is not set -CONFIG_IP_NF_TARGET_CONNMARK=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_TARGET_NOTRACK=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m # # DCCP Configuration (EXPERIMENTAL) @@ -250,6 +219,11 @@ CONFIG_IP_NF_ARP_MANGLE=m # SCTP Configuration (EXPERIMENTAL) # # CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set @@ -263,8 +237,11 @@ CONFIG_LLC2=m # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set # # Network testing @@ -304,6 +281,7 @@ CONFIG_PARPORT=y CONFIG_PARPORT_PC=m # CONFIG_PARPORT_PC_FIFO is not set # CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_NOT_PC=y CONFIG_PARPORT_GSC=y # CONFIG_PARPORT_1284 is not set @@ -314,7 +292,6 @@ CONFIG_PARPORT_GSC=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_PARIDE is not set # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y @@ -325,14 +302,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=6144 CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y CONFIG_ATA_OVER_ETH=m # @@ -376,6 +345,7 @@ CONFIG_SCSI_ISCSI_ATTRS=m # # SCSI low-level drivers # +# CONFIG_ISCSI_TCP is not set # CONFIG_SCSI_SATA is not set # CONFIG_SCSI_PPA is not set # CONFIG_SCSI_IMM is not set @@ -407,7 +377,6 @@ CONFIG_MD_RAID1=m # # IEEE 1394 (FireWire) support # -# CONFIG_IEEE1394 is not set # # I2O device support @@ -471,6 +440,7 @@ CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_MPPE=m CONFIG_PPPOE=m # CONFIG_SLIP is not set # CONFIG_SHAPER is not set @@ -516,8 +486,8 @@ CONFIG_KEYBOARD_ATKBD_HP_KEYCODES=y # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set -CONFIG_KEYBOARD_HIL_OLD=y -# CONFIG_KEYBOARD_HIL is not set +# CONFIG_KEYBOARD_HIL_OLD is not set +CONFIG_KEYBOARD_HIL=y CONFIG_INPUT_MOUSE=y CONFIG_MOUSE_PS2=y CONFIG_MOUSE_SERIAL=m @@ -554,6 +524,7 @@ CONFIG_HW_CONSOLE=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=17 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y @@ -598,12 +569,20 @@ CONFIG_MAX_RAW_DEVS=256 # # TPM devices # +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set # # I2C support # # CONFIG_I2C is not set +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + # # Dallas's 1-wire bus # @@ -640,7 +619,6 @@ CONFIG_FB=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_SOFT_CURSOR=y # CONFIG_FB_MACMODES is not set CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y @@ -655,6 +633,7 @@ CONFIG_DUMMY_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=128 CONFIG_DUMMY_CONSOLE_ROWS=48 CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set CONFIG_STI_CONSOLE=y CONFIG_FONTS=y CONFIG_FONT_8x8=y @@ -695,6 +674,8 @@ CONFIG_SND_OSSEMUL=y CONFIG_SND_MIXER_OSS=y CONFIG_SND_PCM_OSS=y CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y # CONFIG_SND_VERBOSE_PRINTK is not set # CONFIG_SND_DEBUG is not set @@ -723,6 +704,10 @@ CONFIG_SND_HARMONY=y # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + # # USB Gadget Support # @@ -736,10 +721,9 @@ CONFIG_SND_HARMONY=y # # InfiniBand support # -# CONFIG_INFINIBAND is not set # -# SN Devices +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) # # @@ -765,6 +749,7 @@ CONFIG_XFS_EXPORT=y # CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set # CONFIG_XFS_RT is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_INOTIFY=y @@ -800,10 +785,10 @@ CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y CONFIG_TMPFS=y -# CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # CONFIG_RELAYFS_FS is not set +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -821,7 +806,6 @@ CONFIG_RAMFS=y # CONFIG_QNX4FS_FS is not set # CONFIG_SYSV_FS is not set CONFIG_UFS_FS=m -# CONFIG_UFS_FS_WRITE is not set # # Network File Systems @@ -917,18 +901,22 @@ CONFIG_OPROFILE=m # Kernel hacking # # CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set -# CONFIG_DEBUG_IOREMAP is not set # CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_DEBUG_RODATA=y # # Security options diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig index 959ad3c4e372..f3b812f04592 100644 --- a/arch/parisc/configs/a500_defconfig +++ b/arch/parisc/configs/a500_defconfig @@ -1031,8 +1031,8 @@ CONFIG_NLS_CODEPAGE_850=m # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ASCII is not set -# CONFIG_NLS_ISO8859_1 is not set +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set diff --git a/arch/parisc/configs/b180_defconfig b/arch/parisc/configs/b180_defconfig index 37e98241ce4b..35093612ad2c 100644 --- a/arch/parisc/configs/b180_defconfig +++ b/arch/parisc/configs/b180_defconfig @@ -939,10 +939,10 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=m # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set +CONFIG_NLS_CODEPAGE_850=m # CONFIG_NLS_CODEPAGE_852 is not set # CONFIG_NLS_CODEPAGE_855 is not set # CONFIG_NLS_CODEPAGE_857 is not set @@ -962,8 +962,8 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ASCII is not set -# CONFIG_NLS_ISO8859_1 is not set +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -973,10 +973,10 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_ISO8859_9 is not set # CONFIG_NLS_ISO8859_13 is not set # CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set +CONFIG_NLS_ISO8859_15=m # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set +CONFIG_NLS_UTF8=m # # Kernel hacking diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig index 0b1c8c1fa8a3..782906b644dd 100644 --- a/arch/parisc/configs/c3000_defconfig +++ b/arch/parisc/configs/c3000_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.14-rc5-pa1 -# Fri Oct 21 23:06:31 2005 +# Linux kernel version: 2.6.16-pa6 +# Sun Mar 26 20:03:29 2006 # CONFIG_PARISC=y CONFIG_MMU=y @@ -10,14 +10,11 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_HARDIRQS=y CONFIG_GENERIC_IRQ_PROBE=y -CONFIG_ARCH_MAY_HAVE_PC_FDC=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y -# CONFIG_CLEAN_COMPILE is not set -CONFIG_BROKEN=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -32,28 +29,30 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EMBEDDED=y CONFIG_KALLSYMS=y CONFIG_KALLSYMS_ALL=y # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_SHMEM=y CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support @@ -66,6 +65,23 @@ CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y +# +# Block layer +# + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + # # Processor type and features # @@ -78,6 +94,10 @@ CONFIG_PA20=y CONFIG_PREFETCH=y # CONFIG_64BIT is not set # CONFIG_SMP is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set # CONFIG_HZ_100 is not set CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set @@ -89,7 +109,7 @@ CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set -# CONFIG_PREEMPT is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_HPUX is not set # @@ -135,6 +155,7 @@ CONFIG_NET=y # # Networking options # +# CONFIG_NETDEBUG is not set CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y @@ -175,7 +196,12 @@ CONFIG_INET6_TUNNEL=m CONFIG_IPV6_TUNNEL=m CONFIG_NETFILTER=y CONFIG_NETFILTER_DEBUG=y + +# +# Core Netfilter Configuration +# # CONFIG_NETFILTER_NETLINK is not set +# CONFIG_NETFILTER_XTABLES is not set # # IP: Netfilter Configuration @@ -192,87 +218,11 @@ CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_AMANDA=m # CONFIG_IP_NF_PPTP is not set CONFIG_IP_NF_QUEUE=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_LIMIT=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_MAC=m -CONFIG_IP_NF_MATCH_PKTTYPE=m -CONFIG_IP_NF_MATCH_MARK=m -CONFIG_IP_NF_MATCH_MULTIPORT=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_LENGTH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_TCPMSS=m -CONFIG_IP_NF_MATCH_HELPER=m -CONFIG_IP_NF_MATCH_STATE=m -CONFIG_IP_NF_MATCH_CONNTRACK=m -CONFIG_IP_NF_MATCH_OWNER=m -# CONFIG_IP_NF_MATCH_ADDRTYPE is not set -# CONFIG_IP_NF_MATCH_REALM is not set -# CONFIG_IP_NF_MATCH_SCTP is not set -# CONFIG_IP_NF_MATCH_DCCP is not set -# CONFIG_IP_NF_MATCH_COMMENT is not set -# CONFIG_IP_NF_MATCH_HASHLIMIT is not set -# CONFIG_IP_NF_MATCH_STRING is not set -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m -# CONFIG_IP_NF_TARGET_NFQUEUE is not set -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_IP_NF_NAT_SNMP_BASIC=m -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m -CONFIG_IP_NF_NAT_TFTP=m -CONFIG_IP_NF_NAT_AMANDA=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_DSCP=m -CONFIG_IP_NF_TARGET_MARK=m -CONFIG_IP_NF_TARGET_CLASSIFY=m -# CONFIG_IP_NF_TARGET_TTL is not set -# CONFIG_IP_NF_RAW is not set -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m # # IPv6: Netfilter Configuration (EXPERIMENTAL) # # CONFIG_IP6_NF_QUEUE is not set -CONFIG_IP6_NF_IPTABLES=m -# CONFIG_IP6_NF_MATCH_LIMIT is not set -CONFIG_IP6_NF_MATCH_MAC=m -CONFIG_IP6_NF_MATCH_RT=m -# CONFIG_IP6_NF_MATCH_OPTS is not set -# CONFIG_IP6_NF_MATCH_FRAG is not set -# CONFIG_IP6_NF_MATCH_HL is not set -# CONFIG_IP6_NF_MATCH_MULTIPORT is not set -CONFIG_IP6_NF_MATCH_OWNER=m -# CONFIG_IP6_NF_MATCH_MARK is not set -CONFIG_IP6_NF_MATCH_IPV6HEADER=m -# CONFIG_IP6_NF_MATCH_AHESP is not set -CONFIG_IP6_NF_MATCH_LENGTH=m -# CONFIG_IP6_NF_MATCH_EUI64 is not set -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_LOG=m -CONFIG_IP6_NF_TARGET_REJECT=m -# CONFIG_IP6_NF_TARGET_NFQUEUE is not set -CONFIG_IP6_NF_MANGLE=m -# CONFIG_IP6_NF_TARGET_MARK is not set -# CONFIG_IP6_NF_TARGET_HL is not set -# CONFIG_IP6_NF_RAW is not set # # DCCP Configuration (EXPERIMENTAL) @@ -283,6 +233,11 @@ CONFIG_IP6_NF_MANGLE=m # SCTP Configuration (EXPERIMENTAL) # # CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set @@ -295,8 +250,11 @@ CONFIG_IP6_NF_MANGLE=m # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set # # Network testing @@ -341,7 +299,6 @@ CONFIG_FW_LOADER=y # # Block devices # -# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -355,14 +312,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m # CONFIG_BLK_DEV_RAM is not set CONFIG_BLK_DEV_RAM_COUNT=16 # CONFIG_CDROM_PKTCDVD is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y # CONFIG_ATA_OVER_ETH is not set # @@ -458,6 +407,7 @@ CONFIG_SCSI_ISCSI_ATTRS=m # # SCSI low-level drivers # +# CONFIG_ISCSI_TCP is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set @@ -466,7 +416,6 @@ CONFIG_SCSI_ISCSI_ATTRS=m # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_DPT_I2O is not set -# CONFIG_SCSI_ADVANSYS is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set # CONFIG_MEGARAID_SAS is not set @@ -476,18 +425,18 @@ CONFIG_SCSI_SATA=y CONFIG_SCSI_ATA_PIIX=m # CONFIG_SCSI_SATA_MV is not set # CONFIG_SCSI_SATA_NV is not set -CONFIG_SCSI_SATA_PROMISE=m +# CONFIG_SCSI_PDC_ADMA is not set # CONFIG_SCSI_SATA_QSTOR is not set +CONFIG_SCSI_SATA_PROMISE=m # CONFIG_SCSI_SATA_SX4 is not set CONFIG_SCSI_SATA_SIL=m +# CONFIG_SCSI_SATA_SIL24 is not set # CONFIG_SCSI_SATA_SIS is not set # CONFIG_SCSI_SATA_ULI is not set CONFIG_SCSI_SATA_VIA=m # CONFIG_SCSI_SATA_VITESSE is not set CONFIG_SCSI_SATA_INTEL_COMBINED=y -# CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set @@ -496,18 +445,11 @@ CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +CONFIG_SCSI_SYM53C8XX_MMIO=y # CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set -CONFIG_SCSI_QLA2XXX=y -# CONFIG_SCSI_QLA21XX is not set -# CONFIG_SCSI_QLA22XX is not set -# CONFIG_SCSI_QLA2300 is not set -# CONFIG_SCSI_QLA2322 is not set -# CONFIG_SCSI_QLA6312 is not set -# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_QLA_FC is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set @@ -633,6 +575,7 @@ CONFIG_E1000=m # CONFIG_R8169 is not set # CONFIG_SIS190 is not set # CONFIG_SKGE is not set +# CONFIG_SKY2 is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=m @@ -668,6 +611,7 @@ CONFIG_PPP_ASYNC=m CONFIG_PPP_SYNC_TTY=m CONFIG_PPP_DEFLATE=m CONFIG_PPP_BSDCOMP=m +# CONFIG_PPP_MPPE is not set CONFIG_PPPOE=m # CONFIG_SLIP is not set # CONFIG_NET_FC is not set @@ -744,6 +688,7 @@ CONFIG_HW_CONSOLE=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=13 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y @@ -753,7 +698,6 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y # # Non-8250 serial port support # -# CONFIG_SERIAL_MUX is not set # CONFIG_PDC_CONSOLE is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y @@ -788,12 +732,19 @@ CONFIG_MAX_RAW_DEVS=256 # TPM devices # # CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set # # I2C support # # CONFIG_I2C is not set +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + # # Dallas's 1-wire bus # @@ -830,7 +781,6 @@ CONFIG_FB=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_SOFT_CURSOR=y # CONFIG_FB_MACMODES is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set @@ -840,6 +790,7 @@ CONFIG_FB_SOFT_CURSOR=y # CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set CONFIG_FB_STI=y +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_NVIDIA is not set # CONFIG_FB_RIVA is not set # CONFIG_FB_MATROX is not set @@ -853,10 +804,7 @@ CONFIG_FB_STI=y # CONFIG_FB_KYRO is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set -# CONFIG_FB_CYBLA is not set # CONFIG_FB_TRIDENT is not set -# CONFIG_FB_PM3 is not set -# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # @@ -866,6 +814,7 @@ CONFIG_DUMMY_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=160 CONFIG_DUMMY_CONSOLE_ROWS=64 CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set CONFIG_STI_CONSOLE=y # CONFIG_FONTS is not set CONFIG_FONT_8x8=y @@ -898,23 +847,27 @@ CONFIG_SND_OSSEMUL=y CONFIG_SND_MIXER_OSS=y CONFIG_SND_PCM_OSS=y CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y # CONFIG_SND_VERBOSE_PRINTK is not set # CONFIG_SND_DEBUG is not set # # Generic devices # +CONFIG_SND_AC97_CODEC=y +CONFIG_SND_AC97_BUS=y # CONFIG_SND_DUMMY is not set # CONFIG_SND_VIRMIDI is not set # CONFIG_SND_MTPAV is not set # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set -CONFIG_SND_AC97_CODEC=y -CONFIG_SND_AC97_BUS=y # # PCI devices # +CONFIG_SND_AD1889=y +# CONFIG_SND_AD1889_OPL3 is not set # CONFIG_SND_ALI5451 is not set # CONFIG_SND_ATIIXP is not set # CONFIG_SND_ATIIXP_MODEM is not set @@ -923,39 +876,38 @@ CONFIG_SND_AC97_BUS=y # CONFIG_SND_AU8830 is not set # CONFIG_SND_AZT3328 is not set # CONFIG_SND_BT87X is not set -# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMIPCI is not set # CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set # CONFIG_SND_EMU10K1 is not set # CONFIG_SND_EMU10K1X is not set -# CONFIG_SND_CA0106 is not set -# CONFIG_SND_KORG1212 is not set -# CONFIG_SND_MIXART is not set -# CONFIG_SND_NM256 is not set -# CONFIG_SND_RME32 is not set -# CONFIG_SND_RME96 is not set -# CONFIG_SND_RME9652 is not set -# CONFIG_SND_HDSP is not set -# CONFIG_SND_HDSPM is not set -# CONFIG_SND_TRIDENT is not set -# CONFIG_SND_YMFPCI is not set -CONFIG_SND_AD1889=y -# CONFIG_SND_AD1889_OPL3 is not set -# CONFIG_SND_CMIPCI is not set # CONFIG_SND_ENS1370 is not set # CONFIG_SND_ENS1371 is not set # CONFIG_SND_ES1938 is not set # CONFIG_SND_ES1968 is not set -# CONFIG_SND_MAESTRO3 is not set # CONFIG_SND_FM801 is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set # CONFIG_SND_ICE1712 is not set # CONFIG_SND_ICE1724 is not set # CONFIG_SND_INTEL8X0 is not set # CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set # CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_TRIDENT is not set # CONFIG_SND_VIA82XX is not set # CONFIG_SND_VIA82XX_MODEM is not set # CONFIG_SND_VX222 is not set -# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_YMFPCI is not set # # USB devices @@ -998,12 +950,15 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # USB Device Class drivers # # CONFIG_OBSOLETE_OSS_USB_DRIVER is not set -# CONFIG_USB_BLUETOOTH_TTY is not set # CONFIG_USB_ACM is not set CONFIG_USB_PRINTER=m # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information # CONFIG_USB_STORAGE=m # CONFIG_USB_STORAGE_DEBUG is not set @@ -1015,12 +970,15 @@ CONFIG_USB_STORAGE_USBAT=y CONFIG_USB_STORAGE_SDDR09=y CONFIG_USB_STORAGE_SDDR55=y CONFIG_USB_STORAGE_JUMPSHOT=y +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_LIBUSUAL is not set # # USB Input Devices # CONFIG_USB_HID=y CONFIG_USB_HIDINPUT=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set # CONFIG_HID_FF is not set CONFIG_USB_HIDDEV=y # CONFIG_USB_AIPTEK is not set @@ -1034,6 +992,7 @@ CONFIG_USB_HIDDEV=y # CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set @@ -1108,7 +1067,7 @@ CONFIG_USB_LEGOTOWER=m # CONFIG_INFINIBAND is not set # -# SN Devices +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) # # @@ -1130,6 +1089,7 @@ CONFIG_XFS_EXPORT=y # CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set # CONFIG_XFS_RT is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_INOTIFY=y @@ -1164,10 +1124,10 @@ CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y CONFIG_TMPFS=y -# CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # CONFIG_RELAYFS_FS is not set +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -1225,10 +1185,10 @@ CONFIG_MSDOS_PARTITION=y # CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set +CONFIG_NLS_CODEPAGE_437=m # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set +CONFIG_NLS_CODEPAGE_850=m # CONFIG_NLS_CODEPAGE_852 is not set # CONFIG_NLS_CODEPAGE_855 is not set # CONFIG_NLS_CODEPAGE_857 is not set @@ -1248,8 +1208,8 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ASCII is not set -# CONFIG_NLS_ISO8859_1 is not set +CONFIG_NLS_ASCII=m +CONFIG_NLS_ISO8859_1=m # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set # CONFIG_NLS_ISO8859_4 is not set @@ -1259,10 +1219,10 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_ISO8859_9 is not set # CONFIG_NLS_ISO8859_13 is not set # CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set +CONFIG_NLS_ISO8859_15=m # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set +CONFIG_NLS_UTF8=m # # Profiling support @@ -1274,18 +1234,22 @@ CONFIG_OPROFILE=m # Kernel hacking # # CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set -# CONFIG_DEBUG_IOREMAP is not set # CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_DEBUG_RODATA=y # # Security options diff --git a/arch/parisc/defconfig b/arch/parisc/defconfig index f38a4620d24f..59f7bc38e72e 100644 --- a/arch/parisc/defconfig +++ b/arch/parisc/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.14-rc5-pa1 -# Fri Oct 21 23:01:33 2005 +# Linux kernel version: 2.6.16-pa6 +# Sun Mar 26 19:50:07 2006 # CONFIG_PARISC=y CONFIG_MMU=y @@ -15,7 +15,6 @@ CONFIG_GENERIC_IRQ_PROBE=y # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -30,17 +29,18 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -# CONFIG_HOTPLUG is not set -CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_INITRAMFS_SOURCE="" +CONFIG_CC_OPTIMIZE_FOR_SIZE=y # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y +CONFIG_ELF_CORE=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y @@ -49,14 +49,33 @@ CONFIG_CC_ALIGN_FUNCTIONS=0 CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 +CONFIG_SLAB=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 +# CONFIG_SLOB is not set # # Loadable module support # # CONFIG_MODULES is not set +# +# Block layer +# + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" + # # Processor type and features # @@ -67,6 +86,10 @@ CONFIG_PA7000=y # CONFIG_PA8X00 is not set CONFIG_PA11=y # CONFIG_SMP is not set +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set # CONFIG_HZ_100 is not set CONFIG_HZ_250=y # CONFIG_HZ_1000 is not set @@ -78,7 +101,7 @@ CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set -# CONFIG_PREEMPT is not set +CONFIG_SPLIT_PTLOCK_CPUS=4096 # CONFIG_HPUX is not set # @@ -132,6 +155,7 @@ CONFIG_NET=y # # Networking options # +# CONFIG_NETDEBUG is not set CONFIG_PACKET=y CONFIG_PACKET_MMAP=y CONFIG_UNIX=y @@ -174,6 +198,11 @@ CONFIG_IPV6=y # SCTP Configuration (EXPERIMENTAL) # # CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set @@ -186,8 +215,11 @@ CONFIG_IPV6=y # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set + +# +# QoS and/or fair queueing +# # CONFIG_NET_SCHED is not set -# CONFIG_NET_CLS_ROUTE is not set # # Network testing @@ -228,6 +260,7 @@ CONFIG_PARPORT_PC=y # CONFIG_PARPORT_SERIAL is not set # CONFIG_PARPORT_PC_FIFO is not set # CONFIG_PARPORT_PC_SUPERIO is not set +CONFIG_PARPORT_NOT_PC=y CONFIG_PARPORT_GSC=y # CONFIG_PARPORT_1284 is not set @@ -254,14 +287,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # CONFIG_CDROM_PKTCDVD is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y # CONFIG_ATA_OVER_ETH is not set # @@ -305,6 +330,7 @@ CONFIG_SCSI_SPI_ATTRS=y # # SCSI low-level drivers # +# CONFIG_ISCSI_TCP is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set # CONFIG_SCSI_ACARD is not set @@ -331,7 +357,7 @@ CONFIG_SCSI_SYM53C8XX_2=y CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +CONFIG_SCSI_SYM53C8XX_MMIO=y # CONFIG_SCSI_IPR is not set CONFIG_SCSI_ZALON=y CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 @@ -340,13 +366,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC=20 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set -CONFIG_SCSI_QLA2XXX=y -# CONFIG_SCSI_QLA21XX is not set -# CONFIG_SCSI_QLA22XX is not set -# CONFIG_SCSI_QLA2300 is not set -# CONFIG_SCSI_QLA2322 is not set -# CONFIG_SCSI_QLA6312 is not set -# CONFIG_SCSI_QLA24XX is not set +# CONFIG_SCSI_QLA_FC is not set # CONFIG_SCSI_LPFC is not set # CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_DC395x is not set @@ -471,6 +491,7 @@ CONFIG_ACENIC=y # CONFIG_R8169 is not set # CONFIG_SIS190 is not set # CONFIG_SKGE is not set +# CONFIG_SKY2 is not set # CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set CONFIG_TIGON3=y @@ -562,13 +583,13 @@ CONFIG_INPUT_KEYBOARD=y # CONFIG_KEYBOARD_LKKBD is not set # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set -CONFIG_KEYBOARD_HIL_OLD=y +# CONFIG_KEYBOARD_HIL_OLD is not set CONFIG_KEYBOARD_HIL=y CONFIG_INPUT_MOUSE=y # CONFIG_MOUSE_PS2 is not set # CONFIG_MOUSE_SERIAL is not set # CONFIG_MOUSE_VSXXXAA is not set -# CONFIG_MOUSE_HIL is not set +CONFIG_MOUSE_HIL=y CONFIG_INPUT_JOYSTICK=y # CONFIG_JOYSTICK_ANALOG is not set # CONFIG_JOYSTICK_A3D is not set @@ -628,6 +649,7 @@ CONFIG_HW_CONSOLE=y CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_NR_UARTS=13 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_MANY_PORTS=y CONFIG_SERIAL_8250_SHARE_IRQ=y @@ -675,12 +697,19 @@ CONFIG_GEN_RTC=y # TPM devices # # CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set # # I2C support # # CONFIG_I2C is not set +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + # # Dallas's 1-wire bus # @@ -691,6 +720,7 @@ CONFIG_GEN_RTC=y # CONFIG_HWMON=y # CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_F71805F is not set # CONFIG_HWMON_DEBUG_CHIP is not set # @@ -718,7 +748,6 @@ CONFIG_FB=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_SOFT_CURSOR=y # CONFIG_FB_MACMODES is not set # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set @@ -728,6 +757,7 @@ CONFIG_FB_SOFT_CURSOR=y # CONFIG_FB_ASILIANT is not set # CONFIG_FB_IMSTT is not set CONFIG_FB_STI=y +# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_NVIDIA is not set # CONFIG_FB_RIVA is not set # CONFIG_FB_MATROX is not set @@ -741,9 +771,7 @@ CONFIG_FB_STI=y # CONFIG_FB_KYRO is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set -# CONFIG_FB_CYBLA is not set # CONFIG_FB_TRIDENT is not set -# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_VIRTUAL is not set # @@ -753,15 +781,28 @@ CONFIG_DUMMY_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=160 CONFIG_DUMMY_CONSOLE_ROWS=64 CONFIG_FRAMEBUFFER_CONSOLE=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set CONFIG_STI_CONSOLE=y -# CONFIG_FONTS is not set -CONFIG_FONT_8x8=y +CONFIG_FONTS=y +# CONFIG_FONT_8x8 is not set CONFIG_FONT_8x16=y +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set # # Logo configuration # -# CONFIG_LOGO is not set +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +# CONFIG_LOGO_LINUX_CLUT224 is not set +CONFIG_LOGO_PARISC_CLUT224=y # CONFIG_BACKLIGHT_LCD_SUPPORT is not set # @@ -781,23 +822,27 @@ CONFIG_SND_OSSEMUL=y CONFIG_SND_MIXER_OSS=y CONFIG_SND_PCM_OSS=y CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y # CONFIG_SND_VERBOSE_PRINTK is not set # CONFIG_SND_DEBUG is not set # # Generic devices # +CONFIG_SND_AC97_CODEC=y +CONFIG_SND_AC97_BUS=y # CONFIG_SND_DUMMY is not set # CONFIG_SND_VIRMIDI is not set # CONFIG_SND_MTPAV is not set # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_MPU401 is not set -CONFIG_SND_AC97_CODEC=y -CONFIG_SND_AC97_BUS=y # # PCI devices # +CONFIG_SND_AD1889=y +# CONFIG_SND_AD1889_OPL3 is not set # CONFIG_SND_ALI5451 is not set # CONFIG_SND_ATIIXP is not set # CONFIG_SND_ATIIXP_MODEM is not set @@ -806,39 +851,38 @@ CONFIG_SND_AC97_BUS=y # CONFIG_SND_AU8830 is not set # CONFIG_SND_AZT3328 is not set # CONFIG_SND_BT87X is not set -# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMIPCI is not set # CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set # CONFIG_SND_EMU10K1 is not set # CONFIG_SND_EMU10K1X is not set -# CONFIG_SND_CA0106 is not set -# CONFIG_SND_KORG1212 is not set -# CONFIG_SND_MIXART is not set -# CONFIG_SND_NM256 is not set -# CONFIG_SND_RME32 is not set -# CONFIG_SND_RME96 is not set -# CONFIG_SND_RME9652 is not set -# CONFIG_SND_HDSP is not set -# CONFIG_SND_HDSPM is not set -# CONFIG_SND_TRIDENT is not set -# CONFIG_SND_YMFPCI is not set -CONFIG_SND_AD1889=y -# CONFIG_SND_AD1889_OPL3 is not set -# CONFIG_SND_CMIPCI is not set # CONFIG_SND_ENS1370 is not set # CONFIG_SND_ENS1371 is not set # CONFIG_SND_ES1938 is not set # CONFIG_SND_ES1968 is not set -# CONFIG_SND_MAESTRO3 is not set # CONFIG_SND_FM801 is not set +# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set # CONFIG_SND_ICE1712 is not set # CONFIG_SND_ICE1724 is not set # CONFIG_SND_INTEL8X0 is not set # CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set # CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_TRIDENT is not set # CONFIG_SND_VIA82XX is not set # CONFIG_SND_VIA82XX_MODEM is not set # CONFIG_SND_VX222 is not set -# CONFIG_SND_HDA_INTEL is not set +# CONFIG_SND_YMFPCI is not set # # USB devices @@ -888,14 +932,18 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # USB Device Class drivers # # CONFIG_OBSOLETE_OSS_USB_DRIVER is not set -# CONFIG_USB_BLUETOOTH_TTY is not set # CONFIG_USB_ACM is not set # CONFIG_USB_PRINTER is not set # -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# + +# +# may also be needed; see USB_STORAGE Help for more information # # CONFIG_USB_STORAGE is not set +# CONFIG_USB_LIBUSUAL is not set # # USB Input Devices @@ -918,6 +966,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y # CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set +# CONFIG_USB_ATI_REMOTE2 is not set # CONFIG_USB_KEYSPAN_REMOTE is not set # CONFIG_USB_APPLETOUCH is not set @@ -994,7 +1043,7 @@ CONFIG_USB_MON=y # CONFIG_INFINIBAND is not set # -# SN Devices +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) # # @@ -1011,6 +1060,7 @@ CONFIG_JBD=y # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set # CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set CONFIG_INOTIFY=y @@ -1045,6 +1095,7 @@ CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # CONFIG_RELAYFS_FS is not set +# CONFIG_CONFIGFS_FS is not set # # Miscellaneous filesystems @@ -1151,18 +1202,22 @@ CONFIG_OPROFILE=y # Kernel hacking # # CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_KERNEL=y CONFIG_LOG_BUF_SHIFT=15 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set +CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set -# CONFIG_DEBUG_IOREMAP is not set # CONFIG_DEBUG_FS is not set +# CONFIG_DEBUG_VM is not set +CONFIG_FORCED_INLINING=y +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_DEBUG_RODATA=y # # Security options diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index d8a4ca021aac..360b7391cb8c 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -89,7 +89,7 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) if (pfn_valid(page_to_pfn(page)) && page_mapping(page) && test_bit(PG_dcache_dirty, &page->flags)) { - flush_kernel_dcache_page(page_address(page)); + flush_kernel_dcache_page(page); clear_bit(PG_dcache_dirty, &page->flags); } } @@ -278,7 +278,7 @@ void flush_dcache_page(struct page *page) return; } - flush_kernel_dcache_page(page_address(page)); + flush_kernel_dcache_page(page); if (!mapping) return; @@ -317,7 +317,7 @@ EXPORT_SYMBOL(flush_dcache_page); /* Defined in arch/parisc/kernel/pacache.S */ EXPORT_SYMBOL(flush_kernel_dcache_range_asm); -EXPORT_SYMBOL(flush_kernel_dcache_page); +EXPORT_SYMBOL(flush_kernel_dcache_page_asm); EXPORT_SYMBOL(flush_data_cache_local); EXPORT_SYMBOL(flush_kernel_icache_range_asm); diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 9af4b22a6d77..7c95d7663c29 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -563,10 +563,10 @@ extrd,u,*= \pte,_PAGE_GATEWAY_BIT+32,1,%r0 depd %r0,11,2,\prot /* If Gateway, Set PL2 to 0 */ - /* Get rid of prot bits and convert to page addr for iitlbt */ + /* Get rid of prot bits and convert to page addr for iitlbt and idtlbt */ depd %r0,63,PAGE_SHIFT,\pte - extrd,u \pte,56,32,\pte + extrd,s \pte,(63-PAGE_SHIFT)+(63-58),64-PAGE_SHIFT,\pte .endm /* Identical macro to make_insert_tlb above, except it @@ -584,7 +584,7 @@ /* Get rid of prot bits and convert to page addr for iitlba */ - depi 0,31,12,\pte + depi 0,31,PAGE_SHIFT,\pte extru \pte,24,25,\pte .endm @@ -1014,14 +1014,21 @@ intr_restore: nop nop +#ifndef CONFIG_PREEMPT +# define intr_do_preempt intr_restore +#endif /* !CONFIG_PREEMPT */ + .import schedule,code intr_do_resched: - /* Only do reschedule if we are returning to user space */ + /* Only call schedule on return to userspace. If we're returning + * to kernel space, we may schedule if CONFIG_PREEMPT, otherwise + * we jump back to intr_restore. + */ LDREG PT_IASQ0(%r16), %r20 - CMPIB= 0,%r20,intr_restore /* backward */ + CMPIB= 0, %r20, intr_do_preempt nop LDREG PT_IASQ1(%r16), %r20 - CMPIB= 0,%r20,intr_restore /* backward */ + CMPIB= 0, %r20, intr_do_preempt nop #ifdef CONFIG_64BIT @@ -1037,6 +1044,32 @@ intr_do_resched: #endif ldo R%intr_check_sig(%r2), %r2 + /* preempt the current task on returning to kernel + * mode from an interrupt, iff need_resched is set, + * and preempt_count is 0. otherwise, we continue on + * our merry way back to the current running task. + */ +#ifdef CONFIG_PREEMPT + .import preempt_schedule_irq,code +intr_do_preempt: + rsm PSW_SM_I, %r0 /* disable interrupts */ + + /* current_thread_info()->preempt_count */ + mfctl %cr30, %r1 + LDREG TI_PRE_COUNT(%r1), %r19 + CMPIB<> 0, %r19, intr_restore /* if preempt_count > 0 */ + nop /* prev insn branched backwards */ + + /* check if we interrupted a critical path */ + LDREG PT_PSW(%r16), %r20 + bb,<,n %r20, 31 - PSW_SM_I, intr_restore + nop + + BL preempt_schedule_irq, %r2 + nop + + b intr_restore /* ssm PSW_SM_I done by intr_restore */ +#endif /* CONFIG_PREEMPT */ .import do_signal,code intr_do_signal: diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 9534ee17b9be..7a4f07e8d3c3 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -621,9 +621,9 @@ __clear_user_page_asm: .procend - .export flush_kernel_dcache_page + .export flush_kernel_dcache_page_asm -flush_kernel_dcache_page: +flush_kernel_dcache_page_asm: .proc .callinfo NO_CALLS .entry diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index 1d00c365f2b1..fc107add627c 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -30,23 +30,7 @@ #include #include -EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memscan); EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strchr); -EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strcpy); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strncat); -EXPORT_SYMBOL(strncmp); -EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strnlen); -EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strstr); -EXPORT_SYMBOL(strpbrk); #include EXPORT_SYMBOL(__xchg8); @@ -82,16 +66,12 @@ EXPORT_SYMBOL($global$); #endif #include -EXPORT_SYMBOL(__ioremap); -EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(memcpy_toio); EXPORT_SYMBOL(memcpy_fromio); EXPORT_SYMBOL(memset_io); #include -EXPORT_SYMBOL(sys_open); EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_read); EXPORT_SYMBOL(sys_write); #include diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c index 0cea6958f427..a45e2e2ffd9f 100644 --- a/arch/parisc/kernel/pdc_chassis.c +++ b/arch/parisc/kernel/pdc_chassis.c @@ -5,9 +5,8 @@ * Copyright (C) 2002-2004 Thibaut VARENE * * 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. + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index 53f861c82f93..ac8ee205c351 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -805,7 +805,7 @@ static int perf_write_image(uint64_t *memaddr) return -1; } - runway = ioremap(cpu_device->hpa.start, 4096); + runway = ioremap_nocache(cpu_device->hpa.start, 4096); /* Merge intrigue bits into Runway STATUS 0 */ tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful; diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index 89b6c56ea0a8..bbeeb614cfab 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S @@ -287,7 +287,7 @@ ENTRY_SAME(chown) /* 180 */ /* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */ ENTRY_COMP(setsockopt) - ENTRY_SAME(getsockopt) + ENTRY_COMP(getsockopt) ENTRY_COMP(sendmsg) ENTRY_COMP(recvmsg) ENTRY_SAME(semop) /* 185 */ diff --git a/arch/parisc/lib/iomap.c b/arch/parisc/lib/iomap.c index 01bec8fcbd0d..f4a811690ab3 100644 --- a/arch/parisc/lib/iomap.c +++ b/arch/parisc/lib/iomap.c @@ -263,11 +263,7 @@ static const struct iomap_ops iomem_ops = { const struct iomap_ops *iomap_ops[8] = { [0] = &ioport_ops, -#ifdef CONFIG_DEBUG_IOREMAP - [6] = &iomem_ops, -#else [7] = &iomem_ops -#endif }; diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 852eda3953dc..3796be67cd53 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -1013,9 +1013,9 @@ void flush_tlb_all(void) #ifdef CONFIG_BLK_DEV_INITRD void free_initrd_mem(unsigned long start, unsigned long end) { -#if 0 - if (start < end) - printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10); + if (start >= end) + return; + printk(KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { ClearPageReserved(virt_to_page(start)); init_page_count(virt_to_page(start)); @@ -1023,6 +1023,5 @@ void free_initrd_mem(unsigned long start, unsigned long end) num_physpages++; totalram_pages++; } -#endif } #endif diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c index edd9a9559cba..0db12818d7bc 100644 --- a/arch/parisc/mm/ioremap.c +++ b/arch/parisc/mm/ioremap.c @@ -72,7 +72,6 @@ remap_area_pmd(pmd_t *pmd, unsigned long address, unsigned long size, return 0; } -#if USE_HPPA_IOREMAP static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size, unsigned long flags) @@ -114,31 +113,6 @@ remap_area_pages(unsigned long address, unsigned long phys_addr, return error; } -#endif /* USE_HPPA_IOREMAP */ - -#ifdef CONFIG_DEBUG_IOREMAP -static unsigned long last = 0; - -void gsc_bad_addr(unsigned long addr) -{ - if (time_after(jiffies, last + HZ*10)) { - printk("gsc_foo() called with bad address 0x%lx\n", addr); - dump_stack(); - last = jiffies; - } -} -EXPORT_SYMBOL(gsc_bad_addr); - -void __raw_bad_addr(const volatile void __iomem *addr) -{ - if (time_after(jiffies, last + HZ*10)) { - printk("__raw_foo() called with bad address 0x%p\n", addr); - dump_stack(); - last = jiffies; - } -} -EXPORT_SYMBOL(__raw_bad_addr); -#endif /* * Generic mapping function (not visible outside): @@ -154,26 +128,19 @@ EXPORT_SYMBOL(__raw_bad_addr); */ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) { -#if !(USE_HPPA_IOREMAP) - - unsigned long end = phys_addr + size - 1; - /* Support EISA addresses */ - if ((phys_addr >= 0x00080000 && end < 0x000fffff) - || (phys_addr >= 0x00500000 && end < 0x03bfffff)) { - phys_addr |= 0xfc000000; - } - -#ifdef CONFIG_DEBUG_IOREMAP - return (void __iomem *)(phys_addr - (0x1UL << NYBBLE_SHIFT)); -#else - return (void __iomem *)phys_addr; -#endif - -#else void *addr; struct vm_struct *area; unsigned long offset, last_addr; +#ifdef CONFIG_EISA + unsigned long end = phys_addr + size - 1; + /* Support EISA addresses */ + if ((phys_addr >= 0x00080000 && end < 0x000fffff) || + (phys_addr >= 0x00500000 && end < 0x03bfffff)) { + phys_addr |= F_EXTEND(0xfc000000); + } +#endif + /* Don't allow wraparound or zero size */ last_addr = phys_addr + size - 1; if (!size || last_addr < phys_addr) @@ -217,15 +184,12 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l } return (void __iomem *) (offset + (char *)addr); -#endif } +EXPORT_SYMBOL(__ioremap); void iounmap(void __iomem *addr) { -#if !(USE_HPPA_IOREMAP) - return; -#else if (addr > high_memory) return vfree((void *) (PAGE_MASK & (unsigned long __force) addr)); -#endif } +EXPORT_SYMBOL(iounmap); diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a433b7126d33..6729c98b66f9 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -366,6 +366,7 @@ config PPC_PMAC64 select U3_DART select MPIC_BROKEN_U3 select GENERIC_TBSYNC + select PPC_970_NAP default y config PPC_PREP @@ -383,6 +384,7 @@ config PPC_MAPLE select MPIC_BROKEN_U3 select GENERIC_TBSYNC select PPC_UDBG_16550 + select PPC_970_NAP default n help This option enables support for the Maple 970FX Evaluation Board. @@ -457,6 +459,10 @@ config PPC_MPC106 bool default n +config PPC_970_NAP + bool + default n + source "drivers/cpufreq/Kconfig" config CPU_FREQ_PMAC @@ -491,7 +497,7 @@ config PPC601_SYNC_FIX If in doubt, say Y here. config TAU - bool "Thermal Management Support" + bool "On-chip CPU temperature sensor support" depends on 6xx help G3 and G4 processors have an on-chip temperature sensor called the @@ -500,7 +506,7 @@ config TAU on-die temperature in /proc/cpuinfo if the cpu supports it. Unfortunately, on some chip revisions, this sensor is very inaccurate - and in some cases, does not work at all, so don't assume the cpu + and in many cases, does not work at all, so don't assume the cpu temp is actually what /proc/cpuinfo says it is. config TAU_INT @@ -649,6 +655,11 @@ config NUMA depends on PPC64 default y if SMP && PPC_PSERIES +config NODES_SHIFT + int + default "4" + depends on NEED_MULTIPLE_NODES + config ARCH_SELECT_MEMORY_MODEL def_bool y depends on PPC64 diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 9254806f7032..8d48e9e7162a 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -110,11 +110,6 @@ config SERIAL_TEXT_DEBUG depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \ PPC_GEN550 || PPC_MPC52xx -config PPC_OCP - bool - depends on IBM_OCP || XILINX_OCP - default y - choice prompt "Early debugging (dangerous)" bool diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 829e017b8a54..ed5b26aa8be3 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -104,6 +104,10 @@ ifndef CONFIG_FSL_BOOKE CFLAGS += -mstring endif +ifeq ($(CONFIG_6xx),y) +CFLAGS += -mcpu=powerpc +endif + cpu-as-$(CONFIG_PPC64BRIDGE) += -Wa,-mppc64bridge cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_6xx) += -Wa,-maltivec @@ -129,13 +133,8 @@ core-y += arch/powerpc/kernel/ \ arch/powerpc/lib/ \ arch/powerpc/sysdev/ \ arch/powerpc/platforms/ -core-$(CONFIG_PPC32) += arch/ppc/kernel/ -core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ +core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/ core-$(CONFIG_XMON) += arch/powerpc/xmon/ -core-$(CONFIG_APUS) += arch/ppc/amiga/ -drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ -drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/ -drivers-$(CONFIG_CPM2) += arch/ppc/8260_io/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig index 3c2acab63736..fe22e54ab2b0 100644 --- a/arch/powerpc/configs/cell_defconfig +++ b/arch/powerpc/configs/cell_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.16-rc6 -# Wed Mar 15 16:19:48 2006 +# Linux kernel version: 2.6.16 +# Thu Mar 23 20:48:09 2006 # CONFIG_PPC64=y CONFIG_64BIT=y @@ -30,6 +30,7 @@ CONFIG_POWER4=y CONFIG_PPC_FPU=y CONFIG_ALTIVEC=y CONFIG_PPC_STD_MMU=y +CONFIG_VIRT_CPU_ACCOUNTING=y CONFIG_SMP=y CONFIG_NR_CPUS=4 @@ -51,7 +52,8 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -# CONFIG_IKCONFIG is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set CONFIG_INITRAMFS_SOURCE="" CONFIG_CC_OPTIMIZE_FOR_SIZE=y @@ -85,7 +87,7 @@ CONFIG_MODULE_UNLOAD=y CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set -# CONFIG_KMOD is not set +CONFIG_KMOD=y CONFIG_STOP_MACHINE=y # @@ -130,7 +132,8 @@ CONFIG_CELL_IIC=y # # Cell Broadband Engine options # -CONFIG_SPU_FS=y +CONFIG_SPU_FS=m +CONFIG_SPUFS_MMAP=y # # Kernel options @@ -144,7 +147,7 @@ CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT is not set CONFIG_PREEMPT_BKL=y CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_MISC=m CONFIG_FORCE_MAX_ZONEORDER=13 # CONFIG_IOMMU_VMERGE is not set CONFIG_KEXEC=y @@ -155,13 +158,16 @@ CONFIG_ARCH_SELECT_MEMORY_MODEL=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y +# CONFIG_FLATMEM_MANUAL is not set # CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y # CONFIG_SPARSEMEM_STATIC is not set +CONFIG_SPARSEMEM_EXTREME=y +# CONFIG_MEMORY_HOTPLUG is not set CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_MIGRATION=y # CONFIG_PPC_64K_PAGES is not set CONFIG_SCHED_SMT=y CONFIG_PROC_DEVICETREE=y @@ -232,6 +238,7 @@ CONFIG_TCP_CONG_BIC=y # CONFIG_IP_VS is not set CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m @@ -244,25 +251,7 @@ CONFIG_NETFILTER=y # Core Netfilter Configuration # # CONFIG_NETFILTER_NETLINK is not set -CONFIG_NETFILTER_XTABLES=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -# CONFIG_NETFILTER_XT_MATCH_DCCP is not set -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_SCTP=m -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +# CONFIG_NETFILTER_XTABLES is not set # # IP: Netfilter Configuration @@ -278,51 +267,13 @@ CONFIG_IP_NF_IRC=m CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_AMANDA=m # CONFIG_IP_NF_PPTP is not set +# CONFIG_IP_NF_H323 is not set CONFIG_IP_NF_QUEUE=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_MULTIPORT=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_OWNER=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m -CONFIG_IP_NF_MATCH_HASHLIMIT=m -CONFIG_IP_NF_MATCH_POLICY=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_IP_NF_NAT_SNMP_BASIC=m -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m -CONFIG_IP_NF_NAT_TFTP=m -CONFIG_IP_NF_NAT_AMANDA=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_DSCP=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m # # IPv6: Netfilter Configuration (EXPERIMENTAL) # # CONFIG_IP6_NF_QUEUE is not set -# CONFIG_IP6_NF_IPTABLES is not set # # DCCP Configuration (EXPERIMENTAL) @@ -355,7 +306,6 @@ CONFIG_IP_NF_ARP_MANGLE=m # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set -CONFIG_NET_CLS_ROUTE=y # # Network testing @@ -408,7 +358,7 @@ CONFIG_FW_LOADER=y # CONFIG_BLK_DEV_COW_COMMON is not set CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set -CONFIG_BLK_DEV_NBD=y +# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_SX8 is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 @@ -484,7 +434,23 @@ CONFIG_IDEDMA_AUTO=y # # Multi-device support (RAID and LVM) # -# CONFIG_MD is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +CONFIG_MD_LINEAR=m +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +# CONFIG_MD_RAID10 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_RAID6 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +# CONFIG_DM_MULTIPATH_EMC is not set # # Fusion MPT device support @@ -548,7 +514,7 @@ CONFIG_MII=y # CONFIG_ACENIC is not set # CONFIG_DL2K is not set CONFIG_E1000=m -# CONFIG_E1000_NAPI is not set +CONFIG_E1000_NAPI=y # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set @@ -560,7 +526,7 @@ CONFIG_SKGE=m # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set -CONFIG_SPIDER_NET=y +CONFIG_SPIDER_NET=m # CONFIG_MV643XX_ETH is not set # @@ -678,6 +644,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y # CONFIG_LEGACY_PTYS is not set +CONFIG_HVC_DRIVER=y +CONFIG_HVC_RTAS=y # # IPMI @@ -694,14 +662,13 @@ CONFIG_WATCHDOG=y # Watchdog Device Drivers # # CONFIG_SOFT_WATCHDOG is not set -# CONFIG_WATCHDOG_RTAS is not set +CONFIG_WATCHDOG_RTAS=y # # PCI-based Watchdog Cards # # CONFIG_PCIPCWATCHDOG is not set # CONFIG_WDTPCI is not set -# CONFIG_RTC is not set CONFIG_GEN_RTC=y # CONFIG_GEN_RTC_X is not set # CONFIG_DTLK is not set @@ -833,6 +800,7 @@ CONFIG_DUMMY_CONSOLE=y # CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y +CONFIG_USB_ARCH_HAS_EHCI=y # CONFIG_USB is not set # @@ -852,7 +820,14 @@ CONFIG_USB_ARCH_HAS_OHCI=y # # InfiniBand support # -# CONFIG_INFINIBAND is not set +CONFIG_INFINIBAND=y +CONFIG_INFINIBAND_USER_MAD=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_INFINIBAND_MTHCA=m +CONFIG_INFINIBAND_MTHCA_DEBUG=y +CONFIG_INFINIBAND_IPOIB=m +CONFIG_INFINIBAND_IPOIB_DEBUG=y +CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y # # EDAC - error detection and reporting (RAS) (EXPERIMENTAL) @@ -1037,10 +1012,6 @@ CONFIG_CRC32=y # CONFIG_LIBCRC32C is not set CONFIG_ZLIB_INFLATE=m CONFIG_ZLIB_DEFLATE=m -CONFIG_TEXTSEARCH=y -CONFIG_TEXTSEARCH_KMP=m -CONFIG_TEXTSEARCH_BM=m -CONFIG_TEXTSEARCH_FSM=m # # Instrumentation Support @@ -1058,7 +1029,7 @@ CONFIG_LOG_BUF_SHIFT=15 CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_MUTEXES is not set +CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_SPINLOCK is not set CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_KOBJECT is not set diff --git a/arch/powerpc/configs/mpc8540_ads_defconfig b/arch/powerpc/configs/mpc8540_ads_defconfig index 2a8290ee15c6..7f0780f1aa39 100644 --- a/arch/powerpc/configs/mpc8540_ads_defconfig +++ b/arch/powerpc/configs/mpc8540_ads_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: -# Sat Jan 14 15:57:54 2006 +# Linux kernel version: 2.6.16 +# Mon Mar 27 23:37:36 2006 # # CONFIG_PPC64 is not set CONFIG_PPC32=y @@ -9,6 +9,7 @@ CONFIG_PPC_MERGE=y CONFIG_MMU=y CONFIG_GENERIC_HARDIRQS=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_PPC=y CONFIG_EARLY_PRINTK=y @@ -18,6 +19,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y CONFIG_PPC_OF=y CONFIG_PPC_UDBG_16550=y # CONFIG_GENERIC_TBSYNC is not set +CONFIG_DEFAULT_UIMAGE=y # # Processor support @@ -42,7 +44,6 @@ CONFIG_SPE=y # Code maturity level options # CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y CONFIG_INIT_ENV_ARG_LIMIT=32 @@ -58,6 +59,7 @@ CONFIG_SYSVIPC=y CONFIG_SYSCTL=y # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set +# CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EMBEDDED=y @@ -72,10 +74,6 @@ CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 CONFIG_SLAB=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -90,6 +88,8 @@ CONFIG_BASE_SMALL=0 # Block layer # # CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set # # IO Schedulers @@ -183,6 +183,7 @@ CONFIG_NET=y # # Networking options # +# CONFIG_NETDEBUG is not set CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set CONFIG_UNIX=y @@ -220,6 +221,11 @@ CONFIG_TCP_CONG_BIC=y # SCTP Configuration (EXPERIMENTAL) # # CONFIG_IP_SCTP is not set + +# +# TIPC Configuration (EXPERIMENTAL) +# +# CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set @@ -229,11 +235,6 @@ CONFIG_TCP_CONG_BIC=y # CONFIG_ATALK is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set - -# -# TIPC Configuration (EXPERIMENTAL) -# -# CONFIG_TIPC is not set # CONFIG_NET_DIVERT is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -486,6 +487,12 @@ CONFIG_GEN_RTC=y # # CONFIG_I2C is not set +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set + # # Dallas's 1-wire bus # @@ -496,16 +503,13 @@ CONFIG_GEN_RTC=y # CONFIG_HWMON=y # CONFIG_HWMON_VID is not set +# CONFIG_SENSORS_F71805F is not set # CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices # -# -# Multimedia Capabilities Port drivers -# - # # Multimedia devices # @@ -531,6 +535,7 @@ CONFIG_HWMON=y # # CONFIG_USB_ARCH_HAS_HCD is not set # CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' @@ -551,7 +556,7 @@ CONFIG_HWMON=y # # -# SN Devices +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) # # @@ -603,7 +608,6 @@ CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y -# CONFIG_RELAYFS_FS is not set # CONFIG_CONFIGFS_FS is not set # @@ -658,6 +662,7 @@ CONFIG_PARTITION_ADVANCED=y # CONFIG_SGI_PARTITION is not set # CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set # CONFIG_EFI_PARTITION is not set # @@ -695,6 +700,8 @@ CONFIG_DEBUG_MUTEXES=y # CONFIG_DEBUG_INFO is not set # CONFIG_DEBUG_FS is not set # CONFIG_DEBUG_VM is not set +# CONFIG_UNWIND_INFO is not set +CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_DEBUGGER is not set # CONFIG_BDI_SWITCH is not set diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 80e9fe2632b8..803858e86160 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -12,15 +12,15 @@ endif obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ irq.o align.o signal_32.o pmc.o vdso.o \ - init_task.o process.o systbl.o + init_task.o process.o systbl.o idle.o obj-y += vdso32/ obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ signal_64.o ptrace32.o \ paca.o cpu_setup_power4.o \ - firmware.o sysfs.o idle_64.o + firmware.o sysfs.o obj-$(CONFIG_PPC64) += vdso64/ obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o -obj-$(CONFIG_POWER4) += idle_power4.o +obj-$(CONFIG_PPC_970_NAP) += idle_power4.o obj-$(CONFIG_PPC_OF) += of_device.o prom_parse.o procfs-$(CONFIG_PPC64) := proc_ppc64.o obj-$(CONFIG_PROC_FS) += $(procfs-y) @@ -34,6 +34,11 @@ obj-$(CONFIG_IBMEBUS) += ibmebus.o obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o +obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o +obj-$(CONFIG_TAU) += tau_6xx.o +obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o +obj32-$(CONFIG_MODULES) += module_32.o +obj-$(CONFIG_E500) += perfmon_fsl_booke.o ifeq ($(CONFIG_PPC_MERGE),y) @@ -51,7 +56,6 @@ obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_BOOTX_TEXT) += btext.o -obj-$(CONFIG_6xx) += idle_6xx.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o @@ -77,6 +81,7 @@ smpobj-$(CONFIG_SMP) += smp.o endif +obj-$(CONFIG_PPC32) += $(obj32-y) obj-$(CONFIG_PPC64) += $(obj64-y) extra-$(CONFIG_PPC_FPU) += fpu.o diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 882889b15926..8f85c5e8a55a 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -91,6 +91,7 @@ int main(void) #endif /* CONFIG_PPC64 */ DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); + DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); DEFINE(TI_TASK, offsetof(struct thread_info, task)); #ifdef CONFIG_PPC32 @@ -105,8 +106,6 @@ int main(void) DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); - DEFINE(PLATFORM_LPAR, PLATFORM_LPAR); - /* paca */ DEFINE(PACA_SIZE, sizeof(struct paca_struct)); DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index)); diff --git a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S similarity index 100% rename from arch/ppc/kernel/cpu_setup_6xx.S rename to arch/powerpc/kernel/cpu_setup_6xx.S diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 211d72653ea6..764d07329716 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -61,7 +61,7 @@ static int __init parse_elfcorehdr(char *p) if (p) elfcorehdr_addr = memparse(p, &p); - return 0; + return 1; } __setup("elfcorehdr=", parse_elfcorehdr); #endif @@ -71,7 +71,7 @@ static int __init parse_savemaxmem(char *p) if (p) saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1; - return 0; + return 1; } __setup("savemaxmem=", parse_savemaxmem); diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 4827ca1ec89b..8866fd26c6b9 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -128,45 +128,48 @@ transfer_to_handler: stw r12,4(r11) #endif b 3f + 2: /* if from kernel, check interrupted DOZE/NAP mode and * check for stack overflow */ + lwz r9,THREAD_INFO-THREAD(r12) + cmplw r1,r9 /* if r1 <= current->thread_info */ + ble- stack_ovf /* then the kernel stack overflowed */ +5: #ifdef CONFIG_6xx - mfspr r11,SPRN_HID0 - mtcr r11 -BEGIN_FTR_SECTION - bt- 8,power_save_6xx_restore /* Check DOZE */ -END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) -BEGIN_FTR_SECTION - bt- 9,power_save_6xx_restore /* Check NAP */ -END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) + tophys(r9,r9) /* check local flags */ + lwz r12,TI_LOCAL_FLAGS(r9) + mtcrf 0x01,r12 + bt- 31-TLF_NAPPING,4f #endif /* CONFIG_6xx */ .globl transfer_to_handler_cont transfer_to_handler_cont: - lwz r11,THREAD_INFO-THREAD(r12) - cmplw r1,r11 /* if r1 <= current->thread_info */ - ble- stack_ovf /* then the kernel stack overflowed */ 3: mflr r9 lwz r11,0(r9) /* virtual address of handler */ lwz r9,4(r9) /* where to go when done */ - FIX_SRR1(r10,r12) mtspr SPRN_SRR0,r11 mtspr SPRN_SRR1,r10 mtlr r9 SYNC RFI /* jump to handler, enable MMU */ +#ifdef CONFIG_6xx +4: rlwinm r12,r12,0,~_TLF_NAPPING + stw r12,TI_LOCAL_FLAGS(r9) + b power_save_6xx_restore +#endif + /* * On kernel stack overflow, load up an initial stack pointer * and call StackOverflow(regs), which should not return. */ stack_ovf: /* sometimes we use a statically-allocated stack, which is OK. */ - lis r11,_end@h - ori r11,r11,_end@l - cmplw r1,r11 - ble 3b /* r1 <= &_end is OK */ + lis r12,_end@h + ori r12,r12,_end@l + cmplw r1,r12 + ble 5b /* r1 <= &_end is OK */ SAVE_NVGPRS(r11) addi r3,r1,STACK_FRAME_OVERHEAD lis r1,init_thread_union@ha diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 1060155d84c3..19ad5c6b1818 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -617,6 +617,12 @@ _GLOBAL(enter_rtas) mfsrr1 r10 std r10,_SRR1(r1) + /* Temporary workaround to clear CR until RTAS can be modified to + * ignore all bits. + */ + li r0,0 + mtcr r0 + /* There is no way it is acceptable to get here with interrupts enabled, * check it with the asm equivalent of WARN_ON */ diff --git a/arch/powerpc/kernel/firmware.c b/arch/powerpc/kernel/firmware.c index 4d37a3cb80f6..0bfe9061720a 100644 --- a/arch/powerpc/kernel/firmware.c +++ b/arch/powerpc/kernel/firmware.c @@ -14,7 +14,9 @@ */ #include +#include #include -unsigned long ppc64_firmware_features; +unsigned long powerpc_firmware_features; +EXPORT_SYMBOL_GPL(powerpc_firmware_features); diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 35084f3a841b..b7d140430a41 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -376,17 +376,53 @@ label##_common: \ bl hdlr; \ b .ret_from_except +/* + * Like STD_EXCEPTION_COMMON, but for exceptions that can occur + * in the idle task and therefore need the special idle handling. + */ +#define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + FINISH_NAP; \ + DISABLE_INTS; \ + bl .save_nvgprs; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b .ret_from_except + #define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \ .align 7; \ .globl label##_common; \ label##_common: \ EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + FINISH_NAP; \ DISABLE_INTS; \ bl .ppc64_runlatch_on; \ addi r3,r1,STACK_FRAME_OVERHEAD; \ bl hdlr; \ b .ret_from_except_lite +/* + * When the idle code in power4_idle puts the CPU into NAP mode, + * it has to do so in a loop, and relies on the external interrupt + * and decrementer interrupt entry code to get it out of the loop. + * It sets the _TLF_NAPPING bit in current_thread_info()->local_flags + * to signal that it is in the loop and needs help to get out. + */ +#ifdef CONFIG_PPC_970_NAP +#define FINISH_NAP \ +BEGIN_FTR_SECTION \ + clrrdi r11,r1,THREAD_SHIFT; \ + ld r9,TI_LOCAL_FLAGS(r11); \ + andi. r10,r9,_TLF_NAPPING; \ + bnel power4_fixup_nap; \ +END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) +#else +#define FINISH_NAP +#endif + /* * Start of pSeries system interrupt routines */ @@ -772,6 +808,7 @@ hardware_interrupt_iSeries_masked: .globl machine_check_common machine_check_common: EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC) + FINISH_NAP DISABLE_INTS bl .save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD @@ -783,7 +820,7 @@ machine_check_common: STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) - STD_EXCEPTION_COMMON(0xf00, performance_monitor, .performance_monitor_exception) + STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception) STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) #ifdef CONFIG_ALTIVEC STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) @@ -1034,6 +1071,7 @@ unrecov_slb: .globl hardware_interrupt_entry hardware_interrupt_common: EXCEPTION_PROLOG_COMMON(0x500, PACA_EXGEN) + FINISH_NAP hardware_interrupt_entry: DISABLE_INTS bl .ppc64_runlatch_on @@ -1041,6 +1079,15 @@ hardware_interrupt_entry: bl .do_IRQ b .ret_from_except_lite +#ifdef CONFIG_PPC_970_NAP +power4_fixup_nap: + andc r9,r9,r10 + std r9,TI_LOCAL_FLAGS(r11) + ld r10,_LINK(r1) /* make idle task do the */ + std r10,_NIP(r1) /* equivalent of a blr */ + blr +#endif + .align 7 .globl alignment_common alignment_common: @@ -1544,7 +1591,11 @@ _STATIC(__boot_from_prom) mr r28,r6 mr r27,r7 - /* Align the stack to 16-byte boundary for broken yaboot */ + /* + * Align the stack to 16-byte boundary + * Depending on the size and layout of the ELF sections in the initial + * boot binary, the stack pointer will be unalignet on PowerMac + */ rldicr r1,r1,0,59 /* Make sure we are running in 64 bits mode */ @@ -1847,21 +1898,6 @@ _STATIC(start_here_multiplatform) bl .__save_cpu_setup sync - /* Setup a valid physical PACA pointer in SPRG3 for early_setup - * note that boot_cpuid can always be 0 nowadays since there is - * nowhere it can be initialized differently before we reach this - * code - */ - LOAD_REG_IMMEDIATE(r27, boot_cpuid) - add r27,r27,r26 - lwz r27,0(r27) - - LOAD_REG_IMMEDIATE(r24, paca) /* Get base vaddr of paca array */ - mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */ - add r13,r13,r24 /* for this processor. */ - add r13,r13,r26 /* convert to physical addr */ - mtspr SPRN_SPRG3,r13 - /* Do very early kernel initializations, including initial hash table, * stab and slb setup before we turn on relocation. */ @@ -1930,6 +1966,17 @@ _STATIC(start_here_common) /* Not reached */ BUG_OPCODE +/* Put the paca pointer into r13 and SPRG3 */ +_GLOBAL(setup_boot_paca) + LOAD_REG_IMMEDIATE(r3, boot_cpuid) + lwz r3,0(r3) + LOAD_REG_IMMEDIATE(r4, paca) /* Get base vaddr of paca array */ + mulli r3,r3,PACA_SIZE /* Calculate vaddr of right paca */ + add r13,r3,r4 /* for this processor. */ + mtspr SPRN_SPRG3,r13 + + blr + /* * We put a few things here that have to be page-aligned. * This stuff goes at the beginning of the bss, which is page-aligned. diff --git a/arch/powerpc/kernel/idle_64.c b/arch/powerpc/kernel/idle.c similarity index 64% rename from arch/powerpc/kernel/idle_64.c rename to arch/powerpc/kernel/idle.c index b879d3057ef8..d491052c8e0c 100644 --- a/arch/powerpc/kernel/idle_64.c +++ b/arch/powerpc/kernel/idle.c @@ -2,13 +2,17 @@ * Idle daemon for PowerPC. Idle daemon will handle any action * that needs to be taken when the system becomes idle. * - * Originally Written by Cort Dougan (cort@cs.nmt.edu) + * Originally written by Cort Dougan (cort@cs.nmt.edu). + * Subsequent 32-bit hacking by Tom Rini, Armin Kuster, + * Paul Mackerras and others. * * iSeries supported added by Mike Corrigan * * Additional shared processor, SMT, and firmware support * Copyright (c) 2003 Dave Engebretsen * + * 32-bit and 64-bit versions merged by Paul Mackerras + * * 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 @@ -29,18 +33,43 @@ #include #include -extern void power4_idle(void); +#ifdef CONFIG_HOTPLUG_CPU +#define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \ + system_state == SYSTEM_RUNNING) +#else +#define cpu_should_die() 0 +#endif -void default_idle(void) +/* + * The body of the idle task. + */ +void cpu_idle(void) { - unsigned int cpu = smp_processor_id(); + if (ppc_md.idle_loop) + ppc_md.idle_loop(); /* doesn't return */ + set_thread_flag(TIF_POLLING_NRFLAG); - while (1) { - if (!need_resched()) { - while (!need_resched() && !cpu_is_offline(cpu)) { - ppc64_runlatch_off(); + while (!need_resched() && !cpu_should_die()) { + ppc64_runlatch_off(); + if (ppc_md.power_save) { + clear_thread_flag(TIF_POLLING_NRFLAG); + /* + * smp_mb is so clearing of TIF_POLLING_NRFLAG + * is ordered w.r.t. need_resched() test. + */ + smp_mb(); + local_irq_disable(); + + /* check again after disabling irqs */ + if (!need_resched() && !cpu_should_die()) + ppc_md.power_save(); + + local_irq_enable(); + set_thread_flag(TIF_POLLING_NRFLAG); + + } else { /* * Go into low thread priority and possibly * low power mode. @@ -48,46 +77,18 @@ void default_idle(void) HMT_low(); HMT_very_low(); } - - HMT_medium(); } + HMT_medium(); ppc64_runlatch_on(); + if (cpu_should_die()) + cpu_die(); preempt_enable_no_resched(); schedule(); preempt_disable(); - if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) - cpu_die(); } } -void native_idle(void) -{ - while (1) { - ppc64_runlatch_off(); - - if (!need_resched()) - power4_idle(); - - if (need_resched()) { - ppc64_runlatch_on(); - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - } - - if (cpu_is_offline(smp_processor_id()) && - system_state == SYSTEM_RUNNING) - cpu_die(); - } -} - -void cpu_idle(void) -{ - BUG_ON(NULL == ppc_md.idle_loop); - ppc_md.idle_loop(); -} - int powersave_nap; #ifdef CONFIG_SYSCTL diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S index 444fdcc769f1..b45fa0e37212 100644 --- a/arch/powerpc/kernel/idle_6xx.S +++ b/arch/powerpc/kernel/idle_6xx.S @@ -22,8 +22,6 @@ #include #include -#undef DEBUG - .text /* @@ -87,19 +85,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) cmpwi 0,r3,0 beqlr - /* Clear MSR:EE */ - mfmsr r7 - rlwinm r0,r7,0,17,15 - mtmsr r0 - - /* Check current_thread_info()->flags */ - rlwinm r4,r1,0,0,18 - lwz r4,TI_FLAGS(r4) - andi. r0,r4,_TIF_NEED_RESCHED - beq 1f - mtmsr r7 /* out of line this ? */ - blr -1: /* Some pre-nap cleanups needed on some CPUs */ andis. r0,r3,HID0_NAP@h beq 2f @@ -122,12 +107,6 @@ BEGIN_FTR_SECTION dcbf 0,r4 dcbf 0,r4 END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR) -#ifdef DEBUG - lis r6,nap_enter_count@ha - lwz r4,nap_enter_count@l(r6) - addi r4,r4,1 - stw r4,nap_enter_count@l(r6) -#endif 2: BEGIN_FTR_SECTION /* Go to low speed mode on some 750FX */ @@ -157,47 +136,42 @@ BEGIN_FTR_SECTION DSSALL sync END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) - ori r7,r7,MSR_EE /* Could be ommited (already set) */ + rlwinm r9,r1,0,0,31-THREAD_SHIFT /* current thread_info */ + lwz r8,TI_LOCAL_FLAGS(r9) /* set napping bit */ + ori r8,r8,_TLF_NAPPING /* so when we take an exception */ + stw r8,TI_LOCAL_FLAGS(r9) /* it will return to our caller */ + mfmsr r7 + ori r7,r7,MSR_EE oris r7,r7,MSR_POW@h - sync - isync +1: sync mtmsr r7 isync - sync - blr - + b 1b + /* * Return from NAP/DOZE mode, restore some CPU specific registers, * we are called with DR/IR still off and r2 containing physical - * address of current. + * address of current. R11 points to the exception frame (physical + * address). We have to preserve r10. */ _GLOBAL(power_save_6xx_restore) - mfspr r11,SPRN_HID0 - rlwinm. r11,r11,0,10,8 /* Clear NAP & copy NAP bit !state to cr1 EQ */ - cror 4*cr1+eq,4*cr0+eq,4*cr0+eq -BEGIN_FTR_SECTION - rlwinm r11,r11,0,9,7 /* Clear DOZE */ -END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) - mtspr SPRN_HID0, r11 + lwz r9,_LINK(r11) /* interrupted in ppc6xx_idle: */ + stw r9,_NIP(r11) /* make it do a blr */ -#ifdef DEBUG - beq cr1,1f - lis r11,(nap_return_count-KERNELBASE)@ha - lwz r9,nap_return_count@l(r11) - addi r9,r9,1 - stw r9,nap_return_count@l(r11) -1: -#endif - - rlwinm r9,r1,0,0,18 - tophys(r9,r9) - lwz r11,TI_CPU(r9) +#ifdef CONFIG_SMP + mfspr r12,SPRN_SPRG3 + lwz r11,TI_CPU(r12) /* get cpu number * 4 */ slwi r11,r11,2 +#else + li r11,0 +#endif /* Todo make sure all these are in the same page - * and load r22 (@ha part + CPU offset) only once + * and load r11 (@ha part + CPU offset) only once */ BEGIN_FTR_SECTION - beq cr1,1f + mfspr r9,SPRN_HID0 + andis. r9,r9,HID0_NAP@h + beq 1f addis r9,r11,(nap_save_msscr0-KERNELBASE)@ha lwz r9,nap_save_msscr0@l(r9) mtspr SPRN_MSSCR0, r9 @@ -220,14 +194,5 @@ _GLOBAL(nap_save_msscr0) _GLOBAL(nap_save_hid1) .space 4*NR_CPUS -_GLOBAL(powersave_nap) - .long 0 _GLOBAL(powersave_lowspeed) .long 0 - -#ifdef DEBUG -_GLOBAL(nap_enter_count) - .space 4 -_GLOBAL(nap_return_count) - .space 4 -#endif diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S index c16b4afab582..d85c7c938eed 100644 --- a/arch/powerpc/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S @@ -1,11 +1,5 @@ /* - * This file contains the power_save function for 6xx & 7xxx CPUs - * rewritten in assembler - * - * Warning ! This code assumes that if your machine has a 750fx - * it will have PLL 1 set to low speed mode (used during NAP/DOZE). - * if this is not the case some additional changes will have to - * be done to check a runtime var (a bit like powersave-nap) + * This file contains the power_save function for 970-family CPUs. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,53 +20,31 @@ .text -/* - * Here is the power_save_6xx function. This could eventually be - * split into several functions & changing the function pointer - * depending on the various features. - */ _GLOBAL(power4_idle) BEGIN_FTR_SECTION blr END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) - /* We must dynamically check for the NAP feature as it - * can be cleared by CPU init after the fixups are done - */ - LOAD_REG_ADDRBASE(r3,cur_cpu_spec) - ld r4,ADDROFF(cur_cpu_spec)(r3) - ld r4,CPU_SPEC_FEATURES(r4) - andi. r0,r4,CPU_FTR_CAN_NAP - beqlr /* Now check if user or arch enabled NAP mode */ LOAD_REG_ADDRBASE(r3,powersave_nap) lwz r4,ADDROFF(powersave_nap)(r3) cmpwi 0,r4,0 beqlr - /* Clear MSR:EE */ - mfmsr r7 - li r4,0 - ori r4,r4,MSR_EE - andc r0,r7,r4 - mtmsrd r0 - - /* Check current_thread_info()->flags */ - clrrdi r4,r1,THREAD_SHIFT - ld r4,TI_FLAGS(r4) - andi. r0,r4,_TIF_NEED_RESCHED - beq 1f - mtmsrd r7 /* out of line this ? */ - blr -1: /* Go to NAP now */ BEGIN_FTR_SECTION DSSALL sync END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + clrrdi r9,r1,THREAD_SHIFT /* current thread_info */ + ld r8,TI_LOCAL_FLAGS(r9) /* set napping bit */ + ori r8,r8,_TLF_NAPPING /* so when we take an exception */ + std r8,TI_LOCAL_FLAGS(r9) /* it will return to our caller */ + mfmsr r7 + ori r7,r7,MSR_EE oris r7,r7,MSR_POW@h - sync +1: sync isync mtmsrd r7 isync - sync - blr + b 1b + diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 771a59cbd213..57d560c68897 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -272,18 +272,26 @@ unsigned int virt_irq_to_real_map[NR_IRQS]; * Don't use virtual irqs 0, 1, 2 for devices. * The pcnet32 driver considers interrupt numbers < 2 to be invalid, * and 2 is the XICS IPI interrupt. - * We limit virtual irqs to 17 less than NR_IRQS so that when we - * offset them by 16 (to reserve the first 16 for ISA interrupts) - * we don't end up with an interrupt number >= NR_IRQS. + * We limit virtual irqs to __irq_offet_value less than virt_irq_max so + * that when we offset them we don't end up with an interrupt + * number >= virt_irq_max. */ #define MIN_VIRT_IRQ 3 -#define MAX_VIRT_IRQ (NR_IRQS - NUM_ISA_INTERRUPTS - 1) -#define NR_VIRT_IRQS (MAX_VIRT_IRQ - MIN_VIRT_IRQ + 1) + +unsigned int virt_irq_max; +static unsigned int max_virt_irq; +static unsigned int nr_virt_irqs; void virt_irq_init(void) { int i; + + if ((virt_irq_max == 0) || (virt_irq_max > (NR_IRQS - 1))) + virt_irq_max = NR_IRQS - 1; + max_virt_irq = virt_irq_max - __irq_offset_value; + nr_virt_irqs = max_virt_irq - MIN_VIRT_IRQ + 1; + for (i = 0; i < NR_IRQS; i++) virt_irq_to_real_map[i] = UNDEFINED_IRQ; } @@ -308,17 +316,17 @@ int virt_irq_create_mapping(unsigned int real_irq) return real_irq; } - /* map to a number between MIN_VIRT_IRQ and MAX_VIRT_IRQ */ + /* map to a number between MIN_VIRT_IRQ and max_virt_irq */ virq = real_irq; - if (virq > MAX_VIRT_IRQ) - virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ; + if (virq > max_virt_irq) + virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ; /* search for this number or a free slot */ first_virq = virq; while (virt_irq_to_real_map[virq] != UNDEFINED_IRQ) { if (virt_irq_to_real_map[virq] == real_irq) return virq; - if (++virq > MAX_VIRT_IRQ) + if (++virq > max_virt_irq) virq = MIN_VIRT_IRQ; if (virq == first_virq) goto nospace; /* oops, no free slots */ @@ -330,8 +338,8 @@ int virt_irq_create_mapping(unsigned int real_irq) nospace: if (!warned) { printk(KERN_CRIT "Interrupt table is full\n"); - printk(KERN_CRIT "Increase NR_IRQS (currently %d) " - "in your kernel sources and rebuild.\n", NR_IRQS); + printk(KERN_CRIT "Increase virt_irq_max (currently %d) " + "in your kernel sources and rebuild.\n", virt_irq_max); warned = 1; } return NO_IRQ; @@ -349,8 +357,8 @@ unsigned int real_irq_to_virt_slowpath(unsigned int real_irq) virq = real_irq; - if (virq > MAX_VIRT_IRQ) - virq = (virq % NR_VIRT_IRQS) + MIN_VIRT_IRQ; + if (virq > max_virt_irq) + virq = (virq % nr_virt_irqs) + MIN_VIRT_IRQ; first_virq = virq; @@ -360,7 +368,7 @@ unsigned int real_irq_to_virt_slowpath(unsigned int real_irq) virq++; - if (virq >= MAX_VIRT_IRQ) + if (virq >= max_virt_irq) virq = 0; } while (first_virq != virq); @@ -379,7 +387,7 @@ void irq_ctx_init(void) struct thread_info *tp; int i; - for_each_cpu(i) { + for_each_possible_cpu(i) { memset((void *)softirq_ctx[i], 0, THREAD_SIZE); tp = softirq_ctx[i]; tp->cpu = i; diff --git a/arch/ppc/kernel/l2cr.S b/arch/powerpc/kernel/l2cr_6xx.S similarity index 100% rename from arch/ppc/kernel/l2cr.S rename to arch/powerpc/kernel/l2cr_6xx.S diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index c7a799a09516..6e67b5b49ba1 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -37,7 +37,7 @@ static int legacy_serial_console = -1; static int __init add_legacy_port(struct device_node *np, int want_index, int iotype, phys_addr_t base, phys_addr_t taddr, unsigned long irq, - unsigned int flags) + upf_t flags) { u32 *clk, *spd, clock = BASE_BAUD * 16; int index; @@ -113,7 +113,7 @@ static int __init add_legacy_soc_port(struct device_node *np, { phys_addr_t addr; u32 *addrp; - unsigned int flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; + upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; /* We only support ports that have a clock frequency properly * encoded in the device-tree. @@ -236,6 +236,23 @@ static int __init add_legacy_pci_port(struct device_node *np, } #endif +static void __init setup_legacy_serial_console(int console) +{ + struct legacy_serial_info *info = + &legacy_serial_infos[console]; + void __iomem *addr; + + if (info->taddr == 0) + return; + addr = ioremap(info->taddr, 0x1000); + if (addr == NULL) + return; + if (info->speed == 0) + info->speed = udbg_probe_uart_speed(addr, info->clock); + DBG("default console speed = %d\n", info->speed); + udbg_init_uart(addr, info->speed, info->clock); +} + /* * This is called very early, as part of setup_system() or eventually * setup_arch(), basically before anything else in this file. This function @@ -318,25 +335,8 @@ void __init find_legacy_serial_ports(void) #endif DBG("legacy_serial_console = %d\n", legacy_serial_console); - - /* udbg is 64 bits only for now, that will change soon though ... */ - while (legacy_serial_console >= 0) { - struct legacy_serial_info *info = - &legacy_serial_infos[legacy_serial_console]; - void __iomem *addr; - - if (info->taddr == 0) - break; - addr = ioremap(info->taddr, 0x1000); - if (addr == NULL) - break; - if (info->speed == 0) - info->speed = udbg_probe_uart_speed(addr, info->clock); - DBG("default console speed = %d\n", info->speed); - udbg_init_uart(addr, info->speed, info->clock); - break; - } - + if (legacy_serial_console >= 0) + setup_legacy_serial_console(legacy_serial_console); DBG(" <- find_legacy_serial_port()\n"); } diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index e789fef4eb8a..2cbde865d4f5 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -37,7 +37,7 @@ #include #include -#define MODULE_VERS "1.6" +#define MODULE_VERS "1.7" #define MODULE_NAME "lparcfg" /* #define LPARCFG_DEBUG */ @@ -56,7 +56,7 @@ static unsigned long get_purr(void) unsigned long sum_purr = 0; int cpu; - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { sum_purr += lppaca[cpu].emulated_time_base; #ifdef PURR_DEBUG @@ -149,17 +149,17 @@ static void log_plpar_hcall_return(unsigned long rc, char *tag) if (rc == 0) /* success, return */ return; /* check for null tag ? */ - if (rc == H_Hardware) + if (rc == H_HARDWARE) printk(KERN_INFO "plpar-hcall (%s) failed with hardware fault\n", tag); - else if (rc == H_Function) + else if (rc == H_FUNCTION) printk(KERN_INFO "plpar-hcall (%s) failed; function not allowed\n", tag); - else if (rc == H_Authority) + else if (rc == H_AUTHORITY) printk(KERN_INFO - "plpar-hcall (%s) failed; not authorized to this function\n", - tag); - else if (rc == H_Parameter) + "plpar-hcall (%s) failed; not authorized to this" + " function\n", tag); + else if (rc == H_PARAMETER) printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n", tag); else @@ -209,7 +209,7 @@ static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs) unsigned long dummy; rc = plpar_hcall(H_PIC, 0, 0, 0, 0, pool_idle_time, num_procs, &dummy); - if (rc != H_Authority) + if (rc != H_AUTHORITY) log_plpar_hcall_return(rc, "H_PIC"); } @@ -222,7 +222,7 @@ static unsigned long get_purr(void) int cpu; struct cpu_usage *cu; - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { cu = &per_cpu(cpu_usage_array, cpu); sum_purr += cu->current_tb; } @@ -242,7 +242,7 @@ static void parse_system_parameter_string(struct seq_file *m) { int call_status; - char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); + unsigned char *local_buffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL); if (!local_buffer) { printk(KERN_ERR "%s %s kmalloc failure at line %d \n", __FILE__, __FUNCTION__, __LINE__); @@ -254,7 +254,8 @@ static void parse_system_parameter_string(struct seq_file *m) call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, NULL, SPLPAR_CHARACTERISTICS_TOKEN, - __pa(rtas_data_buf)); + __pa(rtas_data_buf), + RTAS_DATA_BUF_SIZE); memcpy(local_buffer, rtas_data_buf, SPLPAR_MAXLENGTH); spin_unlock(&rtas_data_buf_lock); @@ -275,7 +276,7 @@ static void parse_system_parameter_string(struct seq_file *m) #ifdef LPARCFG_DEBUG printk(KERN_INFO "success calling get-system-parameter \n"); #endif - splpar_strlen = local_buffer[0] * 16 + local_buffer[1]; + splpar_strlen = local_buffer[0] * 256 + local_buffer[1]; local_buffer += 2; /* step over strlen value */ memset(workbuffer, 0, SPLPAR_MAXLENGTH); @@ -529,13 +530,13 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, retval = plpar_hcall_norets(H_SET_PPP, *new_entitled_ptr, *new_weight_ptr); - if (retval == H_Success || retval == H_Constrained) { + if (retval == H_SUCCESS || retval == H_CONSTRAINED) { retval = count; - } else if (retval == H_Busy) { + } else if (retval == H_BUSY) { retval = -EBUSY; - } else if (retval == H_Hardware) { + } else if (retval == H_HARDWARE) { retval = -EIO; - } else if (retval == H_Parameter) { + } else if (retval == H_PARAMETER) { retval = -EINVAL; } else { printk(KERN_WARNING "%s: received unknown hv return code %ld", diff --git a/arch/ppc/kernel/module.c b/arch/powerpc/kernel/module_32.c similarity index 100% rename from arch/ppc/kernel/module.c rename to arch/powerpc/kernel/module_32.c diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index fd7db8d542db..ada50aa5b600 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -160,7 +160,7 @@ static int dev_nvram_ioctl(struct inode *inode, struct file *file, case IOC_NVRAM_GET_OFFSET: { int part, offset; - if (_machine != PLATFORM_POWERMAC) + if (!machine_is(powermac)) return -EINVAL; if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0) return -EFAULT; @@ -174,8 +174,9 @@ static int dev_nvram_ioctl(struct inode *inode, struct file *file, return 0; } #endif /* CONFIG_PPC_PMAC */ + default: + return -EINVAL; } - return -EINVAL; } struct file_operations nvram_fops = { @@ -443,7 +444,7 @@ static int nvram_setup_partition(void) * in our nvram, as Apple defined partitions use pretty much * all of the space */ - if (_machine == PLATFORM_POWERMAC) + if (machine_is(powermac)) return -ENOSPC; /* see if we have an OS partition that meets our needs. diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 5d1b708086bd..f505a8827e3e 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -56,14 +56,11 @@ struct lppaca lppaca[] = { * processors. The processor VPD array needs one entry per physical * processor (not thread). */ -#define PACA_INIT_COMMON(number, start, asrr, asrv) \ +#define PACA_INIT_COMMON(number) \ .lppaca_ptr = &lppaca[number], \ .lock_token = 0x8000, \ .paca_index = (number), /* Paca Index */ \ .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \ - .stab_real = (asrr), /* Real pointer to segment table */ \ - .stab_addr = (asrv), /* Virt pointer to segment table */ \ - .cpu_start = (start), /* Processor start */ \ .hw_cpu_id = 0xffff, #ifdef CONFIG_PPC_ISERIES @@ -72,30 +69,20 @@ struct lppaca lppaca[] = { #define PACA_INIT(number) \ { \ - PACA_INIT_COMMON(number, 0, 0, 0) \ - PACA_INIT_ISERIES(number) \ -} - -#define BOOTCPU_PACA_INIT(number) \ -{ \ - PACA_INIT_COMMON(number, 1, 0, (u64)&initial_stab) \ + PACA_INIT_COMMON(number) \ PACA_INIT_ISERIES(number) \ } #else #define PACA_INIT(number) \ { \ - PACA_INIT_COMMON(number, 0, 0, 0) \ + PACA_INIT_COMMON(number) \ } -#define BOOTCPU_PACA_INIT(number) \ -{ \ - PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, (u64)&initial_stab) \ -} #endif struct paca_struct paca[] = { - BOOTCPU_PACA_INIT(0), + PACA_INIT(0), #if NR_CPUS > 1 PACA_INIT( 1), PACA_INIT( 2), PACA_INIT( 3), #if NR_CPUS > 4 diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 704c846b2b0f..b129d2e4b759 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -787,7 +787,7 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) * fix has to be done by making the remapping per-host and always * filling the pci_to_OF map. --BenH */ - if (_machine == _MACH_Pmac && busnr >= 0xf0) + if (machine_is(powermac) && busnr >= 0xf0) busnr -= 0xf0; else #endif @@ -1728,7 +1728,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) * (bus 0 is HT root), we return the AGP one instead. */ #ifdef CONFIG_PPC_PMAC - if (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4")) + if (machine_is(powermac) && machine_is_compatible("MacRISC4")) if (bus == 0) bus = 0xf0; #endif /* CONFIG_PPC_PMAC */ diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index ba92bab7cc2c..4c4449be81ce 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -78,6 +78,7 @@ int global_phb_number; /* Global phb counter */ /* Cached ISA bridge dev. */ struct pci_dev *ppc64_isabridge_dev = NULL; +EXPORT_SYMBOL_GPL(ppc64_isabridge_dev); static void fixup_broken_pcnet32(struct pci_dev* dev) { diff --git a/arch/ppc/kernel/perfmon_fsl_booke.c b/arch/powerpc/kernel/perfmon_fsl_booke.c similarity index 100% rename from arch/ppc/kernel/perfmon_fsl_booke.c rename to arch/powerpc/kernel/perfmon_fsl_booke.c diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c index 7ba42a405f41..3c2cf661f6d9 100644 --- a/arch/powerpc/kernel/proc_ppc64.c +++ b/arch/powerpc/kernel/proc_ppc64.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -51,7 +52,7 @@ static int __init proc_ppc64_create(void) if (!root) return 1; - if (!(platform_is_pseries() || _machine == PLATFORM_CELL)) + if (!machine_is(pseries) && !machine_is(cell)) return 0; if (!proc_mkdir("rtas", root)) diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index f698aa77127e..2dd47d2dd998 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -45,6 +45,7 @@ #include #include #include +#include #ifdef CONFIG_PPC64 #include #endif @@ -362,7 +363,11 @@ static void show_instructions(struct pt_regs *regs) if (!(i % 8)) printk("\n"); - if (BAD_PC(pc) || __get_user(instr, (unsigned int *)pc)) { + /* We use __get_user here *only* to avoid an OOPS on a + * bad address because the pc *should* only be a + * kernel address. + */ + if (BAD_PC(pc) || __get_user(instr, (unsigned int __user *)pc)) { printk("XXXXXXXX "); } else { if (regs->nip == pc) @@ -765,7 +770,7 @@ out: return error; } -static int validate_sp(unsigned long sp, struct task_struct *p, +int validate_sp(unsigned long sp, struct task_struct *p, unsigned long nbytes) { unsigned long stack_page = (unsigned long)task_stack_page(p); @@ -803,6 +808,8 @@ static int validate_sp(unsigned long sp, struct task_struct *p, #define FRAME_MARKER 2 #endif +EXPORT_SYMBOL(validate_sp); + unsigned long get_wchan(struct task_struct *p) { unsigned long ip, sp; @@ -827,7 +834,6 @@ unsigned long get_wchan(struct task_struct *p) } while (count++ < 16); return 0; } -EXPORT_SYMBOL(get_wchan); static int kstack_depth_to_print = 64; diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index d63cd562d9d5..4336390bcf34 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -383,14 +383,14 @@ static int __devinit finish_node_interrupts(struct device_node *np, /* Apple uses bits in there in a different way, let's * only keep the real sense bit on macs */ - if (_machine == PLATFORM_POWERMAC) + if (machine_is(powermac)) sense &= 0x1; np->intrs[intrcount].sense = map_mpic_senses[sense]; } #ifdef CONFIG_PPC64 /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ - if (_machine == PLATFORM_POWERMAC && ic && ic->parent) { + if (machine_is(powermac) && ic && ic->parent) { char *name = get_property(ic->parent, "name", NULL); if (name && !strcmp(name, "u3")) np->intrs[intrcount].line += 128; @@ -570,6 +570,18 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, return rc; } +unsigned long __init of_get_flat_dt_root(void) +{ + unsigned long p = ((unsigned long)initial_boot_params) + + initial_boot_params->off_dt_struct; + + while(*((u32 *)p) == OF_DT_NOP) + p += 4; + BUG_ON (*((u32 *)p) != OF_DT_BEGIN_NODE); + p += 4; + return _ALIGN(p + strlen((char *)p) + 1, 4); +} + /** * This function can be used within scan_flattened_dt callback to get * access to properties @@ -612,6 +624,25 @@ void* __init of_get_flat_dt_prop(unsigned long node, const char *name, } while(1); } +int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) +{ + const char* cp; + unsigned long cplen, l; + + cp = of_get_flat_dt_prop(node, "compatible", &cplen); + if (cp == NULL) + return 0; + while (cplen > 0) { + if (strncasecmp(cp, compat, strlen(compat)) == 0) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, unsigned long align) { @@ -686,7 +717,7 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, #ifdef DEBUG if ((strlen(p) + l + 1) != allocl) { DBG("%s: p: %d, l: %d, a: %d\n", - pathp, strlen(p), l, allocl); + pathp, (int)strlen(p), l, allocl); } #endif p += strlen(p); @@ -854,35 +885,73 @@ void __init unflatten_device_tree(void) DBG(" <- unflatten_device_tree()\n"); } - static int __init early_init_dt_scan_cpus(unsigned long node, - const char *uname, int depth, void *data) + const char *uname, int depth, + void *data) { + static int logical_cpuid = 0; + char *type = of_get_flat_dt_prop(node, "device_type", NULL); +#ifdef CONFIG_ALTIVEC u32 *prop; - unsigned long size; - char *type = of_get_flat_dt_prop(node, "device_type", &size); +#endif + u32 *intserv; + int i, nthreads; + unsigned long len; + int found = 0; /* We are scanning "cpu" nodes only */ if (type == NULL || strcmp(type, "cpu") != 0) return 0; - boot_cpuid = 0; - boot_cpuid_phys = 0; - if (initial_boot_params && initial_boot_params->version >= 2) { - /* version 2 of the kexec param format adds the phys cpuid - * of booted proc. - */ - boot_cpuid_phys = initial_boot_params->boot_cpuid_phys; + /* Get physical cpuid */ + intserv = of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", &len); + if (intserv) { + nthreads = len / sizeof(int); } else { - /* Check if it's the boot-cpu, set it's hw index now */ - if (of_get_flat_dt_prop(node, - "linux,boot-cpu", NULL) != NULL) { - prop = of_get_flat_dt_prop(node, "reg", NULL); - if (prop != NULL) - boot_cpuid_phys = *prop; - } + intserv = of_get_flat_dt_prop(node, "reg", NULL); + nthreads = 1; + } + + /* + * Now see if any of these threads match our boot cpu. + * NOTE: This must match the parsing done in smp_setup_cpu_maps. + */ + for (i = 0; i < nthreads; i++) { + /* + * version 2 of the kexec param format adds the phys cpuid of + * booted proc. + */ + if (initial_boot_params && initial_boot_params->version >= 2) { + if (intserv[i] == + initial_boot_params->boot_cpuid_phys) { + found = 1; + break; + } + } else { + /* + * Check if it's the boot-cpu, set it's hw index now, + * unfortunately this format did not support booting + * off secondary threads. + */ + if (of_get_flat_dt_prop(node, + "linux,boot-cpu", NULL) != NULL) { + found = 1; + break; + } + } + +#ifdef CONFIG_SMP + /* logical cpu id is always 0 on UP kernels */ + logical_cpuid++; +#endif + } + + if (found) { + DBG("boot cpu: logical %d physical %d\n", logical_cpuid, + intserv[i]); + boot_cpuid = logical_cpuid; + set_hard_smp_processor_id(boot_cpuid, intserv[i]); } - set_hard_smp_processor_id(0, boot_cpuid_phys); #ifdef CONFIG_ALTIVEC /* Check if we have a VMX and eventually update CPU features */ @@ -901,16 +970,10 @@ static int __init early_init_dt_scan_cpus(unsigned long node, #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_PPC_PSERIES - /* - * Check for an SMT capable CPU and set the CPU feature. We do - * this by looking at the size of the ibm,ppc-interrupt-server#s - * property - */ - prop = (u32 *)of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", - &size); - cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT; - if (prop && ((size / sizeof(u32)) > 1)) + if (nthreads > 1) cur_cpu_spec->cpu_features |= CPU_FTR_SMT; + else + cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT; #endif return 0; @@ -919,7 +982,6 @@ static int __init early_init_dt_scan_cpus(unsigned long node, static int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, int depth, void *data) { - u32 *prop; unsigned long *lprop; unsigned long l; char *p; @@ -930,14 +992,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node, (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) return 0; - /* get platform type */ - prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL); - if (prop == NULL) - return 0; -#ifdef CONFIG_PPC_MULTIPLATFORM - _machine = *prop; -#endif - #ifdef CONFIG_PPC64 /* check if iommu is forced on or off */ if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) @@ -964,15 +1018,15 @@ static int __init early_init_dt_scan_chosen(unsigned long node, * set of RTAS infos now if available */ { - u64 *basep, *entryp; + u64 *basep, *entryp, *sizep; basep = of_get_flat_dt_prop(node, "linux,rtas-base", NULL); entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL); - prop = of_get_flat_dt_prop(node, "linux,rtas-size", NULL); - if (basep && entryp && prop) { + sizep = of_get_flat_dt_prop(node, "linux,rtas-size", NULL); + if (basep && entryp && sizep) { rtas.base = *basep; rtas.entry = *entryp; - rtas.size = *prop; + rtas.size = *sizep; } } #endif /* CONFIG_PPC_RTAS */ @@ -1001,25 +1055,13 @@ static int __init early_init_dt_scan_chosen(unsigned long node, if (strstr(cmd_line, "mem=")) { char *p, *q; - unsigned long maxmem = 0; for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { q = p + 4; if (p > cmd_line && p[-1] != ' ') continue; - maxmem = simple_strtoul(q, &q, 0); - if (*q == 'k' || *q == 'K') { - maxmem <<= 10; - ++q; - } else if (*q == 'm' || *q == 'M') { - maxmem <<= 20; - ++q; - } else if (*q == 'g' || *q == 'G') { - maxmem <<= 30; - ++q; - } + memory_limit = memparse(q, &q); } - memory_limit = maxmem; } /* break now */ @@ -1755,7 +1797,7 @@ static int of_finish_dynamic_node(struct device_node *node) /* We don't support that function on PowerMac, at least * not yet */ - if (_machine == PLATFORM_POWERMAC) + if (machine_is(powermac)) return -ENODEV; /* fix up new node's linux_phandle field */ diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 813c2cd194c2..7e4d54821a07 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -180,6 +180,16 @@ static unsigned long __initdata prom_tce_alloc_start; static unsigned long __initdata prom_tce_alloc_end; #endif +/* Platforms codes are now obsolete in the kernel. Now only used within this + * file and ultimately gone too. Feel free to change them if you need, they + * are not shared with anything outside of this file anymore + */ +#define PLATFORM_PSERIES 0x0100 +#define PLATFORM_PSERIES_LPAR 0x0101 +#define PLATFORM_LPAR 0x0001 +#define PLATFORM_POWERMAC 0x0400 +#define PLATFORM_GENERIC 0x0500 + static int __initdata of_platform; static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; @@ -397,6 +407,11 @@ static void __init __attribute__((noreturn)) prom_panic(const char *reason) reason = PTRRELOC(reason); #endif prom_print(reason); + /* Do not call exit because it clears the screen on pmac + * it also causes some sort of double-fault on early pmacs */ + if (RELOC(of_platform) == PLATFORM_POWERMAC) + asm("trap\n"); + /* ToDo: should put up an SRC here on p/iSeries */ call_prom("exit", 0, 0); @@ -1487,7 +1502,10 @@ static int __init prom_find_machine_type(void) int len, i = 0; #ifdef CONFIG_PPC64 phandle rtas; + int x; #endif + + /* Look for a PowerMac */ len = prom_getprop(_prom->root, "compatible", compat, sizeof(compat)-1); if (len > 0) { @@ -1500,28 +1518,35 @@ static int __init prom_find_machine_type(void) if (strstr(p, RELOC("Power Macintosh")) || strstr(p, RELOC("MacRISC"))) return PLATFORM_POWERMAC; -#ifdef CONFIG_PPC64 - if (strstr(p, RELOC("Momentum,Maple"))) - return PLATFORM_MAPLE; - if (strstr(p, RELOC("IBM,CPB"))) - return PLATFORM_CELL; -#endif i += sl + 1; } } #ifdef CONFIG_PPC64 + /* If not a mac, try to figure out if it's an IBM pSeries or any other + * PAPR compliant platform. We assume it is if : + * - /device_type is "chrp" (please, do NOT use that for future + * non-IBM designs ! + * - it has /rtas + */ + len = prom_getprop(_prom->root, "device_type", + compat, sizeof(compat)-1); + if (len <= 0) + return PLATFORM_GENERIC; + if (strncmp(compat, RELOC("chrp"), 4)) + return PLATFORM_GENERIC; + /* Default to pSeries. We need to know if we are running LPAR */ rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); - 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; - } + if (!PHANDLE_VALID(rtas)) + return PLATFORM_GENERIC; + x = prom_getproplen(rtas, "ibm,hypertas-functions"); + if (x != PROM_ERROR) { + prom_printf("Hypertas detected, assuming LPAR !\n"); + return PLATFORM_PSERIES_LPAR; } return PLATFORM_PSERIES; #else - return PLATFORM_CHRP; + return PLATFORM_GENERIC; #endif } @@ -2029,7 +2054,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, { struct prom_t *_prom; unsigned long hdr; - u32 getprop_rval; unsigned long offset = reloc_offset(); #ifdef CONFIG_PPC32 @@ -2060,6 +2084,12 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, */ prom_init_stdout(); + /* + * Get default machine type. At this point, we do not differentiate + * between pSeries SMP and pSeries LPAR + */ + RELOC(of_platform) = prom_find_machine_type(); + /* Bail if this is a kdump kernel. */ if (PHYSICAL_START > 0) prom_panic("Error: You can't boot a kdump kernel from OF!\n"); @@ -2069,15 +2099,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, */ prom_check_initrd(r3, r4); - /* - * Get default machine type. At this point, we do not differentiate - * between pSeries SMP and pSeries LPAR - */ - RELOC(of_platform) = prom_find_machine_type(); - getprop_rval = RELOC(of_platform); - prom_setprop(_prom->chosen, "/chosen", "linux,platform", - &getprop_rval, sizeof(getprop_rval)); - #ifdef CONFIG_PPC_PSERIES /* * On pSeries, inform the firmware about our capabilities diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c index 1f03fb28cc0a..9c9ad1fa9cce 100644 --- a/arch/powerpc/kernel/rtas-proc.c +++ b/arch/powerpc/kernel/rtas-proc.c @@ -257,12 +257,12 @@ static int __init proc_rtas_init(void) { struct proc_dir_entry *entry; - if (_machine != PLATFORM_PSERIES && _machine != PLATFORM_PSERIES_LPAR) - return 1; + if (!machine_is(pseries)) + return -ENODEV; rtas_node = of_find_node_by_name(NULL, "rtas"); if (rtas_node == NULL) - return 1; + return -ENODEV; entry = create_proc_entry("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL); if (entry) diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index b5b2add7ad1e..0112318213ab 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ #include #include #include +#include struct rtas_t rtas = { .lock = SPIN_LOCK_UNLOCKED @@ -576,26 +578,26 @@ static void rtas_percpu_suspend_me(void *info) * We use "waiting" to indicate our state. As long * as it is >0, we are still trying to all join up. * If it goes to 0, we have successfully joined up and - * one thread got H_Continue. If any error happens, + * one thread got H_CONTINUE. If any error happens, * we set it to <0. */ local_irq_save(flags); do { rc = plpar_hcall_norets(H_JOIN); smp_rmb(); - } while (rc == H_Success && data->waiting > 0); - if (rc == H_Success) + } while (rc == H_SUCCESS && data->waiting > 0); + if (rc == H_SUCCESS) goto out; - if (rc == H_Continue) { + if (rc == H_CONTINUE) { data->waiting = 0; data->args->args[data->args->nargs] = rtas_call(ibm_suspend_me_token, 0, 1, NULL); - for_each_cpu(i) + for_each_possible_cpu(i) plpar_hcall_norets(H_PROD,i); } else { data->waiting = -EBUSY; - printk(KERN_ERR "Error on H_Join hypervisor call\n"); + printk(KERN_ERR "Error on H_JOIN hypervisor call\n"); } out: @@ -622,9 +624,9 @@ static int rtas_ibm_suspend_me(struct rtas_args *args) printk(KERN_ERR "Error doing global join\n"); /* Prod each CPU. This won't hurt, and will wake - * anyone we successfully put to sleep with H_Join + * anyone we successfully put to sleep with H_JOIN. */ - for_each_cpu(i) + for_each_possible_cpu(i) plpar_hcall_norets(H_PROD, i); return data.waiting; @@ -767,7 +769,7 @@ void __init rtas_initialize(void) * the stop-self token if any */ #ifdef CONFIG_PPC64 - if (_machine == PLATFORM_PSERIES_LPAR) { + if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR)) { rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); ibm_suspend_me_token = rtas_token("ibm,suspend-me"); } diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index c1d62bf11f29..1d93e73a7003 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -9,6 +9,9 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ + +#undef DEBUG + #include #include #include @@ -18,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -56,8 +61,6 @@ #include "setup.h" -#undef DEBUG - #ifdef DEBUG #include #define DBG(fmt...) udbg_printf(fmt) @@ -65,10 +68,12 @@ #define DBG(fmt...) #endif -#ifdef CONFIG_PPC_MULTIPLATFORM -int _machine = 0; -EXPORT_SYMBOL(_machine); -#endif +/* The main machine-dep calls structure + */ +struct machdep_calls ppc_md; +EXPORT_SYMBOL(ppc_md); +struct machdep_calls *machine_id; +EXPORT_SYMBOL(machine_id); unsigned long klimit = (unsigned long) _end; @@ -168,7 +173,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); #endif /* CONFIG_SMP && CONFIG_PPC32 */ seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); - + if (ppc_md.name) + seq_printf(m, "platform\t: %s\n", ppc_md.name); if (ppc_md.show_cpuinfo != NULL) ppc_md.show_cpuinfo(m); @@ -352,12 +358,13 @@ void __init check_for_initrd(void) * must be called before using this. * * While we're here, we may as well set the "physical" cpu ids in the paca. + * + * NOTE: This must match the parsing done in early_init_dt_scan_cpus. */ void __init smp_setup_cpu_maps(void) { struct device_node *dn = NULL; int cpu = 0; - int swap_cpuid = 0; while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { int *intserv; @@ -376,30 +383,17 @@ void __init smp_setup_cpu_maps(void) for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { cpu_set(cpu, cpu_present_map); set_hard_smp_processor_id(cpu, intserv[j]); - - if (intserv[j] == boot_cpuid_phys) - swap_cpuid = cpu; cpu_set(cpu, cpu_possible_map); cpu++; } } - /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that - * boot cpu is logical 0. - */ - if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { - u32 tmp; - tmp = get_hard_smp_processor_id(0); - set_hard_smp_processor_id(0, boot_cpuid_phys); - set_hard_smp_processor_id(swap_cpuid, tmp); - } - #ifdef CONFIG_PPC64 /* * On pSeries LPAR, we need to know how many cpus * could possibly be added to this partition. */ - if (_machine == PLATFORM_PSERIES_LPAR && + if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR) && (dn = of_find_node_by_path("/rtas"))) { int num_addr_cell, num_size_cell, maxcpus; unsigned int *ireg; @@ -438,7 +432,7 @@ void __init smp_setup_cpu_maps(void) /* * Do the sibling map; assume only two threads per processor. */ - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { cpu_set(cpu, cpu_sibling_map[cpu]); if (cpu_has_feature(CPU_FTR_SMT)) cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); @@ -468,3 +462,57 @@ static int __init early_xmon(char *p) } early_param("xmon", early_xmon); #endif + +static __init int add_pcspkr(void) +{ + struct device_node *np; + struct platform_device *pd; + int ret; + + np = of_find_compatible_node(NULL, NULL, "pnpPNP,100"); + of_node_put(np); + if (!np) + return -ENODEV; + + pd = platform_device_alloc("pcspkr", -1); + if (!pd) + return -ENOMEM; + + ret = platform_device_add(pd); + if (ret) + platform_device_put(pd); + + return ret; +} +device_initcall(add_pcspkr); + +void probe_machine(void) +{ + extern struct machdep_calls __machine_desc_start; + extern struct machdep_calls __machine_desc_end; + + /* + * Iterate all ppc_md structures until we find the proper + * one for the current machine type + */ + DBG("Probing machine type ...\n"); + + for (machine_id = &__machine_desc_start; + machine_id < &__machine_desc_end; + machine_id++) { + DBG(" %s ...", machine_id->name); + memcpy(&ppc_md, machine_id, sizeof(struct machdep_calls)); + if (ppc_md.probe()) { + DBG(" match !\n"); + break; + } + DBG("\n"); + } + /* What can we do if we didn't find ? */ + if (machine_id >= &__machine_desc_end) { + DBG("No suitable machine found !\n"); + for (;;); + } + + printk(KERN_INFO "Using %s machine description\n", ppc_md.name); +} diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index dc2770df25b3..69ac25701344 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -50,12 +50,8 @@ #include #endif -extern void platform_init(void); extern void bootx_init(unsigned long r4, unsigned long phys); -extern void ppc6xx_idle(void); -extern void power4_idle(void); - boot_infos_t *boot_infos; struct ide_machdep_calls ppc_ide_md; @@ -70,10 +66,6 @@ unsigned int DMA_MODE_WRITE; int have_of = 1; #ifdef CONFIG_PPC_MULTIPLATFORM -extern void prep_init(void); -extern void pmac_init(void); -extern void chrp_init(void); - dev_t boot_dev; #endif /* CONFIG_PPC_MULTIPLATFORM */ @@ -85,9 +77,6 @@ unsigned long SYSRQ_KEY = 0x54; unsigned long vgacon_remap_base; #endif -struct machdep_calls ppc_md; -EXPORT_SYMBOL(ppc_md); - /* * These are used in binfmt_elf.c to put aux entries on the stack * for each elf executable being started. @@ -111,7 +100,7 @@ unsigned long __init early_init(unsigned long dt_ptr) /* First zero the BSS -- use memset_io, some platforms don't have * caches on yet */ - memset_io(PTRRELOC(&__bss_start), 0, _end - __bss_start); + memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, _end - __bss_start); /* * Identify the CPU type and fix up code sections @@ -123,48 +112,6 @@ unsigned long __init early_init(unsigned long dt_ptr) return KERNELBASE + offset; } -#ifdef CONFIG_PPC_MULTIPLATFORM -/* - * The PPC_MULTIPLATFORM version of platform_init... - */ -void __init platform_init(void) -{ - /* if we didn't get any bootinfo telling us what we are... */ - if (_machine == 0) { - /* prep boot loader tells us if we're prep or not */ - if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) - _machine = _MACH_prep; - } - -#ifdef CONFIG_PPC_PREP - /* not much more to do here, if prep */ - if (_machine == _MACH_prep) { - prep_init(); - return; - } -#endif - -#ifdef CONFIG_ADB - if (strstr(cmd_line, "adb_sync")) { - extern int __adb_probe_sync; - __adb_probe_sync = 1; - } -#endif /* CONFIG_ADB */ - - switch (_machine) { -#ifdef CONFIG_PPC_PMAC - case _MACH_Pmac: - pmac_init(); - break; -#endif -#ifdef CONFIG_PPC_CHRP - case _MACH_chrp: - chrp_init(); - break; -#endif - } -} -#endif /* * Find out what kind of machine we're on and save any data we need @@ -190,11 +137,12 @@ void __init machine_init(unsigned long dt_ptr, unsigned long phys) strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); #endif /* CONFIG_CMDLINE */ - /* Base init based on machine type */ - platform_init(); + probe_machine(); #ifdef CONFIG_6xx - ppc_md.power_save = ppc6xx_idle; + if (cpu_has_feature(CPU_FTR_CAN_DOZE) || + cpu_has_feature(CPU_FTR_CAN_NAP)) + ppc_md.power_save = ppc6xx_idle; #endif if (ppc_md.progress) @@ -272,7 +220,7 @@ int __init ppc_init(void) if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); /* register CPU devices */ - for_each_cpu(i) + for_each_possible_cpu(i) register_cpu(&cpu_devices[i], i, NULL); /* call platform init */ @@ -352,12 +300,6 @@ void __init setup_arch(char **cmdline_p) do_init_bootmem(); if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); -#ifdef CONFIG_PPC_OCP - /* Initialize OCP device list */ - ocp_early_init(); - if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab); -#endif - #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif @@ -366,7 +308,4 @@ void __init setup_arch(char **cmdline_p) if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); paging_init(); - - /* this is for modules since _machine can be a define -- Cort */ - ppc_md.ppc_machine = _machine; } diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index e20c1fae3423..13e91c4d70a8 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -73,7 +73,6 @@ int have_of = 1; int boot_cpuid = 0; -int boot_cpuid_phys = 0; dev_t boot_dev; u64 ppc64_pft_size; @@ -96,11 +95,6 @@ int dcache_bsize; int icache_bsize; int ucache_bsize; -/* The main machine-dep calls structure - */ -struct machdep_calls ppc_md; -EXPORT_SYMBOL(ppc_md); - #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY; #endif /* CONFIG_MAGIC_SYSRQ */ @@ -161,32 +155,6 @@ early_param("smt-enabled", early_smt_enabled); #define check_smt_enabled() #endif /* CONFIG_SMP */ -extern struct machdep_calls pSeries_md; -extern struct machdep_calls pmac_md; -extern struct machdep_calls maple_md; -extern struct machdep_calls cell_md; -extern struct machdep_calls iseries_md; - -/* Ultimately, stuff them in an elf section like initcalls... */ -static struct machdep_calls __initdata *machines[] = { -#ifdef CONFIG_PPC_PSERIES - &pSeries_md, -#endif /* CONFIG_PPC_PSERIES */ -#ifdef CONFIG_PPC_PMAC - &pmac_md, -#endif /* CONFIG_PPC_PMAC */ -#ifdef CONFIG_PPC_MAPLE - &maple_md, -#endif /* CONFIG_PPC_MAPLE */ -#ifdef CONFIG_PPC_CELL - &cell_md, -#endif -#ifdef CONFIG_PPC_ISERIES - &iseries_md, -#endif - NULL -}; - /* * Early initialization entry point. This is called by head.S * with MMU translation disabled. We rely on the "feature" of @@ -208,13 +176,10 @@ static struct machdep_calls __initdata *machines[] = { void __init early_setup(unsigned long dt_ptr) { - struct paca_struct *lpaca = get_paca(); - static struct machdep_calls **mach; - /* Enable early debugging if any specified (see udbg.h) */ udbg_early_init(); - DBG(" -> early_setup()\n"); + DBG(" -> early_setup(), dt_ptr: 0x%lx\n", dt_ptr); /* * Do early initializations using the flattened device @@ -223,22 +188,16 @@ void __init early_setup(unsigned long dt_ptr) */ early_init_devtree(__va(dt_ptr)); - /* - * Iterate all ppc_md structures until we find the proper - * one for the current machine type - */ - DBG("Probing machine type for platform %x...\n", _machine); + /* Now we know the logical id of our boot cpu, setup the paca. */ + setup_boot_paca(); - for (mach = machines; *mach; mach++) { - if ((*mach)->probe(_machine)) - break; - } - /* What can we do if we didn't find ? */ - if (*mach == NULL) { - DBG("No suitable machine found !\n"); - for (;;); - } - ppc_md = **mach; + /* Fix up paca fields required for the boot cpu */ + get_paca()->cpu_start = 1; + get_paca()->stab_real = __pa((u64)&initial_stab); + get_paca()->stab_addr = (u64)&initial_stab; + + /* Probe the machine type */ + probe_machine(); #ifdef CONFIG_CRASH_DUMP kdump_setup(); @@ -256,12 +215,10 @@ void __init early_setup(unsigned long dt_ptr) /* * Initialize stab / SLB management except on iSeries */ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) { - if (cpu_has_feature(CPU_FTR_SLB)) - slb_initialize(); - else - stab_initialize(lpaca->stab_real); - } + if (cpu_has_feature(CPU_FTR_SLB)) + slb_initialize(); + else if (!firmware_has_feature(FW_FEATURE_ISERIES)) + stab_initialize(get_paca()->stab_real); DBG(" <- early_setup()\n"); } @@ -340,7 +297,7 @@ static void __init initialize_cache_info(void) const char *dc, *ic; /* Then read cache informations */ - if (_machine == PLATFORM_POWERMAC) { + if (machine_is(powermac)) { dc = "d-cache-block-size"; ic = "i-cache-block-size"; } else { @@ -484,7 +441,6 @@ void __init setup_system(void) printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); - printk("platform = 0x%x\n", _machine); printk("physicalMemorySize = 0x%lx\n", lmb_phys_mem_size()); printk("ppc64_caches.dcache_line_size = 0x%x\n", ppc64_caches.dline_size); @@ -516,7 +472,7 @@ static void __init irqstack_early_init(void) * interrupt stacks must be under 256MB, we cannot afford to take * SLB misses on them. */ - for_each_cpu(i) { + for_each_possible_cpu(i) { softirq_ctx[i] = (struct thread_info *) __va(lmb_alloc_base(THREAD_SIZE, THREAD_SIZE, 0x10000000)); @@ -549,7 +505,7 @@ static void __init emergency_stack_init(void) */ limit = min(0x10000000UL, lmb.rmo_size); - for_each_cpu(i) + for_each_possible_cpu(i) paca[i].emergency_sp = __va(lmb_alloc_base(HW_PAGE_SIZE, 128, limit)) + HW_PAGE_SIZE; } @@ -602,12 +558,6 @@ void __init setup_arch(char **cmdline_p) ppc_md.setup_arch(); - /* Use the default idle loop if the platform hasn't provided one. */ - if (NULL == ppc_md.idle_loop) { - ppc_md.idle_loop = default_idle; - printk(KERN_INFO "Using default idle loop\n"); - } - paging_init(); ppc64_boot_msg(0x15, "Setup Done"); } @@ -672,7 +622,7 @@ void __init setup_per_cpu_areas(void) size = PERCPU_ENOUGH_ROOM; #endif - for_each_cpu(i) { + for_each_possible_cpu(i) { ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size); if (!ptr) panic("Cannot allocate cpu data for CPU %d\n", i); diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index d7a4e814974d..01e3c08cb550 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 47f910380a6a..27f65b95184d 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #define DEBUG_SIG 0 @@ -211,7 +212,7 @@ static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs /* Default to using normal stack */ newsp = regs->gpr[1]; - if (ka->sa.sa_flags & SA_ONSTACK) { + if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) { if (! on_sig_stack(regs->gpr[1])) newsp = (current->sas_ss_sp + current->sas_ss_size); } diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 805eaedbc308..530f7dba0bd2 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -362,7 +362,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) smp_space_timers(max_cpus); - for_each_cpu(cpu) + for_each_possible_cpu(cpu) if (cpu != boot_cpuid) smp_create_idle(cpu); } diff --git a/arch/ppc/kernel/swsusp.S b/arch/powerpc/kernel/swsusp_32.S similarity index 100% rename from arch/ppc/kernel/swsusp.S rename to arch/powerpc/kernel/swsusp_32.S diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index ad895c99813b..9b69d99a9103 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 0f0c3a9ae2e5..73560ef6f802 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -65,20 +65,20 @@ static int __init smt_setup(void) unsigned int cpu; if (!cpu_has_feature(CPU_FTR_SMT)) - return 1; + return -ENODEV; options = find_path_device("/options"); if (!options) - return 1; + return -ENODEV; val = (unsigned int *)get_property(options, "ibm,smt-snooze-delay", NULL); if (!smt_snooze_cmdline && val) { - for_each_cpu(cpu) + for_each_possible_cpu(cpu) per_cpu(smt_snooze_delay, cpu) = *val; } - return 1; + return 0; } __initcall(smt_setup); @@ -93,7 +93,7 @@ static int __init setup_smt_snooze_delay(char *str) smt_snooze_cmdline = 1; if (get_option(&str, &snooze)) { - for_each_cpu(cpu) + for_each_possible_cpu(cpu) per_cpu(smt_snooze_delay, cpu) = snooze; } @@ -347,7 +347,7 @@ static int __init topology_init(void) register_cpu_notifier(&sysfs_cpu_nb); - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { struct cpu *c = &per_cpu(cpu_devices, cpu); #ifdef CONFIG_NUMA diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 1ad55f0466fd..a14c96403840 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -322,3 +322,5 @@ SYSCALL(spu_create) COMPAT_SYS(pselect6) COMPAT_SYS(ppoll) SYSCALL(unshare) +SYSCALL(splice) +SYSCALL(tee) diff --git a/arch/ppc/kernel/temp.c b/arch/powerpc/kernel/tau_6xx.c similarity index 100% rename from arch/ppc/kernel/temp.c rename to arch/powerpc/kernel/tau_6xx.c diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 4a27218a086c..24e3ad756de0 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -261,7 +261,7 @@ void snapshot_timebases(void) if (!cpu_has_feature(CPU_FTR_PURR)) return; - for_each_cpu(cpu) + for_each_possible_cpu(cpu) spin_lock_init(&per_cpu(cpu_purr_data, cpu).lock); on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1); } @@ -751,7 +751,7 @@ void __init smp_space_timers(unsigned int max_cpus) * systems works better if the two threads' timebase interrupts * are staggered by half a jiffy with respect to each other. */ - for_each_cpu(i) { + for_each_possible_cpu(i) { if (i == boot_cpuid) continue; if (i == (boot_cpuid ^ 1)) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 9763faab6739..064a52564692 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -97,7 +97,6 @@ static DEFINE_SPINLOCK(die_lock); int die(const char *str, struct pt_regs *regs, long err) { static int die_counter, crash_dump_start = 0; - int nl = 0; if (debugger(regs)) return 1; @@ -106,7 +105,7 @@ int die(const char *str, struct pt_regs *regs, long err) spin_lock_irq(&die_lock); bust_spinlocks(1); #ifdef CONFIG_PMAC_BACKLIGHT - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { set_backlight_enable(1); set_backlight_level(BACKLIGHT_MAX); } @@ -114,46 +113,18 @@ int die(const char *str, struct pt_regs *regs, long err) printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); #ifdef CONFIG_PREEMPT printk("PREEMPT "); - nl = 1; #endif #ifdef CONFIG_SMP printk("SMP NR_CPUS=%d ", NR_CPUS); - nl = 1; #endif #ifdef CONFIG_DEBUG_PAGEALLOC printk("DEBUG_PAGEALLOC "); - nl = 1; #endif #ifdef CONFIG_NUMA printk("NUMA "); - nl = 1; #endif -#ifdef CONFIG_PPC64 - switch (_machine) { - case PLATFORM_PSERIES: - printk("PSERIES "); - nl = 1; - break; - case PLATFORM_PSERIES_LPAR: - printk("PSERIES LPAR "); - nl = 1; - break; - case PLATFORM_ISERIES_LPAR: - printk("ISERIES LPAR "); - nl = 1; - break; - case PLATFORM_POWERMAC: - printk("POWERMAC "); - nl = 1; - break; - case PLATFORM_CELL: - printk("CELL "); - nl = 1; - break; - } -#endif - if (nl) - printk("\n"); + printk("%s\n", ppc_md.name ? "" : ppc_md.name); + print_modules(); show_regs(regs); bust_spinlocks(0); @@ -257,7 +228,7 @@ void system_reset_exception(struct pt_regs *regs) */ static inline int check_io_access(struct pt_regs *regs) { -#ifdef CONFIG_PPC_PMAC +#if defined(CONFIG_PPC_PMAC) && defined(CONFIG_PPC32) unsigned long msr = regs->msr; const struct exception_table_entry *entry; unsigned int *nip = (unsigned int *)regs->nip; @@ -290,7 +261,7 @@ static inline int check_io_access(struct pt_regs *regs) return 1; } } -#endif /* CONFIG_PPC_PMAC */ +#endif /* CONFIG_PPC_PMAC && CONFIG_PPC32 */ return 0; } @@ -337,8 +308,8 @@ platform_machine_check(struct pt_regs *regs) void machine_check_exception(struct pt_regs *regs) { -#ifdef CONFIG_PPC64 int recover = 0; + unsigned long reason = get_mc_reason(regs); /* See if any machine dependent calls */ if (ppc_md.machine_check_exception) @@ -346,8 +317,6 @@ void machine_check_exception(struct pt_regs *regs) if (recover) return; -#else - unsigned long reason = get_mc_reason(regs); if (user_mode(regs)) { regs->msr |= MSR_RI; @@ -491,7 +460,6 @@ void machine_check_exception(struct pt_regs *regs) * additional info, e.g. bus error registers. */ platform_machine_check(regs); -#endif /* CONFIG_PPC64 */ if (debugger_fault_handler(regs)) return; diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index ec8370368423..573afb68d69e 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -667,7 +668,13 @@ void __init vdso_init(void) vdso_data->version.major = SYSTEMCFG_MAJOR; vdso_data->version.minor = SYSTEMCFG_MINOR; vdso_data->processor = mfspr(SPRN_PVR); - vdso_data->platform = _machine; + /* + * Fake the old platform number for pSeries and iSeries and add + * in LPAR bit if necessary + */ + vdso_data->platform = machine_is(iseries) ? 0x200 : 0x100; + if (firmware_has_feature(FW_FEATURE_LPAR)) + vdso_data->platform |= 1; vdso_data->physicalMemorySize = lmb_phys_mem_size(); vdso_data->dcache_size = ppc64_caches.dsize; vdso_data->dcache_line_size = ppc64_caches.dline_size; diff --git a/arch/powerpc/kernel/vdso32/sigtramp.S b/arch/powerpc/kernel/vdso32/sigtramp.S index e04642781917..0c6a37b29dde 100644 --- a/arch/powerpc/kernel/vdso32/sigtramp.S +++ b/arch/powerpc/kernel/vdso32/sigtramp.S @@ -261,7 +261,7 @@ V_FUNCTION_END(__kernel_sigtramp_rt32) .Lcie_start: .long 0 /* CIE ID */ .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ + .string "zRS" /* NUL-terminated augmentation string */ .uleb128 4 /* Code alignment factor */ .sleb128 -4 /* Data alignment factor */ .byte 67 /* Return address register column, ap */ diff --git a/arch/powerpc/kernel/vdso64/sigtramp.S b/arch/powerpc/kernel/vdso64/sigtramp.S index 31b604ab56de..7479edb101b8 100644 --- a/arch/powerpc/kernel/vdso64/sigtramp.S +++ b/arch/powerpc/kernel/vdso64/sigtramp.S @@ -263,7 +263,7 @@ V_FUNCTION_END(__kernel_sigtramp_rt64) .Lcie_start: .long 0 /* CIE ID */ .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ + .string "zRS" /* NUL-terminated augmentation string */ .uleb128 4 /* Code alignment factor */ .sleb128 -8 /* Data alignment factor */ .byte 67 /* Return address register column, ap */ diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 7fa7b15fd8e6..fe79c2584cb0 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -1,9 +1,11 @@ #include #ifdef CONFIG_PPC64 #include +#define PROVIDE32(x) PROVIDE(__unused__##x) #else #define PAGE_SIZE 4096 #define KERNELBASE CONFIG_KERNEL_START +#define PROVIDE32(x) PROVIDE(x) #endif #include @@ -18,43 +20,42 @@ jiffies = jiffies_64 + 4; #endif SECTIONS { - /* Sections to be discarded. */ - /DISCARD/ : { - *(.exitcall.exit) - *(.exit.data) - } + /* Sections to be discarded. */ + /DISCARD/ : { + *(.exitcall.exit) + *(.exit.data) + } - . = KERNELBASE; + . = KERNELBASE; + +/* + * Text, read only data and other permanent read-only sections + */ + + /* Text and gots */ + .text : { + *(.text .text.*) + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT + *(.fixup) - /* Read-only sections, merged into text segment: */ - .text : { - *(.text .text.*) - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - *(.fixup) #ifdef CONFIG_PPC32 - *(.got1) - __got2_start = .; - *(.got2) - __got2_end = .; -#else - . = ALIGN(PAGE_SIZE); - _etext = .; -#endif - } -#ifdef CONFIG_PPC32 - _etext = .; - PROVIDE (etext = .); + *(.got1) + __got2_start = .; + *(.got2) + __got2_end = .; +#endif /* CONFIG_PPC32 */ - RODATA - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } + . = ALIGN(PAGE_SIZE); + _etext = .; + PROVIDE32 (etext = .); + } - .fixup : { *(.fixup) } -#endif + /* Read-only data */ + RODATA + /* Exception & bug tables */ __ex_table : { __start___ex_table = .; *(__ex_table) @@ -67,192 +68,172 @@ SECTIONS __stop___bug_table = .; } -#ifdef CONFIG_PPC64 +/* + * Init sections discarded at runtime + */ + . = ALIGN(PAGE_SIZE); + __init_begin = .; + + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + + /* .exit.text is discarded at runtime, not link time, + * to deal with references from __bug_table + */ + .exit.text : { *(.exit.text) } + + .init.data : { + *(.init.data); + __vtop_table_begin = .; + *(.vtop_fixup); + __vtop_table_end = .; + __ptov_table_begin = .; + *(.ptov_fixup); + __ptov_table_end = .; + } + + . = ALIGN(16); + .init.setup : { + __setup_start = .; + *(.init.setup) + __setup_end = .; + } + + .initcall.init : { + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + } + + .con_initcall.init : { + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + } + + SECURITY_INIT + + . = ALIGN(8); __ftr_fixup : { __start___ftr_fixup = .; *(__ftr_fixup) __stop___ftr_fixup = .; } - RODATA -#endif + . = ALIGN(PAGE_SIZE); + .init.ramfs : { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; + } #ifdef CONFIG_PPC32 - /* Read-write section, merged into data segment: */ - . = ALIGN(PAGE_SIZE); - _sdata = .; - .data : - { - *(.data) - *(.data1) - *(.sdata) - *(.sdata2) - *(.got.plt) *(.got) - *(.dynamic) - CONSTRUCTORS - } - - . = ALIGN(PAGE_SIZE); - __nosave_begin = .; - .data_nosave : { *(.data.nosave) } - . = ALIGN(PAGE_SIZE); - __nosave_end = .; - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - _edata = .; - PROVIDE (edata = .); - - . = ALIGN(8192); - .data.init_task : { *(.data.init_task) } -#endif - - /* will be freed after init */ - . = ALIGN(PAGE_SIZE); - __init_begin = .; - .init.text : { - _sinittext = .; - *(.init.text) - _einittext = .; - } -#ifdef CONFIG_PPC32 - /* .exit.text is discarded at runtime, not link time, - to deal with references from __bug_table */ - .exit.text : { *(.exit.text) } -#endif - .init.data : { - *(.init.data); - __vtop_table_begin = .; - *(.vtop_fixup); - __vtop_table_end = .; - __ptov_table_begin = .; - *(.ptov_fixup); - __ptov_table_end = .; - } - - . = ALIGN(16); - .init.setup : { - __setup_start = .; - *(.init.setup) - __setup_end = .; - } - - .initcall.init : { - __initcall_start = .; - *(.initcall1.init) - *(.initcall2.init) - *(.initcall3.init) - *(.initcall4.init) - *(.initcall5.init) - *(.initcall6.init) - *(.initcall7.init) - __initcall_end = .; - } - - .con_initcall.init : { - __con_initcall_start = .; - *(.con_initcall.init) - __con_initcall_end = .; - } - - SECURITY_INIT - -#ifdef CONFIG_PPC32 - __start___ftr_fixup = .; - __ftr_fixup : { *(__ftr_fixup) } - __stop___ftr_fixup = .; + . = ALIGN(32); #else - . = ALIGN(PAGE_SIZE); - .init.ramfs : { - __initramfs_start = .; - *(.init.ramfs) - __initramfs_end = .; - } + . = ALIGN(128); #endif + .data.percpu : { + __per_cpu_start = .; + *(.data.percpu) + __per_cpu_end = .; + } + + . = ALIGN(8); + .machine.desc : { + __machine_desc_start = . ; + *(.machine.desc) + __machine_desc_end = . ; + } + + /* freed after init ends here */ + . = ALIGN(PAGE_SIZE); + __init_end = .; + +/* + * And now the various read/write data + */ + + . = ALIGN(PAGE_SIZE); + _sdata = .; #ifdef CONFIG_PPC32 - . = ALIGN(32); -#endif - .data.percpu : { - __per_cpu_start = .; - *(.data.percpu) - __per_cpu_end = .; - } - - . = ALIGN(PAGE_SIZE); -#ifdef CONFIG_PPC64 - . = ALIGN(16384); - __init_end = .; - /* freed after init ends here */ - - /* Read/write sections */ - . = ALIGN(PAGE_SIZE); - . = ALIGN(16384); - _sdata = .; - /* The initial task and kernel stack */ - .data.init_task : { - *(.data.init_task) - } - - . = ALIGN(PAGE_SIZE); - .data.page_aligned : { - *(.data.page_aligned) - } - - .data.cacheline_aligned : { - *(.data.cacheline_aligned) - } - - .data : { - *(.data .data.rel* .toc1) - *(.branch_lt) - } - - .opd : { - *(.opd) - } - - .got : { - __toc_start = .; - *(.got) - *(.toc) - . = ALIGN(PAGE_SIZE); - _edata = .; - } - - . = ALIGN(PAGE_SIZE); + .data : + { + *(.data) + *(.sdata) + *(.got.plt) *(.got) + } #else - __initramfs_start = .; - .init.ramfs : { - *(.init.ramfs) - } - __initramfs_end = .; + .data : { + *(.data .data.rel* .toc1) + *(.branch_lt) + } - . = ALIGN(4096); - __init_end = .; + .opd : { + *(.opd) + } - . = ALIGN(4096); - _sextratext = .; - _eextratext = .; - - __bss_start = .; + .got : { + __toc_start = .; + *(.got) + *(.toc) + } #endif - .bss : { - __bss_start = .; - *(.sbss) *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - __bss_stop = .; - } + . = ALIGN(PAGE_SIZE); + _edata = .; + PROVIDE32 (edata = .); -#ifdef CONFIG_PPC64 - . = ALIGN(PAGE_SIZE); -#endif - _end = . ; + /* The initial task and kernel stack */ #ifdef CONFIG_PPC32 - PROVIDE (end = .); + . = ALIGN(8192); +#else + . = ALIGN(16384); #endif + .data.init_task : { + *(.data.init_task) + } + + . = ALIGN(PAGE_SIZE); + .data.page_aligned : { + *(.data.page_aligned) + } + + .data.cacheline_aligned : { + *(.data.cacheline_aligned) + } + + . = ALIGN(PAGE_SIZE); + __data_nosave : { + __nosave_begin = .; + *(.data.nosave) + . = ALIGN(PAGE_SIZE); + __nosave_end = .; + } + +/* + * And finally the bss + */ + + .bss : { + __bss_start = .; + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + __bss_stop = .; + } + + . = ALIGN(PAGE_SIZE); + _end = . ; + PROVIDE32 (end = .); } diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 666c2aa55016..c251d9936612 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -18,7 +18,7 @@ extern char system_call_common[]; #ifdef CONFIG_PPC64 /* Bits in SRR1 that are copied from MSR */ -#define MSR_MASK 0xffffffff87c0ffff +#define MSR_MASK 0xffffffff87c0ffffUL #else #define MSR_MASK 0x87c0ffff #endif diff --git a/arch/ppc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile similarity index 100% rename from arch/ppc/math-emu/Makefile rename to arch/powerpc/math-emu/Makefile diff --git a/arch/ppc/math-emu/double.h b/arch/powerpc/math-emu/double.h similarity index 100% rename from arch/ppc/math-emu/double.h rename to arch/powerpc/math-emu/double.h diff --git a/arch/ppc/math-emu/fabs.c b/arch/powerpc/math-emu/fabs.c similarity index 100% rename from arch/ppc/math-emu/fabs.c rename to arch/powerpc/math-emu/fabs.c diff --git a/arch/ppc/math-emu/fadd.c b/arch/powerpc/math-emu/fadd.c similarity index 100% rename from arch/ppc/math-emu/fadd.c rename to arch/powerpc/math-emu/fadd.c diff --git a/arch/ppc/math-emu/fadds.c b/arch/powerpc/math-emu/fadds.c similarity index 100% rename from arch/ppc/math-emu/fadds.c rename to arch/powerpc/math-emu/fadds.c diff --git a/arch/ppc/math-emu/fcmpo.c b/arch/powerpc/math-emu/fcmpo.c similarity index 100% rename from arch/ppc/math-emu/fcmpo.c rename to arch/powerpc/math-emu/fcmpo.c diff --git a/arch/ppc/math-emu/fcmpu.c b/arch/powerpc/math-emu/fcmpu.c similarity index 100% rename from arch/ppc/math-emu/fcmpu.c rename to arch/powerpc/math-emu/fcmpu.c diff --git a/arch/ppc/math-emu/fctiw.c b/arch/powerpc/math-emu/fctiw.c similarity index 100% rename from arch/ppc/math-emu/fctiw.c rename to arch/powerpc/math-emu/fctiw.c diff --git a/arch/ppc/math-emu/fctiwz.c b/arch/powerpc/math-emu/fctiwz.c similarity index 100% rename from arch/ppc/math-emu/fctiwz.c rename to arch/powerpc/math-emu/fctiwz.c diff --git a/arch/ppc/math-emu/fdiv.c b/arch/powerpc/math-emu/fdiv.c similarity index 100% rename from arch/ppc/math-emu/fdiv.c rename to arch/powerpc/math-emu/fdiv.c diff --git a/arch/ppc/math-emu/fdivs.c b/arch/powerpc/math-emu/fdivs.c similarity index 100% rename from arch/ppc/math-emu/fdivs.c rename to arch/powerpc/math-emu/fdivs.c diff --git a/arch/ppc/math-emu/fmadd.c b/arch/powerpc/math-emu/fmadd.c similarity index 100% rename from arch/ppc/math-emu/fmadd.c rename to arch/powerpc/math-emu/fmadd.c diff --git a/arch/ppc/math-emu/fmadds.c b/arch/powerpc/math-emu/fmadds.c similarity index 100% rename from arch/ppc/math-emu/fmadds.c rename to arch/powerpc/math-emu/fmadds.c diff --git a/arch/ppc/math-emu/fmr.c b/arch/powerpc/math-emu/fmr.c similarity index 100% rename from arch/ppc/math-emu/fmr.c rename to arch/powerpc/math-emu/fmr.c diff --git a/arch/ppc/math-emu/fmsub.c b/arch/powerpc/math-emu/fmsub.c similarity index 100% rename from arch/ppc/math-emu/fmsub.c rename to arch/powerpc/math-emu/fmsub.c diff --git a/arch/ppc/math-emu/fmsubs.c b/arch/powerpc/math-emu/fmsubs.c similarity index 100% rename from arch/ppc/math-emu/fmsubs.c rename to arch/powerpc/math-emu/fmsubs.c diff --git a/arch/ppc/math-emu/fmul.c b/arch/powerpc/math-emu/fmul.c similarity index 100% rename from arch/ppc/math-emu/fmul.c rename to arch/powerpc/math-emu/fmul.c diff --git a/arch/ppc/math-emu/fmuls.c b/arch/powerpc/math-emu/fmuls.c similarity index 100% rename from arch/ppc/math-emu/fmuls.c rename to arch/powerpc/math-emu/fmuls.c diff --git a/arch/ppc/math-emu/fnabs.c b/arch/powerpc/math-emu/fnabs.c similarity index 100% rename from arch/ppc/math-emu/fnabs.c rename to arch/powerpc/math-emu/fnabs.c diff --git a/arch/ppc/math-emu/fneg.c b/arch/powerpc/math-emu/fneg.c similarity index 100% rename from arch/ppc/math-emu/fneg.c rename to arch/powerpc/math-emu/fneg.c diff --git a/arch/ppc/math-emu/fnmadd.c b/arch/powerpc/math-emu/fnmadd.c similarity index 100% rename from arch/ppc/math-emu/fnmadd.c rename to arch/powerpc/math-emu/fnmadd.c diff --git a/arch/ppc/math-emu/fnmadds.c b/arch/powerpc/math-emu/fnmadds.c similarity index 100% rename from arch/ppc/math-emu/fnmadds.c rename to arch/powerpc/math-emu/fnmadds.c diff --git a/arch/ppc/math-emu/fnmsub.c b/arch/powerpc/math-emu/fnmsub.c similarity index 100% rename from arch/ppc/math-emu/fnmsub.c rename to arch/powerpc/math-emu/fnmsub.c diff --git a/arch/ppc/math-emu/fnmsubs.c b/arch/powerpc/math-emu/fnmsubs.c similarity index 100% rename from arch/ppc/math-emu/fnmsubs.c rename to arch/powerpc/math-emu/fnmsubs.c diff --git a/arch/ppc/math-emu/fres.c b/arch/powerpc/math-emu/fres.c similarity index 100% rename from arch/ppc/math-emu/fres.c rename to arch/powerpc/math-emu/fres.c diff --git a/arch/ppc/math-emu/frsp.c b/arch/powerpc/math-emu/frsp.c similarity index 100% rename from arch/ppc/math-emu/frsp.c rename to arch/powerpc/math-emu/frsp.c diff --git a/arch/ppc/math-emu/frsqrte.c b/arch/powerpc/math-emu/frsqrte.c similarity index 100% rename from arch/ppc/math-emu/frsqrte.c rename to arch/powerpc/math-emu/frsqrte.c diff --git a/arch/ppc/math-emu/fsel.c b/arch/powerpc/math-emu/fsel.c similarity index 100% rename from arch/ppc/math-emu/fsel.c rename to arch/powerpc/math-emu/fsel.c diff --git a/arch/ppc/math-emu/fsqrt.c b/arch/powerpc/math-emu/fsqrt.c similarity index 100% rename from arch/ppc/math-emu/fsqrt.c rename to arch/powerpc/math-emu/fsqrt.c diff --git a/arch/ppc/math-emu/fsqrts.c b/arch/powerpc/math-emu/fsqrts.c similarity index 100% rename from arch/ppc/math-emu/fsqrts.c rename to arch/powerpc/math-emu/fsqrts.c diff --git a/arch/ppc/math-emu/fsub.c b/arch/powerpc/math-emu/fsub.c similarity index 100% rename from arch/ppc/math-emu/fsub.c rename to arch/powerpc/math-emu/fsub.c diff --git a/arch/ppc/math-emu/fsubs.c b/arch/powerpc/math-emu/fsubs.c similarity index 100% rename from arch/ppc/math-emu/fsubs.c rename to arch/powerpc/math-emu/fsubs.c diff --git a/arch/ppc/math-emu/lfd.c b/arch/powerpc/math-emu/lfd.c similarity index 100% rename from arch/ppc/math-emu/lfd.c rename to arch/powerpc/math-emu/lfd.c diff --git a/arch/ppc/math-emu/lfs.c b/arch/powerpc/math-emu/lfs.c similarity index 100% rename from arch/ppc/math-emu/lfs.c rename to arch/powerpc/math-emu/lfs.c diff --git a/arch/ppc/math-emu/math.c b/arch/powerpc/math-emu/math.c similarity index 100% rename from arch/ppc/math-emu/math.c rename to arch/powerpc/math-emu/math.c diff --git a/arch/ppc/math-emu/mcrfs.c b/arch/powerpc/math-emu/mcrfs.c similarity index 100% rename from arch/ppc/math-emu/mcrfs.c rename to arch/powerpc/math-emu/mcrfs.c diff --git a/arch/ppc/math-emu/mffs.c b/arch/powerpc/math-emu/mffs.c similarity index 100% rename from arch/ppc/math-emu/mffs.c rename to arch/powerpc/math-emu/mffs.c diff --git a/arch/ppc/math-emu/mtfsb0.c b/arch/powerpc/math-emu/mtfsb0.c similarity index 100% rename from arch/ppc/math-emu/mtfsb0.c rename to arch/powerpc/math-emu/mtfsb0.c diff --git a/arch/ppc/math-emu/mtfsb1.c b/arch/powerpc/math-emu/mtfsb1.c similarity index 100% rename from arch/ppc/math-emu/mtfsb1.c rename to arch/powerpc/math-emu/mtfsb1.c diff --git a/arch/ppc/math-emu/mtfsf.c b/arch/powerpc/math-emu/mtfsf.c similarity index 100% rename from arch/ppc/math-emu/mtfsf.c rename to arch/powerpc/math-emu/mtfsf.c diff --git a/arch/ppc/math-emu/mtfsfi.c b/arch/powerpc/math-emu/mtfsfi.c similarity index 100% rename from arch/ppc/math-emu/mtfsfi.c rename to arch/powerpc/math-emu/mtfsfi.c diff --git a/arch/ppc/math-emu/op-1.h b/arch/powerpc/math-emu/op-1.h similarity index 100% rename from arch/ppc/math-emu/op-1.h rename to arch/powerpc/math-emu/op-1.h diff --git a/arch/ppc/math-emu/op-2.h b/arch/powerpc/math-emu/op-2.h similarity index 100% rename from arch/ppc/math-emu/op-2.h rename to arch/powerpc/math-emu/op-2.h diff --git a/arch/ppc/math-emu/op-4.h b/arch/powerpc/math-emu/op-4.h similarity index 100% rename from arch/ppc/math-emu/op-4.h rename to arch/powerpc/math-emu/op-4.h diff --git a/arch/ppc/math-emu/op-common.h b/arch/powerpc/math-emu/op-common.h similarity index 100% rename from arch/ppc/math-emu/op-common.h rename to arch/powerpc/math-emu/op-common.h diff --git a/arch/ppc/math-emu/sfp-machine.h b/arch/powerpc/math-emu/sfp-machine.h similarity index 100% rename from arch/ppc/math-emu/sfp-machine.h rename to arch/powerpc/math-emu/sfp-machine.h diff --git a/arch/ppc/math-emu/single.h b/arch/powerpc/math-emu/single.h similarity index 100% rename from arch/ppc/math-emu/single.h rename to arch/powerpc/math-emu/single.h diff --git a/arch/ppc/math-emu/soft-fp.h b/arch/powerpc/math-emu/soft-fp.h similarity index 100% rename from arch/ppc/math-emu/soft-fp.h rename to arch/powerpc/math-emu/soft-fp.h diff --git a/arch/ppc/math-emu/stfd.c b/arch/powerpc/math-emu/stfd.c similarity index 100% rename from arch/ppc/math-emu/stfd.c rename to arch/powerpc/math-emu/stfd.c diff --git a/arch/ppc/math-emu/stfiwx.c b/arch/powerpc/math-emu/stfiwx.c similarity index 100% rename from arch/ppc/math-emu/stfiwx.c rename to arch/powerpc/math-emu/stfiwx.c diff --git a/arch/ppc/math-emu/stfs.c b/arch/powerpc/math-emu/stfs.c similarity index 100% rename from arch/ppc/math-emu/stfs.c rename to arch/powerpc/math-emu/stfs.c diff --git a/arch/ppc/math-emu/types.c b/arch/powerpc/math-emu/types.c similarity index 100% rename from arch/ppc/math-emu/types.c rename to arch/powerpc/math-emu/types.c diff --git a/arch/ppc/math-emu/udivmodti4.c b/arch/powerpc/math-emu/udivmodti4.c similarity index 100% rename from arch/ppc/math-emu/udivmodti4.c rename to arch/powerpc/math-emu/udivmodti4.c diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index ec4adcb4bc28..fdbba4206d59 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -177,15 +177,15 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, /* When running in the kernel we expect faults to occur only to * addresses in user space. All other faults represent errors in the - * kernel and should generate an OOPS. Unfortunatly, in the case of an - * erroneous fault occuring in a code path which already holds mmap_sem + * kernel and should generate an OOPS. Unfortunately, in the case of an + * erroneous fault occurring in a code path which already holds mmap_sem * we will deadlock attempting to validate the fault against the * address space. Luckily the kernel only validly references user * space from well defined areas of code, which are listed in the * exceptions table. * * As the vast majority of faults will be valid we will only perform - * the source reference check when there is a possibilty of a deadlock. + * the source reference check when there is a possibility of a deadlock. * Attempt to lock the address space, if we cannot we then validate the * source. If this is invalid we can skip the address space check, * thus avoiding the deadlock. @@ -267,25 +267,29 @@ good_area: #endif #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) pte_t *ptep; + pmd_t *pmdp; /* Since 4xx/Book-E supports per-page execute permission, * we lazily flush dcache to icache. */ ptep = NULL; - if (get_pteptr(mm, address, &ptep) && pte_present(*ptep)) { - struct page *page = pte_page(*ptep); + if (get_pteptr(mm, address, &ptep, &pmdp)) { + spinlock_t *ptl = pte_lockptr(mm, pmdp); + spin_lock(ptl); + if (pte_present(*ptep)) { + struct page *page = pte_page(*ptep); - if (! test_bit(PG_arch_1, &page->flags)) { - flush_dcache_icache_page(page); - set_bit(PG_arch_1, &page->flags); + if (!test_bit(PG_arch_1, &page->flags)) { + flush_dcache_icache_page(page); + set_bit(PG_arch_1, &page->flags); + } + pte_update(ptep, 0, _PAGE_HWEXEC); + _tlbie(address); + pte_unmap_unlock(ptep, ptl); + up_read(&mm->mmap_sem); + return 0; } - pte_update(ptep, 0, _PAGE_HWEXEC); - _tlbie(address); - pte_unmap(ptep); - up_read(&mm->mmap_sem); - return 0; + pte_unmap_unlock(ptep, ptl); } - if (ptep != NULL) - pte_unmap(ptep); #endif /* a write */ } else if (is_write) { diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 89b35c181314..c006d9039633 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -167,7 +167,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, * normal insert callback here. */ #ifdef CONFIG_PPC_ISERIES - if (_machine == PLATFORM_ISERIES_LPAR) + if (machine_is(iseries)) ret = iSeries_hpte_insert(hpteg, va, paddr, tmp_mode, @@ -176,7 +176,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend, else #endif #ifdef CONFIG_PPC_PSERIES - if (_machine & PLATFORM_LPAR) + if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR)) ret = pSeries_lpar_hpte_insert(hpteg, va, paddr, tmp_mode, @@ -295,8 +295,7 @@ static void __init htab_init_page_sizes(void) * Not in the device-tree, let's fallback on known size * list for 16M capable GP & GR */ - if ((_machine != PLATFORM_ISERIES_LPAR) && - cpu_has_feature(CPU_FTR_16M_PAGE)) + if (cpu_has_feature(CPU_FTR_16M_PAGE) && !machine_is(iseries)) memcpy(mmu_psize_defs, mmu_psize_defaults_gp, sizeof(mmu_psize_defaults_gp)); found: diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 5e435a9c3431..741dd8802d49 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -342,7 +342,7 @@ void __init mem_init(void) #ifdef CONFIG_NEED_MULTIPLE_NODES for_each_online_node(nid) { if (NODE_DATA(nid)->node_spanned_pages != 0) { - printk("freeing bootmem node %x\n", nid); + printk("freeing bootmem node %d\n", nid); totalram_pages += free_all_bootmem_node(NODE_DATA(nid)); } diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index e89b22aa539e..0a335f34974c 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -756,6 +756,7 @@ int hot_add_scn_to_nid(unsigned long scn_addr) struct device_node *memory = NULL; nodemask_t nodes; int default_nid = any_online_node(NODE_MASK_ALL); + int nid; if (!numa_enabled || (min_common_depth < 0)) return default_nid; @@ -790,6 +791,7 @@ ha_new_range: goto ha_new_range; } BUG(); /* section address should be found above */ + return 0; /* Temporary code to ensure that returned node is not empty */ got_nid: diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index d296eb6b4545..90628601fac7 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c @@ -372,7 +372,7 @@ void __init io_block_mapping(unsigned long virt, phys_addr_t phys, * the PTE pointer is unmodified if PTE is not found. */ int -get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep) +get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp) { pgd_t *pgd; pmd_t *pmd; @@ -387,6 +387,8 @@ get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep) if (pte) { retval = 1; *ptep = pte; + if (pmdp) + *pmdp = pmd; /* XXX caller needs to do pte_unmap, yuck */ } } @@ -424,7 +426,7 @@ unsigned long iopa(unsigned long addr) mm = &init_mm; pa = 0; - if (get_pteptr(mm, addr, &pte)) { + if (get_pteptr(mm, addr, &pte, NULL)) { pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK); pte_unmap(pte); } diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 91d25fb27f89..4a9291d9fef8 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -239,7 +239,7 @@ void stabs_alloc(void) if (cpu_has_feature(CPU_FTR_SLB)) return; - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { unsigned long newstab; if (cpu == 0) diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile index 554cd7c75321..f5f9859a8338 100644 --- a/arch/powerpc/oprofile/Makefile +++ b/arch/powerpc/oprofile/Makefile @@ -6,7 +6,7 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ oprofilefs.o oprofile_stats.o \ timer_int.o ) -oprofile-y := $(DRIVER_OBJS) common.o +oprofile-y := $(DRIVER_OBJS) common.o backtrace.o oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o oprofile-$(CONFIG_PPC32) += op_model_7450.o diff --git a/arch/powerpc/oprofile/backtrace.c b/arch/powerpc/oprofile/backtrace.c new file mode 100644 index 000000000000..75f57bc96b40 --- /dev/null +++ b/arch/powerpc/oprofile/backtrace.c @@ -0,0 +1,126 @@ +/** + * Copyright (C) 2005 Brian Rogan , IBM + * + * 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. +**/ + +#include +#include +#include +#include + +#define STACK_SP(STACK) *(STACK) + +#define STACK_LR64(STACK) *((unsigned long *)(STACK) + 2) +#define STACK_LR32(STACK) *((unsigned int *)(STACK) + 1) + +#ifdef CONFIG_PPC64 +#define STACK_LR(STACK) STACK_LR64(STACK) +#else +#define STACK_LR(STACK) STACK_LR32(STACK) +#endif + +static unsigned int user_getsp32(unsigned int sp, int is_first) +{ + unsigned int stack_frame[2]; + + if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame))) + return 0; + + /* + * The most likely reason for this is that we returned -EFAULT, + * which means that we've done all that we can do from + * interrupt context. + */ + if (__copy_from_user_inatomic(stack_frame, (void *)(long)sp, + sizeof(stack_frame))) + return 0; + + if (!is_first) + oprofile_add_trace(STACK_LR32(stack_frame)); + + /* + * We do not enforce increasing stack addresses here because + * we may transition to a different stack, eg a signal handler. + */ + return STACK_SP(stack_frame); +} + +#ifdef CONFIG_PPC64 +static unsigned long user_getsp64(unsigned long sp, int is_first) +{ + unsigned long stack_frame[3]; + + if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame))) + return 0; + + if (__copy_from_user_inatomic(stack_frame, (void *)sp, + sizeof(stack_frame))) + return 0; + + if (!is_first) + oprofile_add_trace(STACK_LR64(stack_frame)); + + return STACK_SP(stack_frame); +} +#endif + +static unsigned long kernel_getsp(unsigned long sp, int is_first) +{ + unsigned long *stack_frame = (unsigned long *)sp; + + if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) + return 0; + + if (!is_first) + oprofile_add_trace(STACK_LR(stack_frame)); + + /* + * We do not enforce increasing stack addresses here because + * we might be transitioning from an interrupt stack to a kernel + * stack. validate_sp() is designed to understand this, so just + * use it. + */ + return STACK_SP(stack_frame); +} + +void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth) +{ + unsigned long sp = regs->gpr[1]; + int first_frame = 1; + + /* We ditch the top stackframe so need to loop through an extra time */ + depth += 1; + + if (!user_mode(regs)) { + while (depth--) { + sp = kernel_getsp(sp, first_frame); + if (!sp) + break; + first_frame = 0; + } + } else { +#ifdef CONFIG_PPC64 + if (!test_thread_flag(TIF_32BIT)) { + while (depth--) { + sp = user_getsp64(sp, first_frame); + if (!sp) + break; + first_frame = 0; + } + + return; + } +#endif + + while (depth--) { + sp = user_getsp32(sp, first_frame); + if (!sp) + break; + first_frame = 0; + } + } +} diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index cc2535be3a73..5b1de7e8041e 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -117,18 +117,10 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel); oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user); -#ifdef CONFIG_PPC64 - oprofilefs_create_ulong(sb, root, "backtrace_spinlocks", - &sys.backtrace_spinlocks); -#endif /* Default to tracing both kernel and user */ sys.enable_kernel = 1; sys.enable_user = 1; -#ifdef CONFIG_PPC64 - /* Turn on backtracing through spinlocks by default */ - sys.backtrace_spinlocks = 1; -#endif return 0; } @@ -168,6 +160,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) ops->shutdown = op_powerpc_shutdown; ops->start = op_powerpc_start; ops->stop = op_powerpc_stop; + ops->backtrace = op_powerpc_backtrace; printk(KERN_INFO "oprofile: using %s performance monitoring.\n", ops->cpu_type); diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c index 32abfdbb0eb1..e0491c3c71f1 100644 --- a/arch/powerpc/oprofile/op_model_7450.c +++ b/arch/powerpc/oprofile/op_model_7450.c @@ -176,13 +176,13 @@ static void fsl7450_handle_interrupt(struct pt_regs *regs, mtmsr(mfmsr() | MSR_PMM); pc = mfspr(SPRN_SIAR); - is_kernel = (pc >= KERNELBASE); + is_kernel = is_kernel_addr(pc); for (i = 0; i < NUM_CTRS; ++i) { val = ctr_read(i); if (val < 0) { if (oprofile_running && ctr[i].enabled) { - oprofile_add_pc(pc, is_kernel, i); + oprofile_add_ext_sample(pc, regs, i, is_kernel); ctr_write(i, reset_value[i]); } else { ctr_write(i, 0); diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c index 26539cda6023..93d63e62662f 100644 --- a/arch/powerpc/oprofile/op_model_fsl_booke.c +++ b/arch/powerpc/oprofile/op_model_fsl_booke.c @@ -154,13 +154,13 @@ static void fsl_booke_handle_interrupt(struct pt_regs *regs, mtmsr(mfmsr() | MSR_PMM); pc = regs->nip; - is_kernel = (pc >= KERNELBASE); + is_kernel = is_kernel_addr(pc); for (i = 0; i < num_counters; ++i) { val = ctr_read(i); if (val < 0) { if (oprofile_running && ctr[i].enabled) { - oprofile_add_pc(pc, is_kernel, i); + oprofile_add_ext_sample(pc, regs, i, is_kernel); ctr_write(i, reset_value[i]); } else { ctr_write(i, 0); diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index 4b06e53eb9b4..4c2beab1fdc1 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c @@ -25,18 +25,14 @@ static unsigned long reset_value[OP_MAX_COUNTER]; static int oprofile_running; static int mmcra_has_sihv; +/* Unfortunately these bits vary between CPUs */ +static unsigned long mmcra_sihv = MMCRA_SIHV; +static unsigned long mmcra_sipr = MMCRA_SIPR; /* mmcr values are set in power4_reg_setup, used in power4_cpu_setup */ static u32 mmcr0_val; static u64 mmcr1_val; -static u32 mmcra_val; - -/* - * Since we do not have an NMI, backtracing through spinlocks is - * only a best guess. In light of this, allow it to be disabled at - * runtime. - */ -static int backtrace_spinlocks; +static u64 mmcra_val; static void power4_reg_setup(struct op_counter_config *ctr, struct op_system_config *sys, @@ -63,8 +59,6 @@ static void power4_reg_setup(struct op_counter_config *ctr, mmcr1_val = sys->mmcr1; mmcra_val = sys->mmcra; - backtrace_spinlocks = sys->backtrace_spinlocks; - for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) reset_value[i] = 0x80000000UL - ctr[i].count; @@ -197,25 +191,6 @@ static void __attribute_used__ kernel_unknown_bucket(void) { } -static unsigned long check_spinlock_pc(struct pt_regs *regs, - unsigned long profile_pc) -{ - unsigned long pc = instruction_pointer(regs); - - /* - * If both the SIAR (sampled instruction) and the perfmon exception - * occurred in a spinlock region then we account the sample to the - * calling function. This isnt 100% correct, we really need soft - * IRQ disable so we always get the perfmon exception at the - * point at which the SIAR is set. - */ - if (backtrace_spinlocks && in_lock_functions(pc) && - in_lock_functions(profile_pc)) - return regs->link; - else - return profile_pc; -} - /* * On GQ and newer the MMCRA stores the HV and PR bits at the time * the SIAR was sampled. We use that to work out if the SIAR was sampled in @@ -228,17 +203,17 @@ static unsigned long get_pc(struct pt_regs *regs) /* Cant do much about it */ if (!mmcra_has_sihv) - return check_spinlock_pc(regs, pc); + return pc; mmcra = mfspr(SPRN_MMCRA); /* Were we in the hypervisor? */ - if (firmware_has_feature(FW_FEATURE_LPAR) && (mmcra & MMCRA_SIHV)) + if (firmware_has_feature(FW_FEATURE_LPAR) && (mmcra & mmcra_sihv)) /* function descriptor madness */ return *((unsigned long *)hypervisor_bucket); /* We were in userspace, nothing to do */ - if (mmcra & MMCRA_SIPR) + if (mmcra & mmcra_sipr) return pc; #ifdef CONFIG_PPC_RTAS @@ -257,7 +232,7 @@ static unsigned long get_pc(struct pt_regs *regs) /* function descriptor madness */ return *((unsigned long *)kernel_unknown_bucket); - return check_spinlock_pc(regs, pc); + return pc; } static int get_kernel(unsigned long pc) @@ -268,7 +243,7 @@ static int get_kernel(unsigned long pc) is_kernel = is_kernel_addr(pc); } else { unsigned long mmcra = mfspr(SPRN_MMCRA); - is_kernel = ((mmcra & MMCRA_SIPR) == 0); + is_kernel = ((mmcra & mmcra_sipr) == 0); } return is_kernel; @@ -293,7 +268,7 @@ static void power4_handle_interrupt(struct pt_regs *regs, val = ctr_read(i); if (val < 0) { if (oprofile_running && ctr[i].enabled) { - oprofile_add_pc(pc, is_kernel, i); + oprofile_add_ext_sample(pc, regs, i, is_kernel); ctr_write(i, reset_value[i]); } else { ctr_write(i, 0); diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c index 5c909ee609fe..042f8f4867ad 100644 --- a/arch/powerpc/oprofile/op_model_rs64.c +++ b/arch/powerpc/oprofile/op_model_rs64.c @@ -175,10 +175,13 @@ static void rs64_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr) { unsigned int mmcr0; + int is_kernel; int val; int i; unsigned long pc = mfspr(SPRN_SIAR); + is_kernel = is_kernel_addr(pc); + /* set the PMM bit (see comment below) */ mtmsrd(mfmsr() | MSR_PMM); @@ -186,7 +189,7 @@ static void rs64_handle_interrupt(struct pt_regs *regs, val = ctr_read(i); if (val < 0) { if (ctr[i].enabled) { - oprofile_add_pc(pc, is_kernel_addr(pc), i); + oprofile_add_ext_sample(pc, regs, i, is_kernel); ctr_write(i, reset_value[i]); } else { ctr_write(i, 0); diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c index 7c18b4cd5db4..7e789d2420ba 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_sys.c +++ b/arch/powerpc/platforms/83xx/mpc834x_sys.c @@ -158,25 +158,25 @@ static int __init mpc834x_rtc_hookup(void) late_initcall(mpc834x_rtc_hookup); #endif -void __init platform_init(void) +/* + * Called very early, MMU is off, device-tree isn't unflattened + */ +static int __init mpc834x_sys_probe(void) { - /* setup the PowerPC module struct */ - ppc_md.setup_arch = mpc834x_sys_setup_arch; - - ppc_md.init_IRQ = mpc834x_sys_init_IRQ; - ppc_md.get_irq = ipic_get_irq; - - ppc_md.restart = mpc83xx_restart; - - ppc_md.time_init = mpc83xx_time_init; - ppc_md.set_rtc_time = NULL; - ppc_md.get_rtc_time = NULL; - ppc_md.calibrate_decr = generic_calibrate_decr; - - ppc_md.progress = udbg_progress; - - if (ppc_md.progress) - ppc_md.progress("mpc834x_sys_init(): exit", 0); - - return; + /* We always match for now, eventually we should look at the flat + dev tree to ensure this is the board we are suppose to run on + */ + return 1; } + +define_machine(mpc834x_sys) { + .name = "MPC834x SYS", + .probe = mpc834x_sys_probe, + .setup_arch = mpc834x_sys_setup_arch, + .init_IRQ = mpc834x_sys_init_IRQ, + .get_irq = ipic_get_irq, + .restart = mpc83xx_restart, + .time_init = mpc83xx_time_init, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index d3d0ff745e84..06e371282f57 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -7,6 +7,7 @@ choice config MPC8540_ADS bool "Freescale MPC8540 ADS" + select DEFAULT_UIMAGE help This option enables support for the MPC 8540 ADS board diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index b7821dbae00d..5eeff370f5fc 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -220,25 +220,25 @@ void mpc85xx_ads_show_cpuinfo(struct seq_file *m) seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); } -void __init platform_init(void) +/* + * Called very early, device-tree isn't unflattened + */ +static int __init mpc85xx_ads_probe(void) { - ppc_md.setup_arch = mpc85xx_ads_setup_arch; - ppc_md.show_cpuinfo = mpc85xx_ads_show_cpuinfo; - - ppc_md.init_IRQ = mpc85xx_ads_pic_init; - ppc_md.get_irq = mpic_get_irq; - - ppc_md.restart = mpc85xx_restart; - ppc_md.power_off = NULL; - ppc_md.halt = NULL; - - ppc_md.time_init = NULL; - ppc_md.set_rtc_time = NULL; - ppc_md.get_rtc_time = NULL; - ppc_md.calibrate_decr = generic_calibrate_decr; - - ppc_md.progress = udbg_progress; - - if (ppc_md.progress) - ppc_md.progress("mpc85xx_ads platform_init(): exit", 0); + /* We always match for now, eventually we should look at the flat + dev tree to ensure this is the board we are suppose to run on + */ + return 1; } + +define_machine(mpc85xx_ads) { + .name = "MPC85xx ADS", + .probe = mpc85xx_ads_probe, + .setup_arch = mpc85xx_ads_setup_arch, + .init_IRQ = mpc85xx_ads_pic_init, + .show_cpuinfo = mpc85xx_ads_show_cpuinfo, + .get_irq = mpic_get_irq, + .restart = mpc85xx_restart, + .calibrate_decr = generic_calibrate_decr, + .progress = udbg_progress, +}; diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig index 3157071e241c..c2a3db8edb0c 100644 --- a/arch/powerpc/platforms/cell/Kconfig +++ b/arch/powerpc/platforms/cell/Kconfig @@ -10,4 +10,9 @@ config SPU_FS Units on machines implementing the Broadband Processor Architecture. +config SPUFS_MMAP + bool + depends on SPU_FS && SPARSEMEM && !PPC_64K_PAGES + default y + endmenu diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 3b998a393e3f..e570bad06394 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile @@ -6,5 +6,11 @@ obj-$(CONFIG_SPU_FS) += spu-base.o spufs/ spu-base-y += spu_base.o spu_priv1.o -builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o -obj-y += $(builtin-spufs-m) +# needed only when building loadable spufs.ko +spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o +obj-y += $(spufs-modular-m) + +# always needed in kernel +spufs-builtin-$(CONFIG_SPU_FS) += spu_callbacks.o +obj-y += $(spufs-builtin-y) $(spufs-builtin-m) + diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 63aa52acf441..978be1c30c1b 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -63,7 +63,24 @@ static DEFINE_PER_CPU(struct iic, iic); void iic_local_enable(void) { - out_be64(&__get_cpu_var(iic).regs->prio, 0xff); + struct iic *iic = &__get_cpu_var(iic); + u64 tmp; + + /* + * There seems to be a bug that is present in DD2.x CPUs + * and still only partially fixed in DD3.1. + * This bug causes a value written to the priority register + * not to make it there, resulting in a system hang unless we + * write it again. + * Masking with 0xf0 is done because the Cell BE does not + * implement the lower four bits of the interrupt priority, + * they always read back as zeroes, although future CPUs + * might implement different bits. + */ + do { + out_be64(&iic->regs->prio, 0xff); + tmp = in_be64(&iic->regs->prio); + } while ((tmp & 0xf0) != 0xf0); } void iic_local_disable(void) @@ -123,7 +140,7 @@ static int iic_external_get_irq(struct iic_pending_bits pending) pending.class != 2) break; irq = IIC_EXT_OFFSET - + spider_get_irq(pending.prio + node * IIC_NODE_STRIDE) + + spider_get_irq(node) + node * IIC_NODE_STRIDE; break; case 0x01 ... 0x04: @@ -174,40 +191,100 @@ int iic_get_irq(struct pt_regs *regs) return irq; } -static int setup_iic(int cpu, struct iic *iic) +/* hardcoded part to be compatible with older firmware */ + +static int setup_iic_hardcoded(void) { struct device_node *np; - int nodeid = cpu / 2; + int nodeid, cpu; unsigned long regs; + struct iic *iic; - for (np = of_find_node_by_type(NULL, "cpu"); - np; - np = of_find_node_by_type(np, "cpu")) { - if (nodeid == *(int *)get_property(np, "node-id", NULL)) - break; + for_each_cpu(cpu) { + iic = &per_cpu(iic, cpu); + nodeid = cpu/2; + + for (np = of_find_node_by_type(NULL, "cpu"); + np; + np = of_find_node_by_type(np, "cpu")) { + if (nodeid == *(int *)get_property(np, "node-id", NULL)) + break; + } + + if (!np) { + printk(KERN_WARNING "IIC: CPU %d not found\n", cpu); + iic->regs = NULL; + iic->target_id = 0xff; + return -ENODEV; + } + + regs = *(long *)get_property(np, "iic", NULL); + + /* hack until we have decided on the devtree info */ + regs += 0x400; + if (cpu & 1) + regs += 0x20; + + printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs); + iic->regs = ioremap(regs, sizeof(struct iic_regs)); + iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); } - if (!np) { - printk(KERN_WARNING "IIC: CPU %d not found\n", cpu); - iic->regs = NULL; - iic->target_id = 0xff; - return -ENODEV; - } - - regs = *(long *)get_property(np, "iic", NULL); - - /* hack until we have decided on the devtree info */ - regs += 0x400; - if (cpu & 1) - regs += 0x20; - - printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs); - iic->regs = __ioremap(regs, sizeof(struct iic_regs), - _PAGE_NO_CACHE); - iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); return 0; } +static int setup_iic(void) +{ + struct device_node *dn; + unsigned long *regs; + char *compatible; + unsigned *np, found = 0; + struct iic *iic = NULL; + + for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) { + compatible = (char *)get_property(dn, "compatible", NULL); + + if (!compatible) { + printk(KERN_WARNING "no compatible property found !\n"); + continue; + } + + if (strstr(compatible, "IBM,CBEA-Internal-Interrupt-Controller")) + regs = (unsigned long *)get_property(dn,"reg", NULL); + else + continue; + + if (!regs) + printk(KERN_WARNING "IIC: no reg property\n"); + + np = (unsigned int *)get_property(dn, "ibm,interrupt-server-ranges", NULL); + + if (!np) { + printk(KERN_WARNING "IIC: CPU association not found\n"); + iic->regs = NULL; + iic->target_id = 0xff; + return -ENODEV; + } + + iic = &per_cpu(iic, np[0]); + iic->regs = ioremap(regs[0], sizeof(struct iic_regs)); + iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe); + printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs); + + iic = &per_cpu(iic, np[1]); + iic->regs = ioremap(regs[2], sizeof(struct iic_regs)); + iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe); + printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs); + + found++; + } + + if (found) + return 0; + else + return -ENODEV; +} + #ifdef CONFIG_SMP /* Use the highest interrupt priorities for IPI */ @@ -283,10 +360,12 @@ void iic_init_IRQ(void) int cpu, irq_offset; struct iic *iic; + if (setup_iic() < 0) + setup_iic_hardcoded(); + irq_offset = 0; - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { iic = &per_cpu(iic, cpu); - setup_iic(cpu, iic); if (iic->regs) out_be64(&iic->regs->prio, 0xff); } diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h index a14bd38791c0..799f77d98f96 100644 --- a/arch/powerpc/platforms/cell/interrupt.h +++ b/arch/powerpc/platforms/cell/interrupt.h @@ -57,7 +57,7 @@ extern void iic_local_disable(void); extern u8 iic_get_target_id(int cpu); extern void spider_init_IRQ(void); -extern int spider_get_irq(unsigned long int_pending); +extern int spider_get_irq(int node); #endif #endif /* ASM_CELL_PIC_H */ diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index 46e7cb9c3e64..a49ceb799a8e 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c @@ -289,7 +289,7 @@ static void cell_do_map_iommu(struct cell_iommu *iommu, ioc_base = iommu->mapped_base; ioc_mmio_base = iommu->mapped_mmio_base; - for (real_address = 0, io_address = 0; + for (real_address = 0, io_address = map_start; io_address <= map_start + map_size; real_address += io_page_size, io_address += io_page_size) { ioste = get_iost_entry(fake_iopt, io_address, io_page_size); @@ -302,7 +302,7 @@ static void cell_do_map_iommu(struct cell_iommu *iommu, set_iopt_cache(ioc_mmio_base, get_ioc_hash_1way(ioste, io_address), get_ioc_tag(ioste, io_address), - get_iopt_entry(real_address-map_start, ioid, IOPT_PROT_RW)); + get_iopt_entry(real_address, ioid, IOPT_PROT_RW)); } } @@ -344,8 +344,8 @@ static int cell_map_iommu_hardcoded(int num_nodes) /* node 0 */ iommu = &cell_iommus[0]; - iommu->mapped_base = __ioremap(0x20000511000, 0x1000, _PAGE_NO_CACHE); - iommu->mapped_mmio_base = __ioremap(0x20000510000, 0x1000, _PAGE_NO_CACHE); + iommu->mapped_base = ioremap(0x20000511000, 0x1000); + iommu->mapped_mmio_base = ioremap(0x20000510000, 0x1000); enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base); @@ -357,8 +357,8 @@ static int cell_map_iommu_hardcoded(int num_nodes) /* node 1 */ iommu = &cell_iommus[1]; - iommu->mapped_base = __ioremap(0x30000511000, 0x1000, _PAGE_NO_CACHE); - iommu->mapped_mmio_base = __ioremap(0x30000510000, 0x1000, _PAGE_NO_CACHE); + iommu->mapped_base = ioremap(0x30000511000, 0x1000); + iommu->mapped_mmio_base = ioremap(0x30000510000, 0x1000); enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base); @@ -407,8 +407,8 @@ static int cell_map_iommu(void) iommu->base = *base; iommu->mmio_base = *mmio_base; - iommu->mapped_base = __ioremap(*base, 0x1000, _PAGE_NO_CACHE); - iommu->mapped_mmio_base = __ioremap(*mmio_base, 0x1000, _PAGE_NO_CACHE); + iommu->mapped_base = ioremap(*base, 0x1000); + iommu->mapped_mmio_base = ioremap(*mmio_base, 0x1000); enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base); diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c index e0e051c675dd..7eed8c624517 100644 --- a/arch/powerpc/platforms/cell/pervasive.c +++ b/arch/powerpc/platforms/cell/pervasive.c @@ -203,7 +203,7 @@ found: pr_debug("pervasive area for CPU %d at %lx, size %x\n", cpu, real_address, size); - p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE); + p->regs = ioremap(real_address, size); p->thread = thread; return 0; } @@ -217,7 +217,7 @@ void __init cell_pervasive_init(void) if (!cpu_has_feature(CPU_FTR_PAUSE_ZERO)) return; - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { p = &cbe_pervasive[cpu]; ret = cbe_find_pmd_mmio(cpu, p); if (ret) diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index fec8e65b36ea..dac5d0365fde 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -195,9 +195,13 @@ static void __init cell_init_early(void) } -static int __init cell_probe(int platform) +static int __init cell_probe(void) { - if (platform != PLATFORM_CELL) + /* XXX This is temporary, the Cell maintainer will come up with + * more appropriate detection logic + */ + unsigned long root = of_get_flat_dt_root(); + if (!of_flat_dt_is_compatible(root, "IBM,CPBW-1.0")) return 0; return 1; @@ -212,7 +216,8 @@ static int cell_check_legacy_ioport(unsigned int baseport) return -ENODEV; } -struct machdep_calls __initdata cell_md = { +define_machine(cell) { + .name = "Cell", .probe = cell_probe, .setup_arch = cell_setup_arch, .init_early = cell_init_early, diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index e74132188bdf..55cbdd77a62d 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c @@ -84,10 +84,11 @@ static void __iomem *spider_get_irq_config(int irq) static void spider_enable_irq(unsigned int irq) { + int nodeid = (irq / IIC_NODE_STRIDE) * 0x10; void __iomem *cfg = spider_get_irq_config(irq); irq = spider_get_nr(irq); - out_be32(cfg, in_be32(cfg) | 0x3107000eu); + out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid); out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq); } @@ -131,61 +132,108 @@ static struct hw_interrupt_type spider_pic = { .end = spider_end_irq, }; - -int spider_get_irq(unsigned long int_pending) +int spider_get_irq(int node) { - void __iomem *regs = spider_get_pic(int_pending); unsigned long cs; - int irq; + void __iomem *regs = spider_pics[node]; - cs = in_be32(regs + TIR_CS); + cs = in_be32(regs + TIR_CS) >> 24; - irq = cs >> 24; - if (irq != 63) - return irq; - - return -1; + if (cs == 63) + return -1; + else + return cs; } - -void spider_init_IRQ(void) + +/* hardcoded part to be compatible with older firmware */ + +void spider_init_IRQ_hardcoded(void) { int node; - struct device_node *dn; - unsigned int *property; long spiderpic; + long pics[] = { 0x24000008000, 0x34000008000 }; int n; -/* FIXME: detect multiple PICs as soon as the device tree has them */ - for (node = 0; node < 1; node++) { - dn = of_find_node_by_path("/"); - n = prom_n_addr_cells(dn); - property = (unsigned int *) get_property(dn, - "platform-spider-pic", NULL); + pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__); - if (!property) - continue; - for (spiderpic = 0; n > 0; --n) - spiderpic = (spiderpic << 32) + *property++; + for (node = 0; node < num_present_cpus()/2; node++) { + spiderpic = pics[node]; printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic); - spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE); + spider_pics[node] = ioremap(spiderpic, 0x800); for (n = 0; n < IIC_NUM_EXT; n++) { int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; get_irq_desc(irq)->handler = &spider_pic; + } /* do not mask any interrupts because of level */ out_be32(spider_pics[node] + TIR_MSK, 0x0); - + /* disable edge detection clear */ /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ - + /* enable interrupt packets to be output */ out_be32(spider_pics[node] + TIR_PIEN, in_be32(spider_pics[node] + TIR_PIEN) | 0x1); - + /* Enable the interrupt detection enable bit. Do this last! */ out_be32(spider_pics[node] + TIR_DEN, - in_be32(spider_pics[node] +TIR_DEN) | 0x1); - - } + in_be32(spider_pics[node] + TIR_DEN) | 0x1); + } +} + +void spider_init_IRQ(void) +{ + long spider_reg; + struct device_node *dn; + char *compatible; + int n, node = 0; + + for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) { + compatible = (char *)get_property(dn, "compatible", NULL); + + if (!compatible) + continue; + + if (strstr(compatible, "CBEA,platform-spider-pic")) + spider_reg = *(long *)get_property(dn,"reg", NULL); + else if (strstr(compatible, "sti,platform-spider-pic")) { + spider_init_IRQ_hardcoded(); + return; + } else + continue; + + if (!spider_reg) + printk("interrupt controller does not have reg property !\n"); + + n = prom_n_addr_cells(dn); + + if ( n != 2) + printk("reg property with invalid number of elements \n"); + + spider_pics[node] = ioremap(spider_reg, 0x800); + + printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n", + spider_reg, n, spider_pics[node]); + + for (n = 0; n < IIC_NUM_EXT; n++) { + int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; + get_irq_desc(irq)->handler = &spider_pic; + } + + /* do not mask any interrupts because of level */ + out_be32(spider_pics[node] + TIR_MSK, 0x0); + + /* disable edge detection clear */ + /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ + + /* enable interrupt packets to be output */ + out_be32(spider_pics[node] + TIR_PIEN, + in_be32(spider_pics[node] + TIR_PIEN) | 0x1); + + /* Enable the interrupt detection enable bit. Do this last! */ + out_be32(spider_pics[node] + TIR_DEN, + in_be32(spider_pics[node] + TIR_DEN) | 0x1); + + node++; } } diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index a8fa1eeeb174..269dda4fd0b4 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c @@ -111,7 +111,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) { - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea); /* Handle kernel space hash faults immediately. User hash faults need to be deferred to process context. */ @@ -168,7 +168,7 @@ static int __spu_trap_halt(struct spu *spu) static int __spu_trap_tag_group(struct spu *spu) { pr_debug("%s\n", __FUNCTION__); - /* wake_up(&spu->dma_wq); */ + spu->mfc_callback(spu); return 0; } @@ -242,6 +242,8 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs) spu_mfc_dsisr_set(spu, 0ul); spu_int_stat_clear(spu, 1, stat); spin_unlock(&spu->register_lock); + pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat, + dar, dsisr); if (stat & 1) /* segment fault */ __spu_trap_data_seg(spu, dar); @@ -484,14 +486,13 @@ int spu_irq_class_1_bottom(struct spu *spu) ea = spu->dar; dsisr = spu->dsisr; - if (dsisr & MFC_DSISR_PTE_NOT_FOUND) { + if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) { access = (_PAGE_PRESENT | _PAGE_USER); access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; if (hash_page(ea, access, 0x300) != 0) error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; } - if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) || - (dsisr & MFC_DSISR_ACCESS_DENIED)) { + if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) { if ((ret = spu_handle_mm_fault(spu)) != 0) error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; else @@ -568,6 +569,11 @@ static int __init spu_map_device(struct spu *spu, struct device_node *spe) if (!spu->local_store) goto out; + prop = get_property(spe, "problem", NULL); + if (!prop) + goto out_unmap; + spu->problem_phys = *(unsigned long *)prop; + spu->problem= map_spe_prop(spe, "problem"); if (!spu->problem) goto out_unmap; @@ -632,6 +638,7 @@ static int __init create_spu(struct device_node *spe) spu->ibox_callback = NULL; spu->wbox_callback = NULL; spu->stop_callback = NULL; + spu->mfc_callback = NULL; mutex_lock(&spu_mutex); spu->number = number++; diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c new file mode 100644 index 000000000000..6594bec73882 --- /dev/null +++ b/arch/powerpc/platforms/cell/spu_callbacks.c @@ -0,0 +1,346 @@ +/* + * System call callback functions for SPUs + */ + +#define DEBUG + +#include +#include +#include + +#include +#include +#include + +/* + * This table defines the system calls that an SPU can call. + * It is currently a subset of the 64 bit powerpc system calls, + * with the exact semantics. + * + * The reasons for disabling some of the system calls are: + * 1. They interact with the way SPU syscalls are handled + * and we can't let them execute ever: + * restart_syscall, exit, for, execve, ptrace, ... + * 2. They are deprecated and replaced by other means: + * uselib, pciconfig_*, sysfs, ... + * 3. They are somewhat interacting with the system in a way + * we don't want an SPU to: + * reboot, init_module, mount, kexec_load + * 4. They are optional and we can't rely on them being + * linked into the kernel. Unfortunately, the cond_syscall + * helper does not work here as it does not add the necessary + * opd symbols: + * mbind, mq_open, ipc, ... + */ + +void *spu_syscall_table[] = { + [__NR_restart_syscall] sys_ni_syscall, /* sys_restart_syscall */ + [__NR_exit] sys_ni_syscall, /* sys_exit */ + [__NR_fork] sys_ni_syscall, /* ppc_fork */ + [__NR_read] sys_read, + [__NR_write] sys_write, + [__NR_open] sys_open, + [__NR_close] sys_close, + [__NR_waitpid] sys_waitpid, + [__NR_creat] sys_creat, + [__NR_link] sys_link, + [__NR_unlink] sys_unlink, + [__NR_execve] sys_ni_syscall, /* sys_execve */ + [__NR_chdir] sys_chdir, + [__NR_time] sys_time, + [__NR_mknod] sys_mknod, + [__NR_chmod] sys_chmod, + [__NR_lchown] sys_lchown, + [__NR_break] sys_ni_syscall, + [__NR_oldstat] sys_ni_syscall, + [__NR_lseek] sys_lseek, + [__NR_getpid] sys_getpid, + [__NR_mount] sys_ni_syscall, /* sys_mount */ + [__NR_umount] sys_ni_syscall, + [__NR_setuid] sys_setuid, + [__NR_getuid] sys_getuid, + [__NR_stime] sys_stime, + [__NR_ptrace] sys_ni_syscall, /* sys_ptrace */ + [__NR_alarm] sys_alarm, + [__NR_oldfstat] sys_ni_syscall, + [__NR_pause] sys_ni_syscall, /* sys_pause */ + [__NR_utime] sys_ni_syscall, /* sys_utime */ + [__NR_stty] sys_ni_syscall, + [__NR_gtty] sys_ni_syscall, + [__NR_access] sys_access, + [__NR_nice] sys_nice, + [__NR_ftime] sys_ni_syscall, + [__NR_sync] sys_sync, + [__NR_kill] sys_kill, + [__NR_rename] sys_rename, + [__NR_mkdir] sys_mkdir, + [__NR_rmdir] sys_rmdir, + [__NR_dup] sys_dup, + [__NR_pipe] sys_pipe, + [__NR_times] sys_times, + [__NR_prof] sys_ni_syscall, + [__NR_brk] sys_brk, + [__NR_setgid] sys_setgid, + [__NR_getgid] sys_getgid, + [__NR_signal] sys_ni_syscall, /* sys_signal */ + [__NR_geteuid] sys_geteuid, + [__NR_getegid] sys_getegid, + [__NR_acct] sys_ni_syscall, /* sys_acct */ + [__NR_umount2] sys_ni_syscall, /* sys_umount */ + [__NR_lock] sys_ni_syscall, + [__NR_ioctl] sys_ioctl, + [__NR_fcntl] sys_fcntl, + [__NR_mpx] sys_ni_syscall, + [__NR_setpgid] sys_setpgid, + [__NR_ulimit] sys_ni_syscall, + [__NR_oldolduname] sys_ni_syscall, + [__NR_umask] sys_umask, + [__NR_chroot] sys_chroot, + [__NR_ustat] sys_ni_syscall, /* sys_ustat */ + [__NR_dup2] sys_dup2, + [__NR_getppid] sys_getppid, + [__NR_getpgrp] sys_getpgrp, + [__NR_setsid] sys_setsid, + [__NR_sigaction] sys_ni_syscall, + [__NR_sgetmask] sys_sgetmask, + [__NR_ssetmask] sys_ssetmask, + [__NR_setreuid] sys_setreuid, + [__NR_setregid] sys_setregid, + [__NR_sigsuspend] sys_ni_syscall, + [__NR_sigpending] sys_ni_syscall, + [__NR_sethostname] sys_sethostname, + [__NR_setrlimit] sys_setrlimit, + [__NR_getrlimit] sys_ni_syscall, + [__NR_getrusage] sys_getrusage, + [__NR_gettimeofday] sys_gettimeofday, + [__NR_settimeofday] sys_settimeofday, + [__NR_getgroups] sys_getgroups, + [__NR_setgroups] sys_setgroups, + [__NR_select] sys_ni_syscall, + [__NR_symlink] sys_symlink, + [__NR_oldlstat] sys_ni_syscall, + [__NR_readlink] sys_readlink, + [__NR_uselib] sys_ni_syscall, /* sys_uselib */ + [__NR_swapon] sys_ni_syscall, /* sys_swapon */ + [__NR_reboot] sys_ni_syscall, /* sys_reboot */ + [__NR_readdir] sys_ni_syscall, + [__NR_mmap] sys_mmap, + [__NR_munmap] sys_munmap, + [__NR_truncate] sys_truncate, + [__NR_ftruncate] sys_ftruncate, + [__NR_fchmod] sys_fchmod, + [__NR_fchown] sys_fchown, + [__NR_getpriority] sys_getpriority, + [__NR_setpriority] sys_setpriority, + [__NR_profil] sys_ni_syscall, + [__NR_statfs] sys_ni_syscall, /* sys_statfs */ + [__NR_fstatfs] sys_ni_syscall, /* sys_fstatfs */ + [__NR_ioperm] sys_ni_syscall, + [__NR_socketcall] sys_socketcall, + [__NR_syslog] sys_syslog, + [__NR_setitimer] sys_setitimer, + [__NR_getitimer] sys_getitimer, + [__NR_stat] sys_newstat, + [__NR_lstat] sys_newlstat, + [__NR_fstat] sys_newfstat, + [__NR_olduname] sys_ni_syscall, + [__NR_iopl] sys_ni_syscall, + [__NR_vhangup] sys_vhangup, + [__NR_idle] sys_ni_syscall, + [__NR_vm86] sys_ni_syscall, + [__NR_wait4] sys_wait4, + [__NR_swapoff] sys_ni_syscall, /* sys_swapoff */ + [__NR_sysinfo] sys_sysinfo, + [__NR_ipc] sys_ni_syscall, /* sys_ipc */ + [__NR_fsync] sys_fsync, + [__NR_sigreturn] sys_ni_syscall, + [__NR_clone] sys_ni_syscall, /* ppc_clone */ + [__NR_setdomainname] sys_setdomainname, + [__NR_uname] ppc_newuname, + [__NR_modify_ldt] sys_ni_syscall, + [__NR_adjtimex] sys_adjtimex, + [__NR_mprotect] sys_mprotect, + [__NR_sigprocmask] sys_ni_syscall, + [__NR_create_module] sys_ni_syscall, + [__NR_init_module] sys_ni_syscall, /* sys_init_module */ + [__NR_delete_module] sys_ni_syscall, /* sys_delete_module */ + [__NR_get_kernel_syms] sys_ni_syscall, + [__NR_quotactl] sys_ni_syscall, /* sys_quotactl */ + [__NR_getpgid] sys_getpgid, + [__NR_fchdir] sys_fchdir, + [__NR_bdflush] sys_bdflush, + [__NR_sysfs] sys_ni_syscall, /* sys_sysfs */ + [__NR_personality] ppc64_personality, + [__NR_afs_syscall] sys_ni_syscall, + [__NR_setfsuid] sys_setfsuid, + [__NR_setfsgid] sys_setfsgid, + [__NR__llseek] sys_llseek, + [__NR_getdents] sys_getdents, + [__NR__newselect] sys_select, + [__NR_flock] sys_flock, + [__NR_msync] sys_msync, + [__NR_readv] sys_readv, + [__NR_writev] sys_writev, + [__NR_getsid] sys_getsid, + [__NR_fdatasync] sys_fdatasync, + [__NR__sysctl] sys_ni_syscall, /* sys_sysctl */ + [__NR_mlock] sys_mlock, + [__NR_munlock] sys_munlock, + [__NR_mlockall] sys_mlockall, + [__NR_munlockall] sys_munlockall, + [__NR_sched_setparam] sys_sched_setparam, + [__NR_sched_getparam] sys_sched_getparam, + [__NR_sched_setscheduler] sys_sched_setscheduler, + [__NR_sched_getscheduler] sys_sched_getscheduler, + [__NR_sched_yield] sys_sched_yield, + [__NR_sched_get_priority_max] sys_sched_get_priority_max, + [__NR_sched_get_priority_min] sys_sched_get_priority_min, + [__NR_sched_rr_get_interval] sys_sched_rr_get_interval, + [__NR_nanosleep] sys_nanosleep, + [__NR_mremap] sys_mremap, + [__NR_setresuid] sys_setresuid, + [__NR_getresuid] sys_getresuid, + [__NR_query_module] sys_ni_syscall, + [__NR_poll] sys_poll, + [__NR_nfsservctl] sys_ni_syscall, /* sys_nfsservctl */ + [__NR_setresgid] sys_setresgid, + [__NR_getresgid] sys_getresgid, + [__NR_prctl] sys_prctl, + [__NR_rt_sigreturn] sys_ni_syscall, /* ppc64_rt_sigreturn */ + [__NR_rt_sigaction] sys_ni_syscall, /* sys_rt_sigaction */ + [__NR_rt_sigprocmask] sys_ni_syscall, /* sys_rt_sigprocmask */ + [__NR_rt_sigpending] sys_ni_syscall, /* sys_rt_sigpending */ + [__NR_rt_sigtimedwait] sys_ni_syscall, /* sys_rt_sigtimedwait */ + [__NR_rt_sigqueueinfo] sys_ni_syscall, /* sys_rt_sigqueueinfo */ + [__NR_rt_sigsuspend] sys_ni_syscall, /* sys_rt_sigsuspend */ + [__NR_pread64] sys_pread64, + [__NR_pwrite64] sys_pwrite64, + [__NR_chown] sys_chown, + [__NR_getcwd] sys_getcwd, + [__NR_capget] sys_capget, + [__NR_capset] sys_capset, + [__NR_sigaltstack] sys_ni_syscall, /* sys_sigaltstack */ + [__NR_sendfile] sys_sendfile64, + [__NR_getpmsg] sys_ni_syscall, + [__NR_putpmsg] sys_ni_syscall, + [__NR_vfork] sys_ni_syscall, /* ppc_vfork */ + [__NR_ugetrlimit] sys_getrlimit, + [__NR_readahead] sys_readahead, + [192] sys_ni_syscall, + [193] sys_ni_syscall, + [194] sys_ni_syscall, + [195] sys_ni_syscall, + [196] sys_ni_syscall, + [197] sys_ni_syscall, + [__NR_pciconfig_read] sys_ni_syscall, /* sys_pciconfig_read */ + [__NR_pciconfig_write] sys_ni_syscall, /* sys_pciconfig_write */ + [__NR_pciconfig_iobase] sys_ni_syscall, /* sys_pciconfig_iobase */ + [__NR_multiplexer] sys_ni_syscall, + [__NR_getdents64] sys_getdents64, + [__NR_pivot_root] sys_pivot_root, + [204] sys_ni_syscall, + [__NR_madvise] sys_madvise, + [__NR_mincore] sys_mincore, + [__NR_gettid] sys_gettid, + [__NR_tkill] sys_tkill, + [__NR_setxattr] sys_setxattr, + [__NR_lsetxattr] sys_lsetxattr, + [__NR_fsetxattr] sys_fsetxattr, + [__NR_getxattr] sys_getxattr, + [__NR_lgetxattr] sys_lgetxattr, + [__NR_fgetxattr] sys_fgetxattr, + [__NR_listxattr] sys_listxattr, + [__NR_llistxattr] sys_llistxattr, + [__NR_flistxattr] sys_flistxattr, + [__NR_removexattr] sys_removexattr, + [__NR_lremovexattr] sys_lremovexattr, + [__NR_fremovexattr] sys_fremovexattr, + [__NR_futex] sys_futex, + [__NR_sched_setaffinity] sys_sched_setaffinity, + [__NR_sched_getaffinity] sys_sched_getaffinity, + [__NR_tuxcall] sys_ni_syscall, + [226] sys_ni_syscall, + [__NR_io_setup] sys_io_setup, + [__NR_io_destroy] sys_io_destroy, + [__NR_io_getevents] sys_io_getevents, + [__NR_io_submit] sys_io_submit, + [__NR_io_cancel] sys_io_cancel, + [__NR_set_tid_address] sys_ni_syscall, /* sys_set_tid_address */ + [__NR_fadvise64] sys_fadvise64, + [__NR_exit_group] sys_ni_syscall, /* sys_exit_group */ + [__NR_lookup_dcookie] sys_ni_syscall, /* sys_lookup_dcookie */ + [__NR_epoll_create] sys_epoll_create, + [__NR_epoll_ctl] sys_epoll_ctl, + [__NR_epoll_wait] sys_epoll_wait, + [__NR_remap_file_pages] sys_remap_file_pages, + [__NR_timer_create] sys_timer_create, + [__NR_timer_settime] sys_timer_settime, + [__NR_timer_gettime] sys_timer_gettime, + [__NR_timer_getoverrun] sys_timer_getoverrun, + [__NR_timer_delete] sys_timer_delete, + [__NR_clock_settime] sys_clock_settime, + [__NR_clock_gettime] sys_clock_gettime, + [__NR_clock_getres] sys_clock_getres, + [__NR_clock_nanosleep] sys_clock_nanosleep, + [__NR_swapcontext] sys_ni_syscall, /* ppc64_swapcontext */ + [__NR_tgkill] sys_tgkill, + [__NR_utimes] sys_utimes, + [__NR_statfs64] sys_statfs64, + [__NR_fstatfs64] sys_fstatfs64, + [254] sys_ni_syscall, + [__NR_rtas] ppc_rtas, + [256] sys_ni_syscall, + [257] sys_ni_syscall, + [258] sys_ni_syscall, + [__NR_mbind] sys_ni_syscall, /* sys_mbind */ + [__NR_get_mempolicy] sys_ni_syscall, /* sys_get_mempolicy */ + [__NR_set_mempolicy] sys_ni_syscall, /* sys_set_mempolicy */ + [__NR_mq_open] sys_ni_syscall, /* sys_mq_open */ + [__NR_mq_unlink] sys_ni_syscall, /* sys_mq_unlink */ + [__NR_mq_timedsend] sys_ni_syscall, /* sys_mq_timedsend */ + [__NR_mq_timedreceive] sys_ni_syscall, /* sys_mq_timedreceive */ + [__NR_mq_notify] sys_ni_syscall, /* sys_mq_notify */ + [__NR_mq_getsetattr] sys_ni_syscall, /* sys_mq_getsetattr */ + [__NR_kexec_load] sys_ni_syscall, /* sys_kexec_load */ + [__NR_add_key] sys_ni_syscall, /* sys_add_key */ + [__NR_request_key] sys_ni_syscall, /* sys_request_key */ + [__NR_keyctl] sys_ni_syscall, /* sys_keyctl */ + [__NR_waitid] sys_ni_syscall, /* sys_waitid */ + [__NR_ioprio_set] sys_ni_syscall, /* sys_ioprio_set */ + [__NR_ioprio_get] sys_ni_syscall, /* sys_ioprio_get */ + [__NR_inotify_init] sys_ni_syscall, /* sys_inotify_init */ + [__NR_inotify_add_watch] sys_ni_syscall, /* sys_inotify_add_watch */ + [__NR_inotify_rm_watch] sys_ni_syscall, /* sys_inotify_rm_watch */ + [__NR_spu_run] sys_ni_syscall, /* sys_spu_run */ + [__NR_spu_create] sys_ni_syscall, /* sys_spu_create */ + [__NR_pselect6] sys_ni_syscall, /* sys_pselect */ + [__NR_ppoll] sys_ni_syscall, /* sys_ppoll */ + [__NR_unshare] sys_unshare, + [__NR_splice] sys_splice, +}; + +long spu_sys_callback(struct spu_syscall_block *s) +{ + long (*syscall)(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5, u64 a6); + + BUILD_BUG_ON(ARRAY_SIZE(spu_syscall_table) != __NR_syscalls); + + syscall = spu_syscall_table[s->nr_ret]; + + if (s->nr_ret >= __NR_syscalls) { + pr_debug("%s: invalid syscall #%ld", __FUNCTION__, s->nr_ret); + return -ENOSYS; + } + +#ifdef DEBUG + print_symbol(KERN_DEBUG "SPU-syscall %s:", (unsigned long)syscall); + printk("syscall%ld(%lx, %lx, %lx, %lx, %lx, %lx)\n", + s->nr_ret, + s->parm[0], s->parm[1], s->parm[2], + s->parm[3], s->parm[4], s->parm[5]); +#endif + + return syscall(s->parm[0], s->parm[1], s->parm[2], + s->parm[3], s->parm[4], s->parm[5]); +} +EXPORT_SYMBOL_GPL(spu_sys_callback); diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c index a5c489a53c61..f1d35ddc9df3 100644 --- a/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c @@ -285,6 +285,49 @@ static void spu_backing_runcntl_stop(struct spu_context *ctx) spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP); } +static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask, + u32 mode) +{ + struct spu_problem_collapsed *prob = &ctx->csa.prob; + int ret; + + spin_lock(&ctx->csa.register_lock); + ret = -EAGAIN; + if (prob->dma_querytype_RW) + goto out; + ret = 0; + /* FIXME: what are the side-effects of this? */ + prob->dma_querymask_RW = mask; + prob->dma_querytype_RW = mode; +out: + spin_unlock(&ctx->csa.register_lock); + + return ret; +} + +static u32 spu_backing_read_mfc_tagstatus(struct spu_context * ctx) +{ + return ctx->csa.prob.dma_tagstatus_R; +} + +static u32 spu_backing_get_mfc_free_elements(struct spu_context *ctx) +{ + return ctx->csa.prob.dma_qstatus_R; +} + +static int spu_backing_send_mfc_command(struct spu_context *ctx, + struct mfc_dma_command *cmd) +{ + int ret; + + spin_lock(&ctx->csa.register_lock); + ret = -EAGAIN; + /* FIXME: set up priv2->puq */ + spin_unlock(&ctx->csa.register_lock); + + return ret; +} + struct spu_context_ops spu_backing_ops = { .mbox_read = spu_backing_mbox_read, .mbox_stat_read = spu_backing_mbox_stat_read, @@ -305,4 +348,8 @@ struct spu_context_ops spu_backing_ops = { .get_ls = spu_backing_get_ls, .runcntl_write = spu_backing_runcntl_write, .runcntl_stop = spu_backing_runcntl_stop, + .set_mfc_query = spu_backing_set_mfc_query, + .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus, + .get_mfc_free_elements = spu_backing_get_mfc_free_elements, + .send_mfc_command = spu_backing_send_mfc_command, }; diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 336f238102fd..8bb33abfad17 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c @@ -27,7 +27,7 @@ #include #include "spufs.h" -struct spu_context *alloc_spu_context(struct address_space *local_store) +struct spu_context *alloc_spu_context(void) { struct spu_context *ctx; ctx = kmalloc(sizeof *ctx, GFP_KERNEL); @@ -47,10 +47,17 @@ struct spu_context *alloc_spu_context(struct address_space *local_store) init_waitqueue_head(&ctx->ibox_wq); init_waitqueue_head(&ctx->wbox_wq); init_waitqueue_head(&ctx->stop_wq); + init_waitqueue_head(&ctx->mfc_wq); ctx->ibox_fasync = NULL; ctx->wbox_fasync = NULL; + ctx->mfc_fasync = NULL; + ctx->mfc = NULL; + ctx->tagwait = 0; ctx->state = SPU_STATE_SAVED; - ctx->local_store = local_store; + ctx->local_store = NULL; + ctx->cntl = NULL; + ctx->signal1 = NULL; + ctx->signal2 = NULL; ctx->spu = NULL; ctx->ops = &spu_backing_ops; ctx->owner = get_task_mm(current); @@ -68,8 +75,6 @@ void destroy_spu_context(struct kref *kref) ctx = container_of(kref, struct spu_context, kref); down_write(&ctx->state_sema); spu_deactivate(ctx); - ctx->ibox_fasync = NULL; - ctx->wbox_fasync = NULL; up_write(&ctx->state_sema); spu_fini_csa(&ctx->csa); kfree(ctx); @@ -109,7 +114,16 @@ void spu_release(struct spu_context *ctx) void spu_unmap_mappings(struct spu_context *ctx) { - unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); + if (ctx->local_store) + unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); + if (ctx->mfc) + unmap_mapping_range(ctx->mfc, 0, 0x4000, 1); + if (ctx->cntl) + unmap_mapping_range(ctx->cntl, 0, 0x4000, 1); + if (ctx->signal1) + unmap_mapping_range(ctx->signal1, 0, 0x4000, 1); + if (ctx->signal2) + unmap_mapping_range(ctx->signal2, 0, 0x4000, 1); } int spu_acquire_runnable(struct spu_context *ctx) diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index dfa649c9b956..366185e92667 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -20,6 +20,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#undef DEBUG + #include #include #include @@ -39,8 +41,10 @@ static int spufs_mem_open(struct inode *inode, struct file *file) { struct spufs_inode_info *i = SPUFS_I(inode); - file->private_data = i->i_ctx; - file->f_mapping = i->i_ctx->local_store; + struct spu_context *ctx = i->i_ctx; + file->private_data = ctx; + file->f_mapping = inode->i_mapping; + ctx->local_store = inode->i_mapping; return 0; } @@ -84,7 +88,7 @@ spufs_mem_write(struct file *file, const char __user *buffer, return ret; } -#ifdef CONFIG_SPARSEMEM +#ifdef CONFIG_SPUFS_MMAP static struct page * spufs_mem_mmap_nopage(struct vm_area_struct *vma, unsigned long address, int *type) @@ -136,11 +140,113 @@ static struct file_operations spufs_mem_fops = { .read = spufs_mem_read, .write = spufs_mem_write, .llseek = generic_file_llseek, -#ifdef CONFIG_SPARSEMEM +#ifdef CONFIG_SPUFS_MMAP .mmap = spufs_mem_mmap, #endif }; +#ifdef CONFIG_SPUFS_MMAP +static struct page *spufs_ps_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type, unsigned long ps_offs) +{ + struct page *page = NOPAGE_SIGBUS; + int fault_type = VM_FAULT_SIGBUS; + struct spu_context *ctx = vma->vm_file->private_data; + unsigned long offset = address - vma->vm_start; + unsigned long area; + int ret; + + offset += vma->vm_pgoff << PAGE_SHIFT; + if (offset >= 0x4000) + goto out; + + ret = spu_acquire_runnable(ctx); + if (ret) + goto out; + + area = ctx->spu->problem_phys + ps_offs; + page = pfn_to_page((area + offset) >> PAGE_SHIFT); + fault_type = VM_FAULT_MINOR; + page_cache_get(page); + + spu_release(ctx); + + out: + if (type) + *type = fault_type; + + return page; +} + +static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + return spufs_ps_nopage(vma, address, type, 0x4000); +} + +static struct vm_operations_struct spufs_cntl_mmap_vmops = { + .nopage = spufs_cntl_mmap_nopage, +}; + +/* + * mmap support for problem state control area [0x4000 - 0x4fff]. + * Mapping this area requires that the application have CAP_SYS_RAWIO, + * as these registers require special care when read/writing. + */ +static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) +{ + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + vma->vm_flags |= VM_RESERVED; + vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) + | _PAGE_NO_CACHE); + + vma->vm_ops = &spufs_cntl_mmap_vmops; + return 0; +} +#endif + +static int spufs_cntl_open(struct inode *inode, struct file *file) +{ + struct spufs_inode_info *i = SPUFS_I(inode); + struct spu_context *ctx = i->i_ctx; + + file->private_data = ctx; + file->f_mapping = inode->i_mapping; + ctx->cntl = inode->i_mapping; + return 0; +} + +static ssize_t +spufs_cntl_read(struct file *file, char __user *buffer, + size_t size, loff_t *pos) +{ + /* FIXME: read from spu status */ + return -EINVAL; +} + +static ssize_t +spufs_cntl_write(struct file *file, const char __user *buffer, + size_t size, loff_t *pos) +{ + /* FIXME: write to runctl bit */ + return -EINVAL; +} + +static struct file_operations spufs_cntl_fops = { + .open = spufs_cntl_open, + .read = spufs_cntl_read, + .write = spufs_cntl_write, +#ifdef CONFIG_SPUFS_MMAP + .mmap = spufs_cntl_mmap, +#endif +}; + static int spufs_regs_open(struct inode *inode, struct file *file) { @@ -501,6 +607,16 @@ static struct file_operations spufs_wbox_stat_fops = { .read = spufs_wbox_stat_read, }; +static int spufs_signal1_open(struct inode *inode, struct file *file) +{ + struct spufs_inode_info *i = SPUFS_I(inode); + struct spu_context *ctx = i->i_ctx; + file->private_data = ctx; + file->f_mapping = inode->i_mapping; + ctx->signal1 = inode->i_mapping; + return nonseekable_open(inode, file); +} + static ssize_t spufs_signal1_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { @@ -541,12 +657,50 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, return 4; } +#ifdef CONFIG_SPUFS_MMAP +static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + return spufs_ps_nopage(vma, address, type, 0x14000); +} + +static struct vm_operations_struct spufs_signal1_mmap_vmops = { + .nopage = spufs_signal1_mmap_nopage, +}; + +static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) +{ + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + vma->vm_flags |= VM_RESERVED; + vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) + | _PAGE_NO_CACHE); + + vma->vm_ops = &spufs_signal1_mmap_vmops; + return 0; +} +#endif + static struct file_operations spufs_signal1_fops = { - .open = spufs_pipe_open, + .open = spufs_signal1_open, .read = spufs_signal1_read, .write = spufs_signal1_write, +#ifdef CONFIG_SPUFS_MMAP + .mmap = spufs_signal1_mmap, +#endif }; +static int spufs_signal2_open(struct inode *inode, struct file *file) +{ + struct spufs_inode_info *i = SPUFS_I(inode); + struct spu_context *ctx = i->i_ctx; + file->private_data = ctx; + file->f_mapping = inode->i_mapping; + ctx->signal2 = inode->i_mapping; + return nonseekable_open(inode, file); +} + static ssize_t spufs_signal2_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { @@ -589,10 +743,39 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, return 4; } +#ifdef CONFIG_SPUFS_MMAP +static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + return spufs_ps_nopage(vma, address, type, 0x1c000); +} + +static struct vm_operations_struct spufs_signal2_mmap_vmops = { + .nopage = spufs_signal2_mmap_nopage, +}; + +static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) +{ + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + /* FIXME: */ + vma->vm_flags |= VM_RESERVED; + vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) + | _PAGE_NO_CACHE); + + vma->vm_ops = &spufs_signal2_mmap_vmops; + return 0; +} +#endif + static struct file_operations spufs_signal2_fops = { - .open = spufs_pipe_open, + .open = spufs_signal2_open, .read = spufs_signal2_read, .write = spufs_signal2_write, +#ifdef CONFIG_SPUFS_MMAP + .mmap = spufs_signal2_mmap, +#endif }; static void spufs_signal1_type_set(void *data, u64 val) @@ -641,6 +824,332 @@ static u64 spufs_signal2_type_get(void *data) DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, spufs_signal2_type_set, "%llu"); +#ifdef CONFIG_SPUFS_MMAP +static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + return spufs_ps_nopage(vma, address, type, 0x3000); +} + +static struct vm_operations_struct spufs_mfc_mmap_vmops = { + .nopage = spufs_mfc_mmap_nopage, +}; + +/* + * mmap support for problem state MFC DMA area [0x0000 - 0x0fff]. + * Mapping this area requires that the application have CAP_SYS_RAWIO, + * as these registers require special care when read/writing. + */ +static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) +{ + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + vma->vm_flags |= VM_RESERVED; + vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) + | _PAGE_NO_CACHE); + + vma->vm_ops = &spufs_mfc_mmap_vmops; + return 0; +} +#endif + +static int spufs_mfc_open(struct inode *inode, struct file *file) +{ + struct spufs_inode_info *i = SPUFS_I(inode); + struct spu_context *ctx = i->i_ctx; + + /* we don't want to deal with DMA into other processes */ + if (ctx->owner != current->mm) + return -EINVAL; + + if (atomic_read(&inode->i_count) != 1) + return -EBUSY; + + file->private_data = ctx; + return nonseekable_open(inode, file); +} + +/* interrupt-level mfc callback function. */ +void spufs_mfc_callback(struct spu *spu) +{ + struct spu_context *ctx = spu->ctx; + + wake_up_all(&ctx->mfc_wq); + + pr_debug("%s %s\n", __FUNCTION__, spu->name); + if (ctx->mfc_fasync) { + u32 free_elements, tagstatus; + unsigned int mask; + + /* no need for spu_acquire in interrupt context */ + free_elements = ctx->ops->get_mfc_free_elements(ctx); + tagstatus = ctx->ops->read_mfc_tagstatus(ctx); + + mask = 0; + if (free_elements & 0xffff) + mask |= POLLOUT; + if (tagstatus & ctx->tagwait) + mask |= POLLIN; + + kill_fasync(&ctx->mfc_fasync, SIGIO, mask); + } +} + +static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status) +{ + /* See if there is one tag group is complete */ + /* FIXME we need locking around tagwait */ + *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait; + ctx->tagwait &= ~*status; + if (*status) + return 1; + + /* enable interrupt waiting for any tag group, + may silently fail if interrupts are already enabled */ + ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); + return 0; +} + +static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, + size_t size, loff_t *pos) +{ + struct spu_context *ctx = file->private_data; + int ret = -EINVAL; + u32 status; + + if (size != 4) + goto out; + + spu_acquire(ctx); + if (file->f_flags & O_NONBLOCK) { + status = ctx->ops->read_mfc_tagstatus(ctx); + if (!(status & ctx->tagwait)) + ret = -EAGAIN; + else + ctx->tagwait &= ~status; + } else { + ret = spufs_wait(ctx->mfc_wq, + spufs_read_mfc_tagstatus(ctx, &status)); + } + spu_release(ctx); + + if (ret) + goto out; + + ret = 4; + if (copy_to_user(buffer, &status, 4)) + ret = -EFAULT; + +out: + return ret; +} + +static int spufs_check_valid_dma(struct mfc_dma_command *cmd) +{ + pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa, + cmd->ea, cmd->size, cmd->tag, cmd->cmd); + + switch (cmd->cmd) { + case MFC_PUT_CMD: + case MFC_PUTF_CMD: + case MFC_PUTB_CMD: + case MFC_GET_CMD: + case MFC_GETF_CMD: + case MFC_GETB_CMD: + break; + default: + pr_debug("invalid DMA opcode %x\n", cmd->cmd); + return -EIO; + } + + if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) { + pr_debug("invalid DMA alignment, ea %lx lsa %x\n", + cmd->ea, cmd->lsa); + return -EIO; + } + + switch (cmd->size & 0xf) { + case 1: + break; + case 2: + if (cmd->lsa & 1) + goto error; + break; + case 4: + if (cmd->lsa & 3) + goto error; + break; + case 8: + if (cmd->lsa & 7) + goto error; + break; + case 0: + if (cmd->lsa & 15) + goto error; + break; + error: + default: + pr_debug("invalid DMA alignment %x for size %x\n", + cmd->lsa & 0xf, cmd->size); + return -EIO; + } + + if (cmd->size > 16 * 1024) { + pr_debug("invalid DMA size %x\n", cmd->size); + return -EIO; + } + + if (cmd->tag & 0xfff0) { + /* we reserve the higher tag numbers for kernel use */ + pr_debug("invalid DMA tag\n"); + return -EIO; + } + + if (cmd->class) { + /* not supported in this version */ + pr_debug("invalid DMA class\n"); + return -EIO; + } + + return 0; +} + +static int spu_send_mfc_command(struct spu_context *ctx, + struct mfc_dma_command cmd, + int *error) +{ + *error = ctx->ops->send_mfc_command(ctx, &cmd); + if (*error == -EAGAIN) { + /* wait for any tag group to complete + so we have space for the new command */ + ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1); + /* try again, because the queue might be + empty again */ + *error = ctx->ops->send_mfc_command(ctx, &cmd); + if (*error == -EAGAIN) + return 0; + } + return 1; +} + +static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, + size_t size, loff_t *pos) +{ + struct spu_context *ctx = file->private_data; + struct mfc_dma_command cmd; + int ret = -EINVAL; + + if (size != sizeof cmd) + goto out; + + ret = -EFAULT; + if (copy_from_user(&cmd, buffer, sizeof cmd)) + goto out; + + ret = spufs_check_valid_dma(&cmd); + if (ret) + goto out; + + spu_acquire_runnable(ctx); + if (file->f_flags & O_NONBLOCK) { + ret = ctx->ops->send_mfc_command(ctx, &cmd); + } else { + int status; + ret = spufs_wait(ctx->mfc_wq, + spu_send_mfc_command(ctx, cmd, &status)); + if (status) + ret = status; + } + spu_release(ctx); + + if (ret) + goto out; + + ctx->tagwait |= 1 << cmd.tag; + +out: + return ret; +} + +static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) +{ + struct spu_context *ctx = file->private_data; + u32 free_elements, tagstatus; + unsigned int mask; + + spu_acquire(ctx); + ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); + free_elements = ctx->ops->get_mfc_free_elements(ctx); + tagstatus = ctx->ops->read_mfc_tagstatus(ctx); + spu_release(ctx); + + poll_wait(file, &ctx->mfc_wq, wait); + + mask = 0; + if (free_elements & 0xffff) + mask |= POLLOUT | POLLWRNORM; + if (tagstatus & ctx->tagwait) + mask |= POLLIN | POLLRDNORM; + + pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__, + free_elements, tagstatus, ctx->tagwait); + + return mask; +} + +static int spufs_mfc_flush(struct file *file) +{ + struct spu_context *ctx = file->private_data; + int ret; + + spu_acquire(ctx); +#if 0 +/* this currently hangs */ + ret = spufs_wait(ctx->mfc_wq, + ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2)); + if (ret) + goto out; + ret = spufs_wait(ctx->mfc_wq, + ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait); +out: +#else + ret = 0; +#endif + spu_release(ctx); + + return ret; +} + +static int spufs_mfc_fsync(struct file *file, struct dentry *dentry, + int datasync) +{ + return spufs_mfc_flush(file); +} + +static int spufs_mfc_fasync(int fd, struct file *file, int on) +{ + struct spu_context *ctx = file->private_data; + + return fasync_helper(fd, file, on, &ctx->mfc_fasync); +} + +static struct file_operations spufs_mfc_fops = { + .open = spufs_mfc_open, + .read = spufs_mfc_read, + .write = spufs_mfc_write, + .poll = spufs_mfc_poll, + .flush = spufs_mfc_flush, + .fsync = spufs_mfc_fsync, + .fasync = spufs_mfc_fasync, +#ifdef CONFIG_SPUFS_MMAP + .mmap = spufs_mfc_mmap, +#endif +}; + static void spufs_npc_set(void *data, u64 val) { struct spu_context *ctx = data; @@ -783,6 +1292,8 @@ struct tree_descr spufs_dir_contents[] = { { "signal2", &spufs_signal2_fops, 0666, }, { "signal1_type", &spufs_signal1_type, 0666, }, { "signal2_type", &spufs_signal2_type, 0666, }, + { "mfc", &spufs_mfc_fops, 0666, }, + { "cntl", &spufs_cntl_fops, 0666, }, { "npc", &spufs_npc_ops, 0666, }, { "fpcr", &spufs_fpcr_fops, 0666, }, { "decr", &spufs_decr_ops, 0666, }, diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c index 5445719bff79..a13a8b5a014d 100644 --- a/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c @@ -232,6 +232,59 @@ static void spu_hw_runcntl_stop(struct spu_context *ctx) spin_unlock_irq(&ctx->spu->register_lock); } +static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode) +{ + struct spu_problem *prob = ctx->spu->problem; + int ret; + + spin_lock_irq(&ctx->spu->register_lock); + ret = -EAGAIN; + if (in_be32(&prob->dma_querytype_RW)) + goto out; + ret = 0; + out_be32(&prob->dma_querymask_RW, mask); + out_be32(&prob->dma_querytype_RW, mode); +out: + spin_unlock_irq(&ctx->spu->register_lock); + return ret; +} + +static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx) +{ + return in_be32(&ctx->spu->problem->dma_tagstatus_R); +} + +static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx) +{ + return in_be32(&ctx->spu->problem->dma_qstatus_R); +} + +static int spu_hw_send_mfc_command(struct spu_context *ctx, + struct mfc_dma_command *cmd) +{ + u32 status; + struct spu_problem *prob = ctx->spu->problem; + + spin_lock_irq(&ctx->spu->register_lock); + out_be32(&prob->mfc_lsa_W, cmd->lsa); + out_be64(&prob->mfc_ea_W, cmd->ea); + out_be32(&prob->mfc_union_W.by32.mfc_size_tag32, + cmd->size << 16 | cmd->tag); + out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32, + cmd->class << 16 | cmd->cmd); + status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32); + spin_unlock_irq(&ctx->spu->register_lock); + + switch (status & 0xffff) { + case 0: + return 0; + case 2: + return -EAGAIN; + default: + return -EINVAL; + } +} + struct spu_context_ops spu_hw_ops = { .mbox_read = spu_hw_mbox_read, .mbox_stat_read = spu_hw_mbox_stat_read, @@ -252,4 +305,8 @@ struct spu_context_ops spu_hw_ops = { .get_ls = spu_hw_get_ls, .runcntl_write = spu_hw_runcntl_write, .runcntl_stop = spu_hw_runcntl_stop, + .set_mfc_query = spu_hw_set_mfc_query, + .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus, + .get_mfc_free_elements = spu_hw_get_mfc_free_elements, + .send_mfc_command = spu_hw_send_mfc_command, }; diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 5be40aa483fd..d9554199afa7 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -241,7 +241,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode) inode->i_gid = dir->i_gid; inode->i_mode &= S_ISGID; } - ctx = alloc_spu_context(inode->i_mapping); + ctx = alloc_spu_context(); SPUFS_I(inode)->i_ctx = ctx; if (!ctx) goto out_iput; @@ -442,7 +442,7 @@ static struct file_system_type spufs_type = { .kill_sb = kill_litter_super, }; -static int spufs_init(void) +static int __init spufs_init(void) { int ret; ret = -ENOMEM; @@ -472,7 +472,7 @@ out: } module_init(spufs_init); -static void spufs_exit(void) +static void __exit spufs_exit(void) { spu_sched_exit(); unregister_spu_syscalls(&spufs_calls); diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 18ea8866c61a..483c8b76232c 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -2,6 +2,7 @@ #include #include +#include #include "spufs.h" @@ -76,6 +77,90 @@ static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, return 0; } +/* + * SPU syscall restarting is tricky because we violate the basic + * assumption that the signal handler is running on the interrupted + * thread. Here instead, the handler runs on PowerPC user space code, + * while the syscall was called from the SPU. + * This means we can only do a very rough approximation of POSIX + * signal semantics. + */ +int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, + unsigned int *npc) +{ + int ret; + + switch (*spu_ret) { + case -ERESTARTSYS: + case -ERESTARTNOINTR: + /* + * Enter the regular syscall restarting for + * sys_spu_run, then restart the SPU syscall + * callback. + */ + *npc -= 8; + ret = -ERESTARTSYS; + break; + case -ERESTARTNOHAND: + case -ERESTART_RESTARTBLOCK: + /* + * Restart block is too hard for now, just return -EINTR + * to the SPU. + * ERESTARTNOHAND comes from sys_pause, we also return + * -EINTR from there. + * Assume that we need to be restarted ourselves though. + */ + *spu_ret = -EINTR; + ret = -ERESTARTSYS; + break; + default: + printk(KERN_WARNING "%s: unexpected return code %ld\n", + __FUNCTION__, *spu_ret); + ret = 0; + } + return ret; +} + +int spu_process_callback(struct spu_context *ctx) +{ + struct spu_syscall_block s; + u32 ls_pointer, npc; + char *ls; + long spu_ret; + int ret; + + /* get syscall block from local store */ + npc = ctx->ops->npc_read(ctx); + ls = ctx->ops->get_ls(ctx); + ls_pointer = *(u32*)(ls + npc); + if (ls_pointer > (LS_SIZE - sizeof(s))) + return -EFAULT; + memcpy(&s, ls + ls_pointer, sizeof (s)); + + /* do actual syscall without pinning the spu */ + ret = 0; + spu_ret = -ENOSYS; + npc += 4; + + if (s.nr_ret < __NR_syscalls) { + spu_release(ctx); + /* do actual system call from here */ + spu_ret = spu_sys_callback(&s); + if (spu_ret <= -ERESTARTSYS) { + ret = spu_handle_restartsys(ctx, &spu_ret, &npc); + } + spu_acquire(ctx); + if (ret == -ERESTARTSYS) + return ret; + } + + /* write result, jump over indirect pointer */ + memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret)); + ctx->ops->npc_write(ctx, npc); + ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); + return ret; +} + static inline int spu_process_events(struct spu_context *ctx) { struct spu *spu = ctx->spu; @@ -107,6 +192,13 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); if (unlikely(ret)) break; + if ((*status & SPU_STATUS_STOPPED_BY_STOP) && + (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { + ret = spu_process_callback(ctx); + if (ret) + break; + *status &= ~SPU_STATUS_STOPPED_BY_STOP; + } if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { ret = spu_reacquire_runnable(ctx, npc, status); if (ret) diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 963182fbd1aa..bf652cd77000 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c @@ -180,6 +180,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) spu->ibox_callback = spufs_ibox_callback; spu->wbox_callback = spufs_wbox_callback; spu->stop_callback = spufs_stop_callback; + spu->mfc_callback = spufs_mfc_callback; mb(); spu_unmap_mappings(ctx); spu_restore(&ctx->csa, spu); @@ -197,6 +198,7 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx) spu->ibox_callback = NULL; spu->wbox_callback = NULL; spu->stop_callback = NULL; + spu->mfc_callback = NULL; spu->mm = NULL; spu->pid = 0; spu->prio = MAX_PRIO; diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index db2601f0abd5..4485738e2102 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h @@ -43,7 +43,11 @@ struct spu_context { struct spu *spu; /* pointer to a physical SPU */ struct spu_state csa; /* SPU context save area. */ spinlock_t mmio_lock; /* protects mmio access */ - struct address_space *local_store;/* local store backing store */ + struct address_space *local_store; /* local store mapping. */ + struct address_space *mfc; /* 'mfc' area mappings. */ + struct address_space *cntl; /* 'control' area mappings. */ + struct address_space *signal1; /* 'signal1' area mappings. */ + struct address_space *signal2; /* 'signal2' area mappings. */ enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; struct rw_semaphore state_sema; @@ -55,13 +59,27 @@ struct spu_context { wait_queue_head_t ibox_wq; wait_queue_head_t wbox_wq; wait_queue_head_t stop_wq; + wait_queue_head_t mfc_wq; struct fasync_struct *ibox_fasync; struct fasync_struct *wbox_fasync; + struct fasync_struct *mfc_fasync; + u32 tagwait; struct spu_context_ops *ops; struct work_struct reap_work; u64 flags; }; +struct mfc_dma_command { + int32_t pad; /* reserved */ + uint32_t lsa; /* local storage address */ + uint64_t ea; /* effective address */ + uint16_t size; /* transfer size */ + uint16_t tag; /* command tag */ + uint16_t class; /* class ID */ + uint16_t cmd; /* command opcode */ +}; + + /* SPU context query/set operations. */ struct spu_context_ops { int (*mbox_read) (struct spu_context * ctx, u32 * data); @@ -84,6 +102,11 @@ struct spu_context_ops { char*(*get_ls) (struct spu_context * ctx); void (*runcntl_write) (struct spu_context * ctx, u32 data); void (*runcntl_stop) (struct spu_context * ctx); + int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode); + u32 (*read_mfc_tagstatus)(struct spu_context * ctx); + u32 (*get_mfc_free_elements)(struct spu_context *ctx); + int (*send_mfc_command)(struct spu_context *ctx, + struct mfc_dma_command *cmd); }; extern struct spu_context_ops spu_hw_ops; @@ -106,7 +129,7 @@ long spufs_create_thread(struct nameidata *nd, extern struct file_operations spufs_context_fops; /* context management */ -struct spu_context * alloc_spu_context(struct address_space *local_store); +struct spu_context * alloc_spu_context(void); void destroy_spu_context(struct kref *kref); struct spu_context * get_spu_context(struct spu_context *ctx); int put_spu_context(struct spu_context *ctx); @@ -159,5 +182,6 @@ size_t spu_ibox_read(struct spu_context *ctx, u32 *data); void spufs_ibox_callback(struct spu *spu); void spufs_wbox_callback(struct spu *spu); void spufs_stop_callback(struct spu *spu); +void spufs_mfc_callback(struct spu *spu); #endif diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 212db28531fa..1726bfe38ee0 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c @@ -1297,7 +1297,7 @@ static inline void setup_decr(struct spu_state *csa, struct spu *spu) cycles_t resume_time = get_cycles(); cycles_t delta_time = resume_time - csa->suspend_time; - csa->lscsa->decr.slot[0] = delta_time; + csa->lscsa->decr.slot[0] -= delta_time; } } @@ -2145,7 +2145,8 @@ static void init_priv1(struct spu_state *csa) csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR | CLASS1_ENABLE_STORAGE_FAULT_INTR; csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR | - CLASS2_ENABLE_SPU_HALT_INTR; + CLASS2_ENABLE_SPU_HALT_INTR | + CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR; } static void init_priv2(struct spu_state *csa) diff --git a/arch/powerpc/platforms/chrp/chrp.h b/arch/powerpc/platforms/chrp/chrp.h index 814f54742e0f..996c28744e96 100644 --- a/arch/powerpc/platforms/chrp/chrp.h +++ b/arch/powerpc/platforms/chrp/chrp.h @@ -8,4 +8,5 @@ extern int chrp_set_rtc_time(struct rtc_time *); extern long chrp_time_init(void); extern void chrp_find_bridges(void); -extern void chrp_event_scan(void); +extern void chrp_event_scan(unsigned long); +extern void chrp_pcibios_fixup(void); diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index 8ef279ad36ad..ac224876ce59 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c @@ -23,6 +23,8 @@ #include #include +#include "chrp.h" + /* LongTrail */ void __iomem *gg2_pci_config_base; @@ -314,6 +316,6 @@ chrp_find_bridges(void) } /* Do not fixup interrupts from OF tree on pegasos */ - if (is_pegasos == 0) - ppc_md.pcibios_fixup = chrp_pcibios_fixup; + if (is_pegasos) + ppc_md.pcibios_fixup = NULL; } diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 8bf4307e323d..18d89f38796b 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,10 @@ EXPORT_SYMBOL(_chrp_type); struct mpic *chrp_mpic; +/* Used for doing CHRP event-scans */ +DEFINE_PER_CPU(struct timer_list, heartbeat_timer); +unsigned long event_scan_interval; + /* * XXX this should be in xmon.h, but putting it there means xmon.h * has to include (to get irqreturn_t), which @@ -229,8 +234,6 @@ void __init chrp_setup_arch(void) { struct device_node *root = find_path_device ("/"); char *machine = NULL; - struct device_node *device; - unsigned int *p = NULL; /* init to some ~sane value until calibrate_delay() runs */ loops_per_jiffy = 50000000/HZ; @@ -287,23 +290,12 @@ void __init chrp_setup_arch(void) */ sio_init(); - /* Get the event scan rate for the rtas so we know how - * often it expects a heartbeat. -- Cort - */ - device = find_devices("rtas"); - if (device) - p = (unsigned int *) get_property - (device, "rtas-event-scan-rate", NULL); - if (p && *p) { - ppc_md.heartbeat = chrp_event_scan; - ppc_md.heartbeat_reset = HZ / (*p * 30) - 1; - ppc_md.heartbeat_count = 1; - printk("RTAS Event Scan Rate: %u (%lu jiffies)\n", - *p, ppc_md.heartbeat_reset); - } - pci_create_OF_bus_map(); +#ifdef CONFIG_SMP + smp_ops = &chrp_smp_ops; +#endif /* CONFIG_SMP */ + /* * Print the banner, then scroll down so boot progress * can be printed. -- Cort @@ -312,7 +304,7 @@ void __init chrp_setup_arch(void) } void -chrp_event_scan(void) +chrp_event_scan(unsigned long unused) { unsigned char log[1024]; int ret = 0; @@ -320,7 +312,8 @@ chrp_event_scan(void) /* XXX: we should loop until the hardware says no more error logs -- Cort */ rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0, __pa(log), 1024); - ppc_md.heartbeat_count = ppc_md.heartbeat_reset; + mod_timer(&__get_cpu_var(heartbeat_timer), + jiffies + event_scan_interval); } /* @@ -447,8 +440,6 @@ void __init chrp_init_IRQ(void) if (_chrp_type == _CHRP_Pegasos) ppc_md.get_irq = i8259_irq; - else - ppc_md.get_irq = mpic_get_irq; #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) /* see if there is a keyboard in the device tree @@ -465,6 +456,9 @@ void __init chrp_init_IRQ(void) void __init chrp_init2(void) { + struct device_node *device; + unsigned int *p = NULL; + #ifdef CONFIG_NVRAM chrp_nvram_init(); #endif @@ -476,12 +470,53 @@ chrp_init2(void) request_region(0x80,0x10,"dma page reg"); request_region(0xc0,0x20,"dma2"); + /* Get the event scan rate for the rtas so we know how + * often it expects a heartbeat. -- Cort + */ + device = find_devices("rtas"); + if (device) + p = (unsigned int *) get_property + (device, "rtas-event-scan-rate", NULL); + if (p && *p) { + /* + * Arrange to call chrp_event_scan at least *p times + * per minute. We use 59 rather than 60 here so that + * the rate will be slightly higher than the minimum. + * This all assumes we don't do hotplug CPU on any + * machine that needs the event scans done. + */ + unsigned long interval, offset; + int cpu, ncpus; + struct timer_list *timer; + + interval = HZ * 59 / *p; + offset = HZ; + ncpus = num_online_cpus(); + event_scan_interval = ncpus * interval; + for (cpu = 0; cpu < ncpus; ++cpu) { + timer = &per_cpu(heartbeat_timer, cpu); + setup_timer(timer, chrp_event_scan, 0); + timer->expires = jiffies + offset; + add_timer_on(timer, cpu); + offset += interval; + } + printk("RTAS Event Scan Rate: %u (%lu jiffies)\n", + *p, interval); + } + if (ppc_md.progress) ppc_md.progress(" Have fun! ", 0x7777); } -void __init chrp_init(void) +static int __init chrp_probe(void) { + char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(), + "device_type", NULL); + if (dtype == NULL) + return 0; + if (strcmp(dtype, "chrp")) + return 0; + ISA_DMA_THRESHOLD = ~0L; DMA_MODE_READ = 0x44; DMA_MODE_WRITE = 0x48; @@ -491,26 +526,24 @@ void __init chrp_init(void) /* Assume we have an 8259... */ __irq_offset_value = NUM_ISA_INTERRUPTS; - ppc_md.setup_arch = chrp_setup_arch; - ppc_md.show_cpuinfo = chrp_show_cpuinfo; - - ppc_md.init_IRQ = chrp_init_IRQ; - ppc_md.init = chrp_init2; - - ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; - - ppc_md.restart = rtas_restart; - ppc_md.power_off = rtas_power_off; - ppc_md.halt = rtas_halt; - - ppc_md.time_init = chrp_time_init; - ppc_md.calibrate_decr = generic_calibrate_decr; - - /* this may get overridden with rtas routines later... */ - ppc_md.set_rtc_time = chrp_set_rtc_time; - ppc_md.get_rtc_time = chrp_get_rtc_time; - -#ifdef CONFIG_SMP - smp_ops = &chrp_smp_ops; -#endif /* CONFIG_SMP */ + return 1; } + +define_machine(chrp) { + .name = "CHRP", + .probe = chrp_probe, + .setup_arch = chrp_setup_arch, + .init = chrp_init2, + .show_cpuinfo = chrp_show_cpuinfo, + .init_IRQ = chrp_init_IRQ, + .get_irq = mpic_get_irq, + .pcibios_fixup = chrp_pcibios_fixup, + .restart = rtas_restart, + .power_off = rtas_power_off, + .halt = rtas_halt, + .time_init = chrp_time_init, + .set_rtc_time = chrp_set_rtc_time, + .get_rtc_time = chrp_get_rtc_time, + .calibrate_decr = generic_calibrate_decr, + .phys_mem_access_prot = pci_phys_mem_access_prot, +}; diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index fa4550611c11..a6fd9bedb074 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c @@ -54,6 +54,7 @@ #include #include #include +#include #include "naca.h" #include "setup.h" @@ -675,18 +676,26 @@ static void iseries_dedicated_idle(void) void __init iSeries_init_IRQ(void) { } #endif -static int __init iseries_probe(int platform) +static int __init iseries_probe(void) { - if (PLATFORM_ISERIES_LPAR != platform) + unsigned long root = of_get_flat_dt_root(); + if (!of_flat_dt_is_compatible(root, "IBM,iSeries")) return 0; - ppc64_firmware_features |= FW_FEATURE_ISERIES; - ppc64_firmware_features |= FW_FEATURE_LPAR; + powerpc_firmware_features |= FW_FEATURE_ISERIES; + powerpc_firmware_features |= FW_FEATURE_LPAR; + + /* + * The Hypervisor only allows us up to 256 interrupt + * sources (the irq number is passed in a u8). + */ + virt_irq_max = 255; return 1; } -struct machdep_calls __initdata iseries_md = { +define_machine(iseries) { + .name = "iSeries", .setup_arch = iSeries_setup_arch, .show_cpuinfo = iSeries_show_cpuinfo, .init_IRQ = iSeries_init_IRQ, @@ -930,7 +939,6 @@ void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size) /* /chosen */ dt_start_node(dt, "chosen"); - dt_prop_u32(dt, "linux,platform", PLATFORM_ISERIES_LPAR); dt_prop_str(dt, "bootargs", cmd_line); if (cmd_mem_limit) dt_prop_u64(dt, "linux,memory-limit", cmd_mem_limit); diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index ec5c1e10c407..24c0aef4ea39 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c @@ -259,9 +259,10 @@ static void __init maple_progress(char *s, unsigned short hex) /* * Called very early, MMU is off, device-tree isn't unflattened */ -static int __init maple_probe(int platform) +static int __init maple_probe(void) { - if (platform != PLATFORM_MAPLE) + unsigned long root = of_get_flat_dt_root(); + if (!of_flat_dt_is_compatible(root, "Momentum,Maple")) return 0; /* * On U3, the DART (iommu) must be allocated now since it @@ -274,7 +275,8 @@ static int __init maple_probe(int platform) return 1; } -struct machdep_calls __initdata maple_md = { +define_machine(maple_md) { + .name = "Maple", .probe = maple_probe, .setup_arch = maple_setup_arch, .init_early = maple_init_early, @@ -290,7 +292,7 @@ struct machdep_calls __initdata maple_md = { .get_rtc_time = maple_get_rtc_time, .calibrate_decr = generic_calibrate_decr, .progress = maple_progress, - .idle_loop = native_idle, + .power_save = power4_idle, #ifdef CONFIG_KEXEC .machine_kexec = default_machine_kexec, .machine_kexec_prepare = default_machine_kexec_prepare, diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c index fa8b4d7b5ded..eacbfd9beabc 100644 --- a/arch/powerpc/platforms/powermac/bootx_init.c +++ b/arch/powerpc/platforms/powermac/bootx_init.c @@ -161,9 +161,7 @@ static void __init bootx_dt_add_prop(char *name, void *data, int size, static void __init bootx_add_chosen_props(unsigned long base, unsigned long *mem_end) { - u32 val = _MACH_Pmac; - - bootx_dt_add_prop("linux,platform", &val, 4, mem_end); + u32 val; if (bootx_info->kernelParamsOffset) { char *args = (char *)((unsigned long)bootx_info) + @@ -493,7 +491,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4) && (strcmp(model, "iMac,1") == 0 || strcmp(model, "PowerMac1,1") == 0)) { bootx_printf("iMac,1 detected, shutting down USB \n"); - out_le32((unsigned *)0x80880008, 1); /* XXX */ + out_le32((unsigned __iomem *)0x80880008, 1); /* XXX */ } } diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c index e49eddd5042d..a5063cd675c5 100644 --- a/arch/powerpc/platforms/powermac/feature.c +++ b/arch/powerpc/platforms/powermac/feature.c @@ -2951,7 +2951,7 @@ static void *pmac_early_vresume_data; void pmac_set_early_video_resume(void (*proc)(void *data), void *data) { - if (_machine != _MACH_Pmac) + if (!machine_is(powermac)) return; preempt_disable(); pmac_early_vresume_proc = proc; diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index 87eb6bb7f0e7..e14f9ac55cf4 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c @@ -1457,6 +1457,9 @@ int __init pmac_i2c_init(void) return 0; i2c_inited = 1; + if (!machine_is(powermac)) + return 0; + /* Probe keywest-i2c busses */ kw_i2c_probe(); diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index 5fd28995c74c..262f967b880a 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/arch/powerpc/platforms/powermac/nvram.c @@ -74,7 +74,7 @@ struct core99_header { * Read and write the non-volatile RAM on PowerMacs and CHRP machines. */ static int nvram_naddrs; -static volatile unsigned char *nvram_data; +static volatile unsigned char __iomem *nvram_data; static int is_core_99; static int core99_bank = 0; static int nvram_partitions[3]; @@ -148,7 +148,7 @@ static ssize_t core99_nvram_size(void) } #ifdef CONFIG_PPC32 -static volatile unsigned char *nvram_addr; +static volatile unsigned char __iomem *nvram_addr; static int nvram_mult; static unsigned char direct_nvram_read_byte(int addr) @@ -285,7 +285,7 @@ static int sm_erase_bank(int bank) int stat, i; unsigned long timeout; - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; + u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank); @@ -317,7 +317,7 @@ static int sm_write_bank(int bank, u8* datas) int i, stat = 0; unsigned long timeout; - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; + u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; DBG("nvram: Sharp/Micron Writing bank %d...\n", bank); @@ -352,7 +352,7 @@ static int amd_erase_bank(int bank) int i, stat = 0; unsigned long timeout; - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; + u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; DBG("nvram: AMD Erasing bank %d...\n", bank); @@ -399,7 +399,7 @@ static int amd_write_bank(int bank, u8* datas) int i, stat = 0; unsigned long timeout; - u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; + u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; DBG("nvram: AMD Writing bank %d...\n", bank); @@ -597,7 +597,7 @@ int __init pmac_nvram_init(void) } #ifdef CONFIG_PPC32 - if (_machine == _MACH_chrp && nvram_naddrs == 1) { + if (machine_is(chrp) && nvram_naddrs == 1) { nvram_data = ioremap(r1.start, s1); nvram_mult = 1; ppc_md.nvram_read_val = direct_nvram_read_byte; diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index de3f30e6b333..f5d8d15d74fa 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c @@ -1201,7 +1201,7 @@ void __init pmac_pcibios_after_init(void) #ifdef CONFIG_PPC32 void pmac_pci_fixup_cardbus(struct pci_dev* dev) { - if (_machine != _MACH_Pmac) + if (!machine_is(powermac)) return; /* * Fix the interrupt routing on the various cardbus bridges @@ -1244,8 +1244,9 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev) * On PowerMacs, we try to switch any PCI ATA controller to * fully native mode */ - if (_machine != _MACH_Pmac) + if (!machine_is(powermac)) return; + /* Some controllers don't have the class IDE */ if (dev->vendor == PCI_VENDOR_ID_PROMISE) switch(dev->device) { diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c index 9b7150f10414..a3bd3e728fa3 100644 --- a/arch/powerpc/platforms/powermac/pfunc_base.c +++ b/arch/powerpc/platforms/powermac/pfunc_base.c @@ -336,6 +336,8 @@ int __init pmac_pfunc_base_install(void) return 0; pfbase_inited = 1; + if (!machine_is(powermac)) + return 0; DBG("Installing base platform functions...\n"); diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 385aab90c4d2..4d15e396655c 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c @@ -350,6 +350,13 @@ static void __init pmac_setup_arch(void) smp_ops = &psurge_smp_ops; #endif #endif /* CONFIG_SMP */ + +#ifdef CONFIG_ADB + if (strstr(cmd_line, "adb_sync")) { + extern int __adb_probe_sync; + __adb_probe_sync = 1; + } +#endif /* CONFIG_ADB */ } char *bootpath; @@ -576,30 +583,6 @@ pmac_halt(void) pmac_power_off(); } -#ifdef CONFIG_PPC32 -void __init pmac_init(void) -{ - /* isa_io_base gets set in pmac_pci_init */ - isa_mem_base = PMAC_ISA_MEM_BASE; - pci_dram_offset = PMAC_PCI_DRAM_OFFSET; - ISA_DMA_THRESHOLD = ~0L; - DMA_MODE_READ = 1; - DMA_MODE_WRITE = 2; - - ppc_md = pmac_md; - -#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) -#ifdef CONFIG_BLK_DEV_IDE_PMAC - ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; - ppc_ide_md.default_io_base = pmac_ide_get_base; -#endif /* CONFIG_BLK_DEV_IDE_PMAC */ -#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ - - if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0); - -} -#endif - /* * Early initialization. */ @@ -646,6 +629,12 @@ static int __init pmac_declare_of_platform_devices(void) { struct device_node *np; + if (machine_is(chrp)) + return -1; + + if (!machine_is(powermac)) + return 0; + np = of_find_node_by_name(NULL, "valkyrie"); if (np) of_platform_device_create(np, "valkyrie", NULL); @@ -666,12 +655,15 @@ device_initcall(pmac_declare_of_platform_devices); /* * Called very early, MMU is off, device-tree isn't unflattened */ -static int __init pmac_probe(int platform) +static int __init pmac_probe(void) { -#ifdef CONFIG_PPC64 - if (platform != PLATFORM_POWERMAC) + unsigned long root = of_get_flat_dt_root(); + + if (!of_flat_dt_is_compatible(root, "Power Macintosh") && + !of_flat_dt_is_compatible(root, "MacRISC")) return 0; +#ifdef CONFIG_PPC64 /* * On U3, the DART (iommu) must be allocated now since it * has an impact on htab_initialize (due to the large page it @@ -681,6 +673,23 @@ static int __init pmac_probe(int platform) alloc_dart_table(); #endif +#ifdef CONFIG_PPC32 + /* isa_io_base gets set in pmac_pci_init */ + isa_mem_base = PMAC_ISA_MEM_BASE; + pci_dram_offset = PMAC_PCI_DRAM_OFFSET; + ISA_DMA_THRESHOLD = ~0L; + DMA_MODE_READ = 1; + DMA_MODE_WRITE = 2; + +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) +#ifdef CONFIG_BLK_DEV_IDE_PMAC + ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports; + ppc_ide_md.default_io_base = pmac_ide_get_base; +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ +#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */ + +#endif /* CONFIG_PPC32 */ + #ifdef CONFIG_PMAC_SMU /* * SMU based G5s need some memory below 2Gb, at least the current @@ -709,10 +718,8 @@ static int pmac_pci_probe_mode(struct pci_bus *bus) } #endif -struct machdep_calls __initdata pmac_md = { -#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64) - .cpu_die = generic_mach_cpu_die, -#endif +define_machine(powermac) { + .name = "PowerMac", .probe = pmac_probe, .setup_arch = pmac_setup_arch, .init_early = pmac_init_early, @@ -733,7 +740,7 @@ struct machdep_calls __initdata pmac_md = { .progress = udbg_progress, #ifdef CONFIG_PPC64 .pci_probe_mode = pmac_pci_probe_mode, - .idle_loop = native_idle, + .power_save = power4_idle, .enable_pmcs = power4_enable_pmcs, #ifdef CONFIG_KEXEC .machine_kexec = default_machine_kexec, @@ -746,4 +753,7 @@ struct machdep_calls __initdata pmac_md = { .pcibios_after_init = pmac_pcibios_after_init, .phys_mem_access_prot = pci_phys_mem_access_prot, #endif +#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64) + .cpu_die = generic_mach_cpu_die, +#endif }; diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index 5d9afa1fa02d..890758aa9667 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c @@ -336,10 +336,10 @@ static struct pmu_sleep_notifier time_sleep_notifier = { */ void __init pmac_calibrate_decr(void) { -#ifdef CONFIG_PM +#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU) /* XXX why here? */ pmu_register_sleep_notifier(&time_sleep_notifier); -#endif /* CONFIG_PM */ +#endif generic_calibrate_decr(); diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c index c4352a8db644..b4fa9f03b461 100644 --- a/arch/powerpc/platforms/powermac/udbg_scc.c +++ b/arch/powerpc/platforms/powermac/udbg_scc.c @@ -116,7 +116,7 @@ void udbg_scc_init(int force_scc) /* Setup for 57600 8N1 */ if (ch == ch_a) addr += 0x20; - sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; + sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ; sccc += addr & ~PAGE_MASK; sccd = sccc + 0x10; diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 2ab9dcdfb415..32eaddfa5470 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -865,7 +865,7 @@ void __init eeh_init(void) * on the CEC architecture, type of the device, on earlier boot * command-line arguments & etc. */ -void eeh_add_device_early(struct device_node *dn) +static void eeh_add_device_early(struct device_node *dn) { struct pci_controller *phb; struct eeh_early_enable_info info; @@ -882,7 +882,6 @@ void eeh_add_device_early(struct device_node *dn) info.buid_lo = BUID_LO(phb->buid); early_enable_eeh(dn, &info); } -EXPORT_SYMBOL_GPL(eeh_add_device_early); void eeh_add_device_tree_early(struct device_node *dn) { @@ -893,20 +892,6 @@ void eeh_add_device_tree_early(struct device_node *dn) } EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); -void eeh_add_device_tree_late(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 (subbus) - eeh_add_device_tree_late(subbus); - } - } -} - /** * eeh_add_device_late - perform EEH initialization for the indicated pci device * @dev: pci device for which to set up EEH @@ -914,7 +899,7 @@ void eeh_add_device_tree_late(struct pci_bus *bus) * This routine must be used to complete EEH initialization for PCI * devices that were added after system boot (e.g. hotplug, dlpar). */ -void eeh_add_device_late(struct pci_dev *dev) +static void eeh_add_device_late(struct pci_dev *dev) { struct device_node *dn; struct pci_dn *pdn; @@ -933,16 +918,33 @@ void eeh_add_device_late(struct pci_dev *dev) pci_addr_cache_insert_device (dev); } -EXPORT_SYMBOL_GPL(eeh_add_device_late); + +void eeh_add_device_tree_late(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 (subbus) + eeh_add_device_tree_late(subbus); + } + } +} +EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); /** * 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 *dev) +static void eeh_remove_device(struct pci_dev *dev) { struct device_node *dn; if (!dev || !eeh_subsystem_enabled) @@ -955,24 +957,22 @@ void eeh_remove_device(struct pci_dev *dev) pci_addr_cache_remove_device(dev); dn = pci_device_to_OF_node(dev); - PCI_DN(dn)->pcidev = NULL; - pci_dev_put (dev); + if (PCI_DN(dn)->pcidev) { + PCI_DN(dn)->pcidev = NULL; + pci_dev_put (dev); + } } -EXPORT_SYMBOL_GPL(eeh_remove_device); void eeh_remove_bus_device(struct pci_dev *dev) { + struct pci_bus *bus = dev->subordinate; + struct pci_dev *child, *tmp; + eeh_remove_device(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - struct pci_bus *bus = dev->subordinate; - struct list_head *ln; - if (!bus) - return; - for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { - struct pci_dev *pdev = pci_dev_b(ln); - if (pdev) - eeh_remove_bus_device(pdev); - } + + if (bus && dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) + eeh_remove_bus_device(child); } } EXPORT_SYMBOL_GPL(eeh_remove_bus_device); @@ -1018,7 +1018,7 @@ static int __init eeh_init_proc(void) { struct proc_dir_entry *e; - if (platform_is_pseries()) { + if (machine_is(pseries)) { e = create_proc_entry("ppc64/eeh", 0, NULL); if (e) e->proc_fops = &proc_eeh_operations; diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index b811d5ff92fe..1fba695e32e8 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -257,6 +257,7 @@ void handle_eeh_events (struct eeh_event *event) struct pci_bus *frozen_bus; int rc = 0; enum pci_ers_result result = PCI_ERS_RESULT_NONE; + const char *pci_str, *drv_str; frozen_dn = find_device_pe(event->dn); frozen_bus = pcibios_find_pci_bus(frozen_dn); @@ -291,9 +292,17 @@ void handle_eeh_events (struct eeh_event *event) frozen_pdn = PCI_DN(frozen_dn); frozen_pdn->eeh_freeze_count++; + + if (frozen_pdn->pcidev) { + pci_str = pci_name (frozen_pdn->pcidev); + drv_str = pcid_name (frozen_pdn->pcidev); + } else { + pci_str = pci_name (event->dev); + drv_str = pcid_name (event->dev); + } if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) - goto hard_fail; + goto excess_failures; /* 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. @@ -306,9 +315,7 @@ void handle_eeh_events (struct eeh_event *event) eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */); printk(KERN_WARNING "EEH: This PCI device has failed %d times since last reboot: %s - %s\n", - frozen_pdn->eeh_freeze_count, - pci_name (frozen_pdn->pcidev), - pcid_name(frozen_pdn->pcidev)); + frozen_pdn->eeh_freeze_count, drv_str, pci_str); /* Walk the various device drivers attached to this slot through * a reset sequence, giving each an opportunity to do what it needs @@ -350,7 +357,7 @@ void handle_eeh_events (struct eeh_event *event) return; -hard_fail: +excess_failures: /* * About 90% of all real-life EEH failures in the field * are due to poorly seated PCI cards. Only 10% or so are @@ -360,10 +367,16 @@ hard_fail: "EEH: PCI 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 (frozen_pdn->pcidev), - pcid_name(frozen_pdn->pcidev), - frozen_pdn->eeh_freeze_count); + drv_str, pci_str, frozen_pdn->eeh_freeze_count); + goto perm_error; +hard_fail: + printk(KERN_ERR + "EEH: Unable to recover from failure of PCI device %s - %s\n" + "Please try reseating this device or replacing it.\n", + drv_str, pci_str); + +perm_error: eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */); /* Notify all devices that they're about to go down. */ diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index 9a9961f27480..a1bda6f96fd1 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -19,7 +19,9 @@ */ #include +#include #include +#include #include #include @@ -37,14 +39,18 @@ LIST_HEAD(eeh_eventlist); static void eeh_thread_launcher(void *); DECLARE_WORK(eeh_event_wq, eeh_thread_launcher, NULL); +/* Serialize reset sequences for a given pci device */ +DEFINE_MUTEX(eeh_event_mutex); + /** - * 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. - * + * eeh_event_handler - dispatch EEH events. * @dummy - unused + * + * 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. */ static int eeh_event_handler(void * dummy) { @@ -64,23 +70,24 @@ static int eeh_event_handler(void * dummy) event = list_entry(eeh_eventlist.next, struct eeh_event, list); list_del(&event->list); } - - if (event) - eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); - spin_unlock_irqrestore(&eeh_eventlist_lock, flags); + if (event == NULL) break; + /* Serialize processing of EEH events */ + mutex_lock(&eeh_event_mutex); + eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); + printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", pci_name(event->dev)); handle_eeh_events(event); eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); - pci_dev_put(event->dev); kfree(event); + mutex_unlock(&eeh_event_mutex); } return 0; @@ -88,7 +95,6 @@ static int eeh_event_handler(void * dummy) /** * eeh_thread_launcher - * * @dummy - unused */ static void eeh_thread_launcher(void *dummy) diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index 989f4bc136cb..c01d8f0cbe6d 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c @@ -91,7 +91,7 @@ void __init fw_feature_init(void) continue; /* we have a match */ - ppc64_firmware_features |= + powerpc_firmware_features |= firmware_features_table[i].val; break; } diff --git a/arch/powerpc/platforms/pseries/hvCall.S b/arch/powerpc/platforms/pseries/hvCall.S index db7c19fe9297..c9ff547f9d25 100644 --- a/arch/powerpc/platforms/pseries/hvCall.S +++ b/arch/powerpc/platforms/pseries/hvCall.S @@ -127,3 +127,103 @@ _GLOBAL(plpar_hcall_4out) mtcrf 0xff,r0 blr /* return r3 = status */ + +/* plpar_hcall_7arg_7ret(unsigned long opcode, R3 + unsigned long arg1, R4 + unsigned long arg2, R5 + unsigned long arg3, R6 + unsigned long arg4, R7 + unsigned long arg5, R8 + unsigned long arg6, R9 + unsigned long arg7, R10 + unsigned long *out1, 112(R1) + unsigned long *out2, 110(R1) + unsigned long *out3, 108(R1) + unsigned long *out4, 106(R1) + unsigned long *out5, 104(R1) + unsigned long *out6, 102(R1) + unsigned long *out7); 100(R1) +*/ +_GLOBAL(plpar_hcall_7arg_7ret) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + HVSC /* invoke the hypervisor */ + + lwz r0,8(r1) + + ld r11,STK_PARM(r11)(r1) /* Fetch r4 ret arg */ + std r4,0(r11) + ld r11,STK_PARM(r12)(r1) /* Fetch r5 ret arg */ + std r5,0(r11) + ld r11,STK_PARM(r13)(r1) /* Fetch r6 ret arg */ + std r6,0(r11) + ld r11,STK_PARM(r14)(r1) /* Fetch r7 ret arg */ + std r7,0(r11) + ld r11,STK_PARM(r15)(r1) /* Fetch r8 ret arg */ + std r8,0(r11) + ld r11,STK_PARM(r16)(r1) /* Fetch r9 ret arg */ + std r9,0(r11) + ld r11,STK_PARM(r17)(r1) /* Fetch r10 ret arg */ + std r10,0(r11) + + mtcrf 0xff,r0 + + blr /* return r3 = status */ + +/* plpar_hcall_9arg_9ret(unsigned long opcode, R3 + unsigned long arg1, R4 + unsigned long arg2, R5 + unsigned long arg3, R6 + unsigned long arg4, R7 + unsigned long arg5, R8 + unsigned long arg6, R9 + unsigned long arg7, R10 + unsigned long arg8, 112(R1) + unsigned long arg9, 110(R1) + unsigned long *out1, 108(R1) + unsigned long *out2, 106(R1) + unsigned long *out3, 104(R1) + unsigned long *out4, 102(R1) + unsigned long *out5, 100(R1) + unsigned long *out6, 98(R1) + unsigned long *out7); 96(R1) + unsigned long *out8, 94(R1) + unsigned long *out9, 92(R1) +*/ +_GLOBAL(plpar_hcall_9arg_9ret) + HMT_MEDIUM + + mfcr r0 + stw r0,8(r1) + + ld r11,STK_PARM(r11)(r1) /* put arg8 in R11 */ + ld r12,STK_PARM(r12)(r1) /* put arg9 in R12 */ + + HVSC /* invoke the hypervisor */ + + ld r0,STK_PARM(r13)(r1) /* Fetch r4 ret arg */ + stdx r4,r0,r0 + ld r0,STK_PARM(r14)(r1) /* Fetch r5 ret arg */ + stdx r5,r0,r0 + ld r0,STK_PARM(r15)(r1) /* Fetch r6 ret arg */ + stdx r6,r0,r0 + ld r0,STK_PARM(r16)(r1) /* Fetch r7 ret arg */ + stdx r7,r0,r0 + ld r0,STK_PARM(r17)(r1) /* Fetch r8 ret arg */ + stdx r8,r0,r0 + ld r0,STK_PARM(r18)(r1) /* Fetch r9 ret arg */ + stdx r9,r0,r0 + ld r0,STK_PARM(r19)(r1) /* Fetch r10 ret arg */ + stdx r10,r0,r0 + ld r0,STK_PARM(r20)(r1) /* Fetch r11 ret arg */ + stdx r11,r0,r0 + ld r0,STK_PARM(r21)(r1) /* Fetch r12 ret arg */ + stdx r12,r0,r0 + + lwz r0,8(r1) + mtcrf 0xff,r0 + + blr /* return r3 = status */ diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c index 138e128a3886..a72a987f1d4d 100644 --- a/arch/powerpc/platforms/pseries/hvconsole.c +++ b/arch/powerpc/platforms/pseries/hvconsole.c @@ -41,7 +41,7 @@ int hvc_get_chars(uint32_t vtermno, char *buf, int count) unsigned long got; if (plpar_hcall(H_GET_TERM_CHAR, vtermno, 0, 0, 0, &got, - (unsigned long *)buf, (unsigned long *)buf+1) == H_Success) + (unsigned long *)buf, (unsigned long *)buf+1) == H_SUCCESS) return got; return 0; } @@ -62,11 +62,16 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count) unsigned long *lbuf = (unsigned long *) buf; long ret; + + /* hcall will ret H_PARAMETER if 'count' exceeds firmware max.*/ + if (count > MAX_VIO_PUT_CHARS) + count = MAX_VIO_PUT_CHARS; + ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0], lbuf[1]); - if (ret == H_Success) + if (ret == H_SUCCESS) return count; - if (ret == H_Busy) + if (ret == H_BUSY) return 0; return -EIO; } diff --git a/arch/powerpc/platforms/pseries/hvcserver.c b/arch/powerpc/platforms/pseries/hvcserver.c index 22bfb5c89db9..fcf4b4cbeaf3 100644 --- a/arch/powerpc/platforms/pseries/hvcserver.c +++ b/arch/powerpc/platforms/pseries/hvcserver.c @@ -43,21 +43,21 @@ MODULE_VERSION(HVCS_ARCH_VERSION); static int hvcs_convert(long to_convert) { switch (to_convert) { - case H_Success: + case H_SUCCESS: return 0; - case H_Parameter: + case H_PARAMETER: return -EINVAL; - case H_Hardware: + case H_HARDWARE: return -EIO; - case H_Busy: - case H_LongBusyOrder1msec: - case H_LongBusyOrder10msec: - case H_LongBusyOrder100msec: - case H_LongBusyOrder1sec: - case H_LongBusyOrder10sec: - case H_LongBusyOrder100sec: + case H_BUSY: + case H_LONG_BUSY_ORDER_1_MSEC: + case H_LONG_BUSY_ORDER_10_MSEC: + case H_LONG_BUSY_ORDER_100_MSEC: + case H_LONG_BUSY_ORDER_1_SEC: + case H_LONG_BUSY_ORDER_10_SEC: + case H_LONG_BUSY_ORDER_100_SEC: return -EBUSY; - case H_Function: /* fall through */ + case H_FUNCTION: /* fall through */ default: return -EPERM; } diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 8952528d31ac..634b7d06d3cc 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -54,7 +54,8 @@ EXPORT_SYMBOL(plpar_hcall); EXPORT_SYMBOL(plpar_hcall_4out); EXPORT_SYMBOL(plpar_hcall_norets); EXPORT_SYMBOL(plpar_hcall_8arg_2ret); - +EXPORT_SYMBOL(plpar_hcall_7arg_7ret); +EXPORT_SYMBOL(plpar_hcall_9arg_9ret); extern void pSeries_find_serial_port(void); @@ -72,7 +73,7 @@ static void udbg_hvsi_putc(char c) do { rc = plpar_put_term_char(vtermno, sizeof(packet), packet); - } while (rc == H_Busy); + } while (rc == H_BUSY); } static long hvsi_udbg_buf_len; @@ -85,7 +86,7 @@ static int udbg_hvsi_getc_poll(void) if (hvsi_udbg_buf_len == 0) { rc = plpar_get_term_char(vtermno, &hvsi_udbg_buf_len, hvsi_udbg_buf); - if (rc != H_Success || hvsi_udbg_buf[0] != 0xff) { + if (rc != H_SUCCESS || hvsi_udbg_buf[0] != 0xff) { /* bad read or non-data packet */ hvsi_udbg_buf_len = 0; } else { @@ -139,7 +140,7 @@ static void udbg_putcLP(char c) buf[0] = c; do { rc = plpar_put_term_char(vtermno, 1, buf); - } while(rc == H_Busy); + } while(rc == H_BUSY); } /* Buffered chars getc */ @@ -158,7 +159,7 @@ static int udbg_getc_pollLP(void) /* get some more chars. */ inbuflen = 0; rc = plpar_get_term_char(vtermno, &inbuflen, buf); - if (rc != H_Success) + if (rc != H_SUCCESS) inbuflen = 0; /* otherwise inbuflen is garbage */ } if (inbuflen <= 0 || inbuflen > 16) { @@ -304,7 +305,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, hpte_v, hpte_r, &slot, &dummy0, &dummy1); - if (unlikely(lpar_rc == H_PTEG_Full)) { + if (unlikely(lpar_rc == H_PTEG_FULL)) { if (!(vflags & HPTE_V_BOLTED)) DBG_LOW(" full\n"); return -1; @@ -315,7 +316,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, * will fail. However we must catch the failure in hash_page * or we will loop forever, so return -2 in this case. */ - if (unlikely(lpar_rc != H_Success)) { + if (unlikely(lpar_rc != H_SUCCESS)) { if (!(vflags & HPTE_V_BOLTED)) DBG_LOW(" lpar err %d\n", lpar_rc); return -2; @@ -346,9 +347,9 @@ static long pSeries_lpar_hpte_remove(unsigned long hpte_group) /* don't remove a bolted entry */ lpar_rc = plpar_pte_remove(H_ANDCOND, hpte_group + slot_offset, (0x1UL << 4), &dummy1, &dummy2); - if (lpar_rc == H_Success) + if (lpar_rc == H_SUCCESS) return i; - BUG_ON(lpar_rc != H_Not_Found); + BUG_ON(lpar_rc != H_NOT_FOUND); slot_offset++; slot_offset &= 0x7; @@ -391,14 +392,14 @@ static long pSeries_lpar_hpte_updatepp(unsigned long slot, lpar_rc = plpar_pte_protect(flags, slot, want_v & HPTE_V_AVPN); - if (lpar_rc == H_Not_Found) { + if (lpar_rc == H_NOT_FOUND) { DBG_LOW("not found !\n"); return -1; } DBG_LOW("ok\n"); - BUG_ON(lpar_rc != H_Success); + BUG_ON(lpar_rc != H_SUCCESS); return 0; } @@ -417,7 +418,7 @@ static unsigned long pSeries_lpar_hpte_getword0(unsigned long slot) lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1); - BUG_ON(lpar_rc != H_Success); + BUG_ON(lpar_rc != H_SUCCESS); return dword0; } @@ -468,7 +469,7 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp, flags = newpp & 7; lpar_rc = plpar_pte_protect(flags, slot, 0); - BUG_ON(lpar_rc != H_Success); + BUG_ON(lpar_rc != H_SUCCESS); } static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, @@ -484,10 +485,10 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, want_v = hpte_encode_v(va, psize); lpar_rc = plpar_pte_remove(H_AVPN, slot, want_v & HPTE_V_AVPN, &dummy1, &dummy2); - if (lpar_rc == H_Not_Found) + if (lpar_rc == H_NOT_FOUND) return; - BUG_ON(lpar_rc != H_Success); + BUG_ON(lpar_rc != H_SUCCESS); } /* diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 946ad59e3352..e97e67f5e079 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c @@ -120,7 +120,7 @@ static void fixup_winbond_82c105(struct pci_dev* dev) int i; unsigned int reg; - if (!platform_is_pseries()) + if (!machine_is(pseries)) return; printk("Using INTC for W82c105 IDE controller.\n"); diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 44abdeb9ca03..6bfacc217085 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -28,6 +28,7 @@ #include #include #include +#include static struct pci_bus * find_bus_among_children(struct pci_bus *bus, @@ -152,20 +153,24 @@ pcibios_pci_config_bridge(struct pci_dev *dev) void pcibios_add_pci_devices(struct pci_bus * bus) { - int slotno, num; + int slotno, num, mode; struct pci_dev *dev; struct device_node *dn = pci_bus_to_OF_node(bus); eeh_add_device_tree_early(dn); - if (_machine == PLATFORM_PSERIES_LPAR) { + mode = PCI_PROBE_NORMAL; + if (ppc_md.pci_probe_mode) + mode = ppc_md.pci_probe_mode(bus); + + if (mode == PCI_PROBE_DEVTREE) { /* use ofdt-based probe */ of_scan_bus(dn, bus); if (!list_empty(&bus->devices)) { pcibios_fixup_new_pci_devices(bus, 0); pci_bus_add_devices(bus); } - } else { + } else if (mode == PCI_PROBE_NORMAL) { /* use legacy probe */ slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index b046bcf7443d..9639c66b453d 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -132,7 +132,7 @@ static int __init init_ras_IRQ(void) of_node_put(np); } - return 1; + return 0; } __initcall(init_ras_IRQ); diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 5ad90676567a..1773103354be 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -17,8 +17,9 @@ #include #include -#include +#include #include +#include @@ -508,7 +509,7 @@ static int proc_ppc64_create_ofdt(void) { struct proc_dir_entry *ent; - if (!platform_is_pseries()) + if (!machine_is(pseries)) return 0; ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index a6f628d4c9dc..e0000ce769e5 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c @@ -27,6 +27,7 @@ #include #include #include +#include #if 0 #define DEBUG(A...) printk(KERN_ERR A) @@ -481,13 +482,13 @@ static int __init rtas_init(void) { struct proc_dir_entry *entry; - if (!platform_is_pseries()) + if (!machine_is(pseries)) return 0; /* No RTAS */ if (rtas_token("event-scan") == RTAS_UNKNOWN_SERVICE) { printk(KERN_INFO "rtasd: no event-scan on system\n"); - return 1; + return -ENODEV; } entry = create_proc_entry("ppc64/rtas/error_log", S_IRUSR, NULL); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 44d5c7fdcd97..5eb55ef1c91c 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -81,8 +81,8 @@ extern void find_udbg_vterm(void); int fwnmi_active; /* TRUE if an FWNMI handler is present */ -static void pseries_shared_idle(void); -static void pseries_dedicated_idle(void); +static void pseries_shared_idle_sleep(void); +static void pseries_dedicated_idle_sleep(void); struct mpic *pSeries_mpic; @@ -236,14 +236,13 @@ static void __init pSeries_setup_arch(void) vpa_init(boot_cpuid); if (get_lppaca()->shared_proc) { printk(KERN_INFO "Using shared processor idle loop\n"); - ppc_md.idle_loop = pseries_shared_idle; + ppc_md.power_save = pseries_shared_idle_sleep; } else { printk(KERN_INFO "Using dedicated idle loop\n"); - ppc_md.idle_loop = pseries_dedicated_idle; + ppc_md.power_save = pseries_dedicated_idle_sleep; } } else { printk(KERN_INFO "Using default idle loop\n"); - ppc_md.idle_loop = default_idle; } if (firmware_has_feature(FW_FEATURE_LPAR)) @@ -373,156 +372,123 @@ static int pSeries_check_legacy_ioport(unsigned int baseport) /* * Called very early, MMU is off, device-tree isn't unflattened */ -extern struct machdep_calls pSeries_md; -static int __init pSeries_probe(int platform) +static int __init pSeries_probe_hypertas(unsigned long node, + const char *uname, int depth, + void *data) { - if (platform != PLATFORM_PSERIES && - platform != PLATFORM_PSERIES_LPAR) + if (depth != 1 || + (strcmp(uname, "rtas") != 0 && strcmp(uname, "rtas@0") != 0)) + return 0; + + if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL) + powerpc_firmware_features |= FW_FEATURE_LPAR; + + return 1; +} + +static int __init pSeries_probe(void) +{ + char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(), + "device_type", NULL); + if (dtype == NULL) + return 0; + if (strcmp(dtype, "chrp")) return 0; - /* if we have some ppc_md fixups for LPAR to do, do - * it here ... - */ + DBG("pSeries detected, looking for LPAR capability...\n"); - if (platform == PLATFORM_PSERIES_LPAR) - ppc64_firmware_features |= FW_FEATURE_LPAR; + /* Now try to figure out if we are running on LPAR */ + of_scan_flat_dt(pSeries_probe_hypertas, NULL); + + DBG("Machine is%s LPAR !\n", + (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not"); return 1; } + DECLARE_PER_CPU(unsigned long, smt_snooze_delay); -static inline void dedicated_idle_sleep(unsigned int cpu) -{ - struct lppaca *plppaca = &lppaca[cpu ^ 1]; - - /* Only sleep if the other thread is not idle */ - if (!(plppaca->idle)) { - local_irq_disable(); - - /* - * We are about to sleep the thread and so wont be polling any - * more. - */ - clear_thread_flag(TIF_POLLING_NRFLAG); - smp_mb__after_clear_bit(); - - /* - * SMT dynamic mode. Cede will result in this thread going - * dormant, if the partner thread is still doing work. Thread - * wakes up if partner goes idle, an interrupt is presented, or - * a prod occurs. Returning from the cede enables external - * interrupts. - */ - if (!need_resched()) - cede_processor(); - else - local_irq_enable(); - set_thread_flag(TIF_POLLING_NRFLAG); - } else { - /* - * Give the HV an opportunity at the processor, since we are - * not doing any work. - */ - poll_pending(); - } -} - -static void pseries_dedicated_idle(void) +static void pseries_dedicated_idle_sleep(void) { unsigned int cpu = smp_processor_id(); unsigned long start_snooze; unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay); - set_thread_flag(TIF_POLLING_NRFLAG); - while (1) { - /* - * Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. - */ - get_lppaca()->idle = 1; + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ + get_lppaca()->idle = 1; - if (!need_resched()) { - start_snooze = get_tb() + - *smt_snooze_delay * tb_ticks_per_usec; + /* + * We come in with interrupts disabled, and need_resched() + * has been checked recently. If we should poll for a little + * while, do so. + */ + if (*smt_snooze_delay) { + start_snooze = get_tb() + + *smt_snooze_delay * tb_ticks_per_usec; + local_irq_enable(); + set_thread_flag(TIF_POLLING_NRFLAG); - while (!need_resched() && !cpu_is_offline(cpu)) { - ppc64_runlatch_off(); - - /* - * Go into low thread priority and possibly - * low power mode. - */ - HMT_low(); - HMT_very_low(); - - if (*smt_snooze_delay != 0 && - get_tb() > start_snooze) { - HMT_medium(); - dedicated_idle_sleep(cpu); - } - - } - - HMT_medium(); + while (get_tb() < start_snooze) { + if (need_resched() || cpu_is_offline(cpu)) + goto out; + ppc64_runlatch_off(); + HMT_low(); + HMT_very_low(); } - get_lppaca()->idle = 0; - ppc64_runlatch_on(); - - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - - if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) - cpu_die(); + HMT_medium(); + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb(); + local_irq_disable(); + if (need_resched() || cpu_is_offline(cpu)) + goto out; } + + /* + * Cede if the other thread is not idle, so that it can + * go single-threaded. If the other thread is idle, + * we ask the hypervisor if it has pending work it + * wants to do and cede if it does. Otherwise we keep + * polling in order to reduce interrupt latency. + * + * Doing the cede when the other thread is active will + * result in this thread going dormant, meaning the other + * thread gets to run in single-threaded (ST) mode, which + * is slightly faster than SMT mode with this thread at + * very low priority. The cede enables interrupts, which + * doesn't matter here. + */ + if (!lppaca[cpu ^ 1].idle || poll_pending() == H_PENDING) + cede_processor(); + +out: + HMT_medium(); + get_lppaca()->idle = 0; } -static void pseries_shared_idle(void) +static void pseries_shared_idle_sleep(void) { - unsigned int cpu = smp_processor_id(); + /* + * Indicate to the HV that we are idle. Now would be + * a good time to find other work to dispatch. + */ + get_lppaca()->idle = 1; - while (1) { - /* - * Indicate to the HV that we are idle. Now would be - * a good time to find other work to dispatch. - */ - get_lppaca()->idle = 1; + /* + * Yield the processor to the hypervisor. We return if + * an external interrupt occurs (which are driven prior + * to returning here) or if a prod occurs from another + * processor. When returning here, external interrupts + * are enabled. + */ + cede_processor(); - while (!need_resched() && !cpu_is_offline(cpu)) { - local_irq_disable(); - ppc64_runlatch_off(); - - /* - * Yield the processor to the hypervisor. We return if - * an external interrupt occurs (which are driven prior - * to returning here) or if a prod occurs from another - * processor. When returning here, external interrupts - * are enabled. - * - * Check need_resched() again with interrupts disabled - * to avoid a race. - */ - if (!need_resched()) - cede_processor(); - else - local_irq_enable(); - - HMT_medium(); - } - - get_lppaca()->idle = 0; - ppc64_runlatch_on(); - - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - - if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) - cpu_die(); - } + get_lppaca()->idle = 0; } static int pSeries_pci_probe_mode(struct pci_bus *bus) @@ -553,7 +519,8 @@ static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) } #endif -struct machdep_calls __initdata pSeries_md = { +define_machine(pseries) { + .name = "pSeries", .probe = pSeries_probe, .setup_arch = pSeries_setup_arch, .init_early = pSeries_init_early, diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c index 866379b80c09..8e53e04ada8b 100644 --- a/arch/powerpc/platforms/pseries/vio.c +++ b/arch/powerpc/platforms/pseries/vio.c @@ -258,7 +258,7 @@ EXPORT_SYMBOL(vio_find_node); int vio_enable_interrupts(struct vio_dev *dev) { int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE); - if (rc != H_Success) + if (rc != H_SUCCESS) printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc); return rc; } @@ -267,7 +267,7 @@ EXPORT_SYMBOL(vio_enable_interrupts); int vio_disable_interrupts(struct vio_dev *dev) { int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE); - if (rc != H_Success) + if (rc != H_SUCCESS) printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc); return rc; } diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index eb86cdb9b802..2d60ea30fed6 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c @@ -168,7 +168,7 @@ static int pSeriesLP_xirr_info_get(int n_cpu) unsigned long return_value; lpar_rc = plpar_xirr(&return_value); - if (lpar_rc != H_Success) + if (lpar_rc != H_SUCCESS) panic(" bad return code xirr - rc = %lx \n", lpar_rc); return (int)return_value; } @@ -179,7 +179,7 @@ static void pSeriesLP_xirr_info_set(int n_cpu, int value) unsigned long val64 = value & 0xffffffff; lpar_rc = plpar_eoi(val64); - if (lpar_rc != H_Success) + if (lpar_rc != H_SUCCESS) panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc, val64); } @@ -189,7 +189,7 @@ void pSeriesLP_cppr_info(int n_cpu, u8 value) unsigned long lpar_rc; lpar_rc = plpar_cppr(value); - if (lpar_rc != H_Success) + if (lpar_rc != H_SUCCESS) panic("bad return code cppr - rc = %lx\n", lpar_rc); } @@ -198,7 +198,7 @@ static void pSeriesLP_qirr_info(int n_cpu , u8 value) unsigned long lpar_rc; lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value); - if (lpar_rc != H_Success) + if (lpar_rc != H_SUCCESS) panic("bad return code qirr - rc = %lx\n", lpar_rc); } @@ -500,7 +500,7 @@ nextnode: np; np = of_find_node_by_type(np, "cpu")) { ireg = (uint *)get_property(np, "reg", &ilen); - if (ireg && ireg[0] == boot_cpuid_phys) { + if (ireg && ireg[0] == get_hard_smp_processor_id(boot_cpuid)) { ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen); i = ilen / sizeof(int); @@ -541,7 +541,7 @@ nextnode: ops = &pSeriesLP_ops; else { #ifdef CONFIG_SMP - for_each_cpu(i) { + for_each_possible_cpu(i) { int hard_id; /* FIXME: Do this dynamically! --RR */ diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 3a3e302b4ea2..e9a8f5d1dfcd 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -61,15 +61,15 @@ config 6xx select PPC_FPU help There are four types of PowerPC chips supported. The more common - types (601, 603, 604, 740, 750, 7400), the Motorola embedded - versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the IBM - embedded versions (403 and 405) and the POWER3 processor. - (For support for more recent 64-bit processors, set ARCH=powerpc.) + types (601, 603, 604, 740, 750, 7400), the older Freescale + (formerly Motorola) embedded versions (821, 823, 850, 855, 860, + 52xx, 82xx, 83xx), the IBM embedded versions (403 and 405) and + the Book E embedded processors from IBM (44x) and Freescale (85xx). + For support for 64-bit processors, set ARCH=powerpc. Unless you are building a kernel for one of the embedded processor - systems or a POWER3-based IBM RS/6000, choose 6xx. - Note that the kernel runs in 32-bit mode even on 64-bit chips. - Also note that because the 52xx, 82xx, & 83xx family has a 603e core, - specific support for that chipset is asked later on. + systems, choose 6xx. + Also note that because the 52xx, 82xx, & 83xx family have a 603e + core, specific support for that chipset is asked later on. config 40x bool "40x" @@ -77,10 +77,6 @@ config 40x config 44x bool "44x" -config POWER3 - select PPC_FPU - bool "POWER3" - config 8xx bool "8xx" @@ -252,14 +248,9 @@ config PPC601_SYNC_FIX source arch/ppc/platforms/4xx/Kconfig source arch/ppc/platforms/85xx/Kconfig -config PPC64BRIDGE - bool - depends on POWER3 - default y - config PPC_STD_MMU bool - depends on 6xx || POWER3 + depends on 6xx default y config NOT_COHERENT_CACHE @@ -534,8 +525,8 @@ endmenu choice prompt "Machine Type" - depends on 6xx || POWER3 - default PPC_MULTIPLATFORM + depends on 6xx + default PPC_PREP ---help--- Linux currently supports several different kinds of PowerPC-based machines: Apple Power Macintoshes and clones (such as the Motorola @@ -545,15 +536,14 @@ choice Platform) machines (including all of the recent IBM RS/6000 and pSeries machines), and several embedded PowerPC systems containing 4xx, 6xx, 7xx, 8xx, 74xx, and 82xx processors. Currently, the - default option is to build a kernel which works on PReP and CHRP. + default option is to build a kernel which works on PReP. - Note that support for Apple machines is now only available with - ARCH=powerpc, and has been removed from this menu. If you wish - to build a kernel for an Apple machine, exit this configuration - process and re-run it with ARCH=powerpc. + Note that support for Apple and CHRP machines is now only available + with ARCH=powerpc, and has been removed from this menu. If you + wish to build a kernel for an Apple or CHRP machine, exit this + configuration process and re-run it with ARCH=powerpc. - Select CHRP/PReP if configuring for an IBM RS/6000 or - pSeries machine, or a PReP machine. + Select PReP if configuring for a PReP machine. Select Gemini if configuring for a Synergy Microsystems' Gemini series Single Board Computer. More information is available at: @@ -562,8 +552,8 @@ choice Select APUS if configuring for a PowerUP Amiga. More information is available at: . -config PPC_MULTIPLATFORM - bool "CHRP/PReP" +config PPC_PREP + bool "PReP" config APUS bool "Amiga-APUS" @@ -715,6 +705,13 @@ config LITE5200 much but it's only been tested on this board version. I think this board is also known as IceCube. +config LITE5200B + bool "Freescale LITE5200B" + depends LITE5200 + help + Support for the LITE5200B dev board for the MPC5200 from Freescale. + This is the new board with 2 PCI slots. + config MPC834x_SYS bool "Freescale MPC834x SYS" help @@ -800,25 +797,6 @@ config CPM2 you wish to build a kernel for a machine with a CPM2 coprocessor on it (826x, 827x, 8560). -config PPC_CHRP - bool "Support for CHRP (Common Hardware Reference Platform) machines" - depends on PPC_MULTIPLATFORM - select PPC_I8259 - select PPC_INDIRECT_PCI - default y - -config PPC_PREP - bool "Support for PReP (PowerPC Reference Platform) machines" - depends on PPC_MULTIPLATFORM - select PPC_I8259 - select PPC_INDIRECT_PCI - default y - -config PPC_OF - bool - depends on PPC_CHRP - default y - config PPC_GEN550 bool depends on SANDPOINT || SPRUCE || PPLUS || \ @@ -977,14 +955,6 @@ source "mm/Kconfig" source "fs/Kconfig.binfmt" -config PROC_DEVICETREE - bool "Support for Open Firmware device tree in /proc" - depends on PPC_OF && PROC_FS - help - This option adds a device-tree directory under /proc which contains - an image of the device tree that the kernel copies from Open - Firmware. If unsure, say Y here. - config PREP_RESIDUAL bool "Support for PReP Residual Data" depends on PPC_PREP @@ -1177,8 +1147,7 @@ menu "Bus options" config ISA bool "Support for ISA-bus hardware" - depends on PPC_PREP || PPC_CHRP - select PPC_I8259 + depends on PPC_PREP help Find out whether you have ISA slots on your motherboard. ISA is the name of a bus system, i.e. the way the CPU talks to the other stuff @@ -1188,18 +1157,18 @@ config ISA config GENERIC_ISA_DMA bool - depends on POWER3 || 6xx && !CPM2 + depends on 6xx && !CPM2 default y config PPC_I8259 bool - default y if 85xx + default y if 85xx || PPC_PREP default n config PPC_INDIRECT_PCI bool depends on PCI - default y if 40x || 44x || 85xx || 83xx + default y if 40x || 44x || 85xx || 83xx || PPC_PREP default n config EISA @@ -1390,7 +1359,7 @@ config CONSISTENT_SIZE config BOOT_LOAD_BOOL bool "Set the boot link/load address" - depends on ADVANCED_OPTIONS && !PPC_MULTIPLATFORM + depends on ADVANCED_OPTIONS && !PPC_PREP help This option allows you to set the initial load address of the zImage or zImage.initrd file. This can be useful if you are on a board diff --git a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug index 8cc75abf3d83..f94b87740973 100644 --- a/arch/ppc/Kconfig.debug +++ b/arch/ppc/Kconfig.debug @@ -53,13 +53,6 @@ config BDI_SWITCH Unless you are intending to debug the kernel with one of these machines, say N here. -config BOOTX_TEXT - bool "Support for early boot text console (BootX or OpenFirmware only)" - depends PPC_OF - help - Say Y here to see progress messages from the boot firmware in text - mode. Requires either BootX or Open Firmware. - config SERIAL_TEXT_DEBUG bool "Support for early boot texts over serial port" depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \ diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index 9fbdf54ba2be..0db66dcf0723 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -40,10 +40,8 @@ ifndef CONFIG_FSL_BOOKE CFLAGS += -mstring endif -cpu-as-$(CONFIG_PPC64BRIDGE) += -Wa,-mppc64bridge cpu-as-$(CONFIG_4xx) += -Wa,-m405 cpu-as-$(CONFIG_6xx) += -Wa,-maltivec -cpu-as-$(CONFIG_POWER4) += -Wa,-maltivec cpu-as-$(CONFIG_E500) += -Wa,-me500 cpu-as-$(CONFIG_E200) += -Wa,-me200 @@ -59,8 +57,6 @@ head-$(CONFIG_4xx) := arch/ppc/kernel/head_4xx.o head-$(CONFIG_44x) := arch/ppc/kernel/head_44x.o head-$(CONFIG_FSL_BOOKE) := arch/ppc/kernel/head_fsl_booke.o -head-$(CONFIG_6xx) += arch/ppc/kernel/idle_6xx.o -head-$(CONFIG_POWER4) += arch/ppc/kernel/idle_power4.o head-$(CONFIG_PPC_FPU) += arch/powerpc/kernel/fpu.o core-y += arch/ppc/kernel/ arch/powerpc/kernel/ \ @@ -71,7 +67,7 @@ core-y += arch/ppc/kernel/ arch/powerpc/kernel/ \ core-$(CONFIG_4xx) += arch/ppc/platforms/4xx/ core-$(CONFIG_83xx) += arch/ppc/platforms/83xx/ core-$(CONFIG_85xx) += arch/ppc/platforms/85xx/ -core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/ +core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/ core-$(CONFIG_XMON) += arch/ppc/xmon/ core-$(CONFIG_APUS) += arch/ppc/amiga/ drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/ diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile index 84eec0bef93c..b739e25d4728 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -19,14 +19,13 @@ HOSTCFLAGS += -Iarch/$(ARCH)/boot/include BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd bootdir-y := simple -bootdir-$(CONFIG_PPC_OF) += openfirmware subdir-y := lib common images -subdir-$(CONFIG_PPC_MULTIPLATFORM) += of1275 +subdir-$(CONFIG_PPC_PREP) += of1275 # for cleaning -subdir- += simple openfirmware +subdir- += simple -hostprogs-y := $(addprefix utils/, addnote mknote hack-coff mkprep mkbugboot mktree) +hostprogs-y := $(addprefix utils/, mkprep mkbugboot mktree) PHONY += $(BOOT_TARGETS) $(bootdir-y) diff --git a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile index d4077e69086f..80c84d562fa4 100644 --- a/arch/ppc/boot/lib/Makefile +++ b/arch/ppc/boot/lib/Makefile @@ -3,7 +3,7 @@ # CFLAGS_kbd.o := -Idrivers/char -CFLAGS_vreset.o := -I$(srctree)/arch/ppc/boot/include +CFLAGS_vreset.o := -Iarch/ppc/boot/include zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c diff --git a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile deleted file mode 100644 index 66b739743759..000000000000 --- a/arch/ppc/boot/openfirmware/Makefile +++ /dev/null @@ -1,109 +0,0 @@ -# Makefile for making bootable images on various OpenFirmware machines. -# -# This file is included by the global makefile so that you can add your own -# architecture-specific flags and dependencies. -# -# Paul Mackerras January 1997 -# XCOFF bootable images for PowerMacs -# Geert Uytterhoeven September 1997 -# ELF bootable iamges for CHRP machines. -# Tom Rini January 2001 -# Cleaned up, moved into arch/ppc/boot/pmac -# Tom Rini July/August 2002 -# Merged 'chrp' and 'pmac' into 'openfirmware', and cleaned up the -# rules. - -zImage.initrd znetboot.initrd: del-ramdisk-sec := -R .ramdisk -zImage.initrd znetboot.initrd: initrd := .initrd - - -boot := arch/ppc/boot -common := $(boot)/common -utils := $(boot)/utils -bootlib := $(boot)/lib -of1275 := $(boot)/of1275 -images := $(boot)/images - -CHRP_LD_ARGS := -T $(srctree)/$(boot)/ld.script -e _start -Ttext 0x00800000 - -COMMONOBJS := start.o misc.o common.o -CHRPOBJS := crt0.o $(COMMONOBJS) chrpmain.o - -targets := $(CHRPOBJS) dummy.o -CHRPOBJS := $(addprefix $(obj)/, $(CHRPOBJS)) - -LIBS := lib/lib.a $(bootlib)/lib.a $(of1275)/lib.a $(common)/lib.a - -ifdef CONFIG_SMP -END := .smp -endif -ifdef CONFIG_PPC64BRIDGE -END += .64 -endif - - -$(images)/ramdisk.image.gz: - @echo ' MISSING $@' - @echo ' RAM disk image must be provided separately' - @/bin/false - -quiet_cmd_genimage = GEN $@ - cmd_genimage = $(OBJCOPY) -R .comment \ - --add-section=.image=$(images)/vmlinux.gz \ - --set-section-flags=.image=contents,alloc,load,readonly,data $< $@ - -targets += image.o -$(obj)/image.o: $(obj)/dummy.o $(images)/vmlinux.gz FORCE - $(call if_changed,genimage) - -# Place the ramdisk in the initrd image. -quiet_cmd_genimage-initrd = GEN $@ - cmd_genimage-initrd = $(OBJCOPY) $< $@ \ - --add-section=.ramdisk=$(images)/ramdisk.image.gz \ - --set-section-flags=.ramdisk=contents,alloc,load,readonly,data -targets += image.initrd.o -$(obj)/image.initrd.o: $(obj)/image.o $(images)/ramdisk.image.gz FORCE - $(call if_changed,genimage-initrd) - - -targets += crt0.o -$(obj)/crt0.o: $(common)/crt0.S FORCE - $(call if_changed_dep,as_o_S) - -quiet_cmd_gen-chrp = CHRP $@ - cmd_gen-chrp = $(LD) $(CHRP_LD_ARGS) -o $@ $(CHRPOBJS) $< $(LIBS) && \ - $(OBJCOPY) $@ $@ -R .comment $(del-ramdisk-sec) - -$(images)/zImage.chrp: $(obj)/image.o $(CHRPOBJS) $(LIBS) \ - $(srctree)/$(boot)/ld.script - $(call cmd,gen-chrp) -$(images)/zImage.initrd.chrp: $(obj)/image.initrd.o $(CHRPOBJS) $(LIBS) \ - $(srctree)/$(boot)/ld.script - $(call cmd,gen-chrp) - -quiet_cmd_addnote = ADDNOTE $@ - cmd_addnote = cat $< > $@ && $(utils)/addnote $@ -$(images)/zImage.chrp-rs6k $(images)/zImage.initrd.chrp-rs6k: \ - %-rs6k: % - $(call cmd,addnote) - -# The targets used on the make command-line - -PHONY += zImage zImage.initrd -zImage: $(images)/zImage.chrp \ - $(images)/zImage.chrp-rs6k - @echo ' kernel: $@ is ready ($<)' -zImage.initrd: $(images)/zImage.initrd.chrp \ - $(images)/zImage.initrd.chrp-rs6k - @echo ' kernel: $@ is ready ($<)' - -TFTPIMAGE := /tftpboot/zImage - -PHONY += znetboot znetboot.initrd -znetboot: $(images)/zImage.chrp - cp $(images)/zImage.chrp $(TFTPIMAGE).chrp$(END) - @echo ' kernel: $@ is ready ($<)' -znetboot.initrd:$(images)/zImage.initrd.chrp - cp $(images)/zImage.initrd.chrp $(TFTPIMAGE).chrp$(END) - @echo ' kernel: $@ is ready ($<)' - diff --git a/arch/ppc/boot/openfirmware/chrpmain.c b/arch/ppc/boot/openfirmware/chrpmain.c deleted file mode 100644 index 245dbd9fc120..000000000000 --- a/arch/ppc/boot/openfirmware/chrpmain.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -#include -#include "nonstdio.h" -#include "of1275.h" -#include -#include - -/* Passed from the linker */ -extern char __image_begin, __image_end; -extern char __ramdisk_begin, __ramdisk_end; -extern char _start, _end; - -extern unsigned int heap_max; -extern void flush_cache(void *, unsigned long); -extern void gunzip(void *, int, unsigned char *, int *); -extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach, - unsigned int progend); - -char *avail_ram; -char *begin_avail, *end_avail; -char *avail_high; - -#define RAM_START 0x00000000 -#define RAM_END (64<<20) - -#define BOOT_START ((unsigned long)_start) -#define BOOT_END ((unsigned long)(_end + 0xFFF) & ~0xFFF) - -#define RAM_FREE ((unsigned long)(_end+0x1000)&~0xFFF) -#define PROG_START 0x00010000 -#define PROG_SIZE 0x007f0000 /* 8MB */ - -#define SCRATCH_SIZE (128 << 10) - -static char scratch[SCRATCH_SIZE]; /* 128k of scratch space for gunzip */ - -typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int); - -void -boot(int a1, int a2, void *prom) -{ - unsigned sa, len; - void *dst; - unsigned char *im; - unsigned int initrd_size, initrd_start; - - printf("chrpboot starting: loaded at 0x%p\n\r", &_start); - - initrd_size = &__ramdisk_end - &__ramdisk_begin; - if (initrd_size) { - initrd_start = (RAM_END - initrd_size) & ~0xFFF; - a1 = initrd_start; - a2 = initrd_size; - claim(initrd_start, RAM_END - initrd_start, 0); - printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r", - initrd_start, &__ramdisk_begin, initrd_size); - memcpy((char *)initrd_start, &__ramdisk_begin, initrd_size); - } else { - initrd_start = 0; - initrd_size = 0; - a2 = 0xdeadbeef; - } - - im = &__image_begin; - len = &__image_end - &__image_begin; - /* claim 4MB starting at PROG_START */ - claim(PROG_START, PROG_SIZE - PROG_START, 0); - dst = (void *) PROG_START; - if (im[0] == 0x1f && im[1] == 0x8b) { - avail_ram = scratch; - begin_avail = avail_high = avail_ram; - end_avail = scratch + sizeof(scratch); - printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len); - gunzip(dst, PROG_SIZE - PROG_START, im, &len); - printf("done %u bytes\n\r", len); - printf("%u bytes of heap consumed, max in use %u\n\r", - avail_high - begin_avail, heap_max); - } else { - memmove(dst, im, len); - } - - flush_cache(dst, len); - make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_chrp, - (PROG_START + PROG_SIZE)); - - sa = PROG_START; - printf("start address = 0x%x\n\r", sa); - - (*(kernel_start_t)sa)(a1, a2, prom, initrd_start, initrd_size); - - printf("returned?\n\r"); - - pause(); -} diff --git a/arch/ppc/boot/openfirmware/common.c b/arch/ppc/boot/openfirmware/common.c deleted file mode 100644 index 0f46756a903e..000000000000 --- a/arch/ppc/boot/openfirmware/common.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ - -#include "nonstdio.h" -#include "of1275.h" -#include -#include -#include -#include - -/* Information from the linker */ - -extern int strcmp(const char *s1, const char *s2); -extern char *avail_ram, *avail_high; -extern char *end_avail; - -unsigned int heap_use, heap_max; - -struct memchunk { - unsigned int size; - struct memchunk *next; -}; - -static struct memchunk *freechunks; - -static void *zalloc(unsigned size) -{ - void *p; - struct memchunk **mpp, *mp; - - size = (size + 7) & -8; - heap_use += size; - if (heap_use > heap_max) - heap_max = heap_use; - for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { - if (mp->size == size) { - *mpp = mp->next; - return mp; - } - } - p = avail_ram; - avail_ram += size; - if (avail_ram > avail_high) - avail_high = avail_ram; - if (avail_ram > end_avail) { - printf("oops... out of memory\n\r"); - pause(); - } - return p; -} - -#define HEAD_CRC 2 -#define EXTRA_FIELD 4 -#define ORIG_NAME 8 -#define COMMENT 0x10 -#define RESERVED 0xe0 - -void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp) -{ - z_stream s; - int r, i, flags; - - /* skip header */ - i = 10; - flags = src[3]; - if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) { - printf("bad gzipped data\n\r"); - exit(); - } - if ((flags & EXTRA_FIELD) != 0) - i = 12 + src[10] + (src[11] << 8); - if ((flags & ORIG_NAME) != 0) - while (src[i++] != 0) - ; - if ((flags & COMMENT) != 0) - while (src[i++] != 0) - ; - if ((flags & HEAD_CRC) != 0) - i += 2; - if (i >= *lenp) { - printf("gunzip: ran out of data in header\n\r"); - exit(); - } - - /* Initialize ourself. */ - s.workspace = zalloc(zlib_inflate_workspacesize()); - r = zlib_inflateInit2(&s, -MAX_WBITS); - if (r != Z_OK) { - printf("zlib_inflateInit2 returned %d\n\r", r); - exit(); - } - s.next_in = src + i; - s.avail_in = *lenp - i; - s.next_out = dst; - s.avail_out = dstlen; - r = zlib_inflate(&s, Z_FINISH); - if (r != Z_OK && r != Z_STREAM_END) { - printf("inflate returned %d msg: %s\n\r", r, s.msg); - exit(); - } - *lenp = s.next_out - (unsigned char *) dst; - zlib_inflateEnd(&s); -} - -/* Make a bi_rec in OF. We need to be passed a name for BI_BOOTLOADER_ID, - * a machine type for BI_MACHTYPE, and the location where the end of the - * bootloader is (PROG_START + PROG_SIZE) - */ -void make_bi_recs(unsigned long addr, char *name, unsigned int mach, - unsigned long progend) -{ - struct bi_record *rec; - - - /* leave a 1MB gap then align to the next 1MB boundary */ - addr = _ALIGN(addr+ (1<<20) - 1, (1<<20)); - /* oldworld machine seem very unhappy about this. -- Tom */ - if (addr >= progend) - claim(addr, 0x1000, 0); - - rec = (struct bi_record *)addr; - rec->tag = BI_FIRST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_BOOTLOADER_ID; - sprintf( (char *)rec->data, name); - rec->size = sizeof(struct bi_record) + strlen(name) + 1; - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_MACHTYPE; - rec->data[0] = mach; - rec->data[1] = 1; - rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long); - rec = (struct bi_record *)((unsigned long)rec + rec->size); - - rec->tag = BI_LAST; - rec->size = sizeof(struct bi_record); - rec = (struct bi_record *)((unsigned long)rec + rec->size); -} diff --git a/arch/ppc/boot/openfirmware/dummy.c b/arch/ppc/boot/openfirmware/dummy.c deleted file mode 100644 index 31dbf45bf99c..000000000000 --- a/arch/ppc/boot/openfirmware/dummy.c +++ /dev/null @@ -1,4 +0,0 @@ -int main(void) -{ - return 0; -} diff --git a/arch/ppc/boot/openfirmware/misc.S b/arch/ppc/boot/openfirmware/misc.S deleted file mode 100644 index ab9e897cadd0..000000000000 --- a/arch/ppc/boot/openfirmware/misc.S +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ - .text - -/* - * Use the BAT2 & 3 registers to map the 1st 16MB of RAM to - * the address given as the 1st argument. - */ - .globl setup_bats -setup_bats: - mfpvr 5 - rlwinm 5,5,16,16,31 /* r3 = 1 for 601, 4 for 604 */ - cmpwi 0,5,1 - li 0,0 - bne 4f - mtibatl 3,0 /* invalidate BAT first */ - ori 3,3,4 /* set up BAT registers for 601 */ - li 4,0x7f - mtibatu 2,3 - mtibatl 2,4 - oris 3,3,0x80 - oris 4,4,0x80 - mtibatu 3,3 - mtibatl 3,4 - b 5f -4: mtdbatu 3,0 /* invalidate BATs first */ - mtibatu 3,0 - ori 3,3,0xff /* set up BAT registers for 604 */ - li 4,2 - mtdbatl 2,4 - mtdbatu 2,3 - mtibatl 2,4 - mtibatu 2,3 - oris 3,3,0x80 - oris 4,4,0x80 - mtdbatl 3,4 - mtdbatu 3,3 - mtibatl 3,4 - mtibatu 3,3 -5: sync - isync - blr - -/* - * Flush the dcache and invalidate the icache for a range of addresses. - * - * flush_cache(addr, len) - */ - .global flush_cache -flush_cache: - addi 4,4,0x1f /* len = (len + 0x1f) / 0x20 */ - rlwinm. 4,4,27,5,31 - mtctr 4 - beqlr -1: dcbf 0,3 - icbi 0,3 - addi 3,3,0x20 - bdnz 1b - sync - isync - blr diff --git a/arch/ppc/boot/openfirmware/start.c b/arch/ppc/boot/openfirmware/start.c deleted file mode 100644 index 1617a26956bf..000000000000 --- a/arch/ppc/boot/openfirmware/start.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -#include -#include "of1275.h" - -extern int strlen(const char *s); -extern void boot(int a1, int a2, void *prom); - -phandle stdin; -phandle stdout; -phandle stderr; - -void printk(char *fmt, ...); - -void -start(int a1, int a2, void *promptr) -{ - ofinit(promptr); - if (ofstdio(&stdin, &stdout, &stderr)) - exit(); - - boot(a1, a2, promptr); - for (;;) - exit(); -} - -int writestring(void *f, char *ptr, int nb) -{ - int w = 0, i; - char *ret = "\r"; - - for (i = 0; i < nb; ++i) { - if (ptr[i] == '\n') { - if (i > w) { - write(f, ptr + w, i - w); - w = i; - } - write(f, ret, 1); - } - } - if (w < nb) - write(f, ptr + w, nb - w); - return nb; -} - -int -putc(int c, void *f) -{ - char ch = c; - - return writestring(f, &ch, 1) == 1? c: -1; -} - -int -putchar(int c) -{ - return putc(c, stdout); -} - -int -fputs(char *str, void *f) -{ - int n = strlen(str); - - return writestring(f, str, n) == n? 0: -1; -} - -int -readchar(void) -{ - char ch; - - for (;;) { - switch (read(stdin, &ch, 1)) { - case 1: - return ch; - case -1: - printk("read(stdin) returned -1\n"); - return -1; - } - } -} - -static char line[256]; -static char *lineptr; -static int lineleft; - -int -getchar(void) -{ - int c; - - if (lineleft == 0) { - lineptr = line; - for (;;) { - c = readchar(); - if (c == -1 || c == 4) - break; - if (c == '\r' || c == '\n') { - *lineptr++ = '\n'; - putchar('\n'); - break; - } - switch (c) { - case 0177: - case '\b': - if (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - case 'U' & 0x1F: - while (lineptr > line) { - putchar('\b'); - putchar(' '); - putchar('\b'); - --lineptr; - } - break; - default: - if (lineptr >= &line[sizeof(line) - 1]) - putchar('\a'); - else { - putchar(c); - *lineptr++ = c; - } - } - } - lineleft = lineptr - line; - lineptr = line; - } - if (lineleft == 0) - return -1; - --lineleft; - return *lineptr++; -} - -extern int vsprintf(char *buf, const char *fmt, va_list args); -static char sprint_buf[1024]; - -void -printk(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - writestring(stdout, sprint_buf, n); -} - -int -printf(char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = vsprintf(sprint_buf, fmt, args); - va_end(args); - writestring(stdout, sprint_buf, n); - return n; -} diff --git a/arch/ppc/boot/simple/mpc10x_memory.c b/arch/ppc/boot/simple/mpc10x_memory.c index c24290823f7f..8da8f576031d 100644 --- a/arch/ppc/boot/simple/mpc10x_memory.c +++ b/arch/ppc/boot/simple/mpc10x_memory.c @@ -50,10 +50,10 @@ MPC10X_PCI_OP(read, dword, u32 *, in_le32, 0) * the system. This assumes that the firmware has correctly set up the memory * controller registers. On CONFIG_PPC_PREP, we know we are being called * under a PReP memory map. On all other machines, we assume we are under - * a CHRP memory map. Further, on CONFIG_PPC_MULTIPLATFORM we must rename + * a CHRP memory map. Further, on CONFIG_PPC_PREP we must rename * this function. */ -#ifdef CONFIG_PPC_MULTIPLATFORM +#ifdef CONFIG_PPC_PREP #define get_mem_size mpc10x_get_mem_size #endif unsigned long diff --git a/arch/ppc/boot/simple/relocate.S b/arch/ppc/boot/simple/relocate.S index 7efddc507564..2533113c1cc5 100644 --- a/arch/ppc/boot/simple/relocate.S +++ b/arch/ppc/boot/simple/relocate.S @@ -194,7 +194,7 @@ start_ldr: /* * Start at the begining. */ -#ifdef CONFIG_PPC_MULTIPLATFORM +#ifdef CONFIG_PPC_PREP li r9,0xc mtlr r9 /* tell kernel we're prep, by putting 0xdeadc0de at KERNELLOAD, diff --git a/arch/ppc/boot/utils/addnote.c b/arch/ppc/boot/utils/addnote.c deleted file mode 100644 index 6c52b18f2d04..000000000000 --- a/arch/ppc/boot/utils/addnote.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Program to hack in a PT_NOTE program header entry in an ELF file. - * This is needed for OF on RS/6000s to load an image correctly. - * Note that OF needs a program header entry for the note, not an - * ELF section. - * - * Copyright 2000 Paul Mackerras. - * - * 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. - * - * Usage: addnote zImage - */ -#include -#include -#include -#include -#include - -char arch[] = "PowerPC"; - -#define N_DESCR 6 -unsigned int descr[N_DESCR] = { -#if 1 - /* values for IBM RS/6000 machines */ - 0xffffffff, /* real-mode = true */ - 0x00c00000, /* real-base, i.e. where we expect OF to be */ - 0xffffffff, /* real-size */ - 0xffffffff, /* virt-base */ - 0xffffffff, /* virt-size */ - 0x4000, /* load-base */ -#else - /* values for longtrail CHRP */ - 0, /* real-mode = false */ - 0xffffffff, /* real-base */ - 0xffffffff, /* real-size */ - 0xffffffff, /* virt-base */ - 0xffffffff, /* virt-size */ - 0x00600000, /* load-base */ -#endif -}; - -unsigned char buf[512]; - -#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1])) -#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2)) - -#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \ - buf[(off) + 1] = (v) & 0xff) -#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \ - PUT_16BE((off) + 2, (v))) - -/* Structure of an ELF file */ -#define E_IDENT 0 /* ELF header */ -#define E_PHOFF 28 -#define E_PHENTSIZE 42 -#define E_PHNUM 44 -#define E_HSIZE 52 /* size of ELF header */ - -#define EI_MAGIC 0 /* offsets in E_IDENT area */ -#define EI_CLASS 4 -#define EI_DATA 5 - -#define PH_TYPE 0 /* ELF program header */ -#define PH_OFFSET 4 -#define PH_FILESZ 16 -#define PH_HSIZE 32 /* size of program header */ - -#define PT_NOTE 4 /* Program header type = note */ - -#define ELFCLASS32 1 -#define ELFDATA2MSB 2 - -unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; - -int main(int ac, char **av) -{ - int fd, n, i; - int ph, ps, np; - int nnote, ns; - - if (ac != 2) { - fprintf(stderr, "Usage: %s elf-file\n", av[0]); - exit(1); - } - fd = open(av[1], O_RDWR); - if (fd < 0) { - perror(av[1]); - exit(1); - } - - nnote = strlen(arch) + 1 + (N_DESCR + 3) * 4; - - n = read(fd, buf, sizeof(buf)); - if (n < 0) { - perror("read"); - exit(1); - } - - if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) - goto notelf; - - if (buf[E_IDENT+EI_CLASS] != ELFCLASS32 - || buf[E_IDENT+EI_DATA] != ELFDATA2MSB) { - fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", - av[1]); - exit(1); - } - - ph = GET_32BE(E_PHOFF); - ps = GET_16BE(E_PHENTSIZE); - np = GET_16BE(E_PHNUM); - if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) - goto notelf; - if (ph + (np + 1) * ps + nnote > n) - goto nospace; - - for (i = 0; i < np; ++i) { - if (GET_32BE(ph + PH_TYPE) == PT_NOTE) { - fprintf(stderr, "%s already has a note entry\n", - av[1]); - exit(0); - } - ph += ps; - } - - /* XXX check that the area we want to use is all zeroes */ - for (i = 0; i < ps + nnote; ++i) - if (buf[ph + i] != 0) - goto nospace; - - /* fill in the program header entry */ - ns = ph + ps; - PUT_32BE(ph + PH_TYPE, PT_NOTE); - PUT_32BE(ph + PH_OFFSET, ns); - PUT_32BE(ph + PH_FILESZ, nnote); - - /* fill in the note area we point to */ - /* XXX we should probably make this a proper section */ - PUT_32BE(ns, strlen(arch) + 1); - PUT_32BE(ns + 4, N_DESCR * 4); - PUT_32BE(ns + 8, 0x1275); - strcpy(&buf[ns + 12], arch); - ns += 12 + strlen(arch) + 1; - for (i = 0; i < N_DESCR; ++i) - PUT_32BE(ns + i * 4, descr[i]); - - /* Update the number of program headers */ - PUT_16BE(E_PHNUM, np + 1); - - /* write back */ - lseek(fd, (long) 0, SEEK_SET); - i = write(fd, buf, n); - if (i < 0) { - perror("write"); - exit(1); - } - if (i < n) { - fprintf(stderr, "%s: write truncated\n", av[1]); - exit(1); - } - - exit(0); - - notelf: - fprintf(stderr, "%s does not appear to be an ELF file\n", av[0]); - exit(1); - - nospace: - fprintf(stderr, "sorry, I can't find space in %s to put the note\n", - av[0]); - exit(1); -} diff --git a/arch/ppc/boot/utils/hack-coff.c b/arch/ppc/boot/utils/hack-coff.c deleted file mode 100644 index 5e5a6573a1ef..000000000000 --- a/arch/ppc/boot/utils/hack-coff.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * hack-coff.c - hack the header of an xcoff file to fill in - * a few fields needed by the Open Firmware xcoff loader on - * Power Macs but not initialized by objcopy. - * - * Copyright (C) Paul Mackerras 1997. - * - * 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. - */ -#include -#include -#include -#include -#include -#include "rs6000.h" - -#define AOUT_MAGIC 0x010b - -#define get_16be(x) ((((unsigned char *)(x))[0] << 8) \ - + ((unsigned char *)(x))[1]) -#define put_16be(x, v) (((unsigned char *)(x))[0] = (v) >> 8, \ - ((unsigned char *)(x))[1] = (v) & 0xff) -#define get_32be(x) ((((unsigned char *)(x))[0] << 24) \ - + (((unsigned char *)(x))[1] << 16) \ - + (((unsigned char *)(x))[2] << 8) \ - + ((unsigned char *)(x))[3]) - -int -main(int ac, char **av) -{ - int fd; - int i, nsect; - int aoutsz; - struct external_filehdr fhdr; - AOUTHDR aout; - struct external_scnhdr shdr; - - if (ac != 2) { - fprintf(stderr, "Usage: hack-coff coff-file\n"); - exit(1); - } - if ((fd = open(av[1], 2)) == -1) { - perror(av[2]); - exit(1); - } - if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr)) - goto readerr; - i = get_16be(fhdr.f_magic); - if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) { - fprintf(stderr, "%s: not an xcoff file\n", av[1]); - exit(1); - } - aoutsz = get_16be(fhdr.f_opthdr); - if (read(fd, &aout, aoutsz) != aoutsz) - goto readerr; - nsect = get_16be(fhdr.f_nscns); - for (i = 0; i < nsect; ++i) { - if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr)) - goto readerr; - if (strcmp(shdr.s_name, ".text") == 0) { - put_16be(aout.o_snentry, i+1); - put_16be(aout.o_sntext, i+1); - } else if (strcmp(shdr.s_name, ".data") == 0) { - put_16be(aout.o_sndata, i+1); - } else if (strcmp(shdr.s_name, ".bss") == 0) { - put_16be(aout.o_snbss, i+1); - } - } - put_16be(aout.magic, AOUT_MAGIC); - if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1 - || write(fd, &aout, aoutsz) != aoutsz) { - fprintf(stderr, "%s: write error\n", av[1]); - exit(1); - } - close(fd); - exit(0); - -readerr: - fprintf(stderr, "%s: read error or file too short\n", av[1]); - exit(1); -} diff --git a/arch/ppc/boot/utils/mknote.c b/arch/ppc/boot/utils/mknote.c deleted file mode 100644 index b9fbb2cbfc8f..000000000000 --- a/arch/ppc/boot/utils/mknote.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) Cort Dougan 1999. - * - * 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. - * - * Generate a note section as per the CHRP specification. - * - */ - -#include -#include - -#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff ); - -int main(void) -{ -/* header */ - /* namesz */ - PL(strlen("PowerPC")+1); - /* descrsz */ - PL(6*4); - /* type */ - PL(0x1275); - /* name */ - printf("PowerPC"); printf("%c", 0); - -/* descriptor */ - /* real-mode */ - PL(0xffffffff); - /* real-base */ - PL(0x00c00000); - /* real-size */ - PL(0xffffffff); - /* virt-base */ - PL(0xffffffff); - /* virt-size */ - PL(0xffffffff); - /* load-base */ - PL(0x4000); - return 0; -} diff --git a/arch/ppc/configs/ibmchrp_defconfig b/arch/ppc/configs/ibmchrp_defconfig deleted file mode 100644 index 27f3e69c1f96..000000000000 --- a/arch/ppc/configs/ibmchrp_defconfig +++ /dev/null @@ -1,875 +0,0 @@ -# -# Automatically generated make config: don't edit -# -CONFIG_MMU=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_HAVE_DEC_LOCK=y -CONFIG_PPC=y -CONFIG_PPC32=y -CONFIG_GENERIC_NVRAM=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y -# CONFIG_STANDALONE is not set -CONFIG_BROKEN_ON_SMP=y - -# -# General setup -# -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 -# CONFIG_HOTPLUG is not set -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -# CONFIG_EMBEDDED is not set -CONFIG_KALLSYMS=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_OBSOLETE_MODPARM=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y - -# -# Processor -# -CONFIG_6xx=y -# CONFIG_40x is not set -# CONFIG_44x is not set -# CONFIG_POWER3 is not set -# CONFIG_POWER4 is not set -# CONFIG_8xx is not set -# CONFIG_ALTIVEC is not set -# CONFIG_TAU is not set -# CONFIG_CPU_FREQ is not set -# CONFIG_PPC601_SYNC_FIX is not set -CONFIG_PPC_STD_MMU=y - -# -# Platform options -# -CONFIG_PPC_MULTIPLATFORM=y -# CONFIG_APUS is not set -# CONFIG_WILLOW is not set -# CONFIG_PCORE is not set -# CONFIG_POWERPMC250 is not set -# CONFIG_EV64260 is not set -# CONFIG_SPRUCE is not set -# CONFIG_LOPEC is not set -# CONFIG_MCPN765 is not set -# CONFIG_MVME5100 is not set -# CONFIG_PPLUS is not set -# CONFIG_PRPMC750 is not set -# CONFIG_PRPMC800 is not set -# CONFIG_SANDPOINT is not set -# CONFIG_ADIR is not set -# CONFIG_K2 is not set -# CONFIG_PAL4 is not set -# CONFIG_GEMINI is not set -# CONFIG_EST8260 is not set -# CONFIG_SBS8260 is not set -# CONFIG_RPX6 is not set -# CONFIG_TQM8260 is not set -CONFIG_PPC_CHRP=y -CONFIG_PPC_PMAC=y -CONFIG_PPC_PREP=y -CONFIG_PPC_OF=y -CONFIG_PPCBUG_NVRAM=y -# CONFIG_SMP is not set -# CONFIG_PREEMPT is not set -CONFIG_HIGHMEM=y -CONFIG_KERNEL_ELF=y -CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y -CONFIG_PROC_DEVICETREE=y -CONFIG_PPC_RTAS=y -# CONFIG_PREP_RESIDUAL is not set -# CONFIG_CMDLINE_BOOL is not set - -# -# Bus options -# -CONFIG_ISA=y -CONFIG_GENERIC_ISA_DMA=y -CONFIG_PCI=y -CONFIG_PCI_DOMAINS=y -CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y - -# -# Advanced setup -# -# CONFIG_ADVANCED_OPTIONS is not set - -# -# Default settings for advanced configuration options are used -# -CONFIG_HIGHMEM_START=0xfe000000 -CONFIG_LOWMEM_SIZE=0x30000000 -CONFIG_KERNEL_START=0xc0000000 -CONFIG_TASK_SIZE=0x80000000 -CONFIG_BOOT_LOAD=0x00800000 - -# -# Device Drivers -# - -# -# Generic Driver Options -# - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNP is not set - -# -# Block devices -# -CONFIG_BLK_DEV_FD=y -# CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_UMEM is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_CARMEL is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y -CONFIG_LBD=y - -# -# ATA/ATAPI/MFM/RLL support -# -# CONFIG_IDE is not set - -# -# SCSI device support -# -CONFIG_SCSI=y -CONFIG_SCSI_PROC_FS=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -# CONFIG_CHR_DEV_OSST is not set -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_REPORT_LUNS is not set -CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI Transport Attributes -# -CONFIG_SCSI_SPI_ATTRS=y -# CONFIG_SCSI_FC_ATTRS is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AACRAID is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_IPS is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_NCR53C406A is not set -CONFIG_SCSI_SYM53C8XX_2=y -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 -CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 -CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set -# CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -CONFIG_SCSI_QLA2XXX=y -# CONFIG_SCSI_QLA21XX is not set -# CONFIG_SCSI_QLA22XX is not set -# CONFIG_SCSI_QLA2300 is not set -# CONFIG_SCSI_QLA2322 is not set -# CONFIG_SCSI_QLA6312 is not set -# CONFIG_SCSI_QLA6322 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC395x is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set -# CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_MESH is not set -# CONFIG_SCSI_MAC53C94 is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# -# CONFIG_I2O is not set - -# -# Macintosh device drivers -# -# CONFIG_ADB is not set -# CONFIG_ADB_CUDA is not set -# CONFIG_ADB_PMU is not set -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set - -# -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set - -# -# IP: Virtual Server Configuration -# -# CONFIG_IP_VS is not set -# CONFIG_IPV6 is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set - -# -# IP: Netfilter Configuration -# -CONFIG_IP_NF_CONNTRACK=m -CONFIG_IP_NF_FTP=m -CONFIG_IP_NF_IRC=m -CONFIG_IP_NF_TFTP=m -CONFIG_IP_NF_AMANDA=m -# CONFIG_IP_NF_QUEUE is not set -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_LIMIT=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_MAC=m -# CONFIG_IP_NF_MATCH_PKTTYPE is not set -CONFIG_IP_NF_MATCH_MARK=m -CONFIG_IP_NF_MATCH_MULTIPORT=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_LENGTH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_TCPMSS=m -CONFIG_IP_NF_MATCH_HELPER=m -CONFIG_IP_NF_MATCH_STATE=m -CONFIG_IP_NF_MATCH_CONNTRACK=m -CONFIG_IP_NF_MATCH_OWNER=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_IP_NF_NAT_SNMP_BASIC=m -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m -CONFIG_IP_NF_NAT_TFTP=m -CONFIG_IP_NF_NAT_AMANDA=m -# CONFIG_IP_NF_MANGLE is not set -# CONFIG_IP_NF_TARGET_LOG is not set -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_IP_NF_COMPAT_IPCHAINS=m -# CONFIG_IP_NF_COMPAT_IPFWADM is not set -CONFIG_IP_NF_TARGET_NOTRACK=m -CONFIG_IP_NF_RAW=m - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -# CONFIG_MACE is not set -# CONFIG_BMAC is not set -# CONFIG_OAKNET is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set - -# -# Tulip family network device support -# -# CONFIG_NET_TULIP is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_PCI=y -CONFIG_PCNET32=y -# CONFIG_AMD8111_ETH is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_B44 is not set -# CONFIG_FORCEDETH is not set -# CONFIG_CS89x0 is not set -# CONFIG_DGRS is not set -# CONFIG_EEPRO100 is not set -# CONFIG_E100 is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_8139CP is not set -# CONFIG_8139TOO is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_E1000 is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_R8169 is not set -# CONFIG_SK98LIN is not set -# CONFIG_TIGON3 is not set - -# -# Ethernet (10000 Mbit) -# -# CONFIG_IXGB is not set -# CONFIG_S2IO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Telephony Support -# -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_EVBUG is not set - -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PCIPS2 is not set - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -CONFIG_KEYBOARD_ATKBD=y -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -# CONFIG_KEYBOARD_NEWTON is not set -CONFIG_INPUT_MOUSE=y -CONFIG_MOUSE_PS2=y -# CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_INPORT is not set -# CONFIG_MOUSE_LOGIBM is not set -# CONFIG_MOUSE_PC110PAD is not set -# CONFIG_MOUSE_VSXXXAA is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -CONFIG_INPUT_MISC=y -CONFIG_INPUT_UINPUT=y - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -# CONFIG_SERIAL_8250_CONSOLE is not set -CONFIG_SERIAL_8250_NR_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -# CONFIG_SERIAL_PMACZILOG is not set -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 -# CONFIG_QIC02_TAPE is not set - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -CONFIG_NVRAM=y -CONFIG_GEN_RTC=y -# CONFIG_GEN_RTC_X is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_RAW_DRIVER is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Misc devices -# - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# Graphics support -# -CONFIG_FB=y -# CONFIG_FB_PM2 is not set -# CONFIG_FB_CYBER2000 is not set -CONFIG_FB_OF=y -# CONFIG_FB_CONTROL is not set -# CONFIG_FB_PLATINUM is not set -# CONFIG_FB_VALKYRIE is not set -# CONFIG_FB_CT65550 is not set -# CONFIG_FB_IMSTT is not set -# CONFIG_FB_S3TRIO is not set -# CONFIG_FB_VGA16 is not set -# CONFIG_FB_RIVA is not set -CONFIG_FB_MATROX=y -CONFIG_FB_MATROX_MILLENIUM=y -CONFIG_FB_MATROX_MYSTIQUE=y -# CONFIG_FB_MATROX_G450 is not set -CONFIG_FB_MATROX_G100A=y -CONFIG_FB_MATROX_G100=y -# CONFIG_FB_MATROX_MULTIHEAD is not set -# CONFIG_FB_RADEON_OLD is not set -# CONFIG_FB_RADEON is not set -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_SIS is not set -# CONFIG_FB_NEOMAGIC is not set -# CONFIG_FB_KYRO is not set -CONFIG_FB_3DFX=y -# CONFIG_FB_VOODOO1 is not set -# CONFIG_FB_TRIDENT is not set -# CONFIG_FB_VIRTUAL is not set - -# -# Console display driver support -# -CONFIG_VGA_CONSOLE=y -# CONFIG_MDA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_PCI_CONSOLE=y -# CONFIG_FONTS is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y - -# -# Logo configuration -# -CONFIG_LOGO=y -CONFIG_LOGO_LINUX_MONO=y -CONFIG_LOGO_LINUX_VGA16=y -CONFIG_LOGO_LINUX_CLUT224=y - -# -# Sound -# -# CONFIG_SOUND is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_XFS_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_SYSFS=y -CONFIG_DEVFS_FS=y -# CONFIG_DEVFS_MOUNT is not set -# CONFIG_DEVFS_DEBUG is not set -# CONFIG_DEVPTS_FS_XATTR is not set -CONFIG_TMPFS=y -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -# CONFIG_NFS_FS is not set -# CONFIG_NFSD is not set -# CONFIG_EXPORTFS is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set - -# -# Partition Types -# -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -CONFIG_MAC_PARTITION=y -CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_MINIX_SUBPARTITION is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_LDM_PARTITION is not set -# CONFIG_NEC98_PARTITION is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_ULTRIX_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_EFI_PARTITION is not set - -# -# Native Language Support -# -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -CONFIG_NLS_ISO8859_1=m -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Library routines -# -CONFIG_CRC32=y -# CONFIG_LIBCRC32C is not set - -# -# Kernel hacking -# -# CONFIG_DEBUG_KERNEL is not set -# CONFIG_BOOTX_TEXT is not set - -# -# Security options -# -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -# CONFIG_CRYPTO is not set diff --git a/arch/ppc/configs/pmac_defconfig b/arch/ppc/configs/pmac_defconfig deleted file mode 100644 index a2db8b541c9b..000000000000 --- a/arch/ppc/configs/pmac_defconfig +++ /dev/null @@ -1,1591 +0,0 @@ -# -# Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc3 -# Wed Jul 13 14:13:13 2005 -# -CONFIG_MMU=y -CONFIG_GENERIC_HARDIRQS=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_GENERIC_CALIBRATE_DELAY=y -CONFIG_HAVE_DEC_LOCK=y -CONFIG_PPC=y -CONFIG_PPC32=y -CONFIG_GENERIC_NVRAM=y -CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y -CONFIG_BROKEN_ON_SMP=y -CONFIG_INIT_ENV_ARG_LIMIT=32 - -# -# General setup -# -CONFIG_LOCALVERSION="" -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set -CONFIG_HOTPLUG=y -CONFIG_KOBJECT_UEVENT=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -# CONFIG_EMBEDDED is not set -CONFIG_KALLSYMS=y -# CONFIG_KALLSYMS_ALL is not set -# CONFIG_KALLSYMS_EXTRA_PASS is not set -CONFIG_PRINTK=y -CONFIG_BUG=y -CONFIG_BASE_FULL=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 -# CONFIG_TINY_SHMEM is not set -CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y -CONFIG_MODVERSIONS=y -CONFIG_MODULE_SRCVERSION_ALL=y -CONFIG_KMOD=y - -# -# Processor -# -CONFIG_6xx=y -# CONFIG_40x is not set -# CONFIG_44x is not set -# CONFIG_POWER3 is not set -# CONFIG_POWER4 is not set -# CONFIG_8xx is not set -# CONFIG_E200 is not set -# CONFIG_E500 is not set -CONFIG_PPC_FPU=y -CONFIG_ALTIVEC=y -CONFIG_TAU=y -# CONFIG_TAU_INT is not set -# CONFIG_TAU_AVERAGE is not set -# CONFIG_KEXEC is not set -CONFIG_CPU_FREQ=y -CONFIG_CPU_FREQ_TABLE=y -# CONFIG_CPU_FREQ_DEBUG is not set -CONFIG_CPU_FREQ_STAT=m -CONFIG_CPU_FREQ_STAT_DETAILS=y -CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y -# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set -CONFIG_CPU_FREQ_GOV_PERFORMANCE=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m -CONFIG_CPU_FREQ_GOV_USERSPACE=m -CONFIG_CPU_FREQ_GOV_ONDEMAND=m -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m -CONFIG_CPU_FREQ_PMAC=y -CONFIG_PPC601_SYNC_FIX=y -CONFIG_PM=y -CONFIG_PPC_STD_MMU=y - -# -# Platform options -# -CONFIG_PPC_MULTIPLATFORM=y -# CONFIG_APUS is not set -# CONFIG_KATANA is not set -# CONFIG_WILLOW is not set -# CONFIG_CPCI690 is not set -# CONFIG_PCORE is not set -# CONFIG_POWERPMC250 is not set -# CONFIG_CHESTNUT is not set -# CONFIG_SPRUCE is not set -# CONFIG_HDPU is not set -# CONFIG_EV64260 is not set -# CONFIG_LOPEC is not set -# CONFIG_MCPN765 is not set -# CONFIG_MVME5100 is not set -# CONFIG_PPLUS is not set -# CONFIG_PRPMC750 is not set -# CONFIG_PRPMC800 is not set -# CONFIG_SANDPOINT is not set -# CONFIG_RADSTONE_PPC7D is not set -# CONFIG_ADIR is not set -# CONFIG_K2 is not set -# CONFIG_PAL4 is not set -# CONFIG_GEMINI is not set -# CONFIG_EST8260 is not set -# CONFIG_SBC82xx is not set -# CONFIG_SBS8260 is not set -# CONFIG_RPX8260 is not set -# CONFIG_TQM8260 is not set -# CONFIG_ADS8272 is not set -# CONFIG_PQ2FADS is not set -# CONFIG_LITE5200 is not set -# CONFIG_MPC834x_SYS is not set -CONFIG_PPC_CHRP=y -CONFIG_PPC_PMAC=y -CONFIG_PPC_PREP=y -CONFIG_PPC_OF=y -CONFIG_PPCBUG_NVRAM=y -# CONFIG_SMP is not set -# CONFIG_HIGHMEM is not set -# CONFIG_HZ_100 is not set -CONFIG_HZ_250=y -# CONFIG_HZ_1000 is not set -CONFIG_HZ=250 -CONFIG_PREEMPT_NONE=y -# CONFIG_PREEMPT_VOLUNTARY is not set -# CONFIG_PREEMPT is not set -CONFIG_SELECT_MEMORY_MODEL=y -CONFIG_FLATMEM_MANUAL=y -# CONFIG_DISCONTIGMEM_MANUAL is not set -# CONFIG_SPARSEMEM_MANUAL is not set -CONFIG_FLATMEM=y -CONFIG_FLAT_NODE_MEM_MAP=y -CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=m -CONFIG_PROC_DEVICETREE=y -# CONFIG_PREP_RESIDUAL is not set -# CONFIG_CMDLINE_BOOL is not set -# CONFIG_PM_DEBUG is not set -CONFIG_SOFTWARE_SUSPEND=y -CONFIG_PM_STD_PARTITION="" -# CONFIG_SECCOMP is not set -CONFIG_ISA_DMA_API=y - -# -# Bus options -# -# CONFIG_ISA is not set -CONFIG_GENERIC_ISA_DMA=y -CONFIG_PCI=y -CONFIG_PCI_DOMAINS=y -CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y -# CONFIG_PCI_DEBUG is not set - -# -# PCCARD (PCMCIA/CardBus) support -# -CONFIG_PCCARD=m -# CONFIG_PCMCIA_DEBUG is not set -CONFIG_PCMCIA=m -# CONFIG_PCMCIA_LOAD_CIS is not set -# CONFIG_PCMCIA_IOCTL is not set -CONFIG_CARDBUS=y - -# -# PC-card bridges -# -CONFIG_YENTA=m -# CONFIG_PD6729 is not set -# CONFIG_I82092 is not set -# CONFIG_TCIC is not set -CONFIG_PCCARD_NONSTATIC=m - -# -# Advanced setup -# -CONFIG_ADVANCED_OPTIONS=y -CONFIG_HIGHMEM_START=0xfe000000 -# CONFIG_LOWMEM_SIZE_BOOL is not set -CONFIG_LOWMEM_SIZE=0x30000000 -# CONFIG_KERNEL_START_BOOL is not set -CONFIG_KERNEL_START=0xc0000000 -CONFIG_TASK_SIZE_BOOL=y -CONFIG_TASK_SIZE=0xc0000000 -CONFIG_BOOT_LOAD=0x00800000 - -# -# Networking -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -CONFIG_IP_FIB_HASH=y -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y - -# -# IP: Virtual Server Configuration -# -# CONFIG_IP_VS is not set -# CONFIG_IPV6 is not set -CONFIG_NETFILTER=y -# CONFIG_NETFILTER_DEBUG is not set - -# -# IP: Netfilter Configuration -# -CONFIG_IP_NF_CONNTRACK=m -CONFIG_IP_NF_CT_ACCT=y -CONFIG_IP_NF_CONNTRACK_MARK=y -CONFIG_IP_NF_CT_PROTO_SCTP=m -CONFIG_IP_NF_FTP=m -CONFIG_IP_NF_IRC=m -CONFIG_IP_NF_TFTP=m -CONFIG_IP_NF_AMANDA=m -CONFIG_IP_NF_QUEUE=m -CONFIG_IP_NF_IPTABLES=m -CONFIG_IP_NF_MATCH_LIMIT=m -CONFIG_IP_NF_MATCH_IPRANGE=m -CONFIG_IP_NF_MATCH_MAC=m -CONFIG_IP_NF_MATCH_PKTTYPE=m -CONFIG_IP_NF_MATCH_MARK=m -CONFIG_IP_NF_MATCH_MULTIPORT=m -CONFIG_IP_NF_MATCH_TOS=m -CONFIG_IP_NF_MATCH_RECENT=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_DSCP=m -CONFIG_IP_NF_MATCH_AH_ESP=m -CONFIG_IP_NF_MATCH_LENGTH=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_MATCH_TCPMSS=m -CONFIG_IP_NF_MATCH_HELPER=m -CONFIG_IP_NF_MATCH_STATE=m -CONFIG_IP_NF_MATCH_CONNTRACK=m -CONFIG_IP_NF_MATCH_OWNER=m -CONFIG_IP_NF_MATCH_ADDRTYPE=m -CONFIG_IP_NF_MATCH_REALM=m -CONFIG_IP_NF_MATCH_SCTP=m -CONFIG_IP_NF_MATCH_COMMENT=m -CONFIG_IP_NF_MATCH_CONNMARK=m -CONFIG_IP_NF_MATCH_HASHLIMIT=m -CONFIG_IP_NF_FILTER=m -CONFIG_IP_NF_TARGET_REJECT=m -CONFIG_IP_NF_TARGET_LOG=m -CONFIG_IP_NF_TARGET_ULOG=m -CONFIG_IP_NF_TARGET_TCPMSS=m -CONFIG_IP_NF_NAT=m -CONFIG_IP_NF_NAT_NEEDED=y -CONFIG_IP_NF_TARGET_MASQUERADE=m -CONFIG_IP_NF_TARGET_REDIRECT=m -CONFIG_IP_NF_TARGET_NETMAP=m -CONFIG_IP_NF_TARGET_SAME=m -CONFIG_IP_NF_NAT_SNMP_BASIC=m -CONFIG_IP_NF_NAT_IRC=m -CONFIG_IP_NF_NAT_FTP=m -CONFIG_IP_NF_NAT_TFTP=m -CONFIG_IP_NF_NAT_AMANDA=m -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_TOS=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_DSCP=m -CONFIG_IP_NF_TARGET_MARK=m -CONFIG_IP_NF_TARGET_CLASSIFY=m -CONFIG_IP_NF_TARGET_CONNMARK=m -CONFIG_IP_NF_TARGET_CLUSTERIP=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_TARGET_NOTRACK=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_SCHED is not set -CONFIG_NET_CLS_ROUTE=y - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -CONFIG_NETPOLL=y -# CONFIG_NETPOLL_RX is not set -# CONFIG_NETPOLL_TRAP is not set -CONFIG_NET_POLL_CONTROLLER=y -# CONFIG_HAMRADIO is not set -CONFIG_IRDA=m - -# -# IrDA protocols -# -CONFIG_IRLAN=m -CONFIG_IRNET=m -CONFIG_IRCOMM=m -# CONFIG_IRDA_ULTRA is not set - -# -# IrDA options -# -CONFIG_IRDA_CACHE_LAST_LSAP=y -CONFIG_IRDA_FAST_RR=y -# CONFIG_IRDA_DEBUG is not set - -# -# Infrared-port device drivers -# - -# -# SIR device drivers -# -CONFIG_IRTTY_SIR=m - -# -# Dongle support -# -# CONFIG_DONGLE is not set - -# -# Old SIR device drivers -# -# CONFIG_IRPORT_SIR is not set - -# -# Old Serial dongle support -# - -# -# FIR device drivers -# -# CONFIG_USB_IRDA is not set -# CONFIG_SIGMATEL_FIR is not set -# CONFIG_NSC_FIR is not set -# CONFIG_WINBOND_FIR is not set -# CONFIG_TOSHIBA_FIR is not set -# CONFIG_SMC_IRCC_FIR is not set -# CONFIG_ALI_FIR is not set -# CONFIG_VLSI_FIR is not set -# CONFIG_VIA_FIR is not set -# CONFIG_BT is not set - -# -# Device Drivers -# - -# -# Generic Driver Options -# -# CONFIG_STANDALONE is not set -CONFIG_PREVENT_FIRMWARE_BUILD=y -CONFIG_FW_LOADER=m -# CONFIG_DEBUG_DRIVER is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set - -# -# Plug and Play support -# - -# -# Block devices -# -# CONFIG_BLK_DEV_FD is not set -CONFIG_MAC_FLOPPY=m -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_UMEM is not set -# CONFIG_BLK_DEV_COW_COMMON is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_SX8 is not set -# CONFIG_BLK_DEV_UB is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=16 -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" -CONFIG_LBD=y -CONFIG_CDROM_PKTCDVD=m -CONFIG_CDROM_PKTCDVD_BUFFERS=8 -# CONFIG_CDROM_PKTCDVD_WCACHE is not set - -# -# IO Schedulers -# -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_ATA_OVER_ETH is not set - -# -# ATA/ATAPI/MFM/RLL support -# -CONFIG_IDE=y -CONFIG_BLK_DEV_IDE=y - -# -# Please see Documentation/ide.txt for help/info on IDE drives -# -# CONFIG_BLK_DEV_IDE_SATA is not set -CONFIG_BLK_DEV_IDEDISK=y -# CONFIG_IDEDISK_MULTI_MODE is not set -# CONFIG_BLK_DEV_IDECS is not set -CONFIG_BLK_DEV_IDECD=y -# CONFIG_BLK_DEV_IDETAPE is not set -CONFIG_BLK_DEV_IDEFLOPPY=y -CONFIG_BLK_DEV_IDESCSI=y -# CONFIG_IDE_TASK_IOCTL is not set - -# -# IDE chipset support/bugfixes -# -# CONFIG_IDE_GENERIC is not set -CONFIG_BLK_DEV_IDEPCI=y -CONFIG_IDEPCI_SHARE_IRQ=y -# CONFIG_BLK_DEV_OFFBOARD is not set -CONFIG_BLK_DEV_GENERIC=y -# CONFIG_BLK_DEV_OPTI621 is not set -# CONFIG_BLK_DEV_SL82C105 is not set -CONFIG_BLK_DEV_IDEDMA_PCI=y -# CONFIG_BLK_DEV_IDEDMA_FORCED is not set -CONFIG_IDEDMA_PCI_AUTO=y -# CONFIG_IDEDMA_ONLYDISK is not set -# CONFIG_BLK_DEV_AEC62XX is not set -# CONFIG_BLK_DEV_ALI15X3 is not set -# CONFIG_BLK_DEV_AMD74XX is not set -CONFIG_BLK_DEV_CMD64X=y -# CONFIG_BLK_DEV_TRIFLEX is not set -# CONFIG_BLK_DEV_CY82C693 is not set -# CONFIG_BLK_DEV_CS5520 is not set -# CONFIG_BLK_DEV_CS5530 is not set -# CONFIG_BLK_DEV_HPT34X is not set -# CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_BLK_DEV_SC1200 is not set -# CONFIG_BLK_DEV_PIIX is not set -# CONFIG_BLK_DEV_IT821X is not set -# CONFIG_BLK_DEV_NS87415 is not set -# CONFIG_BLK_DEV_PDC202XX_OLD is not set -CONFIG_BLK_DEV_PDC202XX_NEW=y -# CONFIG_PDC202XX_FORCE is not set -# CONFIG_BLK_DEV_SVWKS is not set -# CONFIG_BLK_DEV_SIIMAGE is not set -# CONFIG_BLK_DEV_SLC90E66 is not set -# CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set -CONFIG_BLK_DEV_IDE_PMAC=y -CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y -CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_BLK_DEV_IDE_PMAC_BLINK=y -# CONFIG_IDE_ARM is not set -CONFIG_BLK_DEV_IDEDMA=y -# CONFIG_IDEDMA_IVB is not set -CONFIG_IDEDMA_AUTO=y -# CONFIG_BLK_DEV_HD is not set - -# -# SCSI device support -# -CONFIG_SCSI=y -CONFIG_SCSI_PROC_FS=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -# CONFIG_CHR_DEV_OSST is not set -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y -# CONFIG_CHR_DEV_SCH is not set - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_LOGGING is not set - -# -# SCSI Transport Attributes -# -CONFIG_SCSI_SPI_ATTRS=y -# CONFIG_SCSI_FC_ATTRS is not set -# CONFIG_SCSI_ISCSI_ATTRS is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_3W_9XXX is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AACRAID is not set -CONFIG_SCSI_AIC7XXX=m -CONFIG_AIC7XXX_CMDS_PER_DEVICE=253 -CONFIG_AIC7XXX_RESET_DELAY_MS=15000 -CONFIG_AIC7XXX_DEBUG_ENABLE=y -CONFIG_AIC7XXX_DEBUG_MASK=0 -CONFIG_AIC7XXX_REG_PRETTY_PRINT=y -CONFIG_SCSI_AIC7XXX_OLD=m -# CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_DPT_I2O is not set -# CONFIG_MEGARAID_NEWGEN is not set -# CONFIG_MEGARAID_LEGACY is not set -# CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_IPS is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set -CONFIG_SCSI_SYM53C8XX_2=y -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 -CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 -CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set -# CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -CONFIG_SCSI_QLA2XXX=y -# CONFIG_SCSI_QLA21XX is not set -# CONFIG_SCSI_QLA22XX is not set -# CONFIG_SCSI_QLA2300 is not set -# CONFIG_SCSI_QLA2322 is not set -# CONFIG_SCSI_QLA6312 is not set -# CONFIG_SCSI_LPFC is not set -# CONFIG_SCSI_DC395x is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_NSP32 is not set -# CONFIG_SCSI_DEBUG is not set -CONFIG_SCSI_MESH=y -CONFIG_SCSI_MESH_SYNC_RATE=5 -CONFIG_SCSI_MESH_RESET_DELAY_MS=1000 -CONFIG_SCSI_MAC53C94=y - -# -# PCMCIA SCSI adapter support -# -# CONFIG_PCMCIA_AHA152X is not set -# CONFIG_PCMCIA_FDOMAIN is not set -# CONFIG_PCMCIA_NINJA_SCSI is not set -# CONFIG_PCMCIA_QLOGIC is not set -# CONFIG_PCMCIA_SYM53C500 is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set -# CONFIG_FUSION_SPI is not set -# CONFIG_FUSION_FC is not set - -# -# IEEE 1394 (FireWire) support -# -CONFIG_IEEE1394=m - -# -# Subsystem Options -# -# CONFIG_IEEE1394_VERBOSEDEBUG is not set -# CONFIG_IEEE1394_OUI_DB is not set -CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y -CONFIG_IEEE1394_CONFIG_ROM_IP1394=y -# CONFIG_IEEE1394_EXPORT_FULL_API is not set - -# -# Device Drivers -# -# CONFIG_IEEE1394_PCILYNX is not set -CONFIG_IEEE1394_OHCI1394=m - -# -# Protocol Drivers -# -CONFIG_IEEE1394_VIDEO1394=m -CONFIG_IEEE1394_SBP2=m -# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set -CONFIG_IEEE1394_ETH1394=m -CONFIG_IEEE1394_DV1394=m -CONFIG_IEEE1394_RAWIO=m -CONFIG_IEEE1394_CMP=m -CONFIG_IEEE1394_AMDTP=m - -# -# I2O device support -# -# CONFIG_I2O is not set - -# -# Macintosh device drivers -# -CONFIG_ADB=y -CONFIG_ADB_CUDA=y -CONFIG_ADB_PMU=y -CONFIG_PMAC_APM_EMU=y -CONFIG_PMAC_MEDIABAY=y -CONFIG_PMAC_BACKLIGHT=y -CONFIG_ADB_MACIO=y -CONFIG_INPUT_ADBHID=y -CONFIG_MAC_EMUMOUSEBTN=y -CONFIG_THERM_WINDTUNNEL=m -CONFIG_THERM_ADT746X=m -# CONFIG_ANSLCD is not set - -# -# Network device support -# -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -CONFIG_TUN=m - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -CONFIG_MACE=y -# CONFIG_MACE_AAUI_PORT is not set -CONFIG_BMAC=y -# CONFIG_HAPPYMEAL is not set -CONFIG_SUNGEM=y -# CONFIG_NET_VENDOR_3COM is not set - -# -# Tulip family network device support -# -# CONFIG_NET_TULIP is not set -# CONFIG_HP100 is not set -CONFIG_NET_PCI=y -CONFIG_PCNET32=y -# CONFIG_AMD8111_ETH is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_B44 is not set -# CONFIG_FORCEDETH is not set -# CONFIG_DGRS is not set -# CONFIG_EEPRO100 is not set -# CONFIG_E100 is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_8139CP is not set -# CONFIG_8139TOO is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_E1000 is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_R8169 is not set -# CONFIG_SKGE is not set -# CONFIG_SK98LIN is not set -# CONFIG_VIA_VELOCITY is not set -# CONFIG_TIGON3 is not set -# CONFIG_BNX2 is not set -# CONFIG_MV643XX_ETH is not set - -# -# Ethernet (10000 Mbit) -# -# CONFIG_IXGB is not set -# CONFIG_S2IO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set - -# -# Wireless LAN (non-hamradio) -# -CONFIG_NET_RADIO=y - -# -# Obsolete Wireless cards support (pre-802.11) -# -# CONFIG_STRIP is not set -# CONFIG_PCMCIA_WAVELAN is not set -# CONFIG_PCMCIA_NETWAVE is not set - -# -# Wireless 802.11 Frequency Hopping cards support -# -# CONFIG_PCMCIA_RAYCS is not set - -# -# Wireless 802.11b ISA/PCI cards support -# -CONFIG_HERMES=m -CONFIG_APPLE_AIRPORT=m -# CONFIG_PLX_HERMES is not set -# CONFIG_TMD_HERMES is not set -# CONFIG_PCI_HERMES is not set -# CONFIG_ATMEL is not set - -# -# Wireless 802.11b Pcmcia/Cardbus cards support -# -CONFIG_PCMCIA_HERMES=m -# CONFIG_AIRO_CS is not set -# CONFIG_PCMCIA_WL3501 is not set - -# -# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support -# -# CONFIG_PRISM54 is not set -CONFIG_NET_WIRELESS=y - -# -# PCMCIA network device support -# -# CONFIG_NET_PCMCIA is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -CONFIG_PPP=y -CONFIG_PPP_MULTILINK=y -# CONFIG_PPP_FILTER is not set -CONFIG_PPP_ASYNC=y -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=y -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -# CONFIG_SLIP is not set -# CONFIG_NET_FC is not set -# CONFIG_SHAPER is not set -CONFIG_NETCONSOLE=m - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Telephony Support -# -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -# CONFIG_INPUT_MOUSEDEV_PSAUX is not set -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_EVBUG is not set - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -# CONFIG_KEYBOARD_ATKBD is not set -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -# CONFIG_KEYBOARD_NEWTON is not set -CONFIG_INPUT_MOUSE=y -# CONFIG_MOUSE_PS2 is not set -# CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_VSXXXAA is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -# CONFIG_INPUT_MISC is not set - -# -# Hardware I/O ports -# -# CONFIG_SERIO is not set -# CONFIG_GAMEPORT is not set - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=m -CONFIG_SERIAL_8250_CS=m -CONFIG_SERIAL_8250_NR_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -CONFIG_SERIAL_PMACZILOG=y -CONFIG_SERIAL_PMACZILOG_CONSOLE=y -# CONFIG_SERIAL_JSM is not set -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -CONFIG_NVRAM=y -CONFIG_GEN_RTC=y -# CONFIG_GEN_RTC_X is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -CONFIG_AGP=m -CONFIG_AGP_UNINORTH=m -CONFIG_DRM=m -# CONFIG_DRM_TDFX is not set -CONFIG_DRM_R128=m -CONFIG_DRM_RADEON=m -# CONFIG_DRM_MGA is not set -# CONFIG_DRM_SIS is not set -# CONFIG_DRM_VIA is not set - -# -# PCMCIA character devices -# -# CONFIG_SYNCLINK_CS is not set -# CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# -# CONFIG_TCG_TPM is not set - -# -# I2C support -# -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=m - -# -# I2C Algorithms -# -CONFIG_I2C_ALGOBIT=y -# CONFIG_I2C_ALGOPCF is not set -# CONFIG_I2C_ALGOPCA is not set - -# -# I2C Hardware Bus support -# -# CONFIG_I2C_ALI1535 is not set -# CONFIG_I2C_ALI1563 is not set -# CONFIG_I2C_ALI15X3 is not set -# CONFIG_I2C_AMD756 is not set -# CONFIG_I2C_AMD8111 is not set -# CONFIG_I2C_HYDRA is not set -# CONFIG_I2C_I801 is not set -# CONFIG_I2C_I810 is not set -# CONFIG_I2C_PIIX4 is not set -# CONFIG_I2C_ISA is not set -CONFIG_I2C_KEYWEST=m -# CONFIG_I2C_MPC is not set -# CONFIG_I2C_NFORCE2 is not set -# CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_PROSAVAGE is not set -# CONFIG_I2C_SAVAGE4 is not set -# CONFIG_SCx200_ACB is not set -# CONFIG_I2C_SIS5595 is not set -# CONFIG_I2C_SIS630 is not set -# CONFIG_I2C_SIS96X is not set -# CONFIG_I2C_STUB is not set -# CONFIG_I2C_VIA is not set -# CONFIG_I2C_VIAPRO is not set -# CONFIG_I2C_VOODOO3 is not set -# CONFIG_I2C_PCA_ISA is not set -# CONFIG_I2C_SENSOR is not set - -# -# Miscellaneous I2C Chip support -# -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -# CONFIG_SENSORS_EEPROM is not set -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 is not set -# CONFIG_SENSORS_M41T00 is not set -# CONFIG_SENSORS_MAX6875 is not set -# CONFIG_I2C_DEBUG_CORE is not set -# CONFIG_I2C_DEBUG_ALGO is not set -# CONFIG_I2C_DEBUG_BUS is not set -# CONFIG_I2C_DEBUG_CHIP is not set - -# -# Dallas's 1-wire bus -# -# CONFIG_W1 is not set - -# -# Hardware Monitoring support -# -# CONFIG_HWMON is not set - -# -# Misc devices -# - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# Graphics support -# -CONFIG_FB=y -CONFIG_FB_CFB_FILLRECT=y -CONFIG_FB_CFB_COPYAREA=y -CONFIG_FB_CFB_IMAGEBLIT=y -CONFIG_FB_SOFT_CURSOR=y -CONFIG_FB_MACMODES=y -CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_TILEBLITTING=y -# CONFIG_FB_CIRRUS is not set -# CONFIG_FB_PM2 is not set -# CONFIG_FB_CYBER2000 is not set -CONFIG_FB_OF=y -CONFIG_FB_CONTROL=y -CONFIG_FB_PLATINUM=y -CONFIG_FB_VALKYRIE=y -CONFIG_FB_CT65550=y -# CONFIG_FB_ASILIANT is not set -CONFIG_FB_IMSTT=y -# CONFIG_FB_VGA16 is not set -# CONFIG_FB_NVIDIA is not set -# CONFIG_FB_RIVA is not set -CONFIG_FB_MATROX=y -CONFIG_FB_MATROX_MILLENIUM=y -CONFIG_FB_MATROX_MYSTIQUE=y -CONFIG_FB_MATROX_G=y -# CONFIG_FB_MATROX_I2C is not set -# CONFIG_FB_MATROX_MULTIHEAD is not set -# CONFIG_FB_RADEON_OLD is not set -CONFIG_FB_RADEON=y -CONFIG_FB_RADEON_I2C=y -# CONFIG_FB_RADEON_DEBUG is not set -CONFIG_FB_ATY128=y -CONFIG_FB_ATY=y -CONFIG_FB_ATY_CT=y -CONFIG_FB_ATY_GENERIC_LCD=y -# CONFIG_FB_ATY_XL_INIT is not set -CONFIG_FB_ATY_GX=y -# CONFIG_FB_SAVAGE is not set -# CONFIG_FB_SIS is not set -# CONFIG_FB_NEOMAGIC is not set -# CONFIG_FB_KYRO is not set -CONFIG_FB_3DFX=y -CONFIG_FB_3DFX_ACCEL=y -# CONFIG_FB_VOODOO1 is not set -# CONFIG_FB_TRIDENT is not set -# CONFIG_FB_S1D13XXX is not set -# CONFIG_FB_VIRTUAL is not set - -# -# Console display driver support -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE=y -# CONFIG_FONTS is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y - -# -# Logo configuration -# -CONFIG_LOGO=y -CONFIG_LOGO_LINUX_MONO=y -CONFIG_LOGO_LINUX_VGA16=y -CONFIG_LOGO_LINUX_CLUT224=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y -CONFIG_BACKLIGHT_DEVICE=y -CONFIG_LCD_CLASS_DEVICE=y -CONFIG_LCD_DEVICE=y - -# -# Sound -# -CONFIG_SOUND=m -CONFIG_DMASOUND_PMAC=m -CONFIG_DMASOUND=m - -# -# Advanced Linux Sound Architecture -# -CONFIG_SND=m -CONFIG_SND_TIMER=m -CONFIG_SND_PCM=m -CONFIG_SND_HWDEP=m -CONFIG_SND_RAWMIDI=m -CONFIG_SND_SEQUENCER=m -CONFIG_SND_SEQ_DUMMY=m -CONFIG_SND_OSSEMUL=y -CONFIG_SND_MIXER_OSS=m -CONFIG_SND_PCM_OSS=m -CONFIG_SND_SEQUENCER_OSS=y -# CONFIG_SND_VERBOSE_PRINTK is not set -# CONFIG_SND_DEBUG is not set - -# -# Generic devices -# -CONFIG_SND_DUMMY=m -# CONFIG_SND_VIRMIDI is not set -# CONFIG_SND_MTPAV is not set -# CONFIG_SND_SERIAL_U16550 is not set -# CONFIG_SND_MPU401 is not set - -# -# PCI devices -# -# CONFIG_SND_ALI5451 is not set -# CONFIG_SND_ATIIXP is not set -# CONFIG_SND_ATIIXP_MODEM is not set -# CONFIG_SND_AU8810 is not set -# CONFIG_SND_AU8820 is not set -# CONFIG_SND_AU8830 is not set -# CONFIG_SND_AZT3328 is not set -# CONFIG_SND_BT87X is not set -# CONFIG_SND_CS46XX is not set -# CONFIG_SND_CS4281 is not set -# CONFIG_SND_EMU10K1 is not set -# CONFIG_SND_EMU10K1X is not set -# CONFIG_SND_CA0106 is not set -# CONFIG_SND_KORG1212 is not set -# CONFIG_SND_MIXART is not set -# CONFIG_SND_NM256 is not set -# CONFIG_SND_RME32 is not set -# CONFIG_SND_RME96 is not set -# CONFIG_SND_RME9652 is not set -# CONFIG_SND_HDSP is not set -# CONFIG_SND_HDSPM is not set -# CONFIG_SND_TRIDENT is not set -# CONFIG_SND_YMFPCI is not set -# CONFIG_SND_ALS4000 is not set -# CONFIG_SND_CMIPCI is not set -# CONFIG_SND_ENS1370 is not set -# CONFIG_SND_ENS1371 is not set -# CONFIG_SND_ES1938 is not set -# CONFIG_SND_ES1968 is not set -# CONFIG_SND_MAESTRO3 is not set -# CONFIG_SND_FM801 is not set -# CONFIG_SND_ICE1712 is not set -# CONFIG_SND_ICE1724 is not set -# CONFIG_SND_INTEL8X0 is not set -# CONFIG_SND_INTEL8X0M is not set -# CONFIG_SND_SONICVIBES is not set -# CONFIG_SND_VIA82XX is not set -# CONFIG_SND_VIA82XX_MODEM is not set -# CONFIG_SND_VX222 is not set -# CONFIG_SND_HDA_INTEL is not set - -# -# ALSA PowerMac devices -# -CONFIG_SND_POWERMAC=m - -# -# USB devices -# -CONFIG_SND_USB_AUDIO=m -CONFIG_SND_USB_USX2Y=m - -# -# PCMCIA devices -# - -# -# Open Sound System -# -# CONFIG_SOUND_PRIME is not set - -# -# USB support -# -CONFIG_USB_ARCH_HAS_HCD=y -CONFIG_USB_ARCH_HAS_OHCI=y -CONFIG_USB=y -# CONFIG_USB_DEBUG is not set - -# -# Miscellaneous USB options -# -CONFIG_USB_DEVICEFS=y -# CONFIG_USB_BANDWIDTH is not set -CONFIG_USB_DYNAMIC_MINORS=y -CONFIG_USB_SUSPEND=y -# CONFIG_USB_OTG is not set - -# -# USB Host Controller Drivers -# -# CONFIG_USB_EHCI_HCD is not set -# CONFIG_USB_ISP116X_HCD is not set -CONFIG_USB_OHCI_HCD=y -# CONFIG_USB_OHCI_BIG_ENDIAN is not set -CONFIG_USB_OHCI_LITTLE_ENDIAN=y -# CONFIG_USB_UHCI_HCD is not set -# CONFIG_USB_SL811_HCD is not set - -# -# USB Device Class drivers -# -# CONFIG_USB_AUDIO is not set -# CONFIG_USB_BLUETOOTH_TTY is not set -# CONFIG_USB_MIDI is not set -CONFIG_USB_ACM=m -CONFIG_USB_PRINTER=m - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# -# CONFIG_USB_STORAGE is not set - -# -# USB Input Devices -# -CONFIG_USB_HID=y -CONFIG_USB_HIDINPUT=y -# CONFIG_HID_FF is not set -CONFIG_USB_HIDDEV=y -# CONFIG_USB_AIPTEK is not set -# CONFIG_USB_WACOM is not set -# CONFIG_USB_ACECAD is not set -# CONFIG_USB_KBTAB is not set -# CONFIG_USB_POWERMATE is not set -# CONFIG_USB_MTOUCH is not set -# CONFIG_USB_ITMTOUCH is not set -# CONFIG_USB_EGALAX is not set -# CONFIG_USB_XPAD is not set -# CONFIG_USB_ATI_REMOTE is not set -# CONFIG_USB_KEYSPAN_REMOTE is not set - -# -# USB Imaging devices -# -# CONFIG_USB_MDC800 is not set -# CONFIG_USB_MICROTEK is not set - -# -# USB Multimedia devices -# -# CONFIG_USB_DABUSB is not set - -# -# Video4Linux support is needed for USB Multimedia device support -# - -# -# USB Network Adapters -# -# CONFIG_USB_CATC is not set -# CONFIG_USB_KAWETH is not set -CONFIG_USB_PEGASUS=m -# CONFIG_USB_RTL8150 is not set -# CONFIG_USB_USBNET is not set -# CONFIG_USB_ZD1201 is not set -# CONFIG_USB_MON is not set - -# -# USB port drivers -# - -# -# USB Serial Converter support -# -CONFIG_USB_SERIAL=m -# CONFIG_USB_SERIAL_GENERIC is not set -# CONFIG_USB_SERIAL_AIRPRIME is not set -# CONFIG_USB_SERIAL_BELKIN is not set -# CONFIG_USB_SERIAL_WHITEHEAT is not set -# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set -# CONFIG_USB_SERIAL_CP2101 is not set -# CONFIG_USB_SERIAL_CYPRESS_M8 is not set -# CONFIG_USB_SERIAL_EMPEG is not set -# CONFIG_USB_SERIAL_FTDI_SIO is not set -CONFIG_USB_SERIAL_VISOR=m -# CONFIG_USB_SERIAL_IPAQ is not set -# CONFIG_USB_SERIAL_IR is not set -# CONFIG_USB_SERIAL_EDGEPORT is not set -# CONFIG_USB_SERIAL_EDGEPORT_TI is not set -# CONFIG_USB_SERIAL_GARMIN is not set -# CONFIG_USB_SERIAL_IPW is not set -# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set -CONFIG_USB_SERIAL_KEYSPAN=m -CONFIG_USB_SERIAL_KEYSPAN_MPR=y -CONFIG_USB_SERIAL_KEYSPAN_USA28=y -CONFIG_USB_SERIAL_KEYSPAN_USA28X=y -CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y -CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y -CONFIG_USB_SERIAL_KEYSPAN_USA19=y -CONFIG_USB_SERIAL_KEYSPAN_USA18X=y -CONFIG_USB_SERIAL_KEYSPAN_USA19W=y -CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y -CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y -CONFIG_USB_SERIAL_KEYSPAN_USA49W=y -CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y -# CONFIG_USB_SERIAL_KLSI is not set -# CONFIG_USB_SERIAL_KOBIL_SCT is not set -# CONFIG_USB_SERIAL_MCT_U232 is not set -# CONFIG_USB_SERIAL_PL2303 is not set -# CONFIG_USB_SERIAL_HP4X is not set -# CONFIG_USB_SERIAL_SAFE is not set -# CONFIG_USB_SERIAL_TI is not set -# CONFIG_USB_SERIAL_CYBERJACK is not set -# CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OPTION is not set -# CONFIG_USB_SERIAL_OMNINET is not set -CONFIG_USB_EZUSB=y - -# -# USB Miscellaneous drivers -# -# CONFIG_USB_EMI62 is not set -# CONFIG_USB_EMI26 is not set -# CONFIG_USB_AUERSWALD is not set -# CONFIG_USB_RIO500 is not set -# CONFIG_USB_LEGOTOWER is not set -# CONFIG_USB_LCD is not set -# CONFIG_USB_LED is not set -# CONFIG_USB_CYTHERM is not set -# CONFIG_USB_PHIDGETKIT is not set -# CONFIG_USB_PHIDGETSERVO is not set -# CONFIG_USB_IDMOUSE is not set -# CONFIG_USB_LD is not set -# CONFIG_USB_TEST is not set - -# -# USB DSL modem support -# - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# MMC/SD Card support -# -# CONFIG_MMC is not set - -# -# InfiniBand support -# -# CONFIG_INFINIBAND is not set - -# -# SN Devices -# - -# -# File systems -# -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -# CONFIG_EXT2_FS_POSIX_ACL is not set -# CONFIG_EXT2_FS_SECURITY is not set -# CONFIG_EXT2_FS_XIP is not set -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_XATTR=y -# CONFIG_EXT3_FS_POSIX_ACL is not set -# CONFIG_EXT3_FS_SECURITY is not set -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -CONFIG_FS_MBCACHE=y -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -CONFIG_FS_POSIX_ACL=y - -# -# XFS support -# -# CONFIG_XFS_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_INOTIFY=y -# CONFIG_QUOTA is not set -CONFIG_DNOTIFY=y -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -CONFIG_UDF_FS=m -CONFIG_UDF_NLS=y - -# -# DOS/FAT/NT Filesystems -# -CONFIG_FAT_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_FAT_DEFAULT_CODEPAGE=437 -CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_SYSFS=y -CONFIG_DEVPTS_FS_XATTR=y -CONFIG_DEVPTS_FS_SECURITY=y -CONFIG_TMPFS=y -CONFIG_TMPFS_XATTR=y -CONFIG_TMPFS_SECURITY=y -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=m -CONFIG_HFSPLUS_FS=m -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -CONFIG_CRAMFS=m -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V3_ACL=y -# CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -CONFIG_NFSD=y -CONFIG_NFSD_V2_ACL=y -CONFIG_NFSD_V3=y -CONFIG_NFSD_V3_ACL=y -# CONFIG_NFSD_V4 is not set -CONFIG_NFSD_TCP=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -CONFIG_EXPORTFS=y -CONFIG_NFS_ACL_SUPPORT=y -CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y -# CONFIG_RPCSEC_GSS_KRB5 is not set -# CONFIG_RPCSEC_GSS_SPKM3 is not set -CONFIG_SMB_FS=m -# CONFIG_SMB_NLS_DEFAULT is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set - -# -# Partition Types -# -CONFIG_PARTITION_ADVANCED=y -# CONFIG_ACORN_PARTITION is not set -# CONFIG_OSF_PARTITION is not set -# CONFIG_AMIGA_PARTITION is not set -# CONFIG_ATARI_PARTITION is not set -CONFIG_MAC_PARTITION=y -CONFIG_MSDOS_PARTITION=y -# CONFIG_BSD_DISKLABEL is not set -# CONFIG_MINIX_SUBPARTITION is not set -# CONFIG_SOLARIS_X86_PARTITION is not set -# CONFIG_UNIXWARE_DISKLABEL is not set -# CONFIG_LDM_PARTITION is not set -# CONFIG_SGI_PARTITION is not set -# CONFIG_ULTRIX_PARTITION is not set -# CONFIG_SUN_PARTITION is not set -# CONFIG_EFI_PARTITION is not set - -# -# Native Language Support -# -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=m -CONFIG_NLS_ISO8859_1=m -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -CONFIG_NLS_ISO8859_15=m -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -CONFIG_NLS_UTF8=m - -# -# Library routines -# -CONFIG_CRC_CCITT=y -CONFIG_CRC32=y -# CONFIG_LIBCRC32C is not set -CONFIG_ZLIB_INFLATE=y -CONFIG_ZLIB_DEFLATE=y - -# -# Profiling support -# -# CONFIG_PROFILING is not set - -# -# Kernel hacking -# -# CONFIG_PRINTK_TIME is not set -CONFIG_DEBUG_KERNEL=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_LOG_BUF_SHIFT=16 -# CONFIG_SCHEDSTATS is not set -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set -# CONFIG_DEBUG_KOBJECT is not set -# CONFIG_DEBUG_INFO is not set -# CONFIG_DEBUG_FS is not set -# CONFIG_XMON is not set -# CONFIG_BDI_SWITCH is not set -CONFIG_BOOTX_TEXT=y - -# -# Security options -# -# CONFIG_KEYS is not set -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -# CONFIG_CRYPTO is not set - -# -# Hardware crypto devices -# diff --git a/arch/ppc/configs/power3_defconfig b/arch/ppc/configs/power3_defconfig deleted file mode 100644 index a1ef929bca59..000000000000 --- a/arch/ppc/configs/power3_defconfig +++ /dev/null @@ -1,1035 +0,0 @@ -# -# Automatically generated make config: don't edit -# -CONFIG_MMU=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y -CONFIG_HAVE_DEC_LOCK=y -CONFIG_PPC=y -CONFIG_PPC32=y -CONFIG_GENERIC_NVRAM=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y -CONFIG_CLEAN_COMPILE=y -# CONFIG_STANDALONE is not set - -# -# General setup -# -CONFIG_SWAP=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -# CONFIG_BSD_PROCESS_ACCT is not set -CONFIG_SYSCTL=y -# CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=15 -# CONFIG_HOTPLUG is not set -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -# CONFIG_EMBEDDED is not set -CONFIG_KALLSYMS=y -CONFIG_FUTEX=y -CONFIG_EPOLL=y -CONFIG_IOSCHED_NOOP=y -CONFIG_IOSCHED_AS=y -CONFIG_IOSCHED_DEADLINE=y -CONFIG_IOSCHED_CFQ=y -# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_OBSOLETE_MODPARM=y -# CONFIG_MODVERSIONS is not set -CONFIG_KMOD=y -CONFIG_STOP_MACHINE=y - -# -# Processor -# -# CONFIG_6xx is not set -# CONFIG_40x is not set -# CONFIG_44x is not set -CONFIG_POWER3=y -# CONFIG_POWER4 is not set -# CONFIG_8xx is not set -# CONFIG_CPU_FREQ is not set -CONFIG_PPC64BRIDGE=y -CONFIG_PPC_STD_MMU=y - -# -# Platform options -# -CONFIG_PPC_MULTIPLATFORM=y -# CONFIG_APUS is not set -# CONFIG_WILLOW is not set -# CONFIG_PCORE is not set -# CONFIG_POWERPMC250 is not set -# CONFIG_EV64260 is not set -# CONFIG_SPRUCE is not set -# CONFIG_LOPEC is not set -# CONFIG_MCPN765 is not set -# CONFIG_MVME5100 is not set -# CONFIG_PPLUS is not set -# CONFIG_PRPMC750 is not set -# CONFIG_PRPMC800 is not set -# CONFIG_SANDPOINT is not set -# CONFIG_ADIR is not set -# CONFIG_K2 is not set -# CONFIG_PAL4 is not set -# CONFIG_GEMINI is not set -# CONFIG_EST8260 is not set -# CONFIG_SBS8260 is not set -# CONFIG_RPX6 is not set -# CONFIG_TQM8260 is not set -CONFIG_PPC_CHRP=y -CONFIG_PPC_PMAC=y -CONFIG_PPC_PREP=y -CONFIG_PPC_OF=y -CONFIG_PPCBUG_NVRAM=y -CONFIG_SMP=y -# CONFIG_IRQ_ALL_CPUS is not set -CONFIG_NR_CPUS=32 -# CONFIG_PREEMPT is not set -CONFIG_HIGHMEM=y -CONFIG_KERNEL_ELF=y -CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y -CONFIG_PROC_DEVICETREE=y -CONFIG_PPC_RTAS=y -# CONFIG_PREP_RESIDUAL is not set -# CONFIG_CMDLINE_BOOL is not set - -# -# Bus options -# -CONFIG_ISA=y -CONFIG_GENERIC_ISA_DMA=y -CONFIG_PCI=y -CONFIG_PCI_DOMAINS=y -CONFIG_PCI_LEGACY_PROC=y -CONFIG_PCI_NAMES=y - -# -# Advanced setup -# -CONFIG_ADVANCED_OPTIONS=y -# CONFIG_HIGHMEM_START_BOOL is not set -CONFIG_HIGHMEM_START=0xfe000000 -# CONFIG_LOWMEM_SIZE_BOOL is not set -CONFIG_LOWMEM_SIZE=0x30000000 -# CONFIG_KERNEL_START_BOOL is not set -CONFIG_KERNEL_START=0xc0000000 -CONFIG_TASK_SIZE_BOOL=y -CONFIG_TASK_SIZE=0xc0000000 -CONFIG_BOOT_LOAD=0x00800000 - -# -# Device Drivers -# - -# -# Generic Driver Options -# - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Parallel port support -# -CONFIG_PARPORT=m -CONFIG_PARPORT_PC=m -CONFIG_PARPORT_PC_CML1=m -# CONFIG_PARPORT_SERIAL is not set -CONFIG_PARPORT_PC_FIFO=y -# CONFIG_PARPORT_PC_SUPERIO is not set -# CONFIG_PARPORT_OTHER is not set -# CONFIG_PARPORT_1284 is not set - -# -# Plug and Play support -# -# CONFIG_PNP is not set - -# -# Block devices -# -CONFIG_BLK_DEV_FD=y -# CONFIG_BLK_DEV_XD is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_CPQ_DA is not set -# CONFIG_BLK_CPQ_CISS_DA is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_BLK_DEV_UMEM is not set -CONFIG_BLK_DEV_LOOP=y -# CONFIG_BLK_DEV_CRYPTOLOOP is not set -# CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_CARMEL is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y -CONFIG_LBD=y - -# -# ATA/ATAPI/MFM/RLL support -# -# CONFIG_IDE is not set - -# -# SCSI device support -# -CONFIG_SCSI=y -CONFIG_SCSI_PROC_FS=y - -# -# SCSI support type (disk, tape, CD-ROM) -# -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -# CONFIG_CHR_DEV_OSST is not set -CONFIG_BLK_DEV_SR=y -CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y - -# -# Some SCSI devices (e.g. CD jukebox) support multiple LUNs -# -# CONFIG_SCSI_MULTI_LUN is not set -# CONFIG_SCSI_REPORT_LUNS is not set -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y - -# -# SCSI Transport Attributes -# -CONFIG_SCSI_SPI_ATTRS=y -# CONFIG_SCSI_FC_ATTRS is not set - -# -# SCSI low-level drivers -# -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set -# CONFIG_SCSI_7000FASST is not set -# CONFIG_SCSI_ACARD is not set -# CONFIG_SCSI_AHA152X is not set -# CONFIG_SCSI_AHA1542 is not set -# CONFIG_SCSI_AACRAID is not set -# CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_AIC7XXX_OLD is not set -# CONFIG_SCSI_AIC79XX is not set -# CONFIG_SCSI_ADVANSYS is not set -# CONFIG_SCSI_IN2000 is not set -# CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_SATA is not set -# CONFIG_SCSI_BUSLOGIC is not set -# CONFIG_SCSI_CPQFCTS is not set -# CONFIG_SCSI_DMX3191D is not set -# CONFIG_SCSI_DTC3280 is not set -# CONFIG_SCSI_EATA is not set -# CONFIG_SCSI_EATA_PIO is not set -# CONFIG_SCSI_FUTURE_DOMAIN is not set -# CONFIG_SCSI_GDTH is not set -# CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set -# CONFIG_SCSI_IPS is not set -# CONFIG_SCSI_INIA100 is not set -# CONFIG_SCSI_PPA is not set -# CONFIG_SCSI_IMM is not set -# CONFIG_SCSI_NCR53C406A is not set -CONFIG_SCSI_SYM53C8XX_2=y -CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 -CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 -CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 -# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set -# CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_PAS16 is not set -# CONFIG_SCSI_PSI240I is not set -# CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -CONFIG_SCSI_QLA2XXX=y -# CONFIG_SCSI_QLA21XX is not set -# CONFIG_SCSI_QLA22XX is not set -# CONFIG_SCSI_QLA2300 is not set -# CONFIG_SCSI_QLA2322 is not set -# CONFIG_SCSI_QLA6312 is not set -# CONFIG_SCSI_QLA6322 is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_DC395x is not set -# CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_T128 is not set -# CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_NSP32 is not set -# CONFIG_SCSI_DEBUG is not set -# CONFIG_SCSI_MESH is not set -# CONFIG_SCSI_MAC53C94 is not set - -# -# Old CD-ROM drivers (not SCSI, not IDE) -# -# CONFIG_CD_NO_IDESCSI is not set - -# -# Multi-device support (RAID and LVM) -# -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -CONFIG_MD_RAID0=y -CONFIG_MD_RAID1=y -CONFIG_MD_RAID5=y -CONFIG_MD_RAID6=y -# CONFIG_MD_MULTIPATH is not set -CONFIG_BLK_DEV_DM=y -CONFIG_DM_CRYPT=y - -# -# Fusion MPT device support -# -# CONFIG_FUSION is not set - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set - -# -# I2O device support -# -# CONFIG_I2O is not set - -# -# Macintosh device drivers -# -# CONFIG_ADB is not set -# CONFIG_ADB_CUDA is not set -# CONFIG_ADB_PMU is not set -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set - -# -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -# CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP is not set -# CONFIG_ATM is not set -# CONFIG_BRIDGE is not set -# CONFIG_VLAN_8021Q is not set -# CONFIG_DECNET is not set -# CONFIG_LLC2 is not set -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network testing -# -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set -CONFIG_NETDEVICES=y -# CONFIG_DUMMY is not set -# CONFIG_BONDING is not set -# CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set - -# -# Ethernet (10 or 100Mbit) -# -CONFIG_NET_ETHERNET=y -CONFIG_MII=y -# CONFIG_MACE is not set -# CONFIG_BMAC is not set -# CONFIG_OAKNET is not set -# CONFIG_HAPPYMEAL is not set -# CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set -# CONFIG_LANCE is not set -# CONFIG_NET_VENDOR_SMC is not set -# CONFIG_NET_VENDOR_RACAL is not set - -# -# Tulip family network device support -# -# CONFIG_NET_TULIP is not set -# CONFIG_AT1700 is not set -# CONFIG_DEPCA is not set -# CONFIG_HP100 is not set -# CONFIG_NET_ISA is not set -CONFIG_NET_PCI=y -CONFIG_PCNET32=y -# CONFIG_AMD8111_ETH is not set -# CONFIG_ADAPTEC_STARFIRE is not set -# CONFIG_AC3200 is not set -# CONFIG_APRICOT is not set -# CONFIG_B44 is not set -# CONFIG_FORCEDETH is not set -# CONFIG_CS89x0 is not set -# CONFIG_DGRS is not set -# CONFIG_EEPRO100 is not set -CONFIG_E100=y -# CONFIG_E100_NAPI is not set -# CONFIG_FEALNX is not set -# CONFIG_NATSEMI is not set -# CONFIG_NE2K_PCI is not set -# CONFIG_8139CP is not set -# CONFIG_8139TOO is not set -# CONFIG_SIS900 is not set -# CONFIG_EPIC100 is not set -# CONFIG_SUNDANCE is not set -# CONFIG_TLAN is not set -# CONFIG_VIA_RHINE is not set -# CONFIG_NET_POCKET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -CONFIG_E1000=y -# CONFIG_E1000_NAPI is not set -# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_R8169 is not set -# CONFIG_SK98LIN is not set -# CONFIG_TIGON3 is not set - -# -# Ethernet (10000 Mbit) -# -# CONFIG_IXGB is not set -# CONFIG_S2IO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -# CONFIG_PLIP is not set -# CONFIG_PPP is not set -# CONFIG_SLIP is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -# CONFIG_SHAPER is not set -# CONFIG_NETCONSOLE is not set - -# -# ISDN subsystem -# -# CONFIG_ISDN is not set - -# -# Telephony Support -# -# CONFIG_PHONE is not set - -# -# Input device support -# -CONFIG_INPUT=y - -# -# Userland interfaces -# -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_PSAUX=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_INPUT_EVBUG is not set - -# -# Input I/O drivers -# -CONFIG_GAMEPORT=m -CONFIG_SOUND_GAMEPORT=m -# CONFIG_GAMEPORT_NS558 is not set -# CONFIG_GAMEPORT_L4 is not set -# CONFIG_GAMEPORT_EMU10K1 is not set -# CONFIG_GAMEPORT_VORTEX is not set -# CONFIG_GAMEPORT_FM801 is not set -# CONFIG_GAMEPORT_CS461x is not set -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -CONFIG_SERIO_SERPORT=y -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PARKBD is not set -# CONFIG_SERIO_PCIPS2 is not set - -# -# Input Device Drivers -# -CONFIG_INPUT_KEYBOARD=y -CONFIG_KEYBOARD_ATKBD=y -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -# CONFIG_KEYBOARD_NEWTON is not set -CONFIG_INPUT_MOUSE=y -CONFIG_MOUSE_PS2=y -# CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_INPORT is not set -# CONFIG_MOUSE_LOGIBM is not set -# CONFIG_MOUSE_PC110PAD is not set -# CONFIG_MOUSE_VSXXXAA is not set -# CONFIG_INPUT_JOYSTICK is not set -# CONFIG_INPUT_TOUCHSCREEN is not set -CONFIG_INPUT_MISC=y -CONFIG_INPUT_UINPUT=y - -# -# Character devices -# -CONFIG_VT=y -CONFIG_VT_CONSOLE=y -CONFIG_HW_CONSOLE=y -# CONFIG_SERIAL_NONSTANDARD is not set - -# -# Serial drivers -# -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=4 -# CONFIG_SERIAL_8250_EXTENDED is not set - -# -# Non-8250 serial port support -# -CONFIG_SERIAL_CORE=y -CONFIG_SERIAL_CORE_CONSOLE=y -# CONFIG_SERIAL_PMACZILOG is not set -CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 -CONFIG_PRINTER=m -# CONFIG_LP_CONSOLE is not set -# CONFIG_PPDEV is not set -# CONFIG_TIPAR is not set -# CONFIG_QIC02_TAPE is not set - -# -# IPMI -# -# CONFIG_IPMI_HANDLER is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -CONFIG_NVRAM=y -CONFIG_GEN_RTC=y -# CONFIG_GEN_RTC_X is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_AGP is not set -# CONFIG_DRM is not set -# CONFIG_RAW_DRIVER is not set - -# -# I2C support -# -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y - -# -# I2C Algorithms -# -CONFIG_I2C_ALGOBIT=y -CONFIG_I2C_ALGOPCF=y - -# -# I2C Hardware Bus support -# -# CONFIG_I2C_ALI1535 is not set -# CONFIG_I2C_ALI1563 is not set -# CONFIG_I2C_ALI15X3 is not set -# CONFIG_I2C_AMD756 is not set -# CONFIG_I2C_AMD8111 is not set -# CONFIG_I2C_HYDRA is not set -# CONFIG_I2C_I801 is not set -# CONFIG_I2C_I810 is not set -# CONFIG_I2C_ISA is not set -# CONFIG_I2C_KEYWEST is not set -# CONFIG_I2C_NFORCE2 is not set -# CONFIG_I2C_PARPORT is not set -# CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_PIIX4 is not set -# CONFIG_I2C_PROSAVAGE is not set -# CONFIG_I2C_SAVAGE4 is not set -# CONFIG_SCx200_ACB is not set -# CONFIG_I2C_SIS5595 is not set -# CONFIG_I2C_SIS630 is not set -# CONFIG_I2C_SIS96X is not set -# CONFIG_I2C_VIA is not set -# CONFIG_I2C_VIAPRO is not set -# CONFIG_I2C_VOODOO3 is not set - -# -# Hardware Sensors Chip support -# -# CONFIG_I2C_SENSOR is not set -# CONFIG_SENSORS_ADM1021 is not set -# CONFIG_SENSORS_ASB100 is not set -# CONFIG_SENSORS_DS1621 is not set -# CONFIG_SENSORS_FSCHER is not set -# CONFIG_SENSORS_GL518SM is not set -# CONFIG_SENSORS_IT87 is not set -# CONFIG_SENSORS_LM75 is not set -# CONFIG_SENSORS_LM78 is not set -# CONFIG_SENSORS_LM80 is not set -# CONFIG_SENSORS_LM83 is not set -# CONFIG_SENSORS_LM85 is not set -# CONFIG_SENSORS_LM90 is not set -# CONFIG_SENSORS_VIA686A is not set -# CONFIG_SENSORS_W83781D is not set -# CONFIG_SENSORS_W83L785TS is not set -# CONFIG_SENSORS_W83627HF is not set - -# -# Other I2C Chip support -# -# CONFIG_SENSORS_EEPROM is not set -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_I2C_DEBUG_CORE is not set -# CONFIG_I2C_DEBUG_ALGO is not set -# CONFIG_I2C_DEBUG_BUS is not set -# CONFIG_I2C_DEBUG_CHIP is not set - -# -# Misc devices -# - -# -# Multimedia devices -# -# CONFIG_VIDEO_DEV is not set - -# -# Digital Video Broadcasting Devices -# -# CONFIG_DVB is not set - -# -# Graphics support -# -CONFIG_FB=y -# CONFIG_FB_PM2 is not set -# CONFIG_FB_CYBER2000 is not set -CONFIG_FB_OF=y -# CONFIG_FB_CONTROL is not set -# CONFIG_FB_PLATINUM is not set -# CONFIG_FB_VALKYRIE is not set -# CONFIG_FB_CT65550 is not set -# CONFIG_FB_IMSTT is not set -# CONFIG_FB_S3TRIO is not set -# CONFIG_FB_VGA16 is not set -# CONFIG_FB_RIVA is not set -CONFIG_FB_MATROX=y -CONFIG_FB_MATROX_MILLENIUM=y -CONFIG_FB_MATROX_MYSTIQUE=y -# CONFIG_FB_MATROX_G450 is not set -CONFIG_FB_MATROX_G100A=y -CONFIG_FB_MATROX_G100=y -CONFIG_FB_MATROX_I2C=y -# CONFIG_FB_MATROX_MAVEN is not set -CONFIG_FB_MATROX_MULTIHEAD=y -# CONFIG_FB_RADEON_OLD is not set -# CONFIG_FB_RADEON is not set -# CONFIG_FB_ATY128 is not set -# CONFIG_FB_ATY is not set -# CONFIG_FB_SIS is not set -# CONFIG_FB_NEOMAGIC is not set -# CONFIG_FB_KYRO is not set -# CONFIG_FB_3DFX is not set -# CONFIG_FB_VOODOO1 is not set -# CONFIG_FB_TRIDENT is not set -# CONFIG_FB_VIRTUAL is not set - -# -# Console display driver support -# -# CONFIG_VGA_CONSOLE is not set -# CONFIG_MDA_CONSOLE is not set -CONFIG_DUMMY_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_PCI_CONSOLE=y -# CONFIG_FONTS is not set -CONFIG_FONT_8x8=y -CONFIG_FONT_8x16=y - -# -# Logo configuration -# -CONFIG_LOGO=y -CONFIG_LOGO_LINUX_MONO=y -CONFIG_LOGO_LINUX_VGA16=y -CONFIG_LOGO_LINUX_CLUT224=y - -# -# Sound -# -CONFIG_SOUND=y -# CONFIG_DMASOUND_PMAC is not set - -# -# Advanced Linux Sound Architecture -# -CONFIG_SND=m -CONFIG_SND_TIMER=m -CONFIG_SND_PCM=m -CONFIG_SND_HWDEP=m -CONFIG_SND_RAWMIDI=m -CONFIG_SND_SEQUENCER=m -CONFIG_SND_SEQ_DUMMY=m -CONFIG_SND_OSSEMUL=y -CONFIG_SND_MIXER_OSS=m -CONFIG_SND_PCM_OSS=m -CONFIG_SND_SEQUENCER_OSS=y -# CONFIG_SND_VERBOSE_PRINTK is not set -# CONFIG_SND_DEBUG is not set - -# -# Generic devices -# -CONFIG_SND_MPU401_UART=m -CONFIG_SND_OPL3_LIB=m -CONFIG_SND_DUMMY=m -# CONFIG_SND_VIRMIDI is not set -# CONFIG_SND_MTPAV is not set -# CONFIG_SND_SERIAL_U16550 is not set -# CONFIG_SND_MPU401 is not set - -# -# ISA devices -# -# CONFIG_SND_AD1848 is not set -# CONFIG_SND_CS4231 is not set -CONFIG_SND_CS4232=m -# CONFIG_SND_CS4236 is not set -# CONFIG_SND_ES1688 is not set -# CONFIG_SND_ES18XX is not set -# CONFIG_SND_GUSCLASSIC is not set -# CONFIG_SND_GUSEXTREME is not set -# CONFIG_SND_GUSMAX is not set -# CONFIG_SND_INTERWAVE is not set -# CONFIG_SND_INTERWAVE_STB is not set -# CONFIG_SND_OPTI92X_AD1848 is not set -# CONFIG_SND_OPTI92X_CS4231 is not set -# CONFIG_SND_OPTI93X is not set -# CONFIG_SND_SB8 is not set -# CONFIG_SND_SB16 is not set -# CONFIG_SND_SBAWE is not set -# CONFIG_SND_WAVEFRONT is not set -# CONFIG_SND_CMI8330 is not set -# CONFIG_SND_OPL3SA2 is not set -# CONFIG_SND_SGALAXY is not set -# CONFIG_SND_SSCAPE is not set - -# -# PCI devices -# -CONFIG_SND_AC97_CODEC=m -# CONFIG_SND_ALI5451 is not set -# CONFIG_SND_ATIIXP is not set -# CONFIG_SND_AU8810 is not set -# CONFIG_SND_AU8820 is not set -# CONFIG_SND_AU8830 is not set -# CONFIG_SND_AZT3328 is not set -# CONFIG_SND_BT87X is not set -CONFIG_SND_CS46XX=m -# CONFIG_SND_CS46XX_NEW_DSP is not set -CONFIG_SND_CS4281=m -# CONFIG_SND_EMU10K1 is not set -# CONFIG_SND_KORG1212 is not set -# CONFIG_SND_MIXART is not set -# CONFIG_SND_NM256 is not set -# CONFIG_SND_RME32 is not set -# CONFIG_SND_RME96 is not set -# CONFIG_SND_RME9652 is not set -# CONFIG_SND_HDSP is not set -# CONFIG_SND_TRIDENT is not set -# CONFIG_SND_YMFPCI is not set -# CONFIG_SND_ALS4000 is not set -# CONFIG_SND_CMIPCI is not set -# CONFIG_SND_ENS1370 is not set -# CONFIG_SND_ENS1371 is not set -# CONFIG_SND_ES1938 is not set -# CONFIG_SND_ES1968 is not set -# CONFIG_SND_MAESTRO3 is not set -# CONFIG_SND_FM801 is not set -# CONFIG_SND_ICE1712 is not set -# CONFIG_SND_ICE1724 is not set -# CONFIG_SND_INTEL8X0 is not set -# CONFIG_SND_INTEL8X0M is not set -# CONFIG_SND_SONICVIBES is not set -# CONFIG_SND_VIA82XX is not set -# CONFIG_SND_VX222 is not set - -# -# ALSA PowerMac devices -# -# CONFIG_SND_POWERMAC is not set - -# -# Open Sound System -# -# CONFIG_SOUND_PRIME is not set - -# -# USB support -# -# CONFIG_USB is not set - -# -# USB Gadget Support -# -# CONFIG_USB_GADGET is not set - -# -# File systems -# -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set -# CONFIG_EXT3_FS is not set -# CONFIG_JBD is not set -# CONFIG_REISERFS_FS is not set -# CONFIG_JFS_FS is not set -# CONFIG_XFS_FS is not set -# CONFIG_MINIX_FS is not set -# CONFIG_ROMFS_FS is not set -# CONFIG_QUOTA is not set -# CONFIG_AUTOFS_FS is not set -# CONFIG_AUTOFS4_FS is not set - -# -# CD-ROM/DVD Filesystems -# -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -# CONFIG_ZISOFS is not set -# CONFIG_UDF_FS is not set - -# -# DOS/FAT/NT Filesystems -# -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -# CONFIG_NTFS_FS is not set - -# -# Pseudo filesystems -# -CONFIG_PROC_FS=y -CONFIG_PROC_KCORE=y -CONFIG_SYSFS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVPTS_FS_XATTR is not set -CONFIG_TMPFS=y -# CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y - -# -# Miscellaneous filesystems -# -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_HFSPLUS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_VXFS_FS is not set -# CONFIG_HPFS_FS is not set -# CONFIG_QNX4FS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_UFS_FS is not set - -# -# Network File Systems -# -CONFIG_NFS_FS=y -# CONFIG_NFS_V3 is not set -# CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set -CONFIG_NFSD=y -# CONFIG_NFSD_V3 is not set -# CONFIG_NFSD_TCP is not set -CONFIG_LOCKD=y -CONFIG_EXPORTFS=y -CONFIG_SUNRPC=y -# CONFIG_RPCSEC_GSS_KRB5 is not set -# CONFIG_SMB_FS is not set -# CONFIG_CIFS is not set -# CONFIG_NCP_FS is not set -# CONFIG_CODA_FS is not set -# CONFIG_AFS_FS is not set - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="iso8859-1" -CONFIG_NLS_CODEPAGE_437=y -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -CONFIG_NLS_ISO8859_1=y -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Library routines -# -CONFIG_CRC32=y -# CONFIG_LIBCRC32C is not set -CONFIG_ZLIB_INFLATE=m -CONFIG_ZLIB_DEFLATE=m - -# -# Kernel hacking -# -# CONFIG_DEBUG_KERNEL is not set -CONFIG_BOOTX_TEXT=y - -# -# Security options -# -# CONFIG_SECURITY is not set - -# -# Cryptographic options -# -CONFIG_CRYPTO=y -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_NULL=y -CONFIG_CRYPTO_MD4=m -CONFIG_CRYPTO_MD5=m -CONFIG_CRYPTO_SHA1=m -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_DES=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_TWOFISH=m -# CONFIG_CRYPTO_SERPENT is not set -CONFIG_CRYPTO_AES=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_ARC4=m -CONFIG_CRYPTO_DEFLATE=m -CONFIG_CRYPTO_MICHAEL_MIC=m -# CONFIG_CRYPTO_CRC32C is not set -# CONFIG_CRYPTO_TEST is not set diff --git a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/prep_defconfig similarity index 100% rename from arch/ppc/configs/common_defconfig rename to arch/ppc/configs/prep_defconfig diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index e399bbb969a4..466437f4bcbb 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -1,48 +1,24 @@ # # Makefile for the linux kernel. # -ifneq ($(CONFIG_PPC_MERGE),y) - extra-$(CONFIG_PPC_STD_MMU) := head.o extra-$(CONFIG_40x) := head_4xx.o extra-$(CONFIG_44x) := head_44x.o extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o extra-$(CONFIG_8xx) := head_8xx.o -extra-$(CONFIG_6xx) += idle_6xx.o extra-y += vmlinux.lds -obj-y := entry.o traps.o idle.o time.o misc.o \ +obj-y := entry.o traps.o time.o misc.o \ setup.o \ ppc_htab.o -obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o -obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o -obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o +obj-$(CONFIG_MODULES) += ppc_ksyms.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_RAPIDIO) += rio.o obj-$(CONFIG_KGDB) += ppc-stub.o obj-$(CONFIG_SMP) += smp.o smp-tbsync.o -obj-$(CONFIG_TAU) += temp.o -ifndef CONFIG_E200 -obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o -endif obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o ifndef CONFIG_MATH_EMULATION obj-$(CONFIG_8xx) += softemu8xx.o endif - -# These are here while we do the architecture merge - -else -obj-y := idle.o -obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o -obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o -obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-mapping.o -obj-$(CONFIG_KGDB) += ppc-stub.o -obj-$(CONFIG_TAU) += temp.o -ifndef CONFIG_E200 -obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o -endif -endif diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S index 3a2815978488..5891ecbdc703 100644 --- a/arch/ppc/kernel/entry.S +++ b/arch/ppc/kernel/entry.S @@ -135,10 +135,10 @@ transfer_to_handler: mfspr r11,SPRN_HID0 mtcr r11 BEGIN_FTR_SECTION - bt- 8,power_save_6xx_restore /* Check DOZE */ + bt- 8,4f /* Check DOZE */ END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) BEGIN_FTR_SECTION - bt- 9,power_save_6xx_restore /* Check NAP */ + bt- 9,4f /* Check NAP */ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) #endif /* CONFIG_6xx */ .globl transfer_to_handler_cont @@ -157,6 +157,10 @@ transfer_to_handler_cont: SYNC RFI /* jump to handler, enable MMU */ +#ifdef CONFIG_6xx +4: b power_save_6xx_restore +#endif + /* * On kernel stack overflow, load up an initial stack pointer * and call StackOverflow(regs), which should not return. @@ -926,55 +930,3 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) b 4b .comm ee_restarts,4 - -/* - * PROM code for specific machines follows. Put it - * here so it's easy to add arch-specific sections later. - * -- Cort - */ -#ifdef CONFIG_PPC_OF -/* - * On CHRP, the Run-Time Abstraction Services (RTAS) have to be - * called with the MMU off. - */ -_GLOBAL(enter_rtas) - stwu r1,-INT_FRAME_SIZE(r1) - mflr r0 - stw r0,INT_FRAME_SIZE+4(r1) - lis r4,rtas_data@ha - lwz r4,rtas_data@l(r4) - lis r6,1f@ha /* physical return address for rtas */ - addi r6,r6,1f@l - tophys(r6,r6) - tophys(r7,r1) - lis r8,rtas_entry@ha - lwz r8,rtas_entry@l(r8) - mfmsr r9 - stw r9,8(r1) - LOAD_MSR_KERNEL(r0,MSR_KERNEL) - SYNC /* disable interrupts so SRR0/1 */ - MTMSRD(r0) /* don't get trashed */ - li r9,MSR_KERNEL & ~(MSR_IR|MSR_DR) - mtlr r6 - CLR_TOP32(r7) - mtspr SPRN_SPRG2,r7 - mtspr SPRN_SRR0,r8 - mtspr SPRN_SRR1,r9 - RFI -1: tophys(r9,r1) - lwz r8,INT_FRAME_SIZE+4(r9) /* get return address */ - lwz r9,8(r9) /* original msr value */ - FIX_SRR1(r9,r0) - addi r1,r1,INT_FRAME_SIZE - li r0,0 - mtspr SPRN_SPRG2,r0 - mtspr SPRN_SRR0,r8 - mtspr SPRN_SRR1,r9 - RFI /* return to caller */ - - .globl machine_check_in_rtas -machine_check_in_rtas: - twi 31,0,0 - /* XXX load up BATs and panic */ - -#endif /* CONFIG_PPC_OF */ diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index 53ea845fb911..01303efeddad 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -37,19 +37,6 @@ #include #endif -#ifdef CONFIG_PPC64BRIDGE -#define LOAD_BAT(n, reg, RA, RB) \ - ld RA,(n*32)+0(reg); \ - ld RB,(n*32)+8(reg); \ - mtspr SPRN_IBAT##n##U,RA; \ - mtspr SPRN_IBAT##n##L,RB; \ - ld RA,(n*32)+16(reg); \ - ld RB,(n*32)+24(reg); \ - mtspr SPRN_DBAT##n##U,RA; \ - mtspr SPRN_DBAT##n##L,RB; \ - -#else /* CONFIG_PPC64BRIDGE */ - /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ #define LOAD_BAT(n, reg, RA, RB) \ /* see the comment for clear_bats() -- Cort */ \ @@ -66,7 +53,6 @@ mtspr SPRN_DBAT##n##U,RA; \ mtspr SPRN_DBAT##n##L,RB; \ 1: -#endif /* CONFIG_PPC64BRIDGE */ .text .stabs "arch/ppc/kernel/",N_SO,0,0,0f @@ -129,11 +115,6 @@ _start: .globl __start __start: -/* - * We have to do any OF calls before we map ourselves to KERNELBASE, - * because OF may have I/O devices mapped into that area - * (particularly on CHRP). - */ mr r31,r3 /* save parameters */ mr r30,r4 mr r29,r5 @@ -148,14 +129,6 @@ __start: */ bl early_init -/* - * On POWER4, we first need to tweak some CPU configuration registers - * like real mode cache inhibit or exception base - */ -#ifdef CONFIG_POWER4 - bl __970_cpu_preinit -#endif /* CONFIG_POWER4 */ - #ifdef CONFIG_APUS /* On APUS the __va/__pa constants need to be set to the correct * values before continuing. @@ -169,7 +142,6 @@ __start: */ bl mmu_off __after_mmu_off: -#ifndef CONFIG_POWER4 bl clear_bats bl flush_tlbs @@ -177,10 +149,6 @@ __after_mmu_off: #if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) bl setup_disp_bat #endif -#else /* CONFIG_POWER4 */ - bl reloc_offset - bl initial_mm_power4 -#endif /* CONFIG_POWER4 */ /* * Call setup_cpu for CPU 0 and initialize 6xx Idle @@ -192,18 +160,11 @@ __after_mmu_off: bl reloc_offset bl init_idle_6xx #endif /* CONFIG_6xx */ -#ifdef CONFIG_POWER4 - bl reloc_offset - bl init_idle_power4 -#endif /* CONFIG_POWER4 */ #ifndef CONFIG_APUS /* * We need to run with _start at physical address 0. - * On CHRP, we are loaded at 0x10000 since OF on CHRP uses - * the exception vectors at 0 (and therefore this copy - * overwrites OF's exception vectors with our own). * If the MMU is already turned on, we copy stuff to KERNELBASE, * otherwise we copy it to 0. */ @@ -358,51 +319,19 @@ i##n: \ #endif /* Machine check */ -/* - * On CHRP, this is complicated by the fact that we could get a - * machine check inside RTAS, and we have no guarantee that certain - * critical registers will have the values we expect. The set of - * registers that might have bad values includes all the GPRs - * and all the BATs. We indicate that we are in RTAS by putting - * a non-zero value, the address of the exception frame to use, - * in SPRG2. The machine check handler checks SPRG2 and uses its - * value if it is non-zero. If we ever needed to free up SPRG2, - * we could use a field in the thread_info or thread_struct instead. - * (Other exception handlers assume that r1 is a valid kernel stack - * pointer when we take an exception from supervisor mode.) - * -- paulus. - */ . = 0x200 mtspr SPRN_SPRG0,r10 mtspr SPRN_SPRG1,r11 mfcr r10 -#ifdef CONFIG_PPC_CHRP - mfspr r11,SPRN_SPRG2 - cmpwi 0,r11,0 - bne 7f -#endif /* CONFIG_PPC_CHRP */ EXCEPTION_PROLOG_1 7: EXCEPTION_PROLOG_2 addi r3,r1,STACK_FRAME_OVERHEAD -#ifdef CONFIG_PPC_CHRP - mfspr r4,SPRN_SPRG2 - cmpwi cr1,r4,0 - bne cr1,1f -#endif EXC_XFER_STD(0x200, machine_check_exception) -#ifdef CONFIG_PPC_CHRP -1: b machine_check_in_rtas -#endif /* Data access exception. */ . = 0x300 -#ifdef CONFIG_PPC64BRIDGE - b DataAccess -DataAccessCont: -#else DataAccess: EXCEPTION_PROLOG -#endif /* CONFIG_PPC64BRIDGE */ mfspr r10,SPRN_DSISR andis. r0,r10,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ @@ -414,21 +343,10 @@ DataAccess: mfspr r4,SPRN_DAR EXC_XFER_EE_LITE(0x300, handle_page_fault) -#ifdef CONFIG_PPC64BRIDGE -/* SLB fault on data access. */ - . = 0x380 - b DataSegment -#endif /* CONFIG_PPC64BRIDGE */ - /* Instruction access exception. */ . = 0x400 -#ifdef CONFIG_PPC64BRIDGE - b InstructionAccess -InstructionAccessCont: -#else InstructionAccess: EXCEPTION_PROLOG -#endif /* CONFIG_PPC64BRIDGE */ andis. r0,r9,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ li r3,0 /* into the hash table */ @@ -438,12 +356,6 @@ InstructionAccess: mr r5,r9 EXC_XFER_EE_LITE(0x400, handle_page_fault) -#ifdef CONFIG_PPC64BRIDGE -/* SLB fault on instruction access. */ - . = 0x480 - b InstructionSegment -#endif /* CONFIG_PPC64BRIDGE */ - /* External interrupt */ EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) @@ -708,15 +620,9 @@ DataStoreTLBMiss: EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE) EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE) EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) -#ifdef CONFIG_POWER4 - EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1700, Trap_17, altivec_assist_exception, EXC_XFER_EE) - EXCEPTION(0x1800, Trap_18, TAUException, EXC_XFER_STD) -#else /* !CONFIG_POWER4 */ EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE) EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD) EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) -#endif /* CONFIG_POWER4 */ EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE) EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE) @@ -754,28 +660,6 @@ AltiVecUnavailable: addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception) -#ifdef CONFIG_PPC64BRIDGE -DataAccess: - EXCEPTION_PROLOG - b DataAccessCont - -InstructionAccess: - EXCEPTION_PROLOG - b InstructionAccessCont - -DataSegment: - EXCEPTION_PROLOG - addi r3,r1,STACK_FRAME_OVERHEAD - mfspr r4,SPRN_DAR - stw r4,_DAR(r11) - EXC_XFER_STD(0x380, unknown_exception) - -InstructionSegment: - EXCEPTION_PROLOG - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x480, unknown_exception) -#endif /* CONFIG_PPC64BRIDGE */ - #ifdef CONFIG_ALTIVEC /* Note that the AltiVec support is closely modeled after the FP * support. Changes to one are likely to be applicable to the @@ -1048,13 +932,6 @@ __secondary_start_pmac_0: .globl __secondary_start __secondary_start: -#ifdef CONFIG_PPC64BRIDGE - mfmsr r0 - clrldi r0,r0,1 /* make sure it's in 32-bit mode */ - SYNC - MTMSRD(r0) - isync -#endif /* Copy some CPU settings from CPU 0 */ bl __restore_cpu_setup @@ -1065,10 +942,6 @@ __secondary_start: lis r3,-KERNELBASE@h bl init_idle_6xx #endif /* CONFIG_6xx */ -#ifdef CONFIG_POWER4 - lis r3,-KERNELBASE@h - bl init_idle_power4 -#endif /* CONFIG_POWER4 */ /* get current_thread_info and current */ lis r1,secondary_ti@ha @@ -1109,12 +982,12 @@ __secondary_start: * Those generic dummy functions are kept for CPUs not * included in CONFIG_6xx */ -#if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) +#if !defined(CONFIG_6xx) _GLOBAL(__save_cpu_setup) blr _GLOBAL(__restore_cpu_setup) blr -#endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */ +#endif /* !defined(CONFIG_6xx) */ /* @@ -1132,11 +1005,6 @@ load_up_mmu: tophys(r6,r6) lwz r6,_SDR1@l(r6) mtspr SPRN_SDR1,r6 -#ifdef CONFIG_PPC64BRIDGE - /* clear the ASR so we only use the pseudo-segment registers. */ - li r6,0 - mtasr r6 -#endif /* CONFIG_PPC64BRIDGE */ li r0,16 /* load up segment register values */ mtctr r0 /* for context 0 */ lis r3,0x2000 /* Ku = 1, VSID = 0 */ @@ -1145,7 +1013,7 @@ load_up_mmu: addi r3,r3,0x111 /* increment VSID */ addis r4,r4,0x1000 /* address of next segment */ bdnz 3b -#ifndef CONFIG_POWER4 + /* Load the BAT registers with the values set up by MMU_init. MMU_init takes care of whether we're on a 601 or not. */ mfpvr r3 @@ -1158,7 +1026,7 @@ load_up_mmu: LOAD_BAT(1,r3,r4,r5) LOAD_BAT(2,r3,r4,r5) LOAD_BAT(3,r3,r4,r5) -#endif /* CONFIG_POWER4 */ + blr /* @@ -1269,9 +1137,6 @@ _GLOBAL(set_context) li r4,0 isync 3: -#ifdef CONFIG_PPC64BRIDGE - slbie r4 -#endif /* CONFIG_PPC64BRIDGE */ mtsrin r3,r4 addi r3,r3,0x111 /* next VSID */ rlwinm r3,r3,0,8,3 /* clear out any overflow from VSID field */ @@ -1358,7 +1223,6 @@ mmu_off: sync RFI -#ifndef CONFIG_POWER4 /* * Use the first pair of BAT registers to map the 1st 16MB * of RAM to KERNELBASE. From this point on we can't safely @@ -1366,7 +1230,6 @@ mmu_off: */ initial_bats: lis r11,KERNELBASE@h -#ifndef CONFIG_PPC64BRIDGE mfspr r9,SPRN_PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ cmpwi 0,r9,1 @@ -1381,7 +1244,6 @@ initial_bats: mtspr SPRN_IBAT1L,r10 isync blr -#endif /* CONFIG_PPC64BRIDGE */ 4: tophys(r8,r11) #ifdef CONFIG_SMP @@ -1395,11 +1257,6 @@ initial_bats: ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ #endif /* CONFIG_APUS */ -#ifdef CONFIG_PPC64BRIDGE - /* clear out the high 32 bits in the BAT */ - clrldi r11,r11,32 - clrldi r8,r8,32 -#endif /* CONFIG_PPC64BRIDGE */ mtspr SPRN_DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ mtspr SPRN_DBAT0U,r11 /* bit in upper BAT register */ mtspr SPRN_IBAT0L,r8 @@ -1432,38 +1289,6 @@ setup_disp_bat: #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ -#else /* CONFIG_POWER4 */ -/* - * Load up the SDR1 and segment register values now - * since we don't have the BATs. - * Also make sure we are running in 32-bit mode. - */ - -initial_mm_power4: - addis r14,r3,_SDR1@ha /* get the value from _SDR1 */ - lwz r14,_SDR1@l(r14) /* assume hash table below 4GB */ - mtspr SPRN_SDR1,r14 - slbia - lis r4,0x2000 /* set pseudo-segment reg 12 */ - ori r5,r4,0x0ccc - mtsr 12,r5 -#if 0 - ori r5,r4,0x0888 /* set pseudo-segment reg 8 */ - mtsr 8,r5 /* (for access to serial port) */ -#endif -#ifdef CONFIG_BOOTX_TEXT - ori r5,r4,0x0999 /* set pseudo-segment reg 9 */ - mtsr 9,r5 /* (for access to screen) */ -#endif - mfmsr r0 - clrldi r0,r0,1 - sync - mtmsr r0 - isync - blr - -#endif /* CONFIG_POWER4 */ - #ifdef CONFIG_8260 /* Jump into the system reset for the rom. * We first disable the MMU, and then jump to the ROM reset address. diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c deleted file mode 100644 index 1be3ca5bae40..000000000000 --- a/arch/ppc/kernel/idle.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Idle daemon for PowerPC. Idle daemon will handle any action - * that needs to be taken when the system becomes idle. - * - * Written by Cort Dougan (cort@cs.nmt.edu). Subsequently hacked - * on by Tom Rini, Armin Kuster, Paul Mackerras and others. - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void default_idle(void) -{ - void (*powersave)(void); - - powersave = ppc_md.power_save; - - if (!need_resched()) { - if (powersave != NULL) - powersave(); -#ifdef CONFIG_SMP - else { - set_thread_flag(TIF_POLLING_NRFLAG); - while (!need_resched() && - !cpu_is_offline(smp_processor_id())) - barrier(); - clear_thread_flag(TIF_POLLING_NRFLAG); - } -#endif - } -} - -/* - * The body of the idle task. - */ -void cpu_idle(void) -{ - int cpu = smp_processor_id(); - - for (;;) { - while (!need_resched()) { - if (ppc_md.idle != NULL) - ppc_md.idle(); - else - default_idle(); - } - - if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) - cpu_die(); - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - } -} - -#if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx) -/* - * Register the sysctl to set/clear powersave_nap. - */ -extern int powersave_nap; - -static ctl_table powersave_nap_ctl_table[]={ - { - .ctl_name = KERN_PPC_POWERSAVE_NAP, - .procname = "powersave-nap", - .data = &powersave_nap, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { 0, }, -}; -static ctl_table powersave_nap_sysctl_root[] = { - { 1, "kernel", NULL, 0, 0755, powersave_nap_ctl_table, }, - { 0,}, -}; - -static int __init -register_powersave_nap_sysctl(void) -{ - register_sysctl_table(powersave_nap_sysctl_root, 0); - - return 0; -} - -__initcall(register_powersave_nap_sysctl); -#endif diff --git a/arch/ppc/kernel/idle_6xx.S b/arch/ppc/kernel/idle_6xx.S deleted file mode 100644 index 1a2194cf6828..000000000000 --- a/arch/ppc/kernel/idle_6xx.S +++ /dev/null @@ -1,233 +0,0 @@ -/* - * This file contains the power_save function for 6xx & 7xxx CPUs - * rewritten in assembler - * - * Warning ! This code assumes that if your machine has a 750fx - * it will have PLL 1 set to low speed mode (used during NAP/DOZE). - * if this is not the case some additional changes will have to - * be done to check a runtime var (a bit like powersave-nap) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#undef DEBUG - - .text - -/* - * Init idle, called at early CPU setup time from head.S for each CPU - * Make sure no rest of NAP mode remains in HID0, save default - * values for some CPU specific registers. Called with r24 - * containing CPU number and r3 reloc offset - */ -_GLOBAL(init_idle_6xx) -BEGIN_FTR_SECTION - mfspr r4,SPRN_HID0 - rlwinm r4,r4,0,10,8 /* Clear NAP */ - mtspr SPRN_HID0, r4 - b 1f -END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) - blr -1: - slwi r5,r24,2 - add r5,r5,r3 -BEGIN_FTR_SECTION - mfspr r4,SPRN_MSSCR0 - addis r6,r5, nap_save_msscr0@ha - stw r4,nap_save_msscr0@l(r6) -END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR) -BEGIN_FTR_SECTION - mfspr r4,SPRN_HID1 - addis r6,r5,nap_save_hid1@ha - stw r4,nap_save_hid1@l(r6) -END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX) - blr - -/* - * Here is the power_save_6xx function. This could eventually be - * split into several functions & changing the function pointer - * depending on the various features. - */ -_GLOBAL(ppc6xx_idle) - /* Check if we can nap or doze, put HID0 mask in r3 - */ - lis r3, 0 -BEGIN_FTR_SECTION - lis r3,HID0_DOZE@h -END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) -BEGIN_FTR_SECTION - /* We must dynamically check for the NAP feature as it - * can be cleared by CPU init after the fixups are done - */ - lis r4,cur_cpu_spec@ha - lwz r4,cur_cpu_spec@l(r4) - lwz r4,CPU_SPEC_FEATURES(r4) - andi. r0,r4,CPU_FTR_CAN_NAP - beq 1f - /* Now check if user or arch enabled NAP mode */ - lis r4,powersave_nap@ha - lwz r4,powersave_nap@l(r4) - cmpwi 0,r4,0 - beq 1f - lis r3,HID0_NAP@h -1: -END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) - cmpwi 0,r3,0 - beqlr - - /* Clear MSR:EE */ - mfmsr r7 - rlwinm r0,r7,0,17,15 - mtmsr r0 - - /* Check current_thread_info()->flags */ - rlwinm r4,r1,0,0,18 - lwz r4,TI_FLAGS(r4) - andi. r0,r4,_TIF_NEED_RESCHED - beq 1f - mtmsr r7 /* out of line this ? */ - blr -1: - /* Some pre-nap cleanups needed on some CPUs */ - andis. r0,r3,HID0_NAP@h - beq 2f -BEGIN_FTR_SECTION - /* Disable L2 prefetch on some 745x and try to ensure - * L2 prefetch engines are idle. As explained by errata - * text, we can't be sure they are, we just hope very hard - * that well be enough (sic !). At least I noticed Apple - * doesn't even bother doing the dcbf's here... - */ - mfspr r4,SPRN_MSSCR0 - rlwinm r4,r4,0,0,29 - sync - mtspr SPRN_MSSCR0,r4 - sync - isync - lis r4,KERNELBASE@h - dcbf 0,r4 - dcbf 0,r4 - dcbf 0,r4 - dcbf 0,r4 -END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR) -#ifdef DEBUG - lis r6,nap_enter_count@ha - lwz r4,nap_enter_count@l(r6) - addi r4,r4,1 - stw r4,nap_enter_count@l(r6) -#endif -2: -BEGIN_FTR_SECTION - /* Go to low speed mode on some 750FX */ - lis r4,powersave_lowspeed@ha - lwz r4,powersave_lowspeed@l(r4) - cmpwi 0,r4,0 - beq 1f - mfspr r4,SPRN_HID1 - oris r4,r4,0x0001 - mtspr SPRN_HID1,r4 -1: -END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX) - - /* Go to NAP or DOZE now */ - mfspr r4,SPRN_HID0 - lis r5,(HID0_NAP|HID0_SLEEP)@h -BEGIN_FTR_SECTION - oris r5,r5,HID0_DOZE@h -END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) - andc r4,r4,r5 - or r4,r4,r3 -BEGIN_FTR_SECTION - oris r4,r4,HID0_DPM@h /* that should be done once for all */ -END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) - mtspr SPRN_HID0,r4 -BEGIN_FTR_SECTION - DSSALL - sync -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) - ori r7,r7,MSR_EE /* Could be ommited (already set) */ - oris r7,r7,MSR_POW@h - sync - isync - mtmsr r7 - isync - sync - blr - -/* - * Return from NAP/DOZE mode, restore some CPU specific registers, - * we are called with DR/IR still off and r2 containing physical - * address of current. - */ -_GLOBAL(power_save_6xx_restore) - mfspr r11,SPRN_HID0 - rlwinm. r11,r11,0,10,8 /* Clear NAP & copy NAP bit !state to cr1 EQ */ - cror 4*cr1+eq,4*cr0+eq,4*cr0+eq -BEGIN_FTR_SECTION - rlwinm r11,r11,0,9,7 /* Clear DOZE */ -END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) - mtspr SPRN_HID0, r11 - -#ifdef DEBUG - beq cr1,1f - lis r11,(nap_return_count-KERNELBASE)@ha - lwz r9,nap_return_count@l(r11) - addi r9,r9,1 - stw r9,nap_return_count@l(r11) -1: -#endif - - rlwinm r9,r1,0,0,18 - tophys(r9,r9) - lwz r11,TI_CPU(r9) - slwi r11,r11,2 - /* Todo make sure all these are in the same page - * and load r22 (@ha part + CPU offset) only once - */ -BEGIN_FTR_SECTION - beq cr1,1f - addis r9,r11,(nap_save_msscr0-KERNELBASE)@ha - lwz r9,nap_save_msscr0@l(r9) - mtspr SPRN_MSSCR0, r9 - sync - isync -1: -END_FTR_SECTION_IFSET(CPU_FTR_NAP_DISABLE_L2_PR) -BEGIN_FTR_SECTION - addis r9,r11,(nap_save_hid1-KERNELBASE)@ha - lwz r9,nap_save_hid1@l(r9) - mtspr SPRN_HID1, r9 -END_FTR_SECTION_IFSET(CPU_FTR_DUAL_PLL_750FX) - b transfer_to_handler_cont - - .data - -_GLOBAL(nap_save_msscr0) - .space 4*NR_CPUS - -_GLOBAL(nap_save_hid1) - .space 4*NR_CPUS - -_GLOBAL(powersave_nap) - .long 0 -_GLOBAL(powersave_lowspeed) - .long 0 - -#ifdef DEBUG -_GLOBAL(nap_enter_count) - .space 4 -_GLOBAL(nap_return_count) - .space 4 -#endif diff --git a/arch/ppc/kernel/idle_power4.S b/arch/ppc/kernel/idle_power4.S deleted file mode 100644 index cc0d535365cd..000000000000 --- a/arch/ppc/kernel/idle_power4.S +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file contains the power_save function for 6xx & 7xxx CPUs - * rewritten in assembler - * - * Warning ! This code assumes that if your machine has a 750fx - * it will have PLL 1 set to low speed mode (used during NAP/DOZE). - * if this is not the case some additional changes will have to - * be done to check a runtime var (a bit like powersave-nap) - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#undef DEBUG - - .text - -/* - * Init idle, called at early CPU setup time from head.S for each CPU - * So nothing for now. Called with r24 containing CPU number and r3 - * reloc offset - */ - .globl init_idle_power4 -init_idle_power4: - blr - -/* - * Here is the power_save_6xx function. This could eventually be - * split into several functions & changing the function pointer - * depending on the various features. - */ - .globl power4_idle -power4_idle: -BEGIN_FTR_SECTION - blr -END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) - /* We must dynamically check for the NAP feature as it - * can be cleared by CPU init after the fixups are done - */ - lis r4,cur_cpu_spec@ha - lwz r4,cur_cpu_spec@l(r4) - lwz r4,CPU_SPEC_FEATURES(r4) - andi. r0,r4,CPU_FTR_CAN_NAP - beqlr - /* Now check if user or arch enabled NAP mode */ - lis r4,powersave_nap@ha - lwz r4,powersave_nap@l(r4) - cmpwi 0,r4,0 - beqlr - - /* Clear MSR:EE */ - mfmsr r7 - rlwinm r0,r7,0,17,15 - mtmsr r0 - - /* Check current_thread_info()->flags */ - rlwinm r4,r1,0,0,18 - lwz r4,TI_FLAGS(r4) - andi. r0,r4,_TIF_NEED_RESCHED - beq 1f - mtmsr r7 /* out of line this ? */ - blr -1: - /* Go to NAP now */ -BEGIN_FTR_SECTION - DSSALL - sync -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) - ori r7,r7,MSR_EE /* Could be ommited (already set) */ - oris r7,r7,MSR_POW@h - sync - isync - mtmsr r7 - isync - sync - blr - - .globl powersave_nap -powersave_nap: - .long 0 diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 04d04c5bfdd0..809673a36f7a 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -46,9 +46,6 @@ static void pcibios_fixup_resources(struct pci_dev* dev); static void fixup_broken_pcnet32(struct pci_dev* dev); static int reparent_resources(struct resource *parent, struct resource *res); static void fixup_cpc710_pci64(struct pci_dev* dev); -#ifdef CONFIG_PPC_OF -static u8* pci_to_OF_bus_map; -#endif /* By default, we don't re-assign bus numbers. */ @@ -625,406 +622,13 @@ pcibios_alloc_controller(void) return hose; } -#ifdef CONFIG_PPC_OF -/* - * Functions below are used on OpenFirmware machines. - */ -static void -make_one_node_map(struct device_node* node, u8 pci_bus) -{ - int *bus_range; - int len; - - if (pci_bus >= pci_bus_count) - return; - bus_range = (int *) get_property(node, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s, " - "assuming it starts at 0\n", node->full_name); - pci_to_OF_bus_map[pci_bus] = 0; - } else - pci_to_OF_bus_map[pci_bus] = bus_range[0]; - - for (node=node->child; node != 0;node = node->sibling) { - struct pci_dev* dev; - unsigned int *class_code, *reg; - - class_code = (unsigned int *) get_property(node, "class-code", NULL); - if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && - (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) - continue; - reg = (unsigned int *)get_property(node, "reg", NULL); - if (!reg) - continue; - dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff)); - if (!dev || !dev->subordinate) - continue; - make_one_node_map(node, dev->subordinate->number); - } -} - -void -pcibios_make_OF_bus_map(void) -{ - int i; - struct pci_controller* hose; - u8* of_prop_map; - - pci_to_OF_bus_map = (u8*)kmalloc(pci_bus_count, GFP_KERNEL); - if (!pci_to_OF_bus_map) { - printk(KERN_ERR "Can't allocate OF bus map !\n"); - return; - } - - /* We fill the bus map with invalid values, that helps - * debugging. - */ - for (i=0; inext) { - struct device_node* node; - node = (struct device_node *)hose->arch_data; - if (!node) - continue; - make_one_node_map(node, hose->first_busno); - } - of_prop_map = get_property(find_path_device("/"), "pci-OF-bus-map", NULL); - if (of_prop_map) - memcpy(of_prop_map, pci_to_OF_bus_map, pci_bus_count); -#ifdef DEBUG - printk("PCI->OF bus map:\n"); - for (i=0; i %d\n", i, pci_to_OF_bus_map[i]); - } -#endif -} - -typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data); - -static struct device_node* -scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data) -{ - struct device_node* sub_node; - - for (; node != 0;node = node->sibling) { - unsigned int *class_code; - - if (filter(node, data)) - return node; - - /* For PCI<->PCI bridges or CardBus bridges, we go down - * Note: some OFs create a parent node "multifunc-device" as - * a fake root for all functions of a multi-function device, - * we go down them as well. - */ - class_code = (unsigned int *) get_property(node, "class-code", NULL); - if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && - (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) && - strcmp(node->name, "multifunc-device")) - continue; - sub_node = scan_OF_pci_childs(node->child, filter, data); - if (sub_node) - return sub_node; - } - return NULL; -} - -static int -scan_OF_pci_childs_iterator(struct device_node* node, void* data) -{ - unsigned int *reg; - u8* fdata = (u8*)data; - - reg = (unsigned int *) get_property(node, "reg", NULL); - if (reg && ((reg[0] >> 8) & 0xff) == fdata[1] - && ((reg[0] >> 16) & 0xff) == fdata[0]) - return 1; - return 0; -} - -static struct device_node* -scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) -{ - u8 filter_data[2] = {bus, dev_fn}; - - return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data); -} - -/* - * Scans the OF tree for a device node matching a PCI device - */ -struct device_node * -pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) -{ - struct pci_controller *hose; - struct device_node *node; - int busnr; - - if (!have_of) - return NULL; - - /* Lookup the hose */ - busnr = bus->number; - hose = pci_bus_to_hose(busnr); - if (!hose) - return NULL; - - /* Check it has an OF node associated */ - node = (struct device_node *) hose->arch_data; - if (!node) - return NULL; - - /* Fixup bus number according to what OF think it is. */ - if (pci_to_OF_bus_map) - busnr = pci_to_OF_bus_map[busnr]; - if (busnr == 0xff) - return NULL; - - /* Now, lookup childs of the hose */ - return scan_OF_childs_for_device(node->child, busnr, devfn); -} -EXPORT_SYMBOL(pci_busdev_to_OF_node); - -struct device_node* -pci_device_to_OF_node(struct pci_dev *dev) -{ - return pci_busdev_to_OF_node(dev->bus, dev->devfn); -} -EXPORT_SYMBOL(pci_device_to_OF_node); - -/* This routine is meant to be used early during boot, when the - * PCI bus numbers have not yet been assigned, and you need to - * issue PCI config cycles to an OF device. - * It could also be used to "fix" RTAS config cycles if you want - * to set pci_assign_all_buses to 1 and still use RTAS for PCI - * config cycles. - */ -struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node) -{ - if (!have_of) - return NULL; - while(node) { - struct pci_controller* hose; - for (hose=hose_head;hose;hose=hose->next) - if (hose->arch_data == node) - return hose; - node=node->parent; - } - return NULL; -} - -static int -find_OF_pci_device_filter(struct device_node* node, void* data) -{ - return ((void *)node == data); -} - -/* - * Returns the PCI device matching a given OF node - */ -int -pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn) -{ - unsigned int *reg; - struct pci_controller* hose; - struct pci_dev* dev = NULL; - - if (!have_of) - return -ENODEV; - /* Make sure it's really a PCI device */ - hose = pci_find_hose_for_OF_device(node); - if (!hose || !hose->arch_data) - return -ENODEV; - if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child, - find_OF_pci_device_filter, (void *)node)) - return -ENODEV; - reg = (unsigned int *) get_property(node, "reg", NULL); - if (!reg) - return -ENODEV; - *bus = (reg[0] >> 16) & 0xff; - *devfn = ((reg[0] >> 8) & 0xff); - - /* Ok, here we need some tweak. If we have already renumbered - * all busses, we can't rely on the OF bus number any more. - * the pci_to_OF_bus_map is not enough as several PCI busses - * may match the same OF bus number. - */ - if (!pci_to_OF_bus_map) - return 0; - - for_each_pci_dev(dev) - if (pci_to_OF_bus_map[dev->bus->number] == *bus && - dev->devfn == *devfn) { - *bus = dev->bus->number; - pci_dev_put(dev); - return 0; - } - - return -ENODEV; -} -EXPORT_SYMBOL(pci_device_from_OF_node); - -void __init -pci_process_bridge_OF_ranges(struct pci_controller *hose, - struct device_node *dev, int primary) -{ - static unsigned int static_lc_ranges[256] __initdata; - unsigned int *dt_ranges, *lc_ranges, *ranges, *prev; - unsigned int size; - int rlen = 0, orig_rlen; - int memno = 0; - struct resource *res; - int np, na = prom_n_addr_cells(dev); - np = na + 5; - - /* First we try to merge ranges to fix a problem with some pmacs - * that can have more than 3 ranges, fortunately using contiguous - * addresses -- BenH - */ - dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen); - if (!dt_ranges) - return; - /* Sanity check, though hopefully that never happens */ - if (rlen > sizeof(static_lc_ranges)) { - printk(KERN_WARNING "OF ranges property too large !\n"); - rlen = sizeof(static_lc_ranges); - } - lc_ranges = static_lc_ranges; - memcpy(lc_ranges, dt_ranges, rlen); - orig_rlen = rlen; - - /* Let's work on a copy of the "ranges" property instead of damaging - * the device-tree image in memory - */ - ranges = lc_ranges; - prev = NULL; - while ((rlen -= np * sizeof(unsigned int)) >= 0) { - if (prev) { - if (prev[0] == ranges[0] && prev[1] == ranges[1] && - (prev[2] + prev[na+4]) == ranges[2] && - (prev[na+2] + prev[na+4]) == ranges[na+2]) { - prev[na+4] += ranges[na+4]; - ranges[0] = 0; - ranges += np; - continue; - } - } - prev = ranges; - ranges += np; - } - - /* - * The ranges property is laid out as an array of elements, - * each of which comprises: - * cells 0 - 2: a PCI address - * cells 3 or 3+4: a CPU physical address - * (size depending on dev->n_addr_cells) - * cells 4+5 or 5+6: the size of the range - */ - ranges = lc_ranges; - rlen = orig_rlen; - while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { - res = NULL; - size = ranges[na+4]; - switch ((ranges[0] >> 24) & 0x3) { - case 1: /* I/O space */ - if (ranges[2] != 0) - break; - hose->io_base_phys = ranges[na+2]; - /* limit I/O space to 16MB */ - if (size > 0x01000000) - size = 0x01000000; - hose->io_base_virt = ioremap(ranges[na+2], size); - if (primary) - isa_io_base = (unsigned long) hose->io_base_virt; - res = &hose->io_resource; - res->flags = IORESOURCE_IO; - res->start = ranges[2]; - DBG("PCI: IO 0x%lx -> 0x%lx\n", - res->start, res->start + size - 1); - break; - case 2: /* memory space */ - memno = 0; - if (ranges[1] == 0 && ranges[2] == 0 - && ranges[na+4] <= (16 << 20)) { - /* 1st 16MB, i.e. ISA memory area */ - if (primary) - isa_mem_base = ranges[na+2]; - memno = 1; - } - while (memno < 3 && hose->mem_resources[memno].flags) - ++memno; - if (memno == 0) - hose->pci_mem_offset = ranges[na+2] - ranges[2]; - if (memno < 3) { - res = &hose->mem_resources[memno]; - res->flags = IORESOURCE_MEM; - if(ranges[0] & 0x40000000) - res->flags |= IORESOURCE_PREFETCH; - res->start = ranges[na+2]; - DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno, - res->start, res->start + size - 1); - } - break; - } - if (res != NULL) { - res->name = dev->full_name; - res->end = res->start + size - 1; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; - } - ranges += np; - } -} - -/* We create the "pci-OF-bus-map" property now so it appears in the - * /proc device tree - */ -void __init -pci_create_OF_bus_map(void) -{ - struct property* of_prop; - - of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256); - if (of_prop && find_path_device("/")) { - memset(of_prop, -1, sizeof(struct property) + 256); - of_prop->name = "pci-OF-bus-map"; - of_prop->length = 256; - of_prop->value = (unsigned char *)&of_prop[1]; - prom_add_property(find_path_device("/"), of_prop); - } -} - -static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct pci_dev *pdev; - struct device_node *np; - - pdev = to_pci_dev (dev); - np = pci_device_to_OF_node(pdev); - if (np == NULL || np->full_name == NULL) - return 0; - return sprintf(buf, "%s", np->full_name); -} -static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL); - -#else /* CONFIG_PPC_OF */ void pcibios_make_OF_bus_map(void) { } -#endif /* CONFIG_PPC_OF */ /* Add sysfs properties */ void pcibios_add_platform_entries(struct pci_dev *pdev) { -#ifdef CONFIG_PPC_OF - device_create_file(&pdev->dev, &dev_attr_devspec); -#endif /* CONFIG_PPC_OF */ } diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index 9b84bffdefce..75c645043746 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -104,7 +104,7 @@ static char *pmc2_lookup(unsigned long mmcr0) static int ppc_htab_show(struct seq_file *m, void *v) { unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0; -#if defined(CONFIG_PPC_STD_MMU) && !defined(CONFIG_PPC64BRIDGE) +#if defined(CONFIG_PPC_STD_MMU) unsigned int kptes = 0, uptes = 0; PTE *ptr; #endif /* CONFIG_PPC_STD_MMU */ @@ -133,7 +133,6 @@ static int ppc_htab_show(struct seq_file *m, void *v) return 0; } -#ifndef CONFIG_PPC64BRIDGE for (ptr = Hash; ptr < Hash_end; ptr++) { unsigned int mctx, vsid; @@ -147,7 +146,6 @@ static int ppc_htab_show(struct seq_file *m, void *v) else uptes++; } -#endif seq_printf(m, "PTE Hash Table Information\n" @@ -155,20 +153,16 @@ static int ppc_htab_show(struct seq_file *m, void *v) "Buckets\t\t: %lu\n" "Address\t\t: %08lx\n" "Entries\t\t: %lu\n" -#ifndef CONFIG_PPC64BRIDGE "User ptes\t: %u\n" "Kernel ptes\t: %u\n" "Percent full\t: %lu%%\n" -#endif , (unsigned long)(Hash_size>>10), (Hash_size/(sizeof(PTE)*8)), (unsigned long)Hash, Hash_size/sizeof(PTE) -#ifndef CONFIG_PPC64BRIDGE , uptes, kptes, ((kptes+uptes)*100) / (Hash_size/sizeof(PTE)) -#endif ); seq_printf(m, diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 82adb4601348..865ba74991a9 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -30,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -208,27 +206,6 @@ EXPORT_SYMBOL(adb_try_handler_change); EXPORT_SYMBOL(cuda_request); EXPORT_SYMBOL(cuda_poll); #endif /* CONFIG_ADB_CUDA */ -#ifdef CONFIG_PPC_OF -EXPORT_SYMBOL(find_devices); -EXPORT_SYMBOL(find_type_devices); -EXPORT_SYMBOL(find_compatible_devices); -EXPORT_SYMBOL(find_path_device); -EXPORT_SYMBOL(device_is_compatible); -EXPORT_SYMBOL(machine_is_compatible); -EXPORT_SYMBOL(find_all_nodes); -EXPORT_SYMBOL(get_property); -EXPORT_SYMBOL(request_OF_resource); -EXPORT_SYMBOL(release_OF_resource); -EXPORT_SYMBOL(of_find_node_by_name); -EXPORT_SYMBOL(of_find_node_by_type); -EXPORT_SYMBOL(of_find_compatible_node); -EXPORT_SYMBOL(of_find_node_by_path); -EXPORT_SYMBOL(of_find_all_nodes); -EXPORT_SYMBOL(of_get_parent); -EXPORT_SYMBOL(of_get_next_child); -EXPORT_SYMBOL(of_node_get); -EXPORT_SYMBOL(of_node_put); -#endif /* CONFIG_PPC_OF */ #if defined(CONFIG_BOOTX_TEXT) EXPORT_SYMBOL(btext_update_display); #endif @@ -262,9 +239,6 @@ EXPORT_SYMBOL(console_drivers); EXPORT_SYMBOL(xmon); EXPORT_SYMBOL(xmon_printf); #endif -EXPORT_SYMBOL(__up); -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_interruptible); #if defined(CONFIG_KGDB) || defined(CONFIG_XMON) extern void (*debugger)(struct pt_regs *regs); diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 53e9deacee82..1f79e84ab464 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -1,5 +1,5 @@ /* - * Common prep/chrp boot and setup code. + * Common prep boot and setup code. */ #include @@ -72,17 +72,12 @@ unsigned long ISA_DMA_THRESHOLD; unsigned int DMA_MODE_READ; unsigned int DMA_MODE_WRITE; -#ifdef CONFIG_PPC_MULTIPLATFORM -int _machine = 0; -EXPORT_SYMBOL(_machine); - +#ifdef CONFIG_PPC_PREP extern void prep_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); -extern void chrp_init(unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, unsigned long r7); dev_t boot_dev; -#endif /* CONFIG_PPC_MULTIPLATFORM */ +#endif /* CONFIG_PPC_PREP */ int have_of; EXPORT_SYMBOL(have_of); @@ -319,72 +314,12 @@ early_init(int r3, int r4, int r5) identify_cpu(offset, 0); do_cpu_ftr_fixups(offset); -#if defined(CONFIG_PPC_OF) - reloc_got2(offset); - - /* - * don't do anything on prep - * for now, don't use bootinfo because it breaks yaboot 0.5 - * and assume that if we didn't find a magic number, we have OF - */ - if (*(unsigned long *)(0) != 0xdeadc0de) - phys = prom_init(r3, r4, (prom_entry)r5); - - reloc_got2(-offset); -#endif - return phys; } -#ifdef CONFIG_PPC_OF +#ifdef CONFIG_PPC_PREP /* - * Assume here that all clock rates are the same in a - * smp system. -- Cort - */ -int -of_show_percpuinfo(struct seq_file *m, int i) -{ - struct device_node *cpu_node; - u32 *fp; - int s; - - cpu_node = find_type_devices("cpu"); - if (!cpu_node) - return 0; - for (s = 0; s < i && cpu_node->next; s++) - cpu_node = cpu_node->next; - fp = (u32 *)get_property(cpu_node, "clock-frequency", NULL); - if (fp) - seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000); - return 0; -} - -void __init -intuit_machine_type(void) -{ - char *model; - struct device_node *root; - - /* ask the OF info if we're a chrp or pmac */ - root = find_path_device("/"); - if (root != 0) { - /* assume pmac unless proven to be chrp -- Cort */ - _machine = _MACH_Pmac; - model = get_property(root, "device_type", NULL); - if (model && !strncmp("chrp", model, 4)) - _machine = _MACH_chrp; - else { - model = get_property(root, "model", NULL); - if (model && !strncmp(model, "IBM", 3)) - _machine = _MACH_chrp; - } - } -} -#endif - -#ifdef CONFIG_PPC_MULTIPLATFORM -/* - * The PPC_MULTIPLATFORM version of platform_init... + * The PPC_PREP version of platform_init... */ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, @@ -399,161 +334,9 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, parse_bootinfo(find_bootinfo()); - /* if we didn't get any bootinfo telling us what we are... */ - if (_machine == 0) { - /* prep boot loader tells us if we're prep or not */ - if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) - _machine = _MACH_prep; - } - -#ifdef CONFIG_PPC_PREP - /* not much more to do here, if prep */ - if (_machine == _MACH_prep) { - prep_init(r3, r4, r5, r6, r7); - return; - } -#endif - -#ifdef CONFIG_PPC_OF - have_of = 1; - - /* prom_init has already been called from __start */ - if (boot_infos) - relocate_nodes(); - - /* If we aren't PReP, we can find out if we're Pmac - * or CHRP with this. */ - if (_machine == 0) - intuit_machine_type(); - - /* finish_device_tree may need _machine defined. */ - finish_device_tree(); - - /* - * If we were booted via quik, r3 points to the physical - * address of the command-line parameters. - * If we were booted from an xcoff image (i.e. netbooted or - * booted from floppy), we get the command line from the - * bootargs property of the /chosen node. - * If an initial ramdisk is present, r3 and r4 - * are used for initrd_start and initrd_size, - * otherwise they contain 0xdeadbeef. - */ - if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) { - strlcpy(cmd_line, (char *)r3 + KERNELBASE, - sizeof(cmd_line)); - } else if (boot_infos != 0) { - /* booted by BootX - check for ramdisk */ - if (boot_infos->kernelParamsOffset != 0) - strlcpy(cmd_line, (char *) boot_infos - + boot_infos->kernelParamsOffset, - sizeof(cmd_line)); -#ifdef CONFIG_BLK_DEV_INITRD - if (boot_infos->ramDisk) { - initrd_start = (unsigned long) boot_infos - + boot_infos->ramDisk; - initrd_end = initrd_start + boot_infos->ramDiskSize; - initrd_below_start_ok = 1; - } -#endif - } else { - struct device_node *chosen; - char *p; - -#ifdef CONFIG_BLK_DEV_INITRD - if (r3 && r4 && r4 != 0xdeadbeef) { - if (r3 < KERNELBASE) - r3 += KERNELBASE; - initrd_start = r3; - initrd_end = r3 + r4; - ROOT_DEV = Root_RAM0; - initrd_below_start_ok = 1; - } -#endif - chosen = find_devices("chosen"); - if (chosen != NULL) { - p = get_property(chosen, "bootargs", NULL); - if (p && *p) { - strlcpy(cmd_line, p, sizeof(cmd_line)); - } - } - } -#ifdef CONFIG_ADB - if (strstr(cmd_line, "adb_sync")) { - extern int __adb_probe_sync; - __adb_probe_sync = 1; - } -#endif /* CONFIG_ADB */ - - switch (_machine) { -#ifdef CONFIG_PPC_CHRP - case _MACH_chrp: - chrp_init(r3, r4, r5, r6, r7); - break; -#endif - } -#endif /* CONFIG_PPC_OF */ + prep_init(r3, r4, r5, r6, r7); } -#endif /* CONFIG_PPC_MULTIPLATFORM */ - -#ifdef CONFIG_PPC_OF -#ifdef CONFIG_SERIAL_CORE_CONSOLE -extern char *of_stdout_device; - -static int __init set_preferred_console(void) -{ - struct device_node *prom_stdout; - char *name; - int offset = 0; - - if (of_stdout_device == NULL) - return -ENODEV; - - /* The user has requested a console so this is already set up. */ - if (strstr(saved_command_line, "console=")) - return -EBUSY; - - prom_stdout = find_path_device(of_stdout_device); - if (!prom_stdout) - return -ENODEV; - - name = (char *)get_property(prom_stdout, "name", NULL); - if (!name) - return -ENODEV; - - if (strcmp(name, "serial") == 0) { - int i; - u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); - if (i > 8) { - switch (reg[1]) { - case 0x3f8: - offset = 0; - break; - case 0x2f8: - offset = 1; - break; - case 0x898: - offset = 2; - break; - case 0x890: - offset = 3; - break; - default: - /* We dont recognise the serial port */ - return -ENODEV; - } - } - } else if (strcmp(name, "ch-a") == 0) - offset = 0; - else if (strcmp(name, "ch-b") == 0) - offset = 1; - else - return -ENODEV; - return add_preferred_console("ttyS", offset, NULL); -} -console_initcall(set_preferred_console); -#endif /* CONFIG_SERIAL_CORE_CONSOLE */ -#endif /* CONFIG_PPC_OF */ +#endif /* CONFIG_PPC_PREP */ struct bi_record *find_bootinfo(void) { @@ -589,23 +372,6 @@ void parse_bootinfo(struct bi_record *rec) initrd_end = data[0] + data[1] + KERNELBASE; break; #endif /* CONFIG_BLK_DEV_INITRD */ -#ifdef CONFIG_PPC_MULTIPLATFORM - case BI_MACHTYPE: - /* Machine types changed with the merge. Since the - * bootinfo are now deprecated, we can just hard code - * the appropriate conversion here for when we are - * called with yaboot which passes us a machine type - * this way. - */ - switch(data[0]) { - case 1: _machine = _MACH_prep; break; - case 2: _machine = _MACH_Pmac; break; - case 4: _machine = _MACH_chrp; break; - default: - _machine = data[0]; - } - break; -#endif case BI_MEMSIZE: boot_mem_size = data[0]; break; @@ -631,9 +397,6 @@ machine_init(unsigned long r3, unsigned long r4, unsigned long r5, #ifdef CONFIG_6xx ppc_md.power_save = ppc6xx_idle; #endif -#ifdef CONFIG_POWER4 - ppc_md.power_save = power4_idle; -#endif platform_init(r3, r4, r5, r6, r7); @@ -711,7 +474,7 @@ int __init ppc_init(void) if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); /* register CPU devices */ - for_each_cpu(i) + for_each_possible_cpu(i) register_cpu(&cpu_devices[i], i, NULL); /* call platform init */ @@ -799,7 +562,4 @@ void __init setup_arch(char **cmdline_p) if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); paging_init(); - - /* this is for modules since _machine can be a define -- Cort */ - ppc_md.ppc_machine = _machine; } diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index e55cdda6149a..f77795a64dae 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -311,7 +311,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) /* Backup CPU 0 state */ __save_cpu_setup(); - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { if (cpu == smp_processor_id()) continue; /* create a process for the processor */ diff --git a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c index 36b521091bbc..3b0094cc2b52 100644 --- a/arch/ppc/lib/strcase.c +++ b/arch/ppc/lib/strcase.c @@ -1,4 +1,5 @@ #include +#include int strcasecmp(const char *s1, const char *s2) { @@ -11,7 +12,7 @@ int strcasecmp(const char *s1, const char *s2) return c1 - c2; } -int strncasecmp(const char *s1, const char *s2, int n) +int strncasecmp(const char *s1, const char *s2, size_t n) { int c1, c2; diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c index 0217188ef465..8e08ca32531a 100644 --- a/arch/ppc/mm/fault.c +++ b/arch/ppc/mm/fault.c @@ -202,6 +202,7 @@ good_area: /* an exec - 4xx/Book-E allows for per-page execute permission */ } else if (TRAP(regs) == 0x400) { pte_t *ptep; + pmd_t *pmdp; #if 0 /* It would be nice to actually enforce the VM execute @@ -215,21 +216,24 @@ good_area: /* Since 4xx/Book-E supports per-page execute permission, * we lazily flush dcache to icache. */ ptep = NULL; - if (get_pteptr(mm, address, &ptep) && pte_present(*ptep)) { - struct page *page = pte_page(*ptep); + if (get_pteptr(mm, address, &ptep, &pmdp)) { + spinlock_t *ptl = pte_lockptr(mm, pmdp); + spin_lock(ptl); + if (pte_present(*ptep)) { + struct page *page = pte_page(*ptep); - if (! test_bit(PG_arch_1, &page->flags)) { - flush_dcache_icache_page(page); - set_bit(PG_arch_1, &page->flags); + if (!test_bit(PG_arch_1, &page->flags)) { + flush_dcache_icache_page(page); + set_bit(PG_arch_1, &page->flags); + } + pte_update(ptep, 0, _PAGE_HWEXEC); + _tlbie(address); + pte_unmap_unlock(ptep, ptl); + up_read(&mm->mmap_sem); + return 0; } - pte_update(ptep, 0, _PAGE_HWEXEC); - _tlbie(address); - pte_unmap(ptep); - up_read(&mm->mmap_sem); - return 0; + pte_unmap_unlock(ptep, ptl); } - if (ptep != NULL) - pte_unmap(ptep); #endif /* a read */ } else { diff --git a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S index f09fa88db35a..31d0a924317c 100644 --- a/arch/ppc/mm/hashtable.S +++ b/arch/ppc/mm/hashtable.S @@ -74,12 +74,6 @@ _GLOBAL(hash_page_sync) */ .text _GLOBAL(hash_page) -#ifdef CONFIG_PPC64BRIDGE - mfmsr r0 - clrldi r0,r0,1 /* make sure it's in 32-bit mode */ - MTMSRD(r0) - isync -#endif tophys(r7,0) /* gets -KERNELBASE into r7 */ #ifdef CONFIG_SMP addis r8,r7,mmu_hash_lock@h @@ -303,7 +297,6 @@ Hash_base = 0xc0180000 Hash_bits = 12 /* e.g. 256kB hash table */ Hash_msk = (((1 << Hash_bits) - 1) * 64) -#ifndef CONFIG_PPC64BRIDGE /* defines for the PTE format for 32-bit PPCs */ #define PTE_SIZE 8 #define PTEG_SIZE 64 @@ -317,21 +310,6 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64) #define SET_V(r) oris r,r,PTE_V@h #define CLR_V(r,t) rlwinm r,r,0,1,31 -#else -/* defines for the PTE format for 64-bit PPCs */ -#define PTE_SIZE 16 -#define PTEG_SIZE 128 -#define LG_PTEG_SIZE 7 -#define LDPTEu ldu -#define STPTE std -#define CMPPTE cmpd -#define PTE_H 2 -#define PTE_V 1 -#define TST_V(r) andi. r,r,PTE_V -#define SET_V(r) ori r,r,PTE_V -#define CLR_V(r,t) li t,PTE_V; andc r,r,t -#endif /* CONFIG_PPC64BRIDGE */ - #define HASH_LEFT 31-(LG_PTEG_SIZE+Hash_bits-1) #define HASH_RIGHT 31-LG_PTEG_SIZE @@ -349,14 +327,8 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT) /* Construct the high word of the PPC-style PTE (r5) */ -#ifndef CONFIG_PPC64BRIDGE rlwinm r5,r3,7,1,24 /* put VSID in 0x7fffff80 bits */ rlwimi r5,r4,10,26,31 /* put in API (abbrev page index) */ -#else /* CONFIG_PPC64BRIDGE */ - clrlwi r3,r3,8 /* reduce vsid to 24 bits */ - sldi r5,r3,12 /* shift vsid into position */ - rlwimi r5,r4,16,20,24 /* put in API (abbrev page index) */ -#endif /* CONFIG_PPC64BRIDGE */ SET_V(r5) /* set V (valid) bit */ /* Get the address of the primary PTE group in the hash table (r3) */ @@ -540,14 +512,8 @@ _GLOBAL(flush_hash_pages) add r3,r3,r0 /* note code below trims to 24 bits */ /* Construct the high word of the PPC-style PTE (r11) */ -#ifndef CONFIG_PPC64BRIDGE rlwinm r11,r3,7,1,24 /* put VSID in 0x7fffff80 bits */ rlwimi r11,r4,10,26,31 /* put in API (abbrev page index) */ -#else /* CONFIG_PPC64BRIDGE */ - clrlwi r3,r3,8 /* reduce vsid to 24 bits */ - sldi r11,r3,12 /* shift vsid into position */ - rlwimi r11,r4,16,20,24 /* put in API (abbrev page index) */ -#endif /* CONFIG_PPC64BRIDGE */ SET_V(r11) /* set V (valid) bit */ #ifdef CONFIG_SMP diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index cb1c294fb932..386e000bcb73 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -412,14 +412,6 @@ void __init mem_init(void) } #endif /* CONFIG_BLK_DEV_INITRD */ -#ifdef CONFIG_PPC_OF - /* mark the RTAS pages as reserved */ - if ( rtas_data ) - for (addr = (ulong)__va(rtas_data); - addr < PAGE_ALIGN((ulong)__va(rtas_data)+rtas_size) ; - addr += PAGE_SIZE) - SetPageReserved(virt_to_page(addr)); -#endif for (addr = PAGE_OFFSET; addr < (unsigned long)high_memory; addr += PAGE_SIZE) { if (!PageReserved(virt_to_page(addr))) @@ -494,11 +486,6 @@ set_phys_avail(unsigned long total_memory) initrd_end - initrd_start, 1); } #endif /* CONFIG_BLK_DEV_INITRD */ -#ifdef CONFIG_PPC_OF - /* remove the RTAS pages from the available memory */ - if (rtas_data) - mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1); -#endif } /* Mark some memory as reserved by removing it from phys_avail. */ diff --git a/arch/ppc/mm/mmu_context.c b/arch/ppc/mm/mmu_context.c index a8816e0f6a86..b4a4b3f02a1c 100644 --- a/arch/ppc/mm/mmu_context.c +++ b/arch/ppc/mm/mmu_context.c @@ -2,7 +2,7 @@ * This file contains the routines for handling the MMU on those * PowerPC implementations where the MMU substantially follows the * architecture specification. This includes the 6xx, 7xx, 7xxx, - * 8260, and POWER3 implementations but excludes the 8xx and 4xx. + * 8260, and 83xx implementations but excludes the 8xx and 4xx. * -- paulus * * Derived from arch/ppc/mm/init.c: diff --git a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c index 6ea9185fd120..706bca8eb144 100644 --- a/arch/ppc/mm/pgtable.c +++ b/arch/ppc/mm/pgtable.c @@ -39,7 +39,7 @@ unsigned long ioremap_base; unsigned long ioremap_bot; int io_bat_index; -#if defined(CONFIG_6xx) || defined(CONFIG_POWER3) +#if defined(CONFIG_6xx) #define HAVE_BATS 1 #endif @@ -368,7 +368,7 @@ void __init io_block_mapping(unsigned long virt, phys_addr_t phys, * the PTE pointer is unmodified if PTE is not found. */ int -get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep) +get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp) { pgd_t *pgd; pmd_t *pmd; @@ -383,6 +383,8 @@ get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep) if (pte) { retval = 1; *ptep = pte; + if (pmdp) + *pmdp = pmd; /* XXX caller needs to do pte_unmap, yuck */ } } @@ -420,7 +422,7 @@ unsigned long iopa(unsigned long addr) mm = &init_mm; pa = 0; - if (get_pteptr(mm, addr, &pte)) { + if (get_pteptr(mm, addr, &pte, NULL)) { pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK); pte_unmap(pte); } diff --git a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c index 9a381ed5eb21..25bb6f3347c1 100644 --- a/arch/ppc/mm/ppc_mmu.c +++ b/arch/ppc/mm/ppc_mmu.c @@ -2,7 +2,7 @@ * This file contains the routines for handling the MMU on those * PowerPC implementations where the MMU substantially follows the * architecture specification. This includes the 6xx, 7xx, 7xxx, - * 8260, and POWER3 implementations but excludes the 8xx and 4xx. + * 8260, and 83xx implementations but excludes the 8xx and 4xx. * -- paulus * * Derived from arch/ppc/mm/init.c: @@ -42,11 +42,7 @@ unsigned long _SDR1; union ubat { /* BAT register values to be loaded */ BAT bat; -#ifdef CONFIG_PPC64BRIDGE - u64 word[2]; -#else u32 word[2]; -#endif } BATS[4][2]; /* 4 pairs of IBAT, DBAT */ struct batrange { /* stores address ranges mapped by BATs */ @@ -83,9 +79,6 @@ unsigned long p_mapped_by_bats(unsigned long pa) unsigned long __init mmu_mapin_ram(void) { -#ifdef CONFIG_POWER4 - return 0; -#else unsigned long tot, bl, done; unsigned long max_size = (256<<20); unsigned long align; @@ -122,7 +115,6 @@ unsigned long __init mmu_mapin_ram(void) } return done; -#endif } /* @@ -205,27 +197,10 @@ void __init MMU_init_hw(void) if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105); -#ifdef CONFIG_PPC64BRIDGE -#define LG_HPTEG_SIZE 7 /* 128 bytes per HPTEG */ -#define SDR1_LOW_BITS (lg_n_hpteg - 11) -#define MIN_N_HPTEG 2048 /* min 256kB hash table */ -#else #define LG_HPTEG_SIZE 6 /* 64 bytes per HPTEG */ #define SDR1_LOW_BITS ((n_hpteg - 1) >> 10) #define MIN_N_HPTEG 1024 /* min 64kB hash table */ -#endif -#ifdef CONFIG_POWER4 - /* The hash table has already been allocated and initialized - in prom.c */ - n_hpteg = Hash_size >> LG_HPTEG_SIZE; - lg_n_hpteg = __ilog2(n_hpteg); - - /* Remove the hash table from the available memory */ - if (Hash) - reserve_phys_mem(__pa(Hash), Hash_size); - -#else /* CONFIG_POWER4 */ /* * Allow 1 HPTE (1/8 HPTEG) for each page of memory. * This is less than the recommended amount, but then @@ -248,7 +223,6 @@ void __init MMU_init_hw(void) Hash = mem_pieces_find(Hash_size, Hash_size); cacheable_memzero(Hash, Hash_size); _SDR1 = __pa(Hash) | SDR1_LOW_BITS; -#endif /* CONFIG_POWER4 */ Hash_end = (PTE *) ((unsigned long)Hash + Hash_size); diff --git a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile index e8b91a33ce91..90c622294423 100644 --- a/arch/ppc/platforms/Makefile +++ b/arch/ppc/platforms/Makefile @@ -2,18 +2,10 @@ # Makefile for the linux kernel. # -# Extra CFLAGS so we don't have to do relative includes -CFLAGS_chrp_setup.o += -Iarch/$(ARCH)/mm - obj-$(CONFIG_APUS) += apus_setup.o ifeq ($(CONFIG_APUS),y) obj-$(CONFIG_PCI) += apus_pci.o endif -obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o \ - chrp_pegasos_eth.o -ifeq ($(CONFIG_PPC_CHRP),y) -obj-$(CONFIG_NVRAM) += chrp_nvram.o -endif obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_setup.o obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_PQ2ADS) += pq2ads.o @@ -40,7 +32,3 @@ obj-$(CONFIG_EV64360) += ev64360.o obj-$(CONFIG_MPC86XADS) += mpc866ads_setup.o obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o obj-$(CONFIG_ADS8272) += mpc8272ads_setup.o - -ifeq ($(CONFIG_SMP),y) -obj-$(CONFIG_PPC_CHRP) += chrp_smp.o -endif diff --git a/arch/ppc/platforms/chrp_nvram.c b/arch/ppc/platforms/chrp_nvram.c deleted file mode 100644 index 465ba9b090ef..000000000000 --- a/arch/ppc/platforms/chrp_nvram.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * c 2001 PPC 64 Team, IBM Corp - * - * 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. - * - * /dev/nvram driver for PPC - * - */ - -#include -#include -#include -#include -#include -#include -#include - -static unsigned int nvram_size; -static unsigned char nvram_buf[4]; -static DEFINE_SPINLOCK(nvram_lock); - -static unsigned char chrp_nvram_read(int addr) -{ - unsigned long done, flags; - unsigned char ret; - - if (addr >= nvram_size) { - printk(KERN_DEBUG "%s: read addr %d > nvram_size %u\n", - current->comm, addr, nvram_size); - return 0xff; - } - spin_lock_irqsave(&nvram_lock, flags); - if ((call_rtas("nvram-fetch", 3, 2, &done, addr, __pa(nvram_buf), 1) != 0) || 1 != done) - ret = 0xff; - else - ret = nvram_buf[0]; - spin_unlock_irqrestore(&nvram_lock, flags); - - return ret; -} - -static void chrp_nvram_write(int addr, unsigned char val) -{ - unsigned long done, flags; - - if (addr >= nvram_size) { - printk(KERN_DEBUG "%s: write addr %d > nvram_size %u\n", - current->comm, addr, nvram_size); - return; - } - spin_lock_irqsave(&nvram_lock, flags); - nvram_buf[0] = val; - if ((call_rtas("nvram-store", 3, 2, &done, addr, __pa(nvram_buf), 1) != 0) || 1 != done) - printk(KERN_DEBUG "rtas IO error storing 0x%02x at %d", val, addr); - spin_unlock_irqrestore(&nvram_lock, flags); -} - -void __init chrp_nvram_init(void) -{ - struct device_node *nvram; - unsigned int *nbytes_p, proplen; - - nvram = of_find_node_by_type(NULL, "nvram"); - if (nvram == NULL) - return; - - nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen); - if (nbytes_p == NULL || proplen != sizeof(unsigned int)) - return; - - nvram_size = *nbytes_p; - - printk(KERN_INFO "CHRP nvram contains %u bytes\n", nvram_size); - of_node_put(nvram); - - ppc_md.nvram_read_val = chrp_nvram_read; - ppc_md.nvram_write_val = chrp_nvram_write; - - return; -} diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c deleted file mode 100644 index c7fe6182bb77..000000000000 --- a/arch/ppc/platforms/chrp_pci.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * CHRP pci routines. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* LongTrail */ -void __iomem *gg2_pci_config_base; - -/* - * The VLSI Golden Gate II has only 512K of PCI configuration space, so we - * limit the bus number to 3 bits - */ - -int gg2_read_config(struct pci_bus *bus, unsigned int devfn, int off, - int len, u32 *val) -{ - volatile void __iomem *cfg_data; - struct pci_controller *hose = bus->sysdata; - - if (bus->number > 7) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that off is - * suitably aligned and that len is 1, 2 or 4. - */ - cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off); - switch (len) { - case 1: - *val = in_8(cfg_data); - break; - case 2: - *val = in_le16(cfg_data); - break; - default: - *val = in_le32(cfg_data); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -int gg2_write_config(struct pci_bus *bus, unsigned int devfn, int off, - int len, u32 val) -{ - volatile void __iomem *cfg_data; - struct pci_controller *hose = bus->sysdata; - - if (bus->number > 7) - return PCIBIOS_DEVICE_NOT_FOUND; - /* - * Note: the caller has already checked that off is - * suitably aligned and that len is 1, 2 or 4. - */ - cfg_data = hose->cfg_data + ((bus->number<<16) | (devfn<<8) | off); - switch (len) { - case 1: - out_8(cfg_data, val); - break; - case 2: - out_le16(cfg_data, val); - break; - default: - out_le32(cfg_data, val); - break; - } - return PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops gg2_pci_ops = -{ - gg2_read_config, - gg2_write_config -}; - -/* - * Access functions for PCI config space using RTAS calls. - */ -int -rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 *val) -{ - struct pci_controller *hose = bus->sysdata; - unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) - | (((bus->number - hose->first_busno) & 0xff) << 16) - | (hose->index << 24); - unsigned long ret = ~0UL; - int rval; - - rval = call_rtas("read-pci-config", 2, 2, &ret, addr, len); - *val = ret; - return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; -} - -int -rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 val) -{ - struct pci_controller *hose = bus->sysdata; - unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) - | (((bus->number - hose->first_busno) & 0xff) << 16) - | (hose->index << 24); - int rval; - - rval = call_rtas("write-pci-config", 3, 1, NULL, addr, len, val); - return rval? PCIBIOS_DEVICE_NOT_FOUND: PCIBIOS_SUCCESSFUL; -} - -static struct pci_ops rtas_pci_ops = -{ - rtas_read_config, - rtas_write_config -}; - -volatile struct Hydra __iomem *Hydra = NULL; - -int __init -hydra_init(void) -{ - struct device_node *np; - - np = find_devices("mac-io"); - if (np == NULL || np->n_addrs == 0) - return 0; - Hydra = ioremap(np->addrs[0].address, np->addrs[0].size); - printk("Hydra Mac I/O at %x\n", np->addrs[0].address); - printk("Hydra Feature_Control was %x", - in_le32(&Hydra->Feature_Control)); - out_le32(&Hydra->Feature_Control, (HYDRA_FC_SCC_CELL_EN | - HYDRA_FC_SCSI_CELL_EN | - HYDRA_FC_SCCA_ENABLE | - HYDRA_FC_SCCB_ENABLE | - HYDRA_FC_ARB_BYPASS | - HYDRA_FC_MPIC_ENABLE | - HYDRA_FC_SLOW_SCC_PCLK | - HYDRA_FC_MPIC_IS_MASTER)); - printk(", now %x\n", in_le32(&Hydra->Feature_Control)); - return 1; -} - -void __init -chrp_pcibios_fixup(void) -{ - struct pci_dev *dev = NULL; - struct device_node *np; - - /* PCI interrupts are controlled by the OpenPIC */ - for_each_pci_dev(dev) { - np = pci_device_to_OF_node(dev); - if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) - dev->irq = np->intrs[0].line; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } -} - -#define PRG_CL_RESET_VALID 0x00010000 - -static void __init -setup_python(struct pci_controller *hose, struct device_node *dev) -{ - u32 __iomem *reg; - u32 val; - unsigned long addr = dev->addrs[0].address; - - setup_indirect_pci(hose, addr + 0xf8000, addr + 0xf8010); - - /* Clear the magic go-slow bit */ - reg = ioremap(dev->addrs[0].address + 0xf6000, 0x40); - val = in_be32(®[12]); - if (val & PRG_CL_RESET_VALID) { - out_be32(®[12], val & ~PRG_CL_RESET_VALID); - in_be32(®[12]); - } - iounmap(reg); -} - -/* Marvell Discovery II based Pegasos 2 */ -static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev) -{ - struct device_node *root = find_path_device("/"); - struct device_node *rtas; - - rtas = of_find_node_by_name (root, "rtas"); - if (rtas) { - hose->ops = &rtas_pci_ops; - } else { - printk ("RTAS supporting Pegasos OF not found, please upgrade" - " your firmware\n"); - } - pci_assign_all_buses = 1; -} - -void __init -chrp_find_bridges(void) -{ - struct device_node *dev; - int *bus_range; - int len, index = -1; - struct pci_controller *hose; - unsigned int *dma; - char *model, *machine; - int is_longtrail = 0, is_mot = 0, is_pegasos = 0; - struct device_node *root = find_path_device("/"); - - /* - * The PCI host bridge nodes on some machines don't have - * properties to adequately identify them, so we have to - * look at what sort of machine this is as well. - */ - machine = get_property(root, "model", NULL); - if (machine != NULL) { - is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0; - is_mot = strncmp(machine, "MOT", 3) == 0; - if (strncmp(machine, "Pegasos2", 8) == 0) - is_pegasos = 2; - else if (strncmp(machine, "Pegasos", 7) == 0) - is_pegasos = 1; - } - for (dev = root->child; dev != NULL; dev = dev->sibling) { - if (dev->type == NULL || strcmp(dev->type, "pci") != 0) - continue; - ++index; - /* The GG2 bridge on the LongTrail doesn't have an address */ - if (dev->n_addrs < 1 && !is_longtrail) { - printk(KERN_WARNING "Can't use %s: no address\n", - dev->full_name); - continue; - } - bus_range = (int *) get_property(dev, "bus-range", &len); - if (bus_range == NULL || len < 2 * sizeof(int)) { - printk(KERN_WARNING "Can't get bus-range for %s\n", - dev->full_name); - continue; - } - if (bus_range[1] == bus_range[0]) - printk(KERN_INFO "PCI bus %d", bus_range[0]); - else - printk(KERN_INFO "PCI buses %d..%d", - bus_range[0], bus_range[1]); - printk(" controlled by %s", dev->type); - if (dev->n_addrs > 0) - printk(" at %x", dev->addrs[0].address); - printk("\n"); - - hose = pcibios_alloc_controller(); - if (!hose) { - printk("Can't allocate PCI controller structure for %s\n", - dev->full_name); - continue; - } - hose->arch_data = dev; - hose->first_busno = bus_range[0]; - hose->last_busno = bus_range[1]; - - model = get_property(dev, "model", NULL); - if (model == NULL) - model = ""; - if (device_is_compatible(dev, "IBM,python")) { - setup_python(hose, dev); - } else if (is_mot - || strncmp(model, "Motorola, Grackle", 17) == 0) { - setup_indirect_pci(hose, 0xfec00000, 0xfee00000); - } else if (is_longtrail) { - void __iomem *p = ioremap(GG2_PCI_CONFIG_BASE, 0x80000); - hose->ops = &gg2_pci_ops; - hose->cfg_data = p; - gg2_pci_config_base = p; - } else if (is_pegasos == 1) { - setup_indirect_pci(hose, 0xfec00cf8, 0xfee00cfc); - } else if (is_pegasos == 2) { - setup_peg2(hose, dev); - } else { - printk("No methods for %s (model %s), using RTAS\n", - dev->full_name, model); - hose->ops = &rtas_pci_ops; - } - - pci_process_bridge_OF_ranges(hose, dev, index == 0); - - /* check the first bridge for a property that we can - use to set pci_dram_offset */ - dma = (unsigned int *) - get_property(dev, "ibm,dma-ranges", &len); - if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) { - pci_dram_offset = dma[2] - dma[3]; - printk("pci_dram_offset = %lx\n", pci_dram_offset); - } - } - - /* Do not fixup interrupts from OF tree on pegasos */ - if (is_pegasos == 0) - ppc_md.pcibios_fixup = chrp_pcibios_fixup; -} diff --git a/arch/ppc/platforms/chrp_pegasos_eth.c b/arch/ppc/platforms/chrp_pegasos_eth.c deleted file mode 100644 index 9305c8aa1373..000000000000 --- a/arch/ppc/platforms/chrp_pegasos_eth.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2005 Sven Luther - * Thanks to : - * Dale Farnsworth - * Mark A. Greer - * Nicolas DET - * Benjamin Herrenschmidt - * And anyone else who helped me on this. - */ - -#include -#include -#include -#include -#include -#include - -#define PEGASOS2_MARVELL_REGBASE (0xf1000000) -#define PEGASOS2_MARVELL_REGSIZE (0x00004000) -#define PEGASOS2_SRAM_BASE (0xf2000000) -#define PEGASOS2_SRAM_SIZE (256*1024) - -#define PEGASOS2_SRAM_BASE_ETH0 (PEGASOS2_SRAM_BASE) -#define PEGASOS2_SRAM_BASE_ETH1 (PEGASOS2_SRAM_BASE_ETH0 + (PEGASOS2_SRAM_SIZE / 2) ) - - -#define PEGASOS2_SRAM_RXRING_SIZE (PEGASOS2_SRAM_SIZE/4) -#define PEGASOS2_SRAM_TXRING_SIZE (PEGASOS2_SRAM_SIZE/4) - -#undef BE_VERBOSE - -static struct resource mv643xx_eth_shared_resources[] = { - [0] = { - .name = "ethernet shared base", - .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS, - .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS + - MV643XX_ETH_SHARED_REGS_SIZE - 1, - .flags = IORESOURCE_MEM, - }, -}; - -static struct platform_device mv643xx_eth_shared_device = { - .name = MV643XX_ETH_SHARED_NAME, - .id = 0, - .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources), - .resource = mv643xx_eth_shared_resources, -}; - -static struct resource mv643xx_eth0_resources[] = { - [0] = { - .name = "eth0 irq", - .start = 9, - .end = 9, - .flags = IORESOURCE_IRQ, - }, -}; - - -static struct mv643xx_eth_platform_data eth0_pd = { - .tx_sram_addr = PEGASOS2_SRAM_BASE_ETH0, - .tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE, - .tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16, - - .rx_sram_addr = PEGASOS2_SRAM_BASE_ETH0 + PEGASOS2_SRAM_TXRING_SIZE, - .rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE, - .rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16, -}; - -static struct platform_device eth0_device = { - .name = MV643XX_ETH_NAME, - .id = 0, - .num_resources = ARRAY_SIZE(mv643xx_eth0_resources), - .resource = mv643xx_eth0_resources, - .dev = { - .platform_data = ð0_pd, - }, -}; - -static struct resource mv643xx_eth1_resources[] = { - [0] = { - .name = "eth1 irq", - .start = 9, - .end = 9, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct mv643xx_eth_platform_data eth1_pd = { - .tx_sram_addr = PEGASOS2_SRAM_BASE_ETH1, - .tx_sram_size = PEGASOS2_SRAM_TXRING_SIZE, - .tx_queue_size = PEGASOS2_SRAM_TXRING_SIZE/16, - - .rx_sram_addr = PEGASOS2_SRAM_BASE_ETH1 + PEGASOS2_SRAM_TXRING_SIZE, - .rx_sram_size = PEGASOS2_SRAM_RXRING_SIZE, - .rx_queue_size = PEGASOS2_SRAM_RXRING_SIZE/16, -}; - -static struct platform_device eth1_device = { - .name = MV643XX_ETH_NAME, - .id = 1, - .num_resources = ARRAY_SIZE(mv643xx_eth1_resources), - .resource = mv643xx_eth1_resources, - .dev = { - .platform_data = ð1_pd, - }, -}; - -static struct platform_device *mv643xx_eth_pd_devs[] __initdata = { - &mv643xx_eth_shared_device, - ð0_device, - ð1_device, -}; - -/***********/ -/***********/ -#define MV_READ(offset,val) { val = readl(mv643xx_reg_base + offset); } -#define MV_WRITE(offset,data) writel(data, mv643xx_reg_base + offset) - -static void __iomem *mv643xx_reg_base; - -static int Enable_SRAM(void) -{ - u32 ALong; - - if (mv643xx_reg_base == NULL) - mv643xx_reg_base = ioremap(PEGASOS2_MARVELL_REGBASE, - PEGASOS2_MARVELL_REGSIZE); - - if (mv643xx_reg_base == NULL) - return -ENOMEM; - -#ifdef BE_VERBOSE - printk("Pegasos II/Marvell MV64361: register remapped from %p to %p\n", - (void *)PEGASOS2_MARVELL_REGBASE, (void *)mv643xx_reg_base); -#endif - - MV_WRITE(MV64340_SRAM_CONFIG, 0); - - MV_WRITE(MV64340_INTEGRATED_SRAM_BASE_ADDR, PEGASOS2_SRAM_BASE >> 16); - - MV_READ(MV64340_BASE_ADDR_ENABLE, ALong); - ALong &= ~(1 << 19); - MV_WRITE(MV64340_BASE_ADDR_ENABLE, ALong); - - ALong = 0x02; - ALong |= PEGASOS2_SRAM_BASE & 0xffff0000; - MV_WRITE(MV643XX_ETH_BAR_4, ALong); - - MV_WRITE(MV643XX_ETH_SIZE_REG_4, (PEGASOS2_SRAM_SIZE-1) & 0xffff0000); - - MV_READ(MV643XX_ETH_BASE_ADDR_ENABLE_REG, ALong); - ALong &= ~(1 << 4); - MV_WRITE(MV643XX_ETH_BASE_ADDR_ENABLE_REG, ALong); - -#ifdef BE_VERBOSE - printk("Pegasos II/Marvell MV64361: register unmapped\n"); - printk("Pegasos II/Marvell MV64361: SRAM at %p, size=%x\n", (void*) PEGASOS2_SRAM_BASE, PEGASOS2_SRAM_SIZE); -#endif - - iounmap(mv643xx_reg_base); - mv643xx_reg_base = NULL; - - return 1; -} - - -/***********/ -/***********/ -int mv643xx_eth_add_pds(void) -{ - int ret = 0; - static struct pci_device_id pci_marvell_mv64360[] = { - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_MV64360) }, - { } - }; - -#ifdef BE_VERBOSE - printk("Pegasos II/Marvell MV64361: init\n"); -#endif - - if (pci_dev_present(pci_marvell_mv64360)) { - ret = platform_add_devices(mv643xx_eth_pd_devs, - ARRAY_SIZE(mv643xx_eth_pd_devs)); - - if ( Enable_SRAM() < 0) - { - eth0_pd.tx_sram_addr = 0; - eth0_pd.tx_sram_size = 0; - eth0_pd.rx_sram_addr = 0; - eth0_pd.rx_sram_size = 0; - - eth1_pd.tx_sram_addr = 0; - eth1_pd.tx_sram_size = 0; - eth1_pd.rx_sram_addr = 0; - eth1_pd.rx_sram_size = 0; - -#ifdef BE_VERBOSE - printk("Pegasos II/Marvell MV64361: Can't enable the " - "SRAM\n"); -#endif - } - } - -#ifdef BE_VERBOSE - printk("Pegasos II/Marvell MV64361: init is over\n"); -#endif - - return ret; -} - -device_initcall(mv643xx_eth_add_pds); diff --git a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c deleted file mode 100644 index f9fd3f4f8e2e..000000000000 --- a/arch/ppc/platforms/chrp_setup.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * Copyright (C) 1995 Linus Torvalds - * Adapted from 'alpha' version by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu) - */ - -/* - * bootup setup stuff.. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mem_pieces.h" - -unsigned long chrp_get_rtc_time(void); -int chrp_set_rtc_time(unsigned long nowtime); -void chrp_calibrate_decr(void); -long chrp_time_init(void); - -void chrp_find_bridges(void); -void chrp_event_scan(void); -void rtas_display_progress(char *, unsigned short); -void rtas_indicator_progress(char *, unsigned short); -void btext_progress(char *, unsigned short); - -extern int of_show_percpuinfo(struct seq_file *, int); - -int _chrp_type; -EXPORT_SYMBOL(_chrp_type); - -/* - * XXX this should be in xmon.h, but putting it there means xmon.h - * has to include (to get irqreturn_t), which - * causes all sorts of problems. -- paulus - */ -extern irqreturn_t xmon_irq(int, void *, struct pt_regs *); - -extern dev_t boot_dev; - -extern PTE *Hash, *Hash_end; -extern unsigned long Hash_size, Hash_mask; -extern int probingmem; -extern unsigned long loops_per_jiffy; -static int max_width; - -#ifdef CONFIG_SMP -extern struct smp_ops_t chrp_smp_ops; -#endif - -static const char *gg2_memtypes[4] = { - "FPM", "SDRAM", "EDO", "BEDO" -}; -static const char *gg2_cachesizes[4] = { - "256 KB", "512 KB", "1 MB", "Reserved" -}; -static const char *gg2_cachetypes[4] = { - "Asynchronous", "Reserved", "Flow-Through Synchronous", - "Pipelined Synchronous" -}; -static const char *gg2_cachemodes[4] = { - "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" -}; - -int -chrp_show_cpuinfo(struct seq_file *m) -{ - int i, sdramen; - unsigned int t; - struct device_node *root; - const char *model = ""; - - root = find_path_device("/"); - if (root) - model = get_property(root, "model", NULL); - seq_printf(m, "machine\t\t: CHRP %s\n", model); - - /* longtrail (goldengate) stuff */ - if (!strncmp(model, "IBM,LongTrail", 13)) { - /* VLSI VAS96011/12 `Golden Gate 2' */ - /* Memory banks */ - sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL) - >>31) & 1; - for (i = 0; i < (sdramen ? 4 : 6); i++) { - t = in_le32(gg2_pci_config_base+ - GG2_PCI_DRAM_BANK0+ - i*4); - if (!(t & 1)) - continue; - switch ((t>>8) & 0x1f) { - case 0x1f: - model = "4 MB"; - break; - case 0x1e: - model = "8 MB"; - break; - case 0x1c: - model = "16 MB"; - break; - case 0x18: - model = "32 MB"; - break; - case 0x10: - model = "64 MB"; - break; - case 0x00: - model = "128 MB"; - break; - default: - model = "Reserved"; - break; - } - seq_printf(m, "memory bank %d\t: %s %s\n", i, model, - gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]); - } - /* L2 cache */ - t = in_le32(gg2_pci_config_base+GG2_PCI_CC_CTRL); - seq_printf(m, "board l2\t: %s %s (%s)\n", - gg2_cachesizes[(t>>7) & 3], - gg2_cachetypes[(t>>2) & 3], - gg2_cachemodes[t & 3]); - } - return 0; -} - -/* - * Fixes for the National Semiconductor PC78308VUL SuperI/O - * - * Some versions of Open Firmware incorrectly initialize the IRQ settings - * for keyboard and mouse - */ -static inline void __init sio_write(u8 val, u8 index) -{ - outb(index, 0x15c); - outb(val, 0x15d); -} - -static inline u8 __init sio_read(u8 index) -{ - outb(index, 0x15c); - return inb(0x15d); -} - -static void __init sio_fixup_irq(const char *name, u8 device, u8 level, - u8 type) -{ - u8 level0, type0, active; - - /* select logical device */ - sio_write(device, 0x07); - active = sio_read(0x30); - level0 = sio_read(0x70); - type0 = sio_read(0x71); - if (level0 != level || type0 != type || !active) { - printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: " - "remapping to level %d, type %d, active\n", - name, level0, type0, !active ? "in" : "", level, type); - sio_write(0x01, 0x30); - sio_write(level, 0x70); - sio_write(type, 0x71); - } -} - -static void __init sio_init(void) -{ - struct device_node *root; - - if ((root = find_path_device("/")) && - !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) { - /* logical device 0 (KBC/Keyboard) */ - sio_fixup_irq("keyboard", 0, 1, 2); - /* select logical device 1 (KBC/Mouse) */ - sio_fixup_irq("mouse", 1, 12, 2); - } -} - - -static void __init pegasos_set_l2cr(void) -{ - struct device_node *np; - - /* On Pegasos, enable the l2 cache if needed, as the OF forgets it */ - if (_chrp_type != _CHRP_Pegasos) - return; - - /* Enable L2 cache if needed */ - np = find_type_devices("cpu"); - if (np != NULL) { - unsigned int *l2cr = (unsigned int *) - get_property (np, "l2cr", NULL); - if (l2cr == NULL) { - printk ("Pegasos l2cr : no cpu l2cr property found\n"); - return; - } - if (!((*l2cr) & 0x80000000)) { - printk ("Pegasos l2cr : L2 cache was not active, " - "activating\n"); - _set_L2CR(0); - _set_L2CR((*l2cr) | 0x80000000); - } - } -} - -void __init chrp_setup_arch(void) -{ - struct device_node *device; - - /* init to some ~sane value until calibrate_delay() runs */ - loops_per_jiffy = 50000000/HZ; - -#ifdef CONFIG_BLK_DEV_INITRD - /* this is fine for chrp */ - initrd_below_start_ok = 1; - - if (initrd_start) - ROOT_DEV = Root_RAM0; - else -#endif - ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ - - /* On pegasos, enable the L2 cache if not already done by OF */ - pegasos_set_l2cr(); - - /* Lookup PCI host bridges */ - chrp_find_bridges(); - -#ifndef CONFIG_PPC64BRIDGE - /* - * Temporary fixes for PCI devices. - * -- Geert - */ - hydra_init(); /* Mac I/O */ - -#endif /* CONFIG_PPC64BRIDGE */ - - /* - * Fix the Super I/O configuration - */ - sio_init(); - - /* Get the event scan rate for the rtas so we know how - * often it expects a heartbeat. -- Cort - */ - if ( rtas_data ) { - struct property *p; - device = find_devices("rtas"); - for ( p = device->properties; - p && strncmp(p->name, "rtas-event-scan-rate", 20); - p = p->next ) - /* nothing */ ; - if ( p && *(unsigned long *)p->value ) { - ppc_md.heartbeat = chrp_event_scan; - ppc_md.heartbeat_reset = (HZ/(*(unsigned long *)p->value)*30)-1; - ppc_md.heartbeat_count = 1; - printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n", - *(unsigned long *)p->value, ppc_md.heartbeat_reset ); - } - } - - pci_create_OF_bus_map(); -} - -void -chrp_event_scan(void) -{ - unsigned char log[1024]; - unsigned long ret = 0; - /* XXX: we should loop until the hardware says no more error logs -- Cort */ - call_rtas( "event-scan", 4, 1, &ret, 0xffffffff, 0, - __pa(log), 1024 ); - ppc_md.heartbeat_count = ppc_md.heartbeat_reset; -} - -void -chrp_restart(char *cmd) -{ - printk("RTAS system-reboot returned %d\n", - call_rtas("system-reboot", 0, 1, NULL)); - for (;;); -} - -void -chrp_power_off(void) -{ - /* allow power on only with power button press */ - printk("RTAS power-off returned %d\n", - call_rtas("power-off", 2, 1, NULL,0xffffffff,0xffffffff)); - for (;;); -} - -void -chrp_halt(void) -{ - chrp_power_off(); -} - -/* - * Finds the open-pic node and sets OpenPIC_Addr based on its reg property. - * Then checks if it has an interrupt-ranges property. If it does then - * we have a distributed open-pic, so call openpic_set_sources to tell - * the openpic code where to find the interrupt source registers. - */ -static void __init chrp_find_openpic(void) -{ - struct device_node *np; - int len, i; - unsigned int *iranges; - void __iomem *isu; - - np = find_type_devices("open-pic"); - if (np == NULL || np->n_addrs == 0) - return; - printk(KERN_INFO "OpenPIC at %x (size %x)\n", - np->addrs[0].address, np->addrs[0].size); - OpenPIC_Addr = ioremap(np->addrs[0].address, 0x40000); - if (OpenPIC_Addr == NULL) { - printk(KERN_ERR "Failed to map OpenPIC!\n"); - return; - } - - iranges = (unsigned int *) get_property(np, "interrupt-ranges", &len); - if (iranges == NULL || len < 2 * sizeof(unsigned int)) - return; /* not distributed */ - - /* - * The first pair of cells in interrupt-ranges refers to the - * IDU; subsequent pairs refer to the ISUs. - */ - len /= 2 * sizeof(unsigned int); - if (np->n_addrs < len) { - printk(KERN_ERR "Insufficient addresses for distributed" - " OpenPIC (%d < %d)\n", np->n_addrs, len); - return; - } - if (iranges[1] != 0) { - printk(KERN_INFO "OpenPIC irqs %d..%d in IDU\n", - iranges[0], iranges[0] + iranges[1] - 1); - openpic_set_sources(iranges[0], iranges[1], NULL); - } - for (i = 1; i < len; ++i) { - iranges += 2; - printk(KERN_INFO "OpenPIC irqs %d..%d in ISU at %x (%x)\n", - iranges[0], iranges[0] + iranges[1] - 1, - np->addrs[i].address, np->addrs[i].size); - isu = ioremap(np->addrs[i].address, np->addrs[i].size); - if (isu != NULL) - openpic_set_sources(iranges[0], iranges[1], isu); - else - printk(KERN_ERR "Failed to map OpenPIC ISU at %x!\n", - np->addrs[i].address); - } -} - -#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) -static struct irqaction xmon_irqaction = { - .handler = xmon_irq, - .mask = CPU_MASK_NONE, - .name = "XMON break", -}; -#endif - -void __init chrp_init_IRQ(void) -{ - struct device_node *np; - unsigned long chrp_int_ack = 0; - unsigned char init_senses[NR_IRQS - NUM_8259_INTERRUPTS]; -#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) - struct device_node *kbd; -#endif - - for (np = find_devices("pci"); np != NULL; np = np->next) { - unsigned int *addrp = (unsigned int *) - get_property(np, "8259-interrupt-acknowledge", NULL); - - if (addrp == NULL) - continue; - chrp_int_ack = addrp[prom_n_addr_cells(np)-1]; - break; - } - if (np == NULL) - printk(KERN_ERR "Cannot find PCI interrupt acknowledge address\n"); - - chrp_find_openpic(); - - if (OpenPIC_Addr) { - prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS); - OpenPIC_InitSenses = init_senses; - OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS; - - openpic_init(NUM_8259_INTERRUPTS); - /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ - openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", - i8259_irq); - - } - i8259_init(chrp_int_ack, 0); - -#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) - /* see if there is a keyboard in the device tree - with a parent of type "adb" */ - for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) - if (kbd->parent && kbd->parent->type - && strcmp(kbd->parent->type, "adb") == 0) - break; - if (kbd) - setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction); -#endif -} - -void __init -chrp_init2(void) -{ -#ifdef CONFIG_NVRAM - chrp_nvram_init(); -#endif - - request_region(0x20,0x20,"pic1"); - request_region(0xa0,0x20,"pic2"); - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); - - if (ppc_md.progress) - ppc_md.progress(" Have fun! ", 0x7777); -} - -static struct device_node *memory_node; - -static int __init get_mem_prop(char *name, struct mem_pieces *mp) -{ - struct reg_property *rp; - int i, s; - unsigned int *ip; - int nac = prom_n_addr_cells(memory_node); - int nsc = prom_n_size_cells(memory_node); - - ip = (unsigned int *) get_property(memory_node, name, &s); - if (ip == NULL) { - printk(KERN_ERR "error: couldn't get %s property on /memory\n", - name); - return 0; - } - s /= (nsc + nac) * 4; - rp = mp->regions; - for (i = 0; i < s; ++i, ip += nac+nsc) { - if (nac >= 2 && ip[nac-2] != 0) - continue; - rp->address = ip[nac-1]; - if (nsc >= 2 && ip[nac+nsc-2] != 0) - rp->size = ~0U; - else - rp->size = ip[nac+nsc-1]; - ++rp; - } - mp->n_regions = rp - mp->regions; - - /* Make sure the pieces are sorted. */ - mem_pieces_sort(mp); - mem_pieces_coalesce(mp); - return 1; -} - -static unsigned long __init chrp_find_end_of_memory(void) -{ - unsigned long a, total; - struct mem_pieces phys_mem; - - /* - * Find out where physical memory is, and check that it - * starts at 0 and is contiguous. It seems that RAM is - * always physically contiguous on Power Macintoshes. - * - * Supporting discontiguous physical memory isn't hard, - * it just makes the virtual <-> physical mapping functions - * more complicated (or else you end up wasting space - * in mem_map). - */ - memory_node = find_devices("memory"); - if (memory_node == NULL || !get_mem_prop("reg", &phys_mem) - || phys_mem.n_regions == 0) - panic("No RAM??"); - a = phys_mem.regions[0].address; - if (a != 0) - panic("RAM doesn't start at physical address 0"); - total = phys_mem.regions[0].size; - - if (phys_mem.n_regions > 1) { - printk("RAM starting at 0x%x is not contiguous\n", - phys_mem.regions[1].address); - printk("Using RAM from 0 to 0x%lx\n", total-1); - } - - return total; -} - -void __init -chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ - struct device_node *root = find_path_device ("/"); - char *machine = NULL; - -#ifdef CONFIG_BLK_DEV_INITRD - /* take care of initrd if we have one */ - if ( r6 ) - { - initrd_start = r6 + KERNELBASE; - initrd_end = r6 + r7 + KERNELBASE; - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - ISA_DMA_THRESHOLD = ~0L; - DMA_MODE_READ = 0x44; - DMA_MODE_WRITE = 0x48; - isa_io_base = CHRP_ISA_IO_BASE; /* default value */ - ppc_do_canonicalize_irqs = 1; - - if (root) - machine = get_property(root, "model", NULL); - if (machine && strncmp(machine, "Pegasos", 7) == 0) { - _chrp_type = _CHRP_Pegasos; - } else if (machine && strncmp(machine, "IBM", 3) == 0) { - _chrp_type = _CHRP_IBM; - } else if (machine && strncmp(machine, "MOT", 3) == 0) { - _chrp_type = _CHRP_Motorola; - } else { - /* Let's assume it is an IBM chrp if all else fails */ - _chrp_type = _CHRP_IBM; - } - - ppc_md.setup_arch = chrp_setup_arch; - ppc_md.show_percpuinfo = of_show_percpuinfo; - ppc_md.show_cpuinfo = chrp_show_cpuinfo; - - ppc_md.init_IRQ = chrp_init_IRQ; - if (_chrp_type == _CHRP_Pegasos) - ppc_md.get_irq = i8259_irq; - else - ppc_md.get_irq = openpic_get_irq; - - ppc_md.init = chrp_init2; - - ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; - - ppc_md.restart = chrp_restart; - ppc_md.power_off = chrp_power_off; - ppc_md.halt = chrp_halt; - - ppc_md.time_init = chrp_time_init; - ppc_md.set_rtc_time = chrp_set_rtc_time; - ppc_md.get_rtc_time = chrp_get_rtc_time; - ppc_md.calibrate_decr = chrp_calibrate_decr; - - ppc_md.find_end_of_memory = chrp_find_end_of_memory; - - if (rtas_data) { - struct device_node *rtas; - unsigned int *p; - - rtas = find_devices("rtas"); - if (rtas != NULL) { - if (get_property(rtas, "display-character", NULL)) { - ppc_md.progress = rtas_display_progress; - p = (unsigned int *) get_property - (rtas, "ibm,display-line-length", NULL); - if (p) - max_width = *p; - } else if (get_property(rtas, "set-indicator", NULL)) - ppc_md.progress = rtas_indicator_progress; - } - } -#ifdef CONFIG_BOOTX_TEXT - if (ppc_md.progress == NULL && boot_text_mapped) - ppc_md.progress = btext_progress; -#endif - -#ifdef CONFIG_SMP - smp_ops = &chrp_smp_ops; -#endif /* CONFIG_SMP */ - - /* - * Print the banner, then scroll down so boot progress - * can be printed. -- Cort - */ - if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); -} - -void -rtas_display_progress(char *s, unsigned short hex) -{ - int width; - char *os = s; - - if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) ) - return; - - width = max_width; - while ( *os ) - { - if ( (*os == '\n') || (*os == '\r') ) - width = max_width; - else - width--; - call_rtas( "display-character", 1, 1, NULL, *os++ ); - /* if we overwrite the screen length */ - if ( width == 0 ) - while ( (*os != 0) && (*os != '\n') && (*os != '\r') ) - os++; - } - - /*while ( width-- > 0 )*/ - call_rtas( "display-character", 1, 1, NULL, ' ' ); -} - -void -rtas_indicator_progress(char *s, unsigned short hex) -{ - call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); -} - -#ifdef CONFIG_BOOTX_TEXT -void -btext_progress(char *s, unsigned short hex) -{ - prom_print(s); - prom_print("\n"); -} -#endif /* CONFIG_BOOTX_TEXT */ diff --git a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c deleted file mode 100644 index 97e539557ecb..000000000000 --- a/arch/ppc/platforms/chrp_smp.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Smp support for CHRP machines. - * - * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great - * deal of code from the sparc and intel versions. - * - * Copyright (C) 1999 Cort Dougan - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern unsigned long smp_chrp_cpu_nr; - -static int __init -smp_chrp_probe(void) -{ - if (smp_chrp_cpu_nr > 1) - openpic_request_IPIs(); - - return smp_chrp_cpu_nr; -} - -static void __devinit -smp_chrp_kick_cpu(int nr) -{ - *(unsigned long *)KERNELBASE = nr; - asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); -} - -static void __devinit -smp_chrp_setup_cpu(int cpu_nr) -{ - if (OpenPIC_Addr) - do_openpic_setup_cpu(); -} - -static DEFINE_SPINLOCK(timebase_lock); -static unsigned int timebase_upper = 0, timebase_lower = 0; - -void __devinit -smp_chrp_give_timebase(void) -{ - spin_lock(&timebase_lock); - call_rtas("freeze-time-base", 0, 1, NULL); - timebase_upper = get_tbu(); - timebase_lower = get_tbl(); - spin_unlock(&timebase_lock); - - while (timebase_upper || timebase_lower) - barrier(); - call_rtas("thaw-time-base", 0, 1, NULL); -} - -void __devinit -smp_chrp_take_timebase(void) -{ - while (!(timebase_upper || timebase_lower)) - barrier(); - spin_lock(&timebase_lock); - set_tb(timebase_upper, timebase_lower); - timebase_upper = 0; - timebase_lower = 0; - spin_unlock(&timebase_lock); - printk("CPU %i taken timebase\n", smp_processor_id()); -} - -/* CHRP with openpic */ -struct smp_ops_t chrp_smp_ops = { - .message_pass = smp_openpic_message_pass, - .probe = smp_chrp_probe, - .kick_cpu = smp_chrp_kick_cpu, - .setup_cpu = smp_chrp_setup_cpu, - .give_timebase = smp_chrp_give_timebase, - .take_timebase = smp_chrp_take_timebase, -}; diff --git a/arch/ppc/platforms/chrp_time.c b/arch/ppc/platforms/chrp_time.c deleted file mode 100644 index 51e06ad66168..000000000000 --- a/arch/ppc/platforms/chrp_time.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * Adapted for PowerPC (PReP) by Gary Thomas - * Modified by Cort Dougan (cort@cs.nmt.edu). - * Copied and modified from arch/i386/kernel/time.c - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -extern spinlock_t rtc_lock; - -static int nvram_as1 = NVRAM_AS1; -static int nvram_as0 = NVRAM_AS0; -static int nvram_data = NVRAM_DATA; - -long __init chrp_time_init(void) -{ - struct device_node *rtcs; - int base; - - rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); - if (rtcs == NULL) - rtcs = find_compatible_devices("rtc", "ds1385-rtc"); - if (rtcs == NULL || rtcs->addrs == NULL) - return 0; - base = rtcs->addrs[0].address; - nvram_as1 = 0; - nvram_as0 = base; - nvram_data = base + 1; - - return 0; -} - -int chrp_cmos_clock_read(int addr) -{ - if (nvram_as1 != 0) - outb(addr>>8, nvram_as1); - outb(addr, nvram_as0); - return (inb(nvram_data)); -} - -void chrp_cmos_clock_write(unsigned long val, int addr) -{ - if (nvram_as1 != 0) - outb(addr>>8, nvram_as1); - outb(addr, nvram_as0); - outb(val, nvram_data); - return; -} - -/* - * Set the hardware clock. -- Cort - */ -int chrp_set_rtc_time(unsigned long nowtime) -{ - unsigned char save_control, save_freq_select; - struct rtc_time tm; - - spin_lock(&rtc_lock); - to_tm(nowtime, &tm); - - save_control = chrp_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */ - - chrp_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = chrp_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */ - - chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - tm.tm_year -= 1900; - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(tm.tm_sec); - BIN_TO_BCD(tm.tm_min); - BIN_TO_BCD(tm.tm_hour); - BIN_TO_BCD(tm.tm_mon); - BIN_TO_BCD(tm.tm_mday); - BIN_TO_BCD(tm.tm_year); - } - chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS); - chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES); - chrp_cmos_clock_write(tm.tm_hour,RTC_HOURS); - chrp_cmos_clock_write(tm.tm_mon,RTC_MONTH); - chrp_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH); - chrp_cmos_clock_write(tm.tm_year,RTC_YEAR); - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - chrp_cmos_clock_write(save_control, RTC_CONTROL); - chrp_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT); - - spin_unlock(&rtc_lock); - return 0; -} - -unsigned long chrp_get_rtc_time(void) -{ - unsigned int year, mon, day, hour, min, sec; - - do { - sec = chrp_cmos_clock_read(RTC_SECONDS); - min = chrp_cmos_clock_read(RTC_MINUTES); - hour = chrp_cmos_clock_read(RTC_HOURS); - day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH); - mon = chrp_cmos_clock_read(RTC_MONTH); - year = chrp_cmos_clock_read(RTC_YEAR); - } while (sec != chrp_cmos_clock_read(RTC_SECONDS)); - - if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) - || RTC_ALWAYS_BCD) { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - } - - year += 1900; - if (year < 1970) - year += 100; - return mktime(year, mon, day, hour, min, sec); -} - -/* - * Calibrate the decrementer frequency with the VIA timer 1. - */ -#define VIA_TIMER_FREQ_6 4700000 /* time 1 frequency * 6 */ - -/* VIA registers */ -#define RS 0x200 /* skip between registers */ -#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ -#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ -#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ -#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ -#define ACR (11*RS) /* Auxiliary control register */ -#define IFR (13*RS) /* Interrupt flag register */ - -/* Bits in ACR */ -#define T1MODE 0xc0 /* Timer 1 mode */ -#define T1MODE_CONT 0x40 /* continuous interrupts */ - -/* Bits in IFR and IER */ -#define T1_INT 0x40 /* Timer 1 interrupt */ - -static int __init chrp_via_calibrate_decr(void) -{ - struct device_node *vias; - volatile unsigned char __iomem *via; - int count = VIA_TIMER_FREQ_6 / 100; - unsigned int dstart, dend; - - vias = find_devices("via-cuda"); - if (vias == 0) - vias = find_devices("via"); - if (vias == 0 || vias->n_addrs == 0) - return 0; - via = ioremap(vias->addrs[0].address, vias->addrs[0].size); - - /* set timer 1 for continuous interrupts */ - out_8(&via[ACR], (via[ACR] & ~T1MODE) | T1MODE_CONT); - /* set the counter to a small value */ - out_8(&via[T1CH], 2); - /* set the latch to `count' */ - out_8(&via[T1LL], count); - out_8(&via[T1LH], count >> 8); - /* wait until it hits 0 */ - while ((in_8(&via[IFR]) & T1_INT) == 0) - ; - dstart = get_dec(); - /* clear the interrupt & wait until it hits 0 again */ - in_8(&via[T1CL]); - while ((in_8(&via[IFR]) & T1_INT) == 0) - ; - dend = get_dec(); - - tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100); - tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); - - printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", - tb_ticks_per_jiffy, dstart - dend); - - iounmap(via); - - return 1; -} - -void __init chrp_calibrate_decr(void) -{ - struct device_node *cpu; - unsigned int freq, *fp; - - if (chrp_via_calibrate_decr()) - return; - - /* - * The cpu node should have a timebase-frequency property - * to tell us the rate at which the decrementer counts. - */ - freq = 16666000; /* hardcoded default */ - cpu = find_type_devices("cpu"); - if (cpu != 0) { - fp = (unsigned int *) - get_property(cpu, "timebase-frequency", NULL); - if (fp != 0) - freq = *fp; - } - printk("time_init: decrementer frequency = %u.%.6u MHz\n", - freq/1000000, freq%1000000); - tb_ticks_per_jiffy = freq / HZ; - tb_to_us = mulhwu_scale_factor(freq, 1000000); -} diff --git a/arch/ppc/platforms/lite5200.c b/arch/ppc/platforms/lite5200.c index 5171b53bccb5..fecbe9adc9e0 100644 --- a/arch/ppc/platforms/lite5200.c +++ b/arch/ppc/platforms/lite5200.c @@ -34,8 +34,7 @@ #include #include #include - -#include +#include extern int powersave_nap; @@ -68,44 +67,53 @@ lite5200_show_cpuinfo(struct seq_file *m) } #ifdef CONFIG_PCI +#ifdef CONFIG_LITE5200B +static int +lite5200_map_irq(struct pci_dev *dev, unsigned char idsel, + unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + {MPC52xx_IRQ0, MPC52xx_IRQ1, MPC52xx_IRQ2, MPC52xx_IRQ3}, + {MPC52xx_IRQ1, MPC52xx_IRQ2, MPC52xx_IRQ3, MPC52xx_IRQ0}, + }; + + const long min_idsel = 24, max_idsel = 25, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} +#else /* Original Lite */ static int lite5200_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) { return (pin == 1) && (idsel==24) ? MPC52xx_IRQ0 : -1; } #endif +#endif static void __init lite5200_setup_cpu(void) { - struct mpc52xx_cdm __iomem *cdm; struct mpc52xx_gpio __iomem *gpio; struct mpc52xx_intr __iomem *intr; - struct mpc52xx_xlb __iomem *xlb; u32 port_config; u32 intr_ctrl; /* Map zones */ - cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE); gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE); - xlb = ioremap(MPC52xx_PA(MPC52xx_XLB_OFFSET), MPC52xx_XLB_SIZE); intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE); - if (!cdm || !gpio || !xlb || !intr) { - printk("lite5200.c: Error while mapping CDM/GPIO/XLB/INTR during" - "lite5200_setup_cpu\n"); + if (!gpio || !intr) { + printk(KERN_ERR __FILE__ ": " + "Error while mapping GPIO/INTR during " + "lite5200_setup_cpu\n"); goto unmap_regs; } - /* Use internal 48 Mhz */ - out_8(&cdm->ext_48mhz_en, 0x00); - out_8(&cdm->fd_enable, 0x01); - if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */ - out_be16(&cdm->fd_counters, 0x0001); - else - out_be16(&cdm->fd_counters, 0x5555); - /* Get port mux config */ port_config = in_be32(&gpio->port_config); @@ -116,29 +124,29 @@ lite5200_setup_cpu(void) port_config &= ~0x00007000; /* Differential mode - USB1 only */ port_config |= 0x00001000; + /* ATA CS is on csb_4/5 */ + port_config &= ~0x03000000; + port_config |= 0x01000000; + /* Commit port config */ out_be32(&gpio->port_config, port_config); - /* Configure the XLB Arbiter */ - out_be32(&xlb->master_pri_enable, 0xff); - out_be32(&xlb->master_priority, 0x11111111); - - /* Enable ram snooping for 1GB window */ - out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP); - out_be32(&xlb->snoop_window, MPC52xx_PCI_TARGET_MEM | 0x1d); - - /* IRQ[0-3] setup : IRQ0 - Level Active Low */ - /* IRQ[1-3] - Level Active High */ + /* IRQ[0-3] setup */ intr_ctrl = in_be32(&intr->ctrl); intr_ctrl &= ~0x00ff0000; - intr_ctrl |= 0x00c00000; +#ifdef CONFIG_LITE5200B + /* IRQ[0-3] Level Active Low */ + intr_ctrl |= 0x00ff0000; +#else + /* IRQ0 Level Active Low + * IRQ[1-3] Level Active High */ + intr_ctrl |= 0x00c00000; +#endif out_be32(&intr->ctrl, intr_ctrl); /* Unmap reg zone */ unmap_regs: - if (cdm) iounmap(cdm); if (gpio) iounmap(gpio); - if (xlb) iounmap(xlb); if (intr) iounmap(intr); } @@ -146,7 +154,8 @@ static void __init lite5200_setup_arch(void) { /* CPU & Port mux setup */ - lite5200_setup_cpu(); + mpc52xx_setup_cpu(); /* Generic */ + lite5200_setup_cpu(); /* Platform specific */ #ifdef CONFIG_PCI /* PCI Bridge setup */ diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index d95c05d9824d..e86f6156d589 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -1067,15 +1067,13 @@ prep_map_io(void) static int __init prep_request_io(void) { - if (_machine == _MACH_prep) { #ifdef CONFIG_NVRAM - request_region(PREP_NVRAM_AS0, 0x8, "nvram"); + request_region(PREP_NVRAM_AS0, 0x8, "nvram"); #endif - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); - } + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xc0,0x20,"dma2"); return 0; } diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 5cb62c6a51c8..490749ca88f9 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -38,8 +38,6 @@ endif obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \ ppc_sys.o mpc8xx_devices.o mpc8xx_sys.o obj-$(CONFIG_PCI_QSPAN) += qspan_pci.o -obj-$(CONFIG_PPC_OF) += prom_init.o prom.o -obj-$(CONFIG_PPC_CHRP) += open_pic.o obj-$(CONFIG_PPC_PREP) += open_pic.o todc_time.o obj-$(CONFIG_BAMBOO) += pci_auto.o todc_time.o obj-$(CONFIG_CPCI690) += todc_time.o pci_auto.o diff --git a/arch/ppc/syslib/mpc52xx_pci.c b/arch/ppc/syslib/mpc52xx_pci.c index 9ec525f9fe98..5a5a7a9cd248 100644 --- a/arch/ppc/syslib/mpc52xx_pci.c +++ b/arch/ppc/syslib/mpc52xx_pci.c @@ -225,7 +225,8 @@ mpc52xx_pci_fixup_resources(struct pci_dev *dev) /* The PCI Host bridge of MPC52xx has a prefetch memory resource fixed to 1Gb. Doesn't fit in the resource system so we remove it */ if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) && - (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200) ) { + ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200 + || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) { struct resource *res = &dev->resource[1]; res->start = res->end = res->flags = 0; } diff --git a/arch/ppc/syslib/mpc52xx_setup.c b/arch/ppc/syslib/mpc52xx_setup.c index 2ee48ce0a517..ee6379bb415e 100644 --- a/arch/ppc/syslib/mpc52xx_setup.c +++ b/arch/ppc/syslib/mpc52xx_setup.c @@ -24,6 +24,8 @@ #include #include +#include + extern bd_t __res; static int core_mult[] = { /* CPU Frequency multiplier, taken */ @@ -216,6 +218,52 @@ mpc52xx_calibrate_decr(void) tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000); } + +void __init +mpc52xx_setup_cpu(void) +{ + struct mpc52xx_cdm __iomem *cdm; + struct mpc52xx_xlb __iomem *xlb; + + /* Map zones */ + cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE); + xlb = ioremap(MPC52xx_PA(MPC52xx_XLB_OFFSET), MPC52xx_XLB_SIZE); + + if (!cdm || !xlb) { + printk(KERN_ERR __FILE__ ": " + "Error while mapping CDM/XLB during " + "mpc52xx_setup_cpu\n"); + goto unmap_regs; + } + + /* Use internal 48 Mhz */ + out_8(&cdm->ext_48mhz_en, 0x00); + out_8(&cdm->fd_enable, 0x01); + if (in_be32(&cdm->rstcfg) & 0x40) /* Assumes 33Mhz clock */ + out_be16(&cdm->fd_counters, 0x0001); + else + out_be16(&cdm->fd_counters, 0x5555); + + /* Configure the XLB Arbiter priorities */ + out_be32(&xlb->master_pri_enable, 0xff); + out_be32(&xlb->master_priority, 0x11111111); + + /* Enable ram snooping for 1GB window */ + out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_SNOOP); + out_be32(&xlb->snoop_window, MPC52xx_PCI_TARGET_MEM | 0x1d); + + /* Disable XLB pipelining */ + /* (cfr errate 292. We could do this only just before ATA PIO + transaction and re-enable it after ...) */ + out_be32(&xlb->config, in_be32(&xlb->config) | MPC52xx_XLB_CFG_PLDIS); + + /* Unmap reg zone */ +unmap_regs: + if (cdm) iounmap(cdm); + if (xlb) iounmap(xlb); +} + + int mpc52xx_match_psc_function(int psc_idx, const char *func) { struct mpc52xx_psc_func *cf = mpc52xx_psc_functions; diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index 38e5b93fbe41..70456c8f998c 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -216,7 +216,7 @@ static void openpic_safe_writefield(volatile u_int __iomem *addr, u_int mask, u_int openpic_read_IPI(volatile u_int __iomem * addr) { u_int val = 0; -#if defined(OPENPIC_BIG_ENDIAN) || defined(CONFIG_POWER3) +#if defined(OPENPIC_BIG_ENDIAN) val = in_be32(addr); #else val = in_le32(addr); diff --git a/arch/ppc/syslib/ppc_sys.c b/arch/ppc/syslib/ppc_sys.c index 60c724e11584..7662c4e6e7d6 100644 --- a/arch/ppc/syslib/ppc_sys.c +++ b/arch/ppc/syslib/ppc_sys.c @@ -156,12 +156,13 @@ void platform_notify_map(const struct platform_notify_dev_map *map, while (map->bus_id != NULL) { idx = -1; s = strrchr(dev->bus_id, '.'); - if (s != NULL) + if (s != NULL) { idx = (int)simple_strtol(s + 1, NULL, 10); - else + len = s - dev->bus_id; + } else { s = dev->bus_id; - - len = s - dev->bus_id; + len = strlen(dev->bus_id); + } if (!strncmp(dev->bus_id, map->bus_id, len)) { pdev = container_of(dev, struct platform_device, dev); diff --git a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c deleted file mode 100644 index 482f837fd373..000000000000 --- a/arch/ppc/syslib/prom.c +++ /dev/null @@ -1,1429 +0,0 @@ -/* - * Procedures for interfacing to the Open Firmware PROM on - * Power Macintosh computers. - * - * In particular, we are interested in the device tree - * and in using some of its services (exit, write to stdout). - * - * Paul Mackerras August 1996. - * Copyright (C) 1996 Paul Mackerras. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -struct pci_address { - unsigned a_hi; - unsigned a_mid; - unsigned a_lo; -}; - -struct pci_reg_property { - struct pci_address addr; - unsigned size_hi; - unsigned size_lo; -}; - -struct isa_reg_property { - unsigned space; - unsigned address; - unsigned size; -}; - -typedef unsigned long interpret_func(struct device_node *, unsigned long, - int, int); -static interpret_func interpret_pci_props; -static interpret_func interpret_dbdma_props; -static interpret_func interpret_isa_props; -static interpret_func interpret_macio_props; -static interpret_func interpret_root_props; - -extern char *klimit; - -/* Set for a newworld or CHRP machine */ -int use_of_interrupt_tree; -struct device_node *dflt_interrupt_controller; -int num_interrupt_controllers; - -extern unsigned int rtas_entry; /* physical pointer */ - -extern struct device_node *allnodes; - -static unsigned long finish_node(struct device_node *, unsigned long, - interpret_func *, int, int); -static unsigned long finish_node_interrupts(struct device_node *, unsigned long); -static struct device_node *find_phandle(phandle); - -extern void enter_rtas(void *); -void phys_call_rtas(int, int, int, ...); - -extern char cmd_line[512]; /* XXX */ -extern boot_infos_t *boot_infos; -unsigned long dev_tree_size; - -void -phys_call_rtas(int service, int nargs, int nret, ...) -{ - va_list list; - union { - unsigned long words[16]; - double align; - } u; - void (*rtas)(void *, unsigned long); - int i; - - u.words[0] = service; - u.words[1] = nargs; - u.words[2] = nret; - va_start(list, nret); - for (i = 0; i < nargs; ++i) - u.words[i+3] = va_arg(list, unsigned long); - va_end(list); - - rtas = (void (*)(void *, unsigned long)) rtas_entry; - rtas(&u, rtas_data); -} - -/* - * finish_device_tree is called once things are running normally - * (i.e. with text and data mapped to the address they were linked at). - * It traverses the device tree and fills in the name, type, - * {n_}addrs and {n_}intrs fields of each node. - */ -void __init -finish_device_tree(void) -{ - unsigned long mem = (unsigned long) klimit; - struct device_node *np; - - /* All CHRPs now use the interrupt tree */ - for (np = allnodes; np != NULL; np = np->allnext) { - if (get_property(np, "interrupt-parent", NULL)) { - use_of_interrupt_tree = 1; - break; - } - } - - if (use_of_interrupt_tree) { - /* - * We want to find out here how many interrupt-controller - * nodes there are, and if we are booted from BootX, - * we need a pointer to the first (and hopefully only) - * such node. But we can't use find_devices here since - * np->name has not been set yet. -- paulus - */ - int n = 0; - char *name, *ic; - int iclen; - - for (np = allnodes; np != NULL; np = np->allnext) { - ic = get_property(np, "interrupt-controller", &iclen); - name = get_property(np, "name", NULL); - /* checking iclen makes sure we don't get a false - match on /chosen.interrupt_controller */ - if ((name != NULL - && strcmp(name, "interrupt-controller") == 0) - || (ic != NULL && iclen == 0 && strcmp(name, "AppleKiwi"))) { - if (n == 0) - dflt_interrupt_controller = np; - ++n; - } - } - num_interrupt_controllers = n; - } - - mem = finish_node(allnodes, mem, NULL, 1, 1); - dev_tree_size = mem - (unsigned long) allnodes; - klimit = (char *) mem; -} - -static unsigned long __init -finish_node(struct device_node *np, unsigned long mem_start, - interpret_func *ifunc, int naddrc, int nsizec) -{ - struct device_node *child; - int *ip; - - np->name = get_property(np, "name", NULL); - np->type = get_property(np, "device_type", NULL); - - if (!np->name) - np->name = ""; - if (!np->type) - np->type = ""; - - /* get the device addresses and interrupts */ - if (ifunc != NULL) - mem_start = ifunc(np, mem_start, naddrc, nsizec); - - if (use_of_interrupt_tree) - mem_start = finish_node_interrupts(np, mem_start); - - /* Look for #address-cells and #size-cells properties. */ - ip = (int *) get_property(np, "#address-cells", NULL); - if (ip != NULL) - naddrc = *ip; - ip = (int *) get_property(np, "#size-cells", NULL); - if (ip != NULL) - nsizec = *ip; - - if (np->parent == NULL) - ifunc = interpret_root_props; - else if (np->type == 0) - ifunc = NULL; - else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci")) - ifunc = interpret_pci_props; - else if (!strcmp(np->type, "dbdma")) - ifunc = interpret_dbdma_props; - else if (!strcmp(np->type, "mac-io") - || ifunc == interpret_macio_props) - ifunc = interpret_macio_props; - else if (!strcmp(np->type, "isa")) - ifunc = interpret_isa_props; - else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3")) - ifunc = interpret_root_props; - else if (!((ifunc == interpret_dbdma_props - || ifunc == interpret_macio_props) - && (!strcmp(np->type, "escc") - || !strcmp(np->type, "media-bay")))) - ifunc = NULL; - - /* if we were booted from BootX, convert the full name */ - if (boot_infos - && strncmp(np->full_name, "Devices:device-tree", 19) == 0) { - if (np->full_name[19] == 0) { - strcpy(np->full_name, "/"); - } else if (np->full_name[19] == ':') { - char *p = np->full_name + 19; - np->full_name = p; - for (; *p; ++p) - if (*p == ':') - *p = '/'; - } - } - - for (child = np->child; child != NULL; child = child->sibling) - mem_start = finish_node(child, mem_start, ifunc, - naddrc, nsizec); - - return mem_start; -} - -/* - * Find the interrupt parent of a node. - */ -static struct device_node * __init -intr_parent(struct device_node *p) -{ - phandle *parp; - - parp = (phandle *) get_property(p, "interrupt-parent", NULL); - if (parp == NULL) - return p->parent; - p = find_phandle(*parp); - if (p != NULL) - return p; - /* - * On a powermac booted with BootX, we don't get to know the - * phandles for any nodes, so find_phandle will return NULL. - * Fortunately these machines only have one interrupt controller - * so there isn't in fact any ambiguity. -- paulus - */ - if (num_interrupt_controllers == 1) - p = dflt_interrupt_controller; - return p; -} - -/* - * Find out the size of each entry of the interrupts property - * for a node. - */ -static int __init -prom_n_intr_cells(struct device_node *np) -{ - struct device_node *p; - unsigned int *icp; - - for (p = np; (p = intr_parent(p)) != NULL; ) { - icp = (unsigned int *) - get_property(p, "#interrupt-cells", NULL); - if (icp != NULL) - return *icp; - if (get_property(p, "interrupt-controller", NULL) != NULL - || get_property(p, "interrupt-map", NULL) != NULL) { - printk("oops, node %s doesn't have #interrupt-cells\n", - p->full_name); - return 1; - } - } - printk("prom_n_intr_cells failed for %s\n", np->full_name); - return 1; -} - -/* - * Map an interrupt from a device up to the platform interrupt - * descriptor. - */ -static int __init -map_interrupt(unsigned int **irq, struct device_node **ictrler, - struct device_node *np, unsigned int *ints, int nintrc) -{ - struct device_node *p, *ipar; - unsigned int *imap, *imask, *ip; - int i, imaplen, match; - int newintrc = 1, newaddrc = 1; - unsigned int *reg; - int naddrc; - - reg = (unsigned int *) get_property(np, "reg", NULL); - naddrc = prom_n_addr_cells(np); - p = intr_parent(np); - while (p != NULL) { - if (get_property(p, "interrupt-controller", NULL) != NULL) - /* this node is an interrupt controller, stop here */ - break; - imap = (unsigned int *) - get_property(p, "interrupt-map", &imaplen); - if (imap == NULL) { - p = intr_parent(p); - continue; - } - imask = (unsigned int *) - get_property(p, "interrupt-map-mask", NULL); - if (imask == NULL) { - printk("oops, %s has interrupt-map but no mask\n", - p->full_name); - return 0; - } - imaplen /= sizeof(unsigned int); - match = 0; - ipar = NULL; - while (imaplen > 0 && !match) { - /* check the child-interrupt field */ - match = 1; - for (i = 0; i < naddrc && match; ++i) - match = ((reg[i] ^ imap[i]) & imask[i]) == 0; - for (; i < naddrc + nintrc && match; ++i) - match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0; - imap += naddrc + nintrc; - imaplen -= naddrc + nintrc; - /* grab the interrupt parent */ - ipar = find_phandle((phandle) *imap++); - --imaplen; - if (ipar == NULL && num_interrupt_controllers == 1) - /* cope with BootX not giving us phandles */ - ipar = dflt_interrupt_controller; - if (ipar == NULL) { - printk("oops, no int parent %x in map of %s\n", - imap[-1], p->full_name); - return 0; - } - /* find the parent's # addr and intr cells */ - ip = (unsigned int *) - get_property(ipar, "#interrupt-cells", NULL); - if (ip == NULL) { - printk("oops, no #interrupt-cells on %s\n", - ipar->full_name); - return 0; - } - newintrc = *ip; - ip = (unsigned int *) - get_property(ipar, "#address-cells", NULL); - newaddrc = (ip == NULL)? 0: *ip; - imap += newaddrc + newintrc; - imaplen -= newaddrc + newintrc; - } - if (imaplen < 0) { - printk("oops, error decoding int-map on %s, len=%d\n", - p->full_name, imaplen); - return 0; - } - if (!match) { - printk("oops, no match in %s int-map for %s\n", - p->full_name, np->full_name); - return 0; - } - p = ipar; - naddrc = newaddrc; - nintrc = newintrc; - ints = imap - nintrc; - reg = ints - naddrc; - } - if (p == NULL) - printk("hmmm, int tree for %s doesn't have ctrler\n", - np->full_name); - *irq = ints; - *ictrler = p; - return nintrc; -} - -/* - * New version of finish_node_interrupts. - */ -static unsigned long __init -finish_node_interrupts(struct device_node *np, unsigned long mem_start) -{ - unsigned int *ints; - int intlen, intrcells; - int i, j, n, offset; - unsigned int *irq; - struct device_node *ic; - - ints = (unsigned int *) get_property(np, "interrupts", &intlen); - if (ints == NULL) - return mem_start; - intrcells = prom_n_intr_cells(np); - intlen /= intrcells * sizeof(unsigned int); - np->n_intrs = intlen; - np->intrs = (struct interrupt_info *) mem_start; - mem_start += intlen * sizeof(struct interrupt_info); - - for (i = 0; i < intlen; ++i) { - np->intrs[i].line = 0; - np->intrs[i].sense = 1; - n = map_interrupt(&irq, &ic, np, ints, intrcells); - if (n <= 0) - continue; - offset = 0; - /* - * On a CHRP we have an 8259 which is subordinate to - * the openpic in the interrupt tree, but we want the - * openpic's interrupt numbers offsetted, not the 8259's. - * So we apply the offset if the controller is at the - * root of the interrupt tree, i.e. has no interrupt-parent. - * This doesn't cope with the general case of multiple - * cascaded interrupt controllers, but then neither will - * irq.c at the moment either. -- paulus - * The G5 triggers that code, I add a machine test. On - * those machines, we want to offset interrupts from the - * second openpic by 128 -- BenH - */ - if (num_interrupt_controllers > 1 - && ic != NULL - && get_property(ic, "interrupt-parent", NULL) == NULL) - offset = 16; - - np->intrs[i].line = irq[0] + offset; - if (n > 1) - np->intrs[i].sense = irq[1]; - if (n > 2) { - printk("hmmm, got %d intr cells for %s:", n, - np->full_name); - for (j = 0; j < n; ++j) - printk(" %d", irq[j]); - printk("\n"); - } - ints += intrcells; - } - - return mem_start; -} - -/* - * When BootX makes a copy of the device tree from the MacOS - * Name Registry, it is in the format we use but all of the pointers - * are offsets from the start of the tree. - * This procedure updates the pointers. - */ -void __init -relocate_nodes(void) -{ - unsigned long base; - struct device_node *np; - struct property *pp; - -#define ADDBASE(x) (x = (typeof (x))((x)? ((unsigned long)(x) + base): 0)) - - base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset; - allnodes = (struct device_node *)(base + 4); - for (np = allnodes; np != 0; np = np->allnext) { - ADDBASE(np->full_name); - ADDBASE(np->properties); - ADDBASE(np->parent); - ADDBASE(np->child); - ADDBASE(np->sibling); - ADDBASE(np->allnext); - for (pp = np->properties; pp != 0; pp = pp->next) { - ADDBASE(pp->name); - ADDBASE(pp->value); - ADDBASE(pp->next); - } - } -} - -int -prom_n_addr_cells(struct device_node* np) -{ - int* ip; - do { - if (np->parent) - np = np->parent; - ip = (int *) get_property(np, "#address-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #address-cells property for the root node, default to 1 */ - return 1; -} - -int -prom_n_size_cells(struct device_node* np) -{ - int* ip; - do { - if (np->parent) - np = np->parent; - ip = (int *) get_property(np, "#size-cells", NULL); - if (ip != NULL) - return *ip; - } while (np->parent); - /* No #size-cells property for the root node, default to 1 */ - return 1; -} - -static unsigned long __init -map_addr(struct device_node *np, unsigned long space, unsigned long addr) -{ - int na; - unsigned int *ranges; - int rlen = 0; - unsigned int type; - - type = (space >> 24) & 3; - if (type == 0) - return addr; - - while ((np = np->parent) != NULL) { - if (strcmp(np->type, "pci") != 0) - continue; - /* PCI bridge: map the address through the ranges property */ - na = prom_n_addr_cells(np); - ranges = (unsigned int *) get_property(np, "ranges", &rlen); - while ((rlen -= (na + 5) * sizeof(unsigned int)) >= 0) { - if (((ranges[0] >> 24) & 3) == type - && ranges[2] <= addr - && addr - ranges[2] < ranges[na+4]) { - /* ok, this matches, translate it */ - addr += ranges[na+2] - ranges[2]; - break; - } - ranges += na + 5; - } - } - return addr; -} - -static unsigned long __init -interpret_pci_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec) -{ - struct address_range *adr; - struct pci_reg_property *pci_addrs; - int i, l, *ip; - - pci_addrs = (struct pci_reg_property *) - get_property(np, "assigned-addresses", &l); - if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) { - i = 0; - adr = (struct address_range *) mem_start; - while ((l -= sizeof(struct pci_reg_property)) >= 0) { - adr[i].space = pci_addrs[i].addr.a_hi; - adr[i].address = map_addr(np, pci_addrs[i].addr.a_hi, - pci_addrs[i].addr.a_lo); - adr[i].size = pci_addrs[i].size_lo; - ++i; - } - np->addrs = adr; - np->n_addrs = i; - mem_start += i * sizeof(struct address_range); - } - - if (use_of_interrupt_tree) - return mem_start; - - ip = (int *) get_property(np, "AAPL,interrupts", &l); - if (ip == 0 && np->parent) - ip = (int *) get_property(np->parent, "AAPL,interrupts", &l); - if (ip == 0) - ip = (int *) get_property(np, "interrupts", &l); - if (ip != 0) { - np->intrs = (struct interrupt_info *) mem_start; - np->n_intrs = l / sizeof(int); - mem_start += np->n_intrs * sizeof(struct interrupt_info); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = *ip++; - np->intrs[i].sense = 1; - } - } - - return mem_start; -} - -static unsigned long __init -interpret_dbdma_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec) -{ - struct reg_property *rp; - struct address_range *adr; - unsigned long base_address; - int i, l, *ip; - struct device_node *db; - - base_address = 0; - for (db = np->parent; db != NULL; db = db->parent) { - if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) { - base_address = db->addrs[0].address; - break; - } - } - - rp = (struct reg_property *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct reg_property)) { - i = 0; - adr = (struct address_range *) mem_start; - while ((l -= sizeof(struct reg_property)) >= 0) { - adr[i].space = 2; - adr[i].address = rp[i].address + base_address; - adr[i].size = rp[i].size; - ++i; - } - np->addrs = adr; - np->n_addrs = i; - mem_start += i * sizeof(struct address_range); - } - - if (use_of_interrupt_tree) - return mem_start; - - ip = (int *) get_property(np, "AAPL,interrupts", &l); - if (ip == 0) - ip = (int *) get_property(np, "interrupts", &l); - if (ip != 0) { - np->intrs = (struct interrupt_info *) mem_start; - np->n_intrs = l / sizeof(int); - mem_start += np->n_intrs * sizeof(struct interrupt_info); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = *ip++; - np->intrs[i].sense = 1; - } - } - - return mem_start; -} - -static unsigned long __init -interpret_macio_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec) -{ - struct reg_property *rp; - struct address_range *adr; - unsigned long base_address; - int i, l, *ip; - struct device_node *db; - - base_address = 0; - for (db = np->parent; db != NULL; db = db->parent) { - if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) { - base_address = db->addrs[0].address; - break; - } - } - - rp = (struct reg_property *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct reg_property)) { - i = 0; - adr = (struct address_range *) mem_start; - while ((l -= sizeof(struct reg_property)) >= 0) { - adr[i].space = 2; - adr[i].address = rp[i].address + base_address; - adr[i].size = rp[i].size; - ++i; - } - np->addrs = adr; - np->n_addrs = i; - mem_start += i * sizeof(struct address_range); - } - - if (use_of_interrupt_tree) - return mem_start; - - ip = (int *) get_property(np, "interrupts", &l); - if (ip == 0) - ip = (int *) get_property(np, "AAPL,interrupts", &l); - if (ip != 0) { - np->intrs = (struct interrupt_info *) mem_start; - np->n_intrs = l / sizeof(int); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = *ip++; - np->intrs[i].sense = 1; - } - mem_start += np->n_intrs * sizeof(struct interrupt_info); - } - - return mem_start; -} - -static unsigned long __init -interpret_isa_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec) -{ - struct isa_reg_property *rp; - struct address_range *adr; - int i, l, *ip; - - rp = (struct isa_reg_property *) get_property(np, "reg", &l); - if (rp != 0 && l >= sizeof(struct isa_reg_property)) { - i = 0; - adr = (struct address_range *) mem_start; - while ((l -= sizeof(struct reg_property)) >= 0) { - adr[i].space = rp[i].space; - adr[i].address = rp[i].address - + (adr[i].space? 0: _ISA_MEM_BASE); - adr[i].size = rp[i].size; - ++i; - } - np->addrs = adr; - np->n_addrs = i; - mem_start += i * sizeof(struct address_range); - } - - if (use_of_interrupt_tree) - return mem_start; - - ip = (int *) get_property(np, "interrupts", &l); - if (ip != 0) { - np->intrs = (struct interrupt_info *) mem_start; - np->n_intrs = l / (2 * sizeof(int)); - mem_start += np->n_intrs * sizeof(struct interrupt_info); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = *ip++; - np->intrs[i].sense = *ip++; - } - } - - return mem_start; -} - -static unsigned long __init -interpret_root_props(struct device_node *np, unsigned long mem_start, - int naddrc, int nsizec) -{ - struct address_range *adr; - int i, l, *ip; - unsigned int *rp; - int rpsize = (naddrc + nsizec) * sizeof(unsigned int); - - rp = (unsigned int *) get_property(np, "reg", &l); - if (rp != 0 && l >= rpsize) { - i = 0; - adr = (struct address_range *) mem_start; - while ((l -= rpsize) >= 0) { - adr[i].space = (naddrc >= 2? rp[naddrc-2]: 2); - adr[i].address = rp[naddrc - 1]; - adr[i].size = rp[naddrc + nsizec - 1]; - ++i; - rp += naddrc + nsizec; - } - np->addrs = adr; - np->n_addrs = i; - mem_start += i * sizeof(struct address_range); - } - - if (use_of_interrupt_tree) - return mem_start; - - ip = (int *) get_property(np, "AAPL,interrupts", &l); - if (ip == 0) - ip = (int *) get_property(np, "interrupts", &l); - if (ip != 0) { - np->intrs = (struct interrupt_info *) mem_start; - np->n_intrs = l / sizeof(int); - mem_start += np->n_intrs * sizeof(struct interrupt_info); - for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = *ip++; - np->intrs[i].sense = 1; - } - } - - return mem_start; -} - -/* - * Work out the sense (active-low level / active-high edge) - * of each interrupt from the device tree. - */ -void __init -prom_get_irq_senses(unsigned char *senses, int off, int max) -{ - struct device_node *np; - int i, j; - - /* default to level-triggered */ - memset(senses, 1, max - off); - if (!use_of_interrupt_tree) - return; - - for (np = allnodes; np != 0; np = np->allnext) { - for (j = 0; j < np->n_intrs; j++) { - i = np->intrs[j].line; - if (i >= off && i < max) { - if (np->intrs[j].sense == 1) - senses[i-off] = (IRQ_SENSE_LEVEL - | IRQ_POLARITY_NEGATIVE); - else - senses[i-off] = (IRQ_SENSE_EDGE - | IRQ_POLARITY_POSITIVE); - } - } - } -} - -/* - * Construct and return a list of the device_nodes with a given name. - */ -struct device_node * -find_devices(const char *name) -{ - struct device_node *head, **prevp, *np; - - prevp = &head; - for (np = allnodes; np != 0; np = np->allnext) { - if (np->name != 0 && strcasecmp(np->name, name) == 0) { - *prevp = np; - prevp = &np->next; - } - } - *prevp = NULL; - return head; -} - -/* - * Construct and return a list of the device_nodes with a given type. - */ -struct device_node * -find_type_devices(const char *type) -{ - struct device_node *head, **prevp, *np; - - prevp = &head; - for (np = allnodes; np != 0; np = np->allnext) { - if (np->type != 0 && strcasecmp(np->type, type) == 0) { - *prevp = np; - prevp = &np->next; - } - } - *prevp = NULL; - return head; -} - -/* - * Returns all nodes linked together - */ -struct device_node * -find_all_nodes(void) -{ - struct device_node *head, **prevp, *np; - - prevp = &head; - for (np = allnodes; np != 0; np = np->allnext) { - *prevp = np; - prevp = &np->next; - } - *prevp = NULL; - return head; -} - -/* Checks if the given "compat" string matches one of the strings in - * the device's "compatible" property - */ -int -device_is_compatible(struct device_node *device, const char *compat) -{ - const char* cp; - int cplen, l; - - cp = (char *) get_property(device, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (strncasecmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; - } - - return 0; -} - - -/* - * Indicates whether the root node has a given value in its - * compatible property. - */ -int -machine_is_compatible(const char *compat) -{ - struct device_node *root; - - root = find_path_device("/"); - if (root == 0) - return 0; - return device_is_compatible(root, compat); -} - -/* - * Construct and return a list of the device_nodes with a given type - * and compatible property. - */ -struct device_node * -find_compatible_devices(const char *type, const char *compat) -{ - struct device_node *head, **prevp, *np; - - prevp = &head; - for (np = allnodes; np != 0; np = np->allnext) { - if (type != NULL - && !(np->type != 0 && strcasecmp(np->type, type) == 0)) - continue; - if (device_is_compatible(np, compat)) { - *prevp = np; - prevp = &np->next; - } - } - *prevp = NULL; - return head; -} - -/* - * Find the device_node with a given full_name. - */ -struct device_node * -find_path_device(const char *path) -{ - struct device_node *np; - - for (np = allnodes; np != 0; np = np->allnext) - if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0) - return np; - return NULL; -} - -/******* - * - * New implementation of the OF "find" APIs, return a refcounted - * object, call of_node_put() when done. Currently, still lacks - * locking as old implementation, this is beeing done for ppc64. - * - * Note that property management will need some locking as well, - * this isn't dealt with yet - * - *******/ - -/** - * of_find_node_by_name - Find a node by it's "name" property - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. of_node_put() will be called on it - * @name: The name string to match against - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_node_by_name(struct device_node *from, - const char *name) -{ - struct device_node *np = from ? from->allnext : allnodes; - - for (; np != 0; np = np->allnext) - if (np->name != 0 && strcasecmp(np->name, name) == 0) - break; - if (from) - of_node_put(from); - return of_node_get(np); -} - -/** - * of_find_node_by_type - Find a node by it's "device_type" property - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. of_node_put() will be called on it - * @name: The type string to match against - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_node_by_type(struct device_node *from, - const char *type) -{ - struct device_node *np = from ? from->allnext : allnodes; - - for (; np != 0; np = np->allnext) - if (np->type != 0 && strcasecmp(np->type, type) == 0) - break; - if (from) - of_node_put(from); - return of_node_get(np); -} - -/** - * of_find_compatible_node - Find a node based on type and one of the - * tokens in it's "compatible" property - * @from: The node to start searching from or NULL, the node - * you pass will not be searched, only the next one - * will; typically, you pass what the previous call - * returned. of_node_put() will be called on it - * @type: The type string to match "device_type" or NULL to ignore - * @compatible: The string to match to one of the tokens in the device - * "compatible" list. - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_compatible_node(struct device_node *from, - const char *type, const char *compatible) -{ - struct device_node *np = from ? from->allnext : allnodes; - - for (; np != 0; np = np->allnext) { - if (type != NULL - && !(np->type != 0 && strcasecmp(np->type, type) == 0)) - continue; - if (device_is_compatible(np, compatible)) - break; - } - if (from) - of_node_put(from); - return of_node_get(np); -} - -/** - * of_find_node_by_path - Find a node matching a full OF path - * @path: The full path to match - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_node_by_path(const char *path) -{ - struct device_node *np = allnodes; - - for (; np != 0; np = np->allnext) - if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0) - break; - return of_node_get(np); -} - -/** - * of_find_all_nodes - Get next node in global list - * @prev: Previous node or NULL to start iteration - * of_node_put() will be called on it - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_find_all_nodes(struct device_node *prev) -{ - return of_node_get(prev ? prev->allnext : allnodes); -} - -/** - * of_get_parent - Get a node's parent if any - * @node: Node to get parent - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_get_parent(const struct device_node *node) -{ - return node ? of_node_get(node->parent) : NULL; -} - -/** - * of_get_next_child - Iterate a node childs - * @node: parent node - * @prev: previous child of the parent node, or NULL to get first - * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. - */ -struct device_node *of_get_next_child(const struct device_node *node, - struct device_node *prev) -{ - struct device_node *next = prev ? prev->sibling : node->child; - - for (; next != 0; next = next->sibling) - if (of_node_get(next)) - break; - if (prev) - of_node_put(prev); - return next; -} - -/** - * of_node_get - Increment refcount of a node - * @node: Node to inc refcount, NULL is supported to - * simplify writing of callers - * - * Returns the node itself or NULL if gone. Current implementation - * does nothing as we don't yet do dynamic node allocation on ppc32 - */ -struct device_node *of_node_get(struct device_node *node) -{ - return node; -} - -/** - * of_node_put - Decrement refcount of a node - * @node: Node to dec refcount, NULL is supported to - * simplify writing of callers - * - * Current implementation does nothing as we don't yet do dynamic node - * allocation on ppc32 - */ -void of_node_put(struct device_node *node) -{ -} - -/* - * Find the device_node with a given phandle. - */ -static struct device_node * __init -find_phandle(phandle ph) -{ - struct device_node *np; - - for (np = allnodes; np != 0; np = np->allnext) - if (np->node == ph) - return np; - return NULL; -} - -/* - * Find a property with a given name for a given node - * and return the value. - */ -unsigned char * -get_property(struct device_node *np, const char *name, int *lenp) -{ - struct property *pp; - - for (pp = np->properties; pp != 0; pp = pp->next) - if (pp->name != NULL && strcmp(pp->name, name) == 0) { - if (lenp != 0) - *lenp = pp->length; - return pp->value; - } - return NULL; -} - -/* - * Add a property to a node - */ -int -prom_add_property(struct device_node* np, struct property* prop) -{ - struct property **next = &np->properties; - - prop->next = NULL; - while (*next) - next = &(*next)->next; - *next = prop; - - return 0; -} - -/* I quickly hacked that one, check against spec ! */ -static inline unsigned long -bus_space_to_resource_flags(unsigned int bus_space) -{ - u8 space = (bus_space >> 24) & 0xf; - if (space == 0) - space = 0x02; - if (space == 0x02) - return IORESOURCE_MEM; - else if (space == 0x01) - return IORESOURCE_IO; - else { - printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n", - bus_space); - return 0; - } -} - -static struct resource* -find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range) -{ - unsigned long mask; - int i; - - /* Check this one */ - mask = bus_space_to_resource_flags(range->space); - for (i=0; iresource[i].flags & mask) == mask && - pdev->resource[i].start <= range->address && - pdev->resource[i].end > range->address) { - if ((range->address + range->size - 1) > pdev->resource[i].end) { - /* Add better message */ - printk(KERN_WARNING "PCI/OF resource overlap !\n"); - return NULL; - } - break; - } - } - if (i == DEVICE_COUNT_RESOURCE) - return NULL; - return &pdev->resource[i]; -} - -/* - * Request an OF device resource. Currently handles child of PCI devices, - * or other nodes attached to the root node. Ultimately, put some - * link to resources in the OF node. - */ -struct resource* -request_OF_resource(struct device_node* node, int index, const char* name_postfix) -{ - struct pci_dev* pcidev; - u8 pci_bus, pci_devfn; - unsigned long iomask; - struct device_node* nd; - struct resource* parent; - struct resource *res = NULL; - int nlen, plen; - - if (index >= node->n_addrs) - goto fail; - - /* Sanity check on bus space */ - iomask = bus_space_to_resource_flags(node->addrs[index].space); - if (iomask & IORESOURCE_MEM) - parent = &iomem_resource; - else if (iomask & IORESOURCE_IO) - parent = &ioport_resource; - else - goto fail; - - /* Find a PCI parent if any */ - nd = node; - pcidev = NULL; - while(nd) { - if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) - pcidev = pci_find_slot(pci_bus, pci_devfn); - if (pcidev) break; - nd = nd->parent; - } - if (pcidev) - parent = find_parent_pci_resource(pcidev, &node->addrs[index]); - if (!parent) { - printk(KERN_WARNING "request_OF_resource(%s), parent not found\n", - node->name); - goto fail; - } - - res = __request_region(parent, node->addrs[index].address, node->addrs[index].size, NULL); - if (!res) - goto fail; - nlen = strlen(node->name); - plen = name_postfix ? strlen(name_postfix) : 0; - res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL); - if (res->name) { - strcpy((char *)res->name, node->name); - if (plen) - strcpy((char *)res->name+nlen, name_postfix); - } - return res; -fail: - return NULL; -} - -int -release_OF_resource(struct device_node* node, int index) -{ - struct pci_dev* pcidev; - u8 pci_bus, pci_devfn; - unsigned long iomask, start, end; - struct device_node* nd; - struct resource* parent; - struct resource *res = NULL; - - if (index >= node->n_addrs) - return -EINVAL; - - /* Sanity check on bus space */ - iomask = bus_space_to_resource_flags(node->addrs[index].space); - if (iomask & IORESOURCE_MEM) - parent = &iomem_resource; - else if (iomask & IORESOURCE_IO) - parent = &ioport_resource; - else - return -EINVAL; - - /* Find a PCI parent if any */ - nd = node; - pcidev = NULL; - while(nd) { - if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn)) - pcidev = pci_find_slot(pci_bus, pci_devfn); - if (pcidev) break; - nd = nd->parent; - } - if (pcidev) - parent = find_parent_pci_resource(pcidev, &node->addrs[index]); - if (!parent) { - printk(KERN_WARNING "release_OF_resource(%s), parent not found\n", - node->name); - return -ENODEV; - } - - /* Find us in the parent and its childs */ - res = parent->child; - start = node->addrs[index].address; - end = start + node->addrs[index].size - 1; - while (res) { - if (res->start == start && res->end == end && - (res->flags & IORESOURCE_BUSY)) - break; - if (res->start <= start && res->end >= end) - res = res->child; - else - res = res->sibling; - } - if (!res) - return -ENODEV; - - kfree(res->name); - res->name = NULL; - release_resource(res); - kfree(res); - - return 0; -} - -#if 0 -void -print_properties(struct device_node *np) -{ - struct property *pp; - char *cp; - int i, n; - - for (pp = np->properties; pp != 0; pp = pp->next) { - printk(KERN_INFO "%s", pp->name); - for (i = strlen(pp->name); i < 16; ++i) - printk(" "); - cp = (char *) pp->value; - for (i = pp->length; i > 0; --i, ++cp) - if ((i > 1 && (*cp < 0x20 || *cp > 0x7e)) - || (i == 1 && *cp != 0)) - break; - if (i == 0 && pp->length > 1) { - /* looks like a string */ - printk(" %s\n", (char *) pp->value); - } else { - /* dump it in hex */ - n = pp->length; - if (n > 64) - n = 64; - if (pp->length % 4 == 0) { - unsigned int *p = (unsigned int *) pp->value; - - n /= 4; - for (i = 0; i < n; ++i) { - if (i != 0 && (i % 4) == 0) - printk("\n "); - printk(" %08x", *p++); - } - } else { - unsigned char *bp = pp->value; - - for (i = 0; i < n; ++i) { - if (i != 0 && (i % 16) == 0) - printk("\n "); - printk(" %02x", *bp++); - } - } - printk("\n"); - if (pp->length > 64) - printk(" ... (length = %d)\n", - pp->length); - } - } -} -#endif - -static DEFINE_SPINLOCK(rtas_lock); - -/* this can be called after setup -- Cort */ -int -call_rtas(const char *service, int nargs, int nret, - unsigned long *outputs, ...) -{ - va_list list; - int i; - unsigned long s; - struct device_node *rtas; - int *tokp; - union { - unsigned long words[16]; - double align; - } u; - - rtas = find_devices("rtas"); - if (rtas == NULL) - return -1; - tokp = (int *) get_property(rtas, service, NULL); - if (tokp == NULL) { - printk(KERN_ERR "No RTAS service called %s\n", service); - return -1; - } - u.words[0] = *tokp; - u.words[1] = nargs; - u.words[2] = nret; - va_start(list, outputs); - for (i = 0; i < nargs; ++i) - u.words[i+3] = va_arg(list, unsigned long); - va_end(list); - - /* - * RTAS doesn't use floating point. - * Or at least, according to the CHRP spec we enter RTAS - * with FP disabled, and it doesn't change the FP registers. - * -- paulus. - */ - spin_lock_irqsave(&rtas_lock, s); - enter_rtas((void *)__pa(&u)); - spin_unlock_irqrestore(&rtas_lock, s); - - if (nret > 1 && outputs != NULL) - for (i = 0; i < nret-1; ++i) - outputs[i] = u.words[i+nargs+4]; - return u.words[nargs+3]; -} diff --git a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c deleted file mode 100644 index df14422ae1c6..000000000000 --- a/arch/ppc/syslib/prom_init.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* - * Note that prom_init() and anything called from prom_init() - * may be running at an address that is different from the address - * that it was linked at. References to static data items are - * handled by compiling this file with -mrelocatable-lib. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_LOGO_LINUX_CLUT224 -#include -extern const struct linux_logo logo_linux_clut224; -#endif - -/* - * Properties whose value is longer than this get excluded from our - * copy of the device tree. This way we don't waste space storing - * things like "driver,AAPL,MacOS,PowerPC" properties. But this value - * does need to be big enough to ensure that we don't lose things - * like the interrupt-map property on a PCI-PCI bridge. - */ -#define MAX_PROPERTY_LENGTH 4096 - -#ifndef FB_MAX /* avoid pulling in all of the fb stuff */ -#define FB_MAX 8 -#endif - -#define ALIGNUL(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long)) - -typedef u32 prom_arg_t; - -struct prom_args { - const char *service; - int nargs; - int nret; - prom_arg_t args[10]; -}; - -struct pci_address { - unsigned a_hi; - unsigned a_mid; - unsigned a_lo; -}; - -struct pci_reg_property { - struct pci_address addr; - unsigned size_hi; - unsigned size_lo; -}; - -struct pci_range { - struct pci_address addr; - unsigned phys; - unsigned size_hi; - unsigned size_lo; -}; - -struct isa_reg_property { - unsigned space; - unsigned address; - unsigned size; -}; - -struct pci_intr_map { - struct pci_address addr; - unsigned dunno; - phandle int_ctrler; - unsigned intr; -}; - -static void prom_exit(void); -static int call_prom(const char *service, int nargs, int nret, ...); -static int call_prom_ret(const char *service, int nargs, int nret, - prom_arg_t *rets, ...); -static void prom_print_hex(unsigned int v); -static int prom_set_color(ihandle ih, int i, int r, int g, int b); -static int prom_next_node(phandle *nodep); -static unsigned long check_display(unsigned long mem); -static void setup_disp_fake_bi(ihandle dp); -static unsigned long copy_device_tree(unsigned long mem_start, - unsigned long mem_end); -static unsigned long inspect_node(phandle node, struct device_node *dad, - unsigned long mem_start, unsigned long mem_end, - struct device_node ***allnextpp); -static void prom_hold_cpus(unsigned long mem); -static void prom_instantiate_rtas(void); -static void * early_get_property(unsigned long base, unsigned long node, - char *prop); - -prom_entry prom __initdata; -ihandle prom_chosen __initdata; -ihandle prom_stdout __initdata; - -static char *prom_display_paths[FB_MAX] __initdata; -static phandle prom_display_nodes[FB_MAX] __initdata; -static unsigned int prom_num_displays __initdata; -static ihandle prom_disp_node __initdata; -char *of_stdout_device __initdata; - -unsigned int rtas_data; /* physical pointer */ -unsigned int rtas_entry; /* physical pointer */ -unsigned int rtas_size; -unsigned int old_rtas; - -boot_infos_t *boot_infos; -char *bootpath; -char *bootdevice; -struct device_node *allnodes; - -extern char *klimit; - -static void __init -prom_exit(void) -{ - struct prom_args args; - - args.service = "exit"; - args.nargs = 0; - args.nret = 0; - prom(&args); - for (;;) /* should never get here */ - ; -} - -static int __init -call_prom(const char *service, int nargs, int nret, ...) -{ - va_list list; - int i; - struct prom_args prom_args; - - prom_args.service = service; - prom_args.nargs = nargs; - prom_args.nret = nret; - va_start(list, nret); - for (i = 0; i < nargs; ++i) - prom_args.args[i] = va_arg(list, prom_arg_t); - va_end(list); - for (i = 0; i < nret; ++i) - prom_args.args[i + nargs] = 0; - prom(&prom_args); - return prom_args.args[nargs]; -} - -static int __init -call_prom_ret(const char *service, int nargs, int nret, prom_arg_t *rets, ...) -{ - va_list list; - int i; - struct prom_args prom_args; - - prom_args.service = service; - prom_args.nargs = nargs; - prom_args.nret = nret; - va_start(list, rets); - for (i = 0; i < nargs; ++i) - prom_args.args[i] = va_arg(list, int); - va_end(list); - for (i = 0; i < nret; ++i) - prom_args.args[i + nargs] = 0; - prom(&prom_args); - for (i = 1; i < nret; ++i) - rets[i-1] = prom_args.args[nargs + i]; - return prom_args.args[nargs]; -} - -void __init -prom_print(const char *msg) -{ - const char *p, *q; - - if (prom_stdout == 0) - return; - - for (p = msg; *p != 0; p = q) { - for (q = p; *q != 0 && *q != '\n'; ++q) - ; - if (q > p) - call_prom("write", 3, 1, prom_stdout, p, q - p); - if (*q != 0) { - ++q; - call_prom("write", 3, 1, prom_stdout, "\r\n", 2); - } - } -} - -static void __init -prom_print_hex(unsigned int v) -{ - char buf[16]; - int i, c; - - for (i = 0; i < 8; ++i) { - c = (v >> ((7-i)*4)) & 0xf; - c += (c >= 10)? ('a' - 10): '0'; - buf[i] = c; - } - buf[i] = ' '; - buf[i+1] = 0; - prom_print(buf); -} - -static int __init -prom_set_color(ihandle ih, int i, int r, int g, int b) -{ - return call_prom("call-method", 6, 1, "color!", ih, i, b, g, r); -} - -static int __init -prom_next_node(phandle *nodep) -{ - phandle node; - - if ((node = *nodep) != 0 - && (*nodep = call_prom("child", 1, 1, node)) != 0) - return 1; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - for (;;) { - if ((node = call_prom("parent", 1, 1, node)) == 0) - return 0; - if ((*nodep = call_prom("peer", 1, 1, node)) != 0) - return 1; - } -} - -#ifdef CONFIG_POWER4 -/* - * Set up a hash table with a set of entries in it to map the - * first 64MB of RAM. This is used on 64-bit machines since - * some of them don't have BATs. - */ - -static inline void make_pte(unsigned long htab, unsigned int hsize, - unsigned int va, unsigned int pa, int mode) -{ - unsigned int *pteg; - unsigned int hash, i, vsid; - - vsid = ((va >> 28) * 0x111) << 12; - hash = ((va ^ vsid) >> 5) & 0x7fff80; - pteg = (unsigned int *)(htab + (hash & (hsize - 1))); - for (i = 0; i < 8; ++i, pteg += 4) { - if ((pteg[1] & 1) == 0) { - pteg[1] = vsid | ((va >> 16) & 0xf80) | 1; - pteg[3] = pa | mode; - break; - } - } -} - -extern unsigned long _SDR1; -extern PTE *Hash; -extern unsigned long Hash_size; - -static void __init -prom_alloc_htab(void) -{ - unsigned int hsize; - unsigned long htab; - unsigned int addr; - - /* - * Because of OF bugs we can't use the "claim" client - * interface to allocate memory for the hash table. - * This code is only used on 64-bit PPCs, and the only - * 64-bit PPCs at the moment are RS/6000s, and their - * OF is based at 0xc00000 (the 12M point), so we just - * arbitrarily use the 0x800000 - 0xc00000 region for the - * hash table. - * -- paulus. - */ - hsize = 4 << 20; /* POWER4 has no BATs */ - htab = (8 << 20); - call_prom("claim", 3, 1, htab, hsize, 0); - Hash = (void *)(htab + KERNELBASE); - Hash_size = hsize; - _SDR1 = htab + __ilog2(hsize) - 18; - - /* - * Put in PTEs for the first 64MB of RAM - */ - memset((void *)htab, 0, hsize); - for (addr = 0; addr < 0x4000000; addr += 0x1000) - make_pte(htab, hsize, addr + KERNELBASE, addr, - _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX); -#if 0 /* DEBUG stuff mapping the SCC */ - make_pte(htab, hsize, 0x80013000, 0x80013000, - _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX); -#endif -} -#endif /* CONFIG_POWER4 */ - - -/* - * If we have a display that we don't know how to drive, - * we will want to try to execute OF's open method for it - * later. However, OF will probably fall over if we do that - * we've taken over the MMU. - * So we check whether we will need to open the display, - * and if so, open it now. - */ -static unsigned long __init -check_display(unsigned long mem) -{ - phandle node; - ihandle ih; - int i, j; - char type[16], *path; - static unsigned char default_colors[] = { - 0x00, 0x00, 0x00, - 0x00, 0x00, 0xaa, - 0x00, 0xaa, 0x00, - 0x00, 0xaa, 0xaa, - 0xaa, 0x00, 0x00, - 0xaa, 0x00, 0xaa, - 0xaa, 0xaa, 0x00, - 0xaa, 0xaa, 0xaa, - 0x55, 0x55, 0x55, - 0x55, 0x55, 0xff, - 0x55, 0xff, 0x55, - 0x55, 0xff, 0xff, - 0xff, 0x55, 0x55, - 0xff, 0x55, 0xff, - 0xff, 0xff, 0x55, - 0xff, 0xff, 0xff - }; - const unsigned char *clut; - - prom_disp_node = 0; - - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - call_prom("getprop", 4, 1, node, "device_type", - type, sizeof(type)); - if (strcmp(type, "display") != 0) - continue; - /* It seems OF doesn't null-terminate the path :-( */ - path = (char *) mem; - memset(path, 0, 256); - if (call_prom("package-to-path", 3, 1, node, path, 255) < 0) - continue; - - /* - * If this display is the device that OF is using for stdout, - * move it to the front of the list. - */ - mem += strlen(path) + 1; - i = prom_num_displays++; - if (of_stdout_device != 0 && i > 0 - && strcmp(of_stdout_device, path) == 0) { - for (; i > 0; --i) { - prom_display_paths[i] - = prom_display_paths[i-1]; - prom_display_nodes[i] - = prom_display_nodes[i-1]; - } - } - prom_display_paths[i] = path; - prom_display_nodes[i] = node; - if (i == 0) - prom_disp_node = node; - if (prom_num_displays >= FB_MAX) - break; - } - - for (j=0; j 0) { - prom_disp_node = prom_display_nodes[j]; - j--; - } else - prom_disp_node = 0; - continue; - } else { - prom_print("... ok\n"); - call_prom("setprop", 4, 1, node, "linux,opened", 0, 0); - - /* - * Setup a usable color table when the appropriate - * method is available. - * Should update this to use set-colors. - */ - clut = default_colors; - for (i = 0; i < 32; i++, clut += 3) - if (prom_set_color(ih, i, clut[0], clut[1], - clut[2]) != 0) - break; - -#ifdef CONFIG_LOGO_LINUX_CLUT224 - clut = PTRRELOC(logo_linux_clut224.clut); - for (i = 0; i < logo_linux_clut224.clutsize; - i++, clut += 3) - if (prom_set_color(ih, i + 32, clut[0], - clut[1], clut[2]) != 0) - break; -#endif /* CONFIG_LOGO_LINUX_CLUT224 */ - } - } - - if (prom_stdout) { - phandle p; - p = call_prom("instance-to-package", 1, 1, prom_stdout); - if (p && p != -1) { - type[0] = 0; - call_prom("getprop", 4, 1, p, "device_type", - type, sizeof(type)); - if (strcmp(type, "display") == 0) - call_prom("setprop", 4, 1, p, "linux,boot-display", - 0, 0); - } - } - - return ALIGNUL(mem); -} - -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too - */ -static void __init -setup_disp_fake_bi(ihandle dp) -{ -#ifdef CONFIG_BOOTX_TEXT - int width = 640, height = 480, depth = 8, pitch; - unsigned address; - struct pci_reg_property addrs[8]; - int i, naddrs; - char name[32]; - char *getprop = "getprop"; - - prom_print("Initializing fake screen: "); - - memset(name, 0, sizeof(name)); - call_prom(getprop, 4, 1, dp, "name", name, sizeof(name)); - name[sizeof(name)-1] = 0; - prom_print(name); - prom_print("\n"); - call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width)); - call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height)); - call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth)); - pitch = width * ((depth + 7) / 8); - call_prom(getprop, 4, 1, dp, "linebytes", - &pitch, sizeof(pitch)); - if (pitch == 1) - pitch = 0x1000; /* for strange IBM display */ - address = 0; - call_prom(getprop, 4, 1, dp, "address", - &address, sizeof(address)); - if (address == 0) { - /* look for an assigned address with a size of >= 1MB */ - naddrs = call_prom(getprop, 4, 1, dp, "assigned-addresses", - addrs, sizeof(addrs)); - naddrs /= sizeof(struct pci_reg_property); - for (i = 0; i < naddrs; ++i) { - if (addrs[i].size_lo >= (1 << 20)) { - address = addrs[i].addr.a_lo; - /* use the BE aperture if possible */ - if (addrs[i].size_lo >= (16 << 20)) - address += (8 << 20); - break; - } - } - if (address == 0) { - prom_print("Failed to get address\n"); - return; - } - } - /* kludge for valkyrie */ - if (strcmp(name, "valkyrie") == 0) - address += 0x1000; - -#ifdef CONFIG_POWER4 -#if CONFIG_TASK_SIZE > 0x80000000 -#error CONFIG_TASK_SIZE cannot be above 0x80000000 with BOOTX_TEXT on G5 -#endif - { - extern boot_infos_t disp_bi; - unsigned long va, pa, i, offset; - va = 0x90000000; - pa = address & 0xfffff000ul; - offset = address & 0x00000fff; - - for (i=0; i<0x4000; i++) { - make_pte((unsigned long)Hash - KERNELBASE, Hash_size, va, pa, - _PAGE_ACCESSED | _PAGE_NO_CACHE | - _PAGE_GUARDED | PP_RWXX); - va += 0x1000; - pa += 0x1000; - } - btext_setup_display(width, height, depth, pitch, 0x90000000 | offset); - disp_bi.dispDeviceBase = (u8 *)address; - } -#else /* CONFIG_POWER4 */ - btext_setup_display(width, height, depth, pitch, address); - btext_prepare_BAT(); -#endif /* CONFIG_POWER4 */ -#endif /* CONFIG_BOOTX_TEXT */ -} - -/* - * Make a copy of the device tree from the PROM. - */ -static unsigned long __init -copy_device_tree(unsigned long mem_start, unsigned long mem_end) -{ - phandle root; - unsigned long new_start; - struct device_node **allnextp; - - root = call_prom("peer", 1, 1, (phandle)0); - if (root == (phandle)0) { - prom_print("couldn't get device tree root\n"); - prom_exit(); - } - allnextp = &allnodes; - mem_start = ALIGNUL(mem_start); - new_start = inspect_node(root, NULL, mem_start, mem_end, &allnextp); - *allnextp = NULL; - return new_start; -} - -static unsigned long __init -inspect_node(phandle node, struct device_node *dad, - unsigned long mem_start, unsigned long mem_end, - struct device_node ***allnextpp) -{ - int l; - phandle child; - struct device_node *np; - struct property *pp, **prev_propp; - char *prev_name, *namep; - unsigned char *valp; - - np = (struct device_node *) mem_start; - mem_start += sizeof(struct device_node); - memset(np, 0, sizeof(*np)); - np->node = node; - **allnextpp = PTRUNRELOC(np); - *allnextpp = &np->allnext; - if (dad != 0) { - np->parent = PTRUNRELOC(dad); - /* we temporarily use the `next' field as `last_child'. */ - if (dad->next == 0) - dad->child = PTRUNRELOC(np); - else - dad->next->sibling = PTRUNRELOC(np); - dad->next = np; - } - - /* get and store all properties */ - prev_propp = &np->properties; - prev_name = ""; - for (;;) { - pp = (struct property *) mem_start; - namep = (char *) (pp + 1); - pp->name = PTRUNRELOC(namep); - if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) - break; - mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1); - prev_name = namep; - valp = (unsigned char *) mem_start; - pp->value = PTRUNRELOC(valp); - pp->length = call_prom("getprop", 4, 1, node, namep, - valp, mem_end - mem_start); - if (pp->length < 0) - continue; -#ifdef MAX_PROPERTY_LENGTH - if (pp->length > MAX_PROPERTY_LENGTH) - continue; /* ignore this property */ -#endif - mem_start = ALIGNUL(mem_start + pp->length); - *prev_propp = PTRUNRELOC(pp); - prev_propp = &pp->next; - } - if (np->node != 0) { - /* Add a "linux,phandle" property" */ - pp = (struct property *) mem_start; - *prev_propp = PTRUNRELOC(pp); - prev_propp = &pp->next; - namep = (char *) (pp + 1); - pp->name = PTRUNRELOC(namep); - strcpy(namep, "linux,phandle"); - mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1); - pp->value = (unsigned char *) PTRUNRELOC(&np->node); - pp->length = sizeof(np->node); - } - *prev_propp = NULL; - - /* get the node's full name */ - l = call_prom("package-to-path", 3, 1, node, - mem_start, mem_end - mem_start); - if (l >= 0) { - char *p, *ep; - - np->full_name = PTRUNRELOC((char *) mem_start); - *(char *)(mem_start + l) = 0; - /* Fixup an Apple bug where they have bogus \0 chars in the - * middle of the path in some properties - */ - for (p = (char *)mem_start, ep = p + l; p < ep; p++) - if ((*p) == '\0') { - memmove(p, p+1, ep - p); - ep--; - } - mem_start = ALIGNUL(mem_start + l + 1); - } - - /* do all our children */ - child = call_prom("child", 1, 1, node); - while (child != 0) { - mem_start = inspect_node(child, np, mem_start, mem_end, - allnextpp); - child = call_prom("peer", 1, 1, child); - } - - return mem_start; -} - -unsigned long smp_chrp_cpu_nr __initdata = 0; - -/* - * With CHRP SMP we need to use the OF to start the other - * processors so we can't wait until smp_boot_cpus (the OF is - * trashed by then) so we have to put the processors into - * a holding pattern controlled by the kernel (not OF) before - * we destroy the OF. - * - * This uses a chunk of high memory, puts some holding pattern - * code there and sends the other processors off to there until - * smp_boot_cpus tells them to do something. We do that by using - * physical address 0x0. The holding pattern checks that address - * until its cpu # is there, when it is that cpu jumps to - * __secondary_start(). smp_boot_cpus() takes care of setting those - * values. - * - * We also use physical address 0x4 here to tell when a cpu - * is in its holding pattern code. - * - * -- Cort - * - * Note that we have to do this if we have more than one CPU, - * even if this is a UP kernel. Otherwise when we trash OF - * the other CPUs will start executing some random instructions - * and crash the system. -- paulus - */ -static void __init -prom_hold_cpus(unsigned long mem) -{ - extern void __secondary_hold(void); - unsigned long i; - int cpu; - phandle node; - char type[16], *path; - unsigned int reg; - - /* - * XXX: hack to make sure we're chrp, assume that if we're - * chrp we have a device_type property -- Cort - */ - node = call_prom("finddevice", 1, 1, "/"); - if (call_prom("getprop", 4, 1, node, - "device_type", type, sizeof(type)) <= 0) - return; - - /* copy the holding pattern code to someplace safe (0) */ - /* the holding pattern is now within the first 0x100 - bytes of the kernel image -- paulus */ - memcpy((void *)0, _stext, 0x100); - flush_icache_range(0, 0x100); - - /* look for cpus */ - *(unsigned long *)(0x0) = 0; - asm volatile("dcbf 0,%0": : "r" (0) : "memory"); - for (node = 0; prom_next_node(&node); ) { - type[0] = 0; - call_prom("getprop", 4, 1, node, "device_type", - type, sizeof(type)); - if (strcmp(type, "cpu") != 0) - continue; - path = (char *) mem; - memset(path, 0, 256); - if (call_prom("package-to-path", 3, 1, node, path, 255) < 0) - continue; - reg = -1; - call_prom("getprop", 4, 1, node, "reg", ®, sizeof(reg)); - cpu = smp_chrp_cpu_nr++; -#ifdef CONFIG_SMP - smp_hw_index[cpu] = reg; -#endif /* CONFIG_SMP */ - /* XXX: hack - don't start cpu 0, this cpu -- Cort */ - if (cpu == 0) - continue; - prom_print("starting cpu "); - prom_print(path); - *(ulong *)(0x4) = 0; - call_prom("start-cpu", 3, 0, node, - (char *)__secondary_hold - _stext, cpu); - prom_print("..."); - for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ ) - ; - if (*(ulong *)(0x4) == cpu) - prom_print("ok\n"); - else { - prom_print("failed: "); - prom_print_hex(*(ulong *)0x4); - prom_print("\n"); - } - } -} - -static void __init -prom_instantiate_rtas(void) -{ - ihandle prom_rtas; - prom_arg_t result; - - prom_rtas = call_prom("finddevice", 1, 1, "/rtas"); - if (prom_rtas == -1) - return; - - rtas_size = 0; - call_prom("getprop", 4, 1, prom_rtas, - "rtas-size", &rtas_size, sizeof(rtas_size)); - prom_print("instantiating rtas"); - if (rtas_size == 0) { - rtas_data = 0; - } else { - /* - * Ask OF for some space for RTAS. - * Actually OF has bugs so we just arbitrarily - * use memory at the 6MB point. - */ - rtas_data = 6 << 20; - prom_print(" at "); - prom_print_hex(rtas_data); - } - - prom_rtas = call_prom("open", 1, 1, "/rtas"); - prom_print("..."); - rtas_entry = 0; - if (call_prom_ret("call-method", 3, 2, &result, - "instantiate-rtas", prom_rtas, rtas_data) == 0) - rtas_entry = result; - if ((rtas_entry == -1) || (rtas_entry == 0)) - prom_print(" failed\n"); - else - prom_print(" done\n"); -} - -/* - * We enter here early on, when the Open Firmware prom is still - * handling exceptions and the MMU hash table for us. - */ -unsigned long __init -prom_init(int r3, int r4, prom_entry pp) -{ - unsigned long mem; - ihandle prom_mmu; - unsigned long offset = reloc_offset(); - int i, l; - char *p, *d; - unsigned long phys; - prom_arg_t result[3]; - char model[32]; - phandle node; - int rc; - - /* Default */ - phys = (unsigned long) &_stext; - - /* First get a handle for the stdout device */ - prom = pp; - prom_chosen = call_prom("finddevice", 1, 1, "/chosen"); - if (prom_chosen == -1) - prom_exit(); - if (call_prom("getprop", 4, 1, prom_chosen, "stdout", - &prom_stdout, sizeof(prom_stdout)) <= 0) - prom_exit(); - - /* Get the full OF pathname of the stdout device */ - mem = (unsigned long) klimit + offset; - p = (char *) mem; - memset(p, 0, 256); - call_prom("instance-to-path", 3, 1, prom_stdout, p, 255); - of_stdout_device = p; - mem += strlen(p) + 1; - - /* Get the boot device and translate it to a full OF pathname. */ - p = (char *) mem; - l = call_prom("getprop", 4, 1, prom_chosen, "bootpath", p, 1<<20); - if (l > 0) { - p[l] = 0; /* should already be null-terminated */ - bootpath = PTRUNRELOC(p); - mem += l + 1; - d = (char *) mem; - *d = 0; - call_prom("canon", 3, 1, p, d, 1<<20); - bootdevice = PTRUNRELOC(d); - mem = ALIGNUL(mem + strlen(d) + 1); - } - - prom_instantiate_rtas(); - -#ifdef CONFIG_POWER4 - /* - * Find out how much memory we have and allocate a - * suitably-sized hash table. - */ - prom_alloc_htab(); -#endif - mem = check_display(mem); - - prom_print("copying OF device tree..."); - mem = copy_device_tree(mem, mem + (1<<20)); - prom_print("done\n"); - - prom_hold_cpus(mem); - - klimit = (char *) (mem - offset); - - node = call_prom("finddevice", 1, 1, "/"); - rc = call_prom("getprop", 4, 1, node, "model", model, sizeof(model)); - if (rc > 0 && !strncmp (model, "Pegasos", 7) - && strncmp (model, "Pegasos2", 8)) { - /* Pegasos 1 has a broken translate method in the OF, - * and furthermore the BATs are mapped 1:1 so the phys - * address calculated above is correct, so let's use - * it directly. - */ - } else if (offset == 0) { - /* If we are already running at 0xc0000000, we assume we were - * loaded by an OF bootloader which did set a BAT for us. - * This breaks OF translate so we force phys to be 0. - */ - prom_print("(already at 0xc0000000) phys=0\n"); - phys = 0; - } else if (call_prom("getprop", 4, 1, prom_chosen, "mmu", - &prom_mmu, sizeof(prom_mmu)) <= 0) { - prom_print(" no MMU found\n"); - } else if (call_prom_ret("call-method", 4, 4, result, "translate", - prom_mmu, &_stext, 1) != 0) { - prom_print(" (translate failed)\n"); - } else { - /* We assume the phys. address size is 3 cells */ - phys = result[2]; - } - - if (prom_disp_node != 0) - setup_disp_fake_bi(prom_disp_node); - - /* Use quiesce call to get OF to shut down any devices it's using */ - prom_print("Calling quiesce ...\n"); - call_prom("quiesce", 0, 0); - - /* Relocate various pointers which will be used once the - kernel is running at the address it was linked at. */ - for (i = 0; i < prom_num_displays; ++i) - prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]); - -#ifdef CONFIG_SERIAL_CORE_CONSOLE - /* Relocate the of stdout for console autodetection */ - of_stdout_device = PTRUNRELOC(of_stdout_device); -#endif - - prom_print("returning 0x"); - prom_print_hex(phys); - prom_print("from prom_init\n"); - prom_stdout = 0; - - return phys; -} - -/* - * early_get_property is used to access the device tree image prepared - * by BootX very early on, before the pointers in it have been relocated. - */ -static void * __init -early_get_property(unsigned long base, unsigned long node, char *prop) -{ - struct device_node *np = (struct device_node *)(base + node); - struct property *pp; - - for (pp = np->properties; pp != 0; pp = pp->next) { - pp = (struct property *) (base + (unsigned long)pp); - if (strcmp((char *)((unsigned long)pp->name + base), - prop) == 0) { - return (void *)((unsigned long)pp->value + base); - } - } - return NULL; -} - -/* Is boot-info compatible ? */ -#define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION) -#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2) -#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4) - -void __init -bootx_init(unsigned long r4, unsigned long phys) -{ - boot_infos_t *bi = (boot_infos_t *) r4; - unsigned long space; - unsigned long ptr, x; - char *model; - - boot_infos = PTRUNRELOC(bi); - if (!BOOT_INFO_IS_V2_COMPATIBLE(bi)) - bi->logicalDisplayBase = NULL; - -#ifdef CONFIG_BOOTX_TEXT - btext_init(bi); - - /* - * Test if boot-info is compatible. Done only in config - * CONFIG_BOOTX_TEXT since there is nothing much we can do - * with an incompatible version, except display a message - * and eventually hang the processor... - * - * I'll try to keep enough of boot-info compatible in the - * future to always allow display of this message; - */ - if (!BOOT_INFO_IS_COMPATIBLE(bi)) { - btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"); - btext_flushscreen(); - } -#endif /* CONFIG_BOOTX_TEXT */ - - /* New BootX enters kernel with MMU off, i/os are not allowed - here. This hack will have been done by the boostrap anyway. - */ - if (bi->version < 4) { - /* - * XXX If this is an iMac, turn off the USB controller. - */ - model = (char *) early_get_property - (r4 + bi->deviceTreeOffset, 4, "model"); - if (model - && (strcmp(model, "iMac,1") == 0 - || strcmp(model, "PowerMac1,1") == 0)) { - out_le32((unsigned *)0x80880008, 1); /* XXX */ - } - } - - /* Move klimit to enclose device tree, args, ramdisk, etc... */ - if (bi->version < 5) { - space = bi->deviceTreeOffset + bi->deviceTreeSize; - if (bi->ramDisk) - space = bi->ramDisk + bi->ramDiskSize; - } else - space = bi->totalParamsSize; - klimit = PTRUNRELOC((char *) bi + space); - - /* New BootX will have flushed all TLBs and enters kernel with - MMU switched OFF, so this should not be useful anymore. - */ - if (bi->version < 4) { - /* - * Touch each page to make sure the PTEs for them - * are in the hash table - the aim is to try to avoid - * getting DSI exceptions while copying the kernel image. - */ - for (ptr = ((unsigned long) &_stext) & PAGE_MASK; - ptr < (unsigned long)bi + space; ptr += PAGE_SIZE) - x = *(volatile unsigned long *)ptr; - } - -#ifdef CONFIG_BOOTX_TEXT - /* - * Note that after we call btext_prepare_BAT, we can't do - * prom_draw*, flushscreen or clearscreen until we turn the MMU - * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase - * to a virtual address. - */ - btext_prepare_BAT(); -#endif -} diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index ff86b2d814cb..cfc2d6ad464d 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -58,7 +58,7 @@ static struct sysrq_key_op sysrq_xmon_op = void xmon_map_scc(void) { -#ifdef CONFIG_PPC_MULTIPLATFORM +#ifdef CONFIG_PPC_PREP volatile unsigned char *base; #elif defined(CONFIG_GEMINI) diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 6c6b197898d0..7bb16fb97d4f 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -67,7 +67,6 @@ cflags-$(CONFIG_WARN_STACK) += -mwarn-framesize=$(CONFIG_WARN_STACK_SIZE) endif CFLAGS += -mbackchain -msoft-float $(cflags-y) -CFLAGS += $(call cc-option,-finline-limit=10000) CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare AFLAGS += $(aflags-y) diff --git a/arch/s390/defconfig b/arch/s390/defconfig index f8d0cd540a06..f4dfc10026d2 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,10 +1,11 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.16-rc2 -# Wed Feb 8 10:44:39 2006 +# Linux kernel version: 2.6.17-rc1 +# Mon Apr 3 14:34:15 2006 # CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_S390=y @@ -30,8 +31,8 @@ CONFIG_AUDIT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +# CONFIG_RELAY is not set CONFIG_INITRAMFS_SOURCE="" -CONFIG_UID16=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y @@ -45,10 +46,6 @@ CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 CONFIG_SLAB=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -60,7 +57,6 @@ CONFIG_BASE_SMALL=0 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set -CONFIG_OBSOLETE_MODPARM=y CONFIG_MODVERSIONS=y # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y @@ -69,7 +65,7 @@ CONFIG_STOP_MACHINE=y # # Block layer # -# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set # # IO Schedulers @@ -91,17 +87,20 @@ CONFIG_DEFAULT_IOSCHED="deadline" # # Processor type and features # -# CONFIG_64BIT is not set +CONFIG_64BIT=y CONFIG_SMP=y CONFIG_NR_CPUS=32 CONFIG_HOTPLUG_CPU=y -CONFIG_MATHEMU=y +CONFIG_DEFAULT_MIGRATION_COST=1000000 +CONFIG_COMPAT=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_BINFMT_ELF32=y # # Code generation options # -CONFIG_MARCH_G5=y -# CONFIG_MARCH_Z900 is not set +# CONFIG_MARCH_G5 is not set +CONFIG_MARCH_Z900=y # CONFIG_MARCH_Z990 is not set CONFIG_PACK_STACK=y # CONFIG_SMALL_STACK is not set @@ -143,7 +142,7 @@ CONFIG_VIRT_CPU_ACCOUNTING=y # CONFIG_APPLDATA_BASE is not set CONFIG_NO_IDLE_HZ=y CONFIG_NO_IDLE_HZ_INIT=y -# CONFIG_KEXEC is not set +CONFIG_KEXEC=y # # Networking @@ -173,6 +172,7 @@ CONFIG_IP_FIB_HASH=y # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y @@ -180,9 +180,11 @@ CONFIG_INET_TCP_DIAG=y CONFIG_TCP_CONG_BIC=y CONFIG_IPV6=y # CONFIG_IPV6_PRIVACY is not set +# CONFIG_IPV6_ROUTER_PREF is not set # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_NETFILTER is not set @@ -275,6 +277,11 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_FW_LOADER is not set # CONFIG_DEBUG_DRIVER is not set +# +# Connector - unified userspace <-> kernelspace linker +# +# CONFIG_CONNECTOR is not set + # # SCSI device support # @@ -340,8 +347,7 @@ CONFIG_DASD_PROFILE=y CONFIG_DASD_ECKD=y CONFIG_DASD_FBA=y CONFIG_DASD_DIAG=y -CONFIG_DASD_EER=m -# CONFIG_DASD_CMB is not set +CONFIG_DASD_EER=y # CONFIG_ATA_OVER_ETH is not set # @@ -354,6 +360,7 @@ CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m # CONFIG_MD_RAID10 is not set CONFIG_MD_RAID5=m +# CONFIG_MD_RAID5_RESHAPE is not set # CONFIG_MD_RAID6 is not set CONFIG_MD_MULTIPATH=m # CONFIG_MD_FAULTY is not set @@ -404,6 +411,7 @@ CONFIG_S390_TAPE_BLOCK=y # S/390 tape hardware support # CONFIG_S390_TAPE_34XX=m +# CONFIG_S390_TAPE_3590 is not set # CONFIG_VMLOGRDR is not set # CONFIG_VMCP is not set # CONFIG_MONREADER is not set @@ -529,7 +537,6 @@ CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y -# CONFIG_RELAYFS_FS is not set # CONFIG_CONFIGFS_FS is not set # @@ -619,14 +626,15 @@ CONFIG_LOG_BUF_SHIFT=17 # CONFIG_DETECT_SOFTLOCKUP is not set # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_PREEMPT is not set +CONFIG_DEBUG_PREEMPT=y CONFIG_DEBUG_MUTEXES=y -# CONFIG_DEBUG_SPINLOCK is not set -# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_SPINLOCK_SLEEP=y # CONFIG_DEBUG_KOBJECT is not set # CONFIG_DEBUG_INFO is not set CONFIG_DEBUG_FS=y # CONFIG_DEBUG_VM is not set +# CONFIG_UNWIND_INFO is not set CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 2b8841f85534..343120c9223d 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -801,7 +801,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) */ print_cpu_info(&S390_lowcore.cpu_data); - for_each_cpu(i) { + for_each_possible_cpu(i) { lowcore_ptr[i] = (struct _lowcore *) __get_free_pages(GFP_KERNEL|GFP_DMA, sizeof(void*) == 8 ? 1 : 0); @@ -831,7 +831,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) #endif set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]); - for_each_cpu(cpu) + for_each_possible_cpu(cpu) if (cpu != smp_processor_id()) smp_create_idle(cpu); } @@ -868,7 +868,7 @@ static int __init topology_init(void) int cpu; int ret; - for_each_cpu(cpu) { + for_each_possible_cpu(cpu) { ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu, NULL); if (ret) printk(KERN_WARNING "topology_init: register_cpu %d " diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 58583f459471..2bcecf422573 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -527,6 +527,11 @@ config CPU_HAS_SR_RB See for further information on SR.RB and register banking in the kernel in general. +config NODES_SHIFT + int + default "1" + depends on NEED_MULTIPLE_NODES + endmenu menu "Boot options" diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index cf94e8ef17c5..868e68b28880 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -30,7 +30,7 @@ static int x##_disabled __initdata = 0; \ static int __init x##_setup(char *opts) \ { \ x##_disabled = 1; \ - return 0; \ + return 1; \ } \ __setup("no" __stringify(x), x##_setup); diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 7ee4ca203616..bb229ef030f3 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -401,7 +401,7 @@ static int __init topology_init(void) { int cpu_id; - for_each_cpu(cpu_id) + for_each_possible_cpu(cpu_id) register_cpu(&cpu[cpu_id], cpu_id, NULL); return 0; diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c index 1cf94a618be3..d5d032533a8b 100644 --- a/arch/sh/kernel/sh_ksyms.c +++ b/arch/sh/kernel/sh_ksyms.c @@ -37,7 +37,6 @@ EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(irq_desc); EXPORT_SYMBOL(no_irq_type); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); diff --git a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c index de29c45f23a7..6f3a1c946339 100644 --- a/arch/sh64/kernel/sh_ksyms.c +++ b/arch/sh64/kernel/sh_ksyms.c @@ -41,7 +41,6 @@ EXPORT_SYMBOL(kernel_thread); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); #ifdef CONFIG_VT diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 2be812115197..a93f5da6855d 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -244,7 +244,7 @@ int setup_profiling_timer(unsigned int multiplier) return -EINVAL; spin_lock_irqsave(&prof_setup_lock, flags); - for_each_cpu(i) { + for_each_possible_cpu(i) { load_profile_irq(i, lvl14_resolution / multiplier); prof_multiplier(i) = multiplier; } diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 2c21d7907635..ec1c9687d679 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c @@ -263,7 +263,6 @@ EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(page_kernel); diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 768de64b371f..db8faa75f94d 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -64,18 +64,18 @@ sys_call_table: /*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_ioprio_get, sys_adjtimex /*220*/ .long sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid /*225*/ .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16 -/*230*/ .long sys_select, sys_time, sys_nis_syscall, sys_stime, sys_statfs64 +/*230*/ .long sys_select, sys_time, sys_splice, sys_stime, sys_statfs64 /* "We are the Knights of the Forest of Ni!!" */ /*235*/ .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl -/*255*/ .long sys_nis_syscall, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep +/*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink /*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid -/*280*/ .long sys_ni_syscall, sys_add_key, sys_request_key, sys_keyctl, sys_openat +/*280*/ .long sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat /*285*/ .long sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_fstatat64 /*290*/ .long sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat /*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare diff --git a/arch/sparc/math-emu/Makefile b/arch/sparc/math-emu/Makefile index f84a9a6162be..8136987977f4 100644 --- a/arch/sparc/math-emu/Makefile +++ b/arch/sparc/math-emu/Makefile @@ -5,4 +5,4 @@ obj-y := math.o EXTRA_AFLAGS := -ansi -EXTRA_CFLAGS = -I. -I$(TOPDIR)/include/math-emu -w +EXTRA_CFLAGS = -I. -Iinclude/math-emu -w diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index d1e2fc566486..648047a0bce3 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -194,6 +194,9 @@ endchoice endmenu +config ARCH_SELECT_MEMORY_MODEL + def_bool y + config ARCH_SPARSEMEM_ENABLE def_bool y diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 900fb0b940d8..1317380fa937 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.16 -# Sun Mar 26 14:58:11 2006 +# Sun Apr 2 19:31:04 2006 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -180,6 +180,7 @@ CONFIG_SYN_COOKIES=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y +CONFIG_INET_XFRM_TUNNEL=y CONFIG_INET_TUNNEL=y CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y @@ -203,6 +204,7 @@ CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m CONFIG_INET6_IPCOMP=m +CONFIG_INET6_XFRM_TUNNEL=m CONFIG_INET6_TUNNEL=m CONFIG_IPV6_TUNNEL=m # CONFIG_NETFILTER is not set @@ -308,7 +310,6 @@ CONFIG_BLK_DEV_NBD=m # CONFIG_BLK_DEV_SX8 is not set CONFIG_BLK_DEV_UB=m # CONFIG_BLK_DEV_RAM is not set -CONFIG_BLK_DEV_RAM_COUNT=16 # CONFIG_BLK_DEV_INITRD is not set CONFIG_CDROM_PKTCDVD=m CONFIG_CDROM_PKTCDVD_BUFFERS=8 @@ -449,6 +450,7 @@ CONFIG_MD_RAID0=m CONFIG_MD_RAID1=m CONFIG_MD_RAID10=m CONFIG_MD_RAID5=m +# CONFIG_MD_RAID5_RESHAPE is not set CONFIG_MD_RAID6=m CONFIG_MD_MULTIPATH=m # CONFIG_MD_FAULTY is not set @@ -741,9 +743,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 is not set # CONFIG_SENSORS_MAX6875 is not set -# CONFIG_RTC_X1205_I2C is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -826,6 +826,7 @@ CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_MACMODES is not set +# CONFIG_FB_FIRMWARE_EDID is not set CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y # CONFIG_FB_CIRRUS is not set @@ -837,7 +838,6 @@ CONFIG_FB_TILEBLITTING=y # CONFIG_FB_NVIDIA is not set # CONFIG_FB_RIVA is not set # CONFIG_FB_MATROX is not set -# CONFIG_FB_RADEON_OLD is not set CONFIG_FB_RADEON=y CONFIG_FB_RADEON_I2C=y # CONFIG_FB_RADEON_DEBUG is not set @@ -923,6 +923,7 @@ CONFIG_SND_MTPAV=m # PCI devices # # CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS300 is not set CONFIG_SND_ALI5451=m # CONFIG_SND_ATIIXP is not set # CONFIG_SND_ATIIXP_MODEM is not set @@ -954,6 +955,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_MIXART is not set # CONFIG_SND_NM256 is not set # CONFIG_SND_PCXHR is not set +# CONFIG_SND_RIPTIDE is not set # CONFIG_SND_RME32 is not set # CONFIG_SND_RME96 is not set # CONFIG_SND_RME9652 is not set @@ -1107,6 +1109,11 @@ CONFIG_USB_HIDDEV=y # # CONFIG_MMC is not set +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + # # InfiniBand support # @@ -1116,6 +1123,11 @@ CONFIG_USB_HIDDEV=y # EDAC - error detection and reporting (RAS) (EXPERIMENTAL) # +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + # # Misc Linux/SPARC drivers # diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index dfccff29e182..f97ddeb105ac 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -419,6 +419,7 @@ void pcibios_resource_to_bus(struct pci_dev *pdev, struct pci_bus_region *region region->start = res->start - zero_res.start; region->end = res->end - zero_res.start; } +EXPORT_SYMBOL(pcibios_resource_to_bus); void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res, struct pci_bus_region *region) diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 9372d4f376d5..9e94db2573a2 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1092,7 +1092,7 @@ void sun4v_pci_init(int node, char *model_name) } } - for_each_cpu(i) { + for_each_possible_cpu(i) { unsigned long page = get_zeroed_page(GFP_ATOMIC); if (!page) diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index eb93e9c52846..49e6dedd027d 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -244,6 +244,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs) } switch(request) { + case PTRACE_PEEKUSR: + if (addr != 0) + pt_error_return(regs, EIO); + else + pt_succ_return(regs, 0); + goto out_tsk; + case PTRACE_PEEKTEXT: /* read word at location addr. */ case PTRACE_PEEKDATA: { unsigned long tmp64; @@ -602,6 +609,22 @@ asmlinkage void do_ptrace(struct pt_regs *regs) /* PTRACE_DUMPCORE unsupported... */ + case PTRACE_GETEVENTMSG: { + int err; + + if (test_thread_flag(TIF_32BIT)) + err = put_user(child->ptrace_message, + (unsigned int __user *) data); + else + err = put_user(child->ptrace_message, + (unsigned long __user *) data); + if (err) + pt_error_return(regs, -err); + else + pt_succ_return(regs, 0); + break; + } + default: { int err = ptrace_request(child, request, addr, data); if (err) diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 7d0e67c1ce50..005167f82419 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -535,7 +535,7 @@ static int __init topology_init(void) while (!cpu_find_by_instance(ncpus_probed, NULL, NULL)) ncpus_probed++; - for_each_cpu(i) { + for_each_possible_cpu(i) { struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL); if (p) { register_cpu(p, i, NULL); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 7dc28a484268..90eaca3ec9a6 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -745,12 +745,21 @@ struct call_data_struct { int wait; }; -static DEFINE_SPINLOCK(call_lock); +static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock); static struct call_data_struct *call_data; extern unsigned long xcall_call_function; -/* +/** + * smp_call_function(): Run a function on all other CPUs. + * @func: The function to run. This must be fast and non-blocking. + * @info: An arbitrary pointer to pass to the function. + * @nonatomic: currently unused. + * @wait: If true, wait (atomically) until function has completed on other CPUs. + * + * Returns 0 on success, else a negative status code. Does not return until + * remote CPUs are nearly ready to execute <> or are or have executed. + * * You must not call this function with disabled interrupts or from a * hardware interrupt handler or from a bottom half handler. */ @@ -759,7 +768,6 @@ static int smp_call_function_mask(void (*func)(void *info), void *info, { struct call_data_struct data; int cpus; - long timeout; /* Can deadlock when called with interrupts disabled */ WARN_ON(irqs_disabled()); @@ -777,31 +785,18 @@ static int smp_call_function_mask(void (*func)(void *info), void *info, goto out_unlock; call_data = &data; + mb(); smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask); - /* - * Wait for other cpus to complete function or at - * least snap the call data. - */ - timeout = 1000000; - while (atomic_read(&data.finished) != cpus) { - if (--timeout <= 0) - goto out_timeout; - barrier(); - udelay(1); - } + /* Wait for response */ + while (atomic_read(&data.finished) != cpus) + cpu_relax(); out_unlock: spin_unlock(&call_lock); return 0; - -out_timeout: - spin_unlock(&call_lock); - printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n", - cpus, atomic_read(&data.finished)); - return 0; } int smp_call_function(void (*func)(void *info), void *info, @@ -830,9 +825,16 @@ void smp_call_function_client(int irq, struct pt_regs *regs) static void tsb_sync(void *info) { + struct trap_per_cpu *tp = &trap_block[raw_smp_processor_id()]; struct mm_struct *mm = info; - if (current->active_mm == mm) + /* It is not valid to test "currrent->active_mm == mm" here. + * + * The value of "current" is not changed atomically with + * switch_mm(). But that's OK, we just need to check the + * current cpu's trap block PGD physical address. + */ + if (tp->pgd_paddr == __pa(mm->pgd)) tsb_context_switch(mm); } @@ -1278,7 +1280,7 @@ int setup_profiling_timer(unsigned int multiplier) return -EINVAL; spin_lock_irqsave(&prof_setup_lock, flags); - for_each_cpu(i) + for_each_possible_cpu(i) prof_multiplier(i) = multiplier; current_tick_offset = (timer_tick_offset / multiplier); spin_unlock_irqrestore(&prof_setup_lock, flags); @@ -1306,12 +1308,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus) } } - for_each_cpu(i) { + for_each_possible_cpu(i) { if (tlb_type == hypervisor) { int j; /* XXX get this mapping from machine description */ - for_each_cpu(j) { + for_each_possible_cpu(j) { if ((j >> 2) == (i >> 2)) cpu_set(j, cpu_sibling_map[i]); } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index f5e8db1de76b..62d8a99271ea 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -276,7 +276,6 @@ EXPORT_SYMBOL(__prom_getsibling); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(__strlen_user); EXPORT_SYMBOL(__strnlen_user); -EXPORT_SYMBOL(strpbrk); #ifdef CONFIG_SOLARIS_EMUL_MODULE EXPORT_SYMBOL(linux_sparc_syscall); diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index c4a1cef4b1e5..f9b75760163c 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -136,6 +136,9 @@ SIGN1(sys32_getpeername, sys_getpeername, %o0) SIGN1(sys32_getsockname, sys_getsockname, %o0) SIGN2(sys32_ioprio_get, sys_ioprio_get, %o0, %o1) SIGN3(sys32_ioprio_set, sys_ioprio_set, %o0, %o1, %o2) +SIGN2(sys32_splice, sys_splice, %o0, %o1) +SIGN2(sys32_sync_file_range, compat_sync_file_range, %o0, %o5) +SIGN2(sys32_tee, sys_tee, %o0, %o1) .globl sys32_mmap2 sys32_mmap2: diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 2e906bad56fa..31030bf00f1a 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1069,3 +1069,11 @@ long sys32_lookup_dcookie(unsigned long cookie_high, return sys_lookup_dcookie((cookie_high << 32) | cookie_low, buf, len); } + +long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_low, unsigned long nb_high, unsigned long nb_low, int flags) +{ + return sys_sync_file_range(fd, + (off_high << 32) | off_low, + (nb_high << 32) | nb_low, + flags); +} diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 3b250f2318fd..62672cd92eca 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -66,17 +66,17 @@ sys_call_table32: .word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex /*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16 -/*230*/ .word sys32_select, compat_sys_time, sys_nis_syscall, compat_sys_stime, compat_sys_statfs64 +/*230*/ .word sys32_select, compat_sys_time, sys32_splice, compat_sys_stime, compat_sys_statfs64 .word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall /*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler .word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep /*250*/ .word sys32_mremap, sys32_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl - .word sys_ni_syscall, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep + .word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid -/*280*/ .word sys_ni_syscall, sys_add_key, sys_request_key, sys_keyctl, compat_sys_openat +/*280*/ .word sys32_tee, sys_add_key, sys_request_key, sys_keyctl, compat_sys_openat .word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64 /*285*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare @@ -135,17 +135,17 @@ sys_call_table: .word sys_ipc, sys_nis_syscall, sys_clone, sys_ioprio_get, sys_adjtimex /*220*/ .word sys_nis_syscall, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid -/*230*/ .word sys_select, sys_nis_syscall, sys_nis_syscall, sys_stime, sys_statfs64 +/*230*/ .word sys_select, sys_nis_syscall, sys_splice, sys_stime, sys_statfs64 .word sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - .word sys_ni_syscall, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep + .word sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy /*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid -/*280*/ .word sys_nis_syscall, sys_add_key, sys_request_key, sys_keyctl, sys_openat +/*280*/ .word sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat .word sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_fstatat64 /*285*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index ff090bb9734b..2793a5d82380 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1130,9 +1130,9 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), afsr, afar, (afsr & CHAFSR_TL1) ? 1 : 0); - printk("%s" "ERROR(%d): TPC[%016lx] TNPC[%016lx] TSTATE[%016lx]\n", + printk("%s" "ERROR(%d): TPC[%lx] TNPC[%lx] O7[%lx] TSTATE[%lx]\n", (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), - regs->tpc, regs->tnpc, regs->tstate); + regs->tpc, regs->tnpc, regs->u_regs[UREG_I7], regs->tstate); printk("%s" "ERROR(%d): M_SYND(%lx), E_SYND(%lx)%s%s\n", (recoverable ? KERN_WARNING : KERN_CRIT), smp_processor_id(), (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT, diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 0db2f7d9fab5..6e002aacb961 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -327,8 +327,12 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) insn = get_fault_insn(regs, 0); if (!insn) goto continue_fault; + /* All loads, stores and atomics have bits 30 and 31 both set + * in the instruction. Bit 21 is set in all stores, but we + * have to avoid prefetches which also have bit 21 set. + */ if ((insn & 0xc0200000) == 0xc0200000 && - (insn & 0x1780000) != 0x1680000) { + (insn & 0x01780000) != 0x01680000) { /* Don't bother updating thread struct value, * because update_mmu_cache only cares which tlb * the access came from. diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c index 074620d413d4..fbbbebbad8a4 100644 --- a/arch/sparc64/mm/hugetlbpage.c +++ b/arch/sparc64/mm/hugetlbpage.c @@ -198,6 +198,13 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) pmd_t *pmd; pte_t *pte = NULL; + /* We must align the address, because our caller will run + * set_huge_pte_at() on whatever we return, which writes out + * all of the sub-ptes for the hugepage range. So we have + * to give it the first such sub-pte. + */ + addr &= HPAGE_MASK; + pgd = pgd_offset(mm, addr); pud = pud_alloc(mm, pgd, addr); if (pud) { diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 5982fe2753e0..05fbb20636cb 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -22,6 +22,9 @@ config SBUS config PCI bool +config PCMCIA + bool + config GENERIC_CALIBRATE_DELAY bool default y diff --git a/arch/um/Makefile b/arch/um/Makefile index 8d14c7a831be..a508e7a02891 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -20,7 +20,7 @@ core-y += $(ARCH_DIR)/kernel/ \ # Have to precede the include because the included Makefiles reference them. SYMLINK_HEADERS := archparam.h system.h sigcontext.h processor.h ptrace.h \ - module.h vm-flags.h elf.h ldt.h + module.h vm-flags.h elf.h host_ldt.h SYMLINK_HEADERS := $(foreach header,$(SYMLINK_HEADERS),include/asm-um/$(header)) # XXX: The "os" symlink is only used by arch/um/include/os.h, which includes @@ -129,7 +129,7 @@ CPPFLAGS_vmlinux.lds = -U$(SUBARCH) \ -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ -DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \ -DKERNEL_STACK_SIZE=$(STACK_SIZE) \ - -DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap_fin.o + -DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap.o #The wrappers will select whether using "malloc" or the kernel allocator. LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc @@ -150,8 +150,7 @@ CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \ $(ARCH_DIR)/include/user_constants.h \ $(ARCH_DIR)/include/kern_constants.h $(ARCH_DIR)/Kconfig.arch -MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \ - $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os +MRPROPER_FILES += $(ARCH_SYMLINKS) archclean: @find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ @@ -160,6 +159,7 @@ archclean: $(SYMLINK_HEADERS): @echo ' SYMLINK $@' ifneq ($(KBUILD_SRC),) + $(Q)mkdir -p $(objtree)/include/asm-um $(Q)ln -fsn $(srctree)/include/asm-um/$(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $@ else $(Q)cd $(TOPDIR)/$(dir $@) ; \ @@ -169,7 +169,7 @@ endif include/asm-um/arch: @echo ' SYMLINK $@' ifneq ($(KBUILD_SRC),) - $(Q)mkdir -p include/asm-um + $(Q)mkdir -p $(objtree)/include/asm-um $(Q)ln -fsn $(srctree)/include/asm-$(SUBARCH) include/asm-um/arch else $(Q)cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64 index 38df311e75dc..dfd88b652fbe 100644 --- a/arch/um/Makefile-x86_64 +++ b/arch/um/Makefile-x86_64 @@ -1,7 +1,7 @@ # Copyright 2003 - 2004 Pathscale, Inc # Released under the GPL -libs-y += arch/um/sys-x86_64/ +core-y += arch/um/sys-x86_64/ START := 0x60000000 #We #undef __x86_64__ for kernelspace, not for userspace where diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h index 04e3958266e0..dc36b222100b 100644 --- a/arch/um/drivers/cow.h +++ b/arch/um/drivers/cow.h @@ -46,7 +46,7 @@ extern int file_reader(__u64 offset, char *buf, int len, void *arg); extern int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, __u32 *version_out, char **backing_file_out, time_t *mtime_out, - __u64 *size_out, int *sectorsize_out, + unsigned long long *size_out, int *sectorsize_out, __u32 *align_out, int *bitmap_offset_out); extern int write_cow_header(char *cow_file, int fd, char *backing_file, diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h index 94de4ead4f7a..7a5b4afde692 100644 --- a/arch/um/drivers/cow_sys.h +++ b/arch/um/drivers/cow_sys.h @@ -28,7 +28,7 @@ static inline int cow_seek_file(int fd, __u64 offset) return(os_seek_file(fd, offset)); } -static inline int cow_file_size(char *file, __u64 *size_out) +static inline int cow_file_size(char *file, unsigned long long *size_out) { return(os_file_size(file, size_out)); } diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index 61951b721268..0ec4052db9c5 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c @@ -17,30 +17,34 @@ #define PATH_LEN_V1 256 -struct cow_header_v1 { - int magic; - int version; - char backing_file[PATH_LEN_V1]; - time_t mtime; - __u64 size; - int sectorsize; -}; +typedef __u32 time32_t; -#define PATH_LEN_V2 MAXPATHLEN +struct cow_header_v1 { + __s32 magic; + __s32 version; + char backing_file[PATH_LEN_V1]; + time32_t mtime; + __u64 size; + __s32 sectorsize; +} __attribute__((packed)); + +/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in + * case other systems have different values for MAXPATHLEN. + * + * The same must hold for V2 - we want file format compatibility, not anything + * else. + */ +#define PATH_LEN_V3 4096 +#define PATH_LEN_V2 PATH_LEN_V3 struct cow_header_v2 { __u32 magic; __u32 version; char backing_file[PATH_LEN_V2]; - time_t mtime; + time32_t mtime; __u64 size; - int sectorsize; -}; - -/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in - * case other systems have different values for MAXPATHLEN - */ -#define PATH_LEN_V3 4096 + __s32 sectorsize; +} __attribute__((packed)); /* Changes from V2 - * PATH_LEN_V3 as described above @@ -66,6 +70,15 @@ struct cow_header_v2 { * Fixed (finally!) the rounding bug */ +/* Until Dec2005, __attribute__((packed)) was left out from the below + * definition, leading on 64-bit systems to 4 bytes of padding after mtime, to + * align size to 8-byte alignment. This shifted all fields above (no padding + * was present on 32-bit, no other padding was added). + * + * However, this _can be detected_: it means that cow_format (always 0 until + * now) is shifted onto the first 4 bytes of backing_file, where it is otherwise + * impossible to find 4 zeros. -bb */ + struct cow_header_v3 { __u32 magic; __u32 version; @@ -75,6 +88,18 @@ struct cow_header_v3 { __u32 alignment; __u32 cow_format; char backing_file[PATH_LEN_V3]; +} __attribute__((packed)); + +/* This is the broken layout used by some 64-bit binaries. */ +struct cow_header_v3_broken { + __u32 magic; + __u32 version; + __s64 mtime; + __u64 size; + __u32 sectorsize; + __u32 alignment; + __u32 cow_format; + char backing_file[PATH_LEN_V3]; }; /* COW format definitions - for now, we have only the usual COW bitmap */ @@ -84,6 +109,7 @@ union cow_header { struct cow_header_v1 v1; struct cow_header_v2 v2; struct cow_header_v3 v3; + struct cow_header_v3_broken v3_b; }; #define COW_MAGIC 0x4f4f4f4d /* MOOO */ @@ -184,8 +210,9 @@ int write_cow_header(char *cow_file, int fd, char *backing_file, err = -EINVAL; if(strlen(backing_file) > sizeof(header->backing_file) - 1){ + /* Below, %zd is for a size_t value */ cow_printf("Backing file name \"%s\" is too long - names are " - "limited to %d characters\n", backing_file, + "limited to %zd characters\n", backing_file, sizeof(header->backing_file) - 1); goto out_free; } @@ -300,7 +327,8 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, *align_out = *sectorsize_out; file = header->v2.backing_file; } - else if(version == 3){ + /* This is very subtle - see above at union cow_header definition */ + else if(version == 3 && (*((int*)header->v3.backing_file) != 0)){ if(n < sizeof(header->v3)){ cow_printf("read_cow_header - failed to read V3 " "header\n"); @@ -310,9 +338,43 @@ int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, *size_out = ntohll(header->v3.size); *sectorsize_out = ntohl(header->v3.sectorsize); *align_out = ntohl(header->v3.alignment); + if (*align_out == 0) { + cow_printf("read_cow_header - invalid COW header, " + "align == 0\n"); + } *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); file = header->v3.backing_file; } + else if(version == 3){ + cow_printf("read_cow_header - broken V3 file with" + " 64-bit layout - recovering content.\n"); + + if(n < sizeof(header->v3_b)){ + cow_printf("read_cow_header - failed to read V3 " + "header\n"); + goto out; + } + + /* this was used until Dec2005 - 64bits are needed to represent + * 2038+. I.e. we can safely do this truncating cast. + * + * Additionally, we must use ntohl() instead of ntohll(), since + * the program used to use the former (tested - I got mtime + * mismatch "0 vs whatever"). + * + * Ever heard about bug-to-bug-compatibility ? ;-) */ + *mtime_out = (time32_t) ntohl(header->v3_b.mtime); + + *size_out = ntohll(header->v3_b.size); + *sectorsize_out = ntohl(header->v3_b.sectorsize); + *align_out = ntohl(header->v3_b.alignment); + if (*align_out == 0) { + cow_printf("read_cow_header - invalid COW header, " + "align == 0\n"); + } + *bitmap_offset_out = ROUND_UP(sizeof(header->v3_b), *align_out); + file = header->v3_b.backing_file; + } else { cow_printf("read_cow_header - invalid COW version\n"); goto out; diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index a61b7b46bc02..53d09ed78b42 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c @@ -95,18 +95,7 @@ static struct transport daemon_transport = { static int register_daemon(void) { register_transport(&daemon_transport); - return(1); + return 0; } __initcall(register_daemon); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index 49acb2badf32..d18a974735e6 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c @@ -104,7 +104,7 @@ static int harddog_release(struct inode *inode, struct file *file) extern int ping_watchdog(int fd); -static ssize_t harddog_write(struct file *file, const char *data, size_t len, +static ssize_t harddog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { /* @@ -118,6 +118,7 @@ static ssize_t harddog_write(struct file *file, const char *data, size_t len, static int harddog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + void __user *argp= (void __user *)arg; static struct watchdog_info ident = { WDIOC_SETTIMEOUT, 0, @@ -127,13 +128,12 @@ static int harddog_ioctl(struct inode *inode, struct file *file, default: return -ENOTTY; case WDIOC_GETSUPPORT: - if(copy_to_user((struct harddog_info *)arg, &ident, - sizeof(ident))) + if(copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; return 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: - return put_user(0,(int *)arg); + return put_user(0,(int __user *)argp); case WDIOC_KEEPALIVE: return(ping_watchdog(harddog_out_fd)); } diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index 59602b81b240..37232f908cd7 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -67,8 +67,8 @@ MODULE_PARM_DESC(mixer, MIXER_HELP); /* /dev/dsp file operations */ -static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, - loff_t *ppos) +static ssize_t hostaudio_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) { struct hostaudio_state *state = file->private_data; void *kbuf; @@ -94,7 +94,7 @@ static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, return(err); } -static ssize_t hostaudio_write(struct file *file, const char *buffer, +static ssize_t hostaudio_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct hostaudio_state *state = file->private_data; @@ -152,7 +152,7 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_CHANNELS: case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SETFRAGMENT: - if(get_user(data, (int *) arg)) + if(get_user(data, (int __user *) arg)) return(-EFAULT); break; default: @@ -168,7 +168,7 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_CHANNELS: case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SETFRAGMENT: - if(put_user(data, (int *) arg)) + if(put_user(data, (int __user *) arg)) return(-EFAULT); break; default: diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index c9b078fba03e..3a7af18cf944 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c @@ -124,18 +124,7 @@ static struct transport mcast_transport = { static int register_mcast(void) { register_transport(&mcast_transport); - return(1); + return 0; } __initcall(register_mcast); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 1488816588ea..6d7173fc55a3 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -20,6 +20,8 @@ #include "linux/namei.h" #include "linux/proc_fs.h" #include "linux/syscalls.h" +#include "linux/list.h" +#include "linux/mm.h" #include "linux/console.h" #include "asm/irq.h" #include "asm/uaccess.h" @@ -60,7 +62,7 @@ static void mc_work_proc(void *unused) unsigned long flags; while(!list_empty(&mc_requests)){ - local_save_flags(flags); + local_irq_save(flags); req = list_entry(mc_requests.next, struct mconsole_entry, list); list_del(&req->list); @@ -85,7 +87,7 @@ static irqreturn_t mconsole_interrupt(int irq, void *dev_id, if(req.cmd->context == MCONSOLE_INTR) (*req.cmd->handler)(&req); else { - new = kmalloc(sizeof(*new), GFP_ATOMIC); + new = kmalloc(sizeof(*new), GFP_NOWAIT); if(new == NULL) mconsole_reply(&req, "Out of memory", 1, 0); else { @@ -347,6 +349,141 @@ static struct mc_device *mconsole_find_dev(char *name) return(NULL); } +#define UNPLUGGED_PER_PAGE \ + ((PAGE_SIZE - sizeof(struct list_head)) / sizeof(unsigned long)) + +struct unplugged_pages { + struct list_head list; + void *pages[UNPLUGGED_PER_PAGE]; +}; + +static unsigned long long unplugged_pages_count = 0; +static struct list_head unplugged_pages = LIST_HEAD_INIT(unplugged_pages); +static int unplug_index = UNPLUGGED_PER_PAGE; + +static int mem_config(char *str) +{ + unsigned long long diff; + int err = -EINVAL, i, add; + char *ret; + + if(str[0] != '=') + goto out; + + str++; + if(str[0] == '-') + add = 0; + else if(str[0] == '+'){ + add = 1; + } + else goto out; + + str++; + diff = memparse(str, &ret); + if(*ret != '\0') + goto out; + + diff /= PAGE_SIZE; + + for(i = 0; i < diff; i++){ + struct unplugged_pages *unplugged; + void *addr; + + if(add){ + if(list_empty(&unplugged_pages)) + break; + + unplugged = list_entry(unplugged_pages.next, + struct unplugged_pages, list); + if(unplug_index > 0) + addr = unplugged->pages[--unplug_index]; + else { + list_del(&unplugged->list); + addr = unplugged; + unplug_index = UNPLUGGED_PER_PAGE; + } + + free_page((unsigned long) addr); + unplugged_pages_count--; + } + else { + struct page *page; + + page = alloc_page(GFP_ATOMIC); + if(page == NULL) + break; + + unplugged = page_address(page); + if(unplug_index == UNPLUGGED_PER_PAGE){ + list_add(&unplugged->list, &unplugged_pages); + unplug_index = 0; + } + else { + struct list_head *entry = unplugged_pages.next; + addr = unplugged; + + unplugged = list_entry(entry, + struct unplugged_pages, + list); + unplugged->pages[unplug_index++] = addr; + err = os_drop_memory(addr, PAGE_SIZE); + if(err) + printk("Failed to release memory - " + "errno = %d\n", err); + } + + unplugged_pages_count++; + } + } + + err = 0; +out: + return err; +} + +static int mem_get_config(char *name, char *str, int size, char **error_out) +{ + char buf[sizeof("18446744073709551615")]; + int len = 0; + + sprintf(buf, "%ld", uml_physmem); + CONFIG_CHUNK(str, size, len, buf, 1); + + return len; +} + +static int mem_id(char **str, int *start_out, int *end_out) +{ + *start_out = 0; + *end_out = 0; + + return 0; +} + +static int mem_remove(int n) +{ + return -EBUSY; +} + +static struct mc_device mem_mc = { + .name = "mem", + .config = mem_config, + .get_config = mem_get_config, + .id = mem_id, + .remove = mem_remove, +}; + +static int mem_mc_init(void) +{ + if(can_drop_memory()) + mconsole_register_dev(&mem_mc); + else printk("Can't release memory to the host - memory hotplug won't " + "be supported\n"); + return 0; +} + +__initcall(mem_mc_init); + #define CONFIG_BUF_SIZE 64 static void mconsole_get_config(int (*get_config)(char *, char *, int, @@ -478,7 +615,7 @@ static void console_write(struct console *console, const char *string, return; while(1){ - n = min(len, ARRAY_SIZE(console_buf) - console_index); + n = min((size_t) len, ARRAY_SIZE(console_buf) - console_index); strncpy(&console_buf[console_index], string, n); console_index += n; string += n; @@ -517,7 +654,6 @@ static void with_console(struct mc_request *req, void (*proc)(void *), struct mconsole_entry entry; unsigned long flags; - INIT_LIST_HEAD(&entry.list); entry.request = *req; list_add(&entry.list, &clients); spin_lock_irqsave(&console_lock, flags); diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 0e2f06187ea7..0a7786e00cfb 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -182,7 +182,9 @@ static int change_tramp(char **argv, char *output, int output_len) pe_data.stdout = fds[1]; pid = run_helper(change_pre_exec, &pe_data, argv, NULL); - read_output(fds[0], output, output_len); + if (pid > 0) /* Avoid hang as we won't get data in failure case. */ + read_output(fds[0], output, output_len); + os_close_file(fds[0]); os_close_file(fds[1]); diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 07c80f2156ef..466ff2c2f918 100644 --- a/arch/um/drivers/pcap_kern.c +++ b/arch/um/drivers/pcap_kern.c @@ -106,18 +106,7 @@ static struct transport pcap_transport = { static int register_pcap(void) { register_transport(&pcap_transport); - return(1); + return 0; } __initcall(register_pcap); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index a62f5ef445cf..163ee0d5f75e 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -93,18 +93,7 @@ static struct transport slip_transport = { static int register_slip(void) { register_transport(&slip_transport); - return(1); + return 0; } __initcall(register_slip); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c index 33d7982be5d3..95e50c943e14 100644 --- a/arch/um/drivers/slirp_kern.c +++ b/arch/um/drivers/slirp_kern.c @@ -77,7 +77,7 @@ static int slirp_setup(char *str, char **mac_out, void *data) int i=0; *init = ((struct slirp_init) - { argw : { { "slirp", NULL } } }); + { .argw = { { "slirp", NULL } } }); str = split_if_spec(str, mac_out, NULL); @@ -116,18 +116,7 @@ static struct transport slirp_transport = { static int register_slirp(void) { register_transport(&slirp_transport); - return(1); + return 0; } __initcall(register_slirp); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index b94c66114bc8..33c5f6e625e8 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -104,7 +104,7 @@ static void slirp_close(int fd, void *data) } if(err == 0) { - printk("slirp_close: process %d has not exited\n"); + printk("slirp_close: process %d has not exited\n", pri->pid); return; } diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 0336575d2448..0897852b09a3 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -891,7 +891,7 @@ int ubd_driver_init(void){ SA_INTERRUPT, "ubd", ubd_dev); if(err != 0) printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); - return(err); + return 0; } device_initcall(ubd_driver_init); diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h index 07176d92e1c9..efa3d33c0be6 100644 --- a/arch/um/include/kern_util.h +++ b/arch/um/include/kern_util.h @@ -116,7 +116,7 @@ extern void *get_current(void); extern struct task_struct *get_task(int pid, int require); extern void machine_halt(void); extern int is_syscall(unsigned long addr); -extern void arch_switch(void); + extern void free_irq(unsigned int, void *); extern int cpu(void); diff --git a/arch/um/include/line.h b/arch/um/include/line.h index 6f4d680dc1d4..6ac0f8252e21 100644 --- a/arch/um/include/line.h +++ b/arch/um/include/line.h @@ -58,23 +58,17 @@ struct line { }; #define LINE_INIT(str, d) \ - { init_str : str, \ - init_pri : INIT_STATIC, \ - valid : 1, \ - throttled : 0, \ - lock : SPIN_LOCK_UNLOCKED, \ - buffer : NULL, \ - head : NULL, \ - tail : NULL, \ - sigio : 0, \ - driver : d, \ - have_irq : 0 } + { .init_str = str, \ + .init_pri = INIT_STATIC, \ + .valid = 1, \ + .lock = SPIN_LOCK_UNLOCKED, \ + .driver = d } struct lines { int num; }; -#define LINES_INIT(n) { num : n } +#define LINES_INIT(n) { .num = n } extern void line_close(struct tty_struct *tty, struct file * filp); extern int line_open(struct line *lines, struct tty_struct *tty); diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index a1064c5823bf..a54514d2cc3a 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h @@ -49,7 +49,6 @@ extern int iomem_size; extern unsigned long host_task_size; extern unsigned long task_size; -extern void check_devanon(void); extern int init_mem_user(void); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); diff --git a/arch/um/include/os.h b/arch/um/include/os.h index d3d1bc6074ef..f88856c28a66 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -13,6 +13,7 @@ #include "kern_util.h" #include "skas/mm_id.h" #include "irq_user.h" +#include "sysdep/tls.h" #define OS_TYPE_FILE 1 #define OS_TYPE_DIR 2 @@ -172,6 +173,7 @@ extern int os_fchange_dir(int fd); extern void os_early_checks(void); extern int can_do_skas(void); extern void os_check_bugs(void); +extern void check_host_supports_tls(int *supports_tls, int *tls_min); /* Make sure they are clear when running in TT mode. Required by * SEGV_MAYBE_FIXABLE */ @@ -205,6 +207,8 @@ extern int os_map_memory(void *virt, int fd, unsigned long long off, extern int os_protect_memory(void *addr, unsigned long len, int r, int w, int x); extern int os_unmap_memory(void *addr, int len); +extern int os_drop_memory(void *addr, int length); +extern int can_drop_memory(void); extern void os_flush_stdout(void); /* tt.c @@ -234,8 +238,12 @@ extern int run_helper_thread(int (*proc)(void *), void *arg, int stack_order); extern int helper_wait(int pid); -/* umid.c */ +/* tls.c */ +extern int os_set_thread_area(user_desc_t *info, int pid); +extern int os_get_thread_area(user_desc_t *info, int pid); + +/* umid.c */ extern int umid_file_name(char *name, char *buf, int len); extern int set_umid(char *name); extern char *get_umid(void); diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h index 7d3d202d7fff..052bb061a978 100644 --- a/arch/um/include/sysdep-i386/checksum.h +++ b/arch/um/include/sysdep-i386/checksum.h @@ -48,7 +48,8 @@ unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char * */ static __inline__ -unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, +unsigned int csum_partial_copy_from_user(const unsigned char __user *src, + unsigned char *dst, int len, int sum, int *err_ptr) { if(copy_from_user(dst, src, len)){ @@ -192,7 +193,7 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, */ #define HAVE_CSUM_COPY_USER static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src, - unsigned char *dst, + unsigned char __user *dst, int len, int sum, int *err_ptr) { if (access_ok(VERIFY_WRITE, dst, len)){ diff --git a/arch/um/include/sysdep-i386/ptrace.h b/arch/um/include/sysdep-i386/ptrace.h index c8ee9559f3ab..6670cc992ecb 100644 --- a/arch/um/include/sysdep-i386/ptrace.h +++ b/arch/um/include/sysdep-i386/ptrace.h @@ -14,7 +14,12 @@ #define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long)) #define MAX_REG_OFFSET (UM_FRAME_SIZE) +#ifdef UML_CONFIG_PT_PROXY extern void update_debugregs(int seq); +#else +static inline void update_debugregs(int seq) {} +#endif + /* syscall emulation path in ptrace */ diff --git a/arch/um/include/sysdep-i386/tls.h b/arch/um/include/sysdep-i386/tls.h new file mode 100644 index 000000000000..918fd3c5ff9c --- /dev/null +++ b/arch/um/include/sysdep-i386/tls.h @@ -0,0 +1,32 @@ +#ifndef _SYSDEP_TLS_H +#define _SYSDEP_TLS_H + +# ifndef __KERNEL__ + +/* Change name to avoid conflicts with the original one from , which + * may be named user_desc (but in 2.4 and in header matching its API was named + * modify_ldt_ldt_s). */ + +typedef struct um_dup_user_desc { + unsigned int entry_number; + unsigned int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; +} user_desc_t; + +# else /* __KERNEL__ */ + +# include +typedef struct user_desc user_desc_t; + +# endif /* __KERNEL__ */ + +#define GDT_ENTRY_TLS_MIN_I386 6 +#define GDT_ENTRY_TLS_MIN_X86_64 12 + +#endif /* _SYSDEP_TLS_H */ diff --git a/arch/um/include/sysdep-x86_64/tls.h b/arch/um/include/sysdep-x86_64/tls.h new file mode 100644 index 000000000000..35f19f25bd3b --- /dev/null +++ b/arch/um/include/sysdep-x86_64/tls.h @@ -0,0 +1,29 @@ +#ifndef _SYSDEP_TLS_H +#define _SYSDEP_TLS_H + +# ifndef __KERNEL__ + +/* Change name to avoid conflicts with the original one from , which + * may be named user_desc (but in 2.4 and in header matching its API was named + * modify_ldt_ldt_s). */ + +typedef struct um_dup_user_desc { + unsigned int entry_number; + unsigned int base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; + unsigned int seg_not_present:1; + unsigned int useable:1; + unsigned int lm:1; +} user_desc_t; + +# else /* __KERNEL__ */ + +# include +typedef struct user_desc user_desc_t; + +# endif /* __KERNEL__ */ +#endif /* _SYSDEP_TLS_H */ diff --git a/arch/um/include/tt/tt.h b/arch/um/include/tt/tt.h index 808521980186..acb8356e1f98 100644 --- a/arch/um/include/tt/tt.h +++ b/arch/um/include/tt/tt.h @@ -19,7 +19,8 @@ extern int fork_tramp(void *sig_stack); extern int do_proc_op(void *t, int proc_id); extern int tracer(int (*init_proc)(void *), void *sp); extern void attach_process(int pid); -extern void tracer_panic(char *format, ...); +extern void tracer_panic(char *format, ...) + __attribute__ ((format (printf, 1, 2))); extern void set_init_pid(int pid); extern int set_user_mode(void *task); extern void set_tracing(void *t, int tracing); diff --git a/arch/um/include/user.h b/arch/um/include/user.h index 91b0ac4ad88c..39f8c8801076 100644 --- a/arch/um/include/user.h +++ b/arch/um/include/user.h @@ -6,8 +6,10 @@ #ifndef __USER_H__ #define __USER_H__ -extern void panic(const char *fmt, ...); -extern int printk(const char *fmt, ...); +extern void panic(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); +extern int printk(const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); extern void schedule(void); extern void *um_kmalloc(int size); extern void *um_kmalloc_atomic(int size); diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index 992a7e1e0fca..802d7842514d 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -8,6 +8,9 @@ #include "sysdep/ptrace.h" +/* Copied from kernel.h */ +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + #define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR)) extern int mode_tt; @@ -31,7 +34,7 @@ extern unsigned long uml_physmem; extern unsigned long uml_reserved; extern unsigned long end_vm; extern unsigned long start_vm; -extern unsigned long highmem; +extern unsigned long long highmem; extern char host_info[]; @@ -52,7 +55,8 @@ extern int get_pty(void); extern void *um_kmalloc(int size); extern int switcheroo(int fd, int prot, void *from, void *to, int size); extern void do_exec(int old_pid, int new_pid); -extern void tracer_panic(char *msg, ...); +extern void tracer_panic(char *msg, ...) + __attribute__ ((format (printf, 1, 2))); extern int detach(int pid, int sig); extern int attach(int pid); extern void kill_child_dead(int pid); diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index 1ca84319317d..c0cb627bf594 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -22,6 +22,7 @@ void flush_thread(void) { + arch_flush_thread(¤t->thread.arch); CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); } @@ -58,14 +59,14 @@ long um_execve(char *file, char __user *__user *argv, char __user *__user *env) return(err); } -long sys_execve(char *file, char __user *__user *argv, +long sys_execve(char __user *file, char __user *__user *argv, char __user *__user *env) { long error; char *filename; lock_kernel(); - filename = getname((char __user *) file); + filename = getname(file); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; error = execve1(filename, argv, env); @@ -74,14 +75,3 @@ long sys_execve(char *file, char __user *__user *argv, unlock_kernel(); return(error); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 7713e7a6f476..432cf0b97a13 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -39,7 +39,6 @@ EXPORT_SYMBOL(um_virt_to_phys); EXPORT_SYMBOL(mode_tt); EXPORT_SYMBOL(handle_page_fault); EXPORT_SYMBOL(find_iomem); -EXPORT_SYMBOL(end_iomem); #ifdef CONFIG_MODE_TT EXPORT_SYMBOL(strncpy_from_user_tt); @@ -89,12 +88,10 @@ EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(do_gettimeofday); EXPORT_SYMBOL(do_settimeofday); -/* This is here because UML expands open to sys_open, not to a system +/* This is here because UML expands lseek to sys_lseek, not to a system * call instruction. */ -EXPORT_SYMBOL(sys_open); EXPORT_SYMBOL(sys_lseek); -EXPORT_SYMBOL(sys_read); EXPORT_SYMBOL(sys_wait4); #ifdef CONFIG_SMP diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 92cce96b5e24..44e41a35f000 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -30,7 +30,7 @@ extern char __binary_start; unsigned long *empty_zero_page = NULL; unsigned long *empty_bad_page = NULL; pgd_t swapper_pg_dir[PTRS_PER_PGD]; -unsigned long highmem; +unsigned long long highmem; int kmalloc_ok = 0; static unsigned long brk_end; diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index 3113cab8675e..f6a5a502120b 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -156,9 +156,25 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { + int ret; + p->thread = (struct thread_struct) INIT_THREAD; - return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, - clone_flags, sp, stack_top, p, regs)); + ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, + clone_flags, sp, stack_top, p, regs); + + if (ret || !current->thread.forking) + goto out; + + clear_flushed_tls(p); + + /* + * Set a new TLS for the child thread? + */ + if (clone_flags & CLONE_SETTLS) + ret = arch_copy_tls(p); + +out: + return ret; } void initial_thread_cb(void (*proc)(void *), void *arg) @@ -185,10 +201,6 @@ void default_idle(void) { CHOOSE_MODE(uml_idle_timer(), (void) 0); - atomic_inc(&init_mm.mm_count); - current->mm = &init_mm; - current->active_mm = &init_mm; - while(1){ /* endless idle loop with no priority at all */ @@ -407,7 +419,7 @@ static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int return strlen(buf); } -static int proc_write_sysemu(struct file *file,const char *buf, unsigned long count,void *data) +static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data) { char tmp[2]; diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 98e09395c093..60d2eda995c1 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -46,6 +46,7 @@ extern int poke_user(struct task_struct * child, long addr, long data); long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int i, ret; + unsigned long __user *p = (void __user *)(unsigned long)data; switch (request) { /* when I and D space are separate, these will need to be fixed. */ @@ -58,7 +59,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); if (copied != sizeof(tmp)) break; - ret = put_user(tmp, (unsigned long __user *) data); + ret = put_user(tmp, p); break; } @@ -136,15 +137,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef PTRACE_GETREGS case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - if (!access_ok(VERIFY_WRITE, (unsigned long *)data, - MAX_REG_OFFSET)) { + if (!access_ok(VERIFY_WRITE, p, MAX_REG_OFFSET)) { ret = -EIO; break; } for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { - __put_user(getreg(child, i), - (unsigned long __user *) data); - data += sizeof(long); + __put_user(getreg(child, i), p); + p++; } ret = 0; break; @@ -153,15 +152,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) #ifdef PTRACE_SETREGS case PTRACE_SETREGS: { /* Set all gp regs in the child. */ unsigned long tmp = 0; - if (!access_ok(VERIFY_READ, (unsigned *)data, - MAX_REG_OFFSET)) { + if (!access_ok(VERIFY_READ, p, MAX_REG_OFFSET)) { ret = -EIO; break; } for ( i = 0; i < MAX_REG_OFFSET; i += sizeof(long) ) { - __get_user(tmp, (unsigned long __user *) data); + __get_user(tmp, p); putreg(child, i, tmp); - data += sizeof(long); + p++; } ret = 0; break; @@ -187,14 +185,23 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = set_fpxregs(data, child); break; #endif + case PTRACE_GET_THREAD_AREA: + ret = ptrace_get_thread_area(child, addr, + (struct user_desc __user *) data); + break; + + case PTRACE_SET_THREAD_AREA: + ret = ptrace_set_thread_area(child, addr, + (struct user_desc __user *) data); + break; + case PTRACE_FAULTINFO: { - /* Take the info from thread->arch->faultinfo, - * but transfer max. sizeof(struct ptrace_faultinfo). - * On i386, ptrace_faultinfo is smaller! - */ - ret = copy_to_user((unsigned long __user *) data, - &child->thread.arch.faultinfo, - sizeof(struct ptrace_faultinfo)); + /* Take the info from thread->arch->faultinfo, + * but transfer max. sizeof(struct ptrace_faultinfo). + * On i386, ptrace_faultinfo is smaller! + */ + ret = copy_to_user(p, &child->thread.arch.faultinfo, + sizeof(struct ptrace_faultinfo)); if(ret) break; break; @@ -204,8 +211,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_LDT: { struct ptrace_ldt ldt; - if(copy_from_user(&ldt, (unsigned long __user *) data, - sizeof(ldt))){ + if(copy_from_user(&ldt, p, sizeof(ldt))){ ret = -EIO; break; } diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 3f70a2e12f06..2135eaf98a93 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -35,6 +35,8 @@ void switch_to_skas(void *prev, void *next) switch_threads(&from->thread.mode.skas.switch_buf, to->thread.mode.skas.switch_buf); + arch_switch_to_skas(current->thread.prev_sched, current); + if(current->pid == 0) switch_timers(1); } @@ -89,10 +91,17 @@ void fork_handler(int sig) panic("blech"); schedule_tail(current->thread.prev_sched); + + /* XXX: if interrupt_end() calls schedule, this call to + * arch_switch_to_skas isn't needed. We could want to apply this to + * improve performance. -bb */ + arch_switch_to_skas(current->thread.prev_sched, current); + current->thread.prev_sched = NULL; /* Handle any immediate reschedules or signals */ interrupt_end(); + userspace(¤t->thread.regs.regs); } @@ -109,6 +118,8 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; handler = fork_handler; + + arch_copy_thread(¤t->thread.arch, &p->thread.arch); } else { init_thread_registers(&p->thread.regs.regs); diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c index 8e1a3501ff46..37d3978337d8 100644 --- a/arch/um/kernel/syscall_kern.c +++ b/arch/um/kernel/syscall_kern.c @@ -104,7 +104,7 @@ long sys_pipe(unsigned long __user * fildes) } -long sys_uname(struct old_utsname * name) +long sys_uname(struct old_utsname __user * name) { long err; if (!name) @@ -115,7 +115,7 @@ long sys_uname(struct old_utsname * name) return err?-EFAULT:0; } -long sys_olduname(struct oldold_utsname * name) +long sys_olduname(struct oldold_utsname __user * name) { long error; diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index d56046c2aba2..02f6d4d8dc3a 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -198,7 +198,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) si.si_signo = SIGBUS; si.si_errno = 0; si.si_code = BUS_ADRERR; - si.si_addr = (void *)address; + si.si_addr = (void __user *)address; current->thread.arch.faultinfo = fi; force_sig_info(SIGBUS, &si, current); } else if (err == -ENOMEM) { @@ -207,7 +207,7 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) } else { BUG_ON(err != -EFAULT); si.si_signo = SIGSEGV; - si.si_addr = (void *) address; + si.si_addr = (void __user *) address; current->thread.arch.faultinfo = fi; force_sig_info(SIGSEGV, &si, current); } @@ -220,8 +220,8 @@ void bad_segv(struct faultinfo fi, unsigned long ip) si.si_signo = SIGSEGV; si.si_code = SEGV_ACCERR; - si.si_addr = (void *) FAULT_ADDRESS(fi); - current->thread.arch.faultinfo = fi; + si.si_addr = (void __user *) FAULT_ADDRESS(fi); + current->thread.arch.faultinfo = fi; force_sig_info(SIGSEGV, &si, current); } diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 295c1ac817b3..a9c1443fc548 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -51,6 +51,13 @@ void switch_to_tt(void *prev, void *next) c = 0; + /* Notice that here we "up" the semaphore on which "to" is waiting, and + * below (the read) we wait on this semaphore (which is implemented by + * switch_pipe) and go sleeping. Thus, after that, we have resumed in + * "to", and can't use any more the value of "from" (which is outdated), + * nor the value in "to" (since it was the task which stole us the CPU, + * which we don't care about). */ + err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) panic("write of switch_pipe failed, err = %d", -err); @@ -77,7 +84,7 @@ void switch_to_tt(void *prev, void *next) change_sig(SIGALRM, alrm); change_sig(SIGPROF, prof); - arch_switch(); + arch_switch_to_tt(prev_sched, current); flush_tlb_all(); local_irq_restore(flags); @@ -141,7 +148,6 @@ static void new_thread_handler(int sig) set_cmdline("(kernel thread)"); change_sig(SIGUSR1, 1); - change_sig(SIGVTALRM, 1); change_sig(SIGPROF, 1); local_irq_enable(); if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 1659386b42bb..f4bfc4c7ccac 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -4,7 +4,7 @@ # obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ - signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o \ + signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o tls.o \ user_syms.o util.o drivers/ sys-$(SUBARCH)/ obj-$(CONFIG_MODE_SKAS) += skas/ @@ -12,12 +12,9 @@ obj-$(CONFIG_TTY_LOG) += tty_log.o user-objs-$(CONFIG_TTY_LOG) += tty_log.o USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ - process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o \ + process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o tls.o \ uaccess.o umid.o util.o -elf_aux.o: $(ARCH_DIR)/kernel-offsets.h -CFLAGS_elf_aux.o += -I$(objtree)/arch/um - CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) HAVE_AIO_ABI := $(shell [ -r /usr/include/linux/aio_abi.h ] && \ diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 6ae4b19d9f50..768606bec233 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c @@ -102,18 +102,7 @@ static struct transport ethertap_transport = { static int register_ethertap(void) { register_transport(ðertap_transport); - return(1); + return 0; } __initcall(register_ethertap); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index 901b85e8a1c6..8f49507e64ef 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -40,7 +40,7 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask, int fd) { struct addr_change change; - void *output; + char *output; int n; change.what = op; diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 4202b9ebad4c..190009a6f89c 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c @@ -87,18 +87,7 @@ static struct transport tuntap_transport = { static int register_tuntap(void) { register_transport(&tuntap_transport); - return(1); + return 0; } __initcall(register_tuntap); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 6490a4ff40ac..6987d1d247a2 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -43,7 +43,7 @@ static int helper_child(void *arg) (*data->pre_exec)(data->pre_data); execvp(argv[0], argv); errval = errno; - printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); + printk("helper_child - execve of '%s' failed - errno = %d\n", argv[0], errno); os_write_file(data->fd, &errval, sizeof(errval)); kill(os_getpid(), SIGKILL); return(0); @@ -92,15 +92,15 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, close(fds[1]); fds[1] = -1; - /*Read the errno value from the child.*/ + /* Read the errno value from the child, if the exec failed, or get 0 if + * the exec succeeded because the pipe fd was set as close-on-exec. */ n = os_read_file(fds[0], &ret, sizeof(ret)); - if(n < 0){ + if (n < 0) { printk("run_helper : read on pipe failed, ret = %d\n", -n); ret = n; kill(pid, SIGKILL); CATCH_EINTR(waitpid(pid, NULL, 0)); - } - else if(n != 0){ + } else if(n != 0){ CATCH_EINTR(n = waitpid(pid, NULL, 0)); ret = -errno; } else { diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index 9d7d69a523bb..71bb90a7606d 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c @@ -53,33 +53,36 @@ static void __init find_tempdir(void) */ int make_tempfile(const char *template, char **out_tempname, int do_unlink) { - char tempname[MAXPATHLEN]; + char *tempname; int fd; + tempname = malloc(MAXPATHLEN); + find_tempdir(); - if (*template != '/') + if (template[0] != '/') strcpy(tempname, tempdir); else - *tempname = 0; + tempname[0] = '\0'; strcat(tempname, template); fd = mkstemp(tempname); if(fd < 0){ fprintf(stderr, "open - cannot create %s: %s\n", tempname, strerror(errno)); - return -1; + goto out; } if(do_unlink && (unlink(tempname) < 0)){ perror("unlink"); - return -1; + goto out; } if(out_tempname){ - *out_tempname = strdup(tempname); - if(*out_tempname == NULL){ - perror("strdup"); - return -1; - } + *out_tempname = tempname; + } else { + free(tempname); } return(fd); +out: + free(tempname); + return -1; } #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" @@ -121,36 +124,11 @@ int create_tmp_file(unsigned long long len) return(fd); } -static int create_anon_file(unsigned long long len) -{ - void *addr; - int fd; - - fd = open("/dev/anon", O_RDWR); - if(fd < 0) { - perror("opening /dev/anon"); - exit(1); - } - - addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if(addr == MAP_FAILED){ - perror("mapping physmem file"); - exit(1); - } - munmap(addr, len); - - return(fd); -} - -extern int have_devanon; - int create_mem_file(unsigned long long len) { int err, fd; - if(have_devanon) - fd = create_anon_file(len); - else fd = create_tmp_file(len); + fd = create_tmp_file(len); err = os_set_exec_close(fd, 1); if(err < 0){ diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index d261888f39c4..8176b0b52047 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "ptrace_user.h" #include "os.h" #include "user.h" @@ -20,6 +21,7 @@ #include "kern_util.h" #include "longjmp.h" #include "skas_ptrace.h" +#include "kern_constants.h" #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 @@ -187,6 +189,48 @@ int os_unmap_memory(void *addr, int len) return(0); } +#ifndef MADV_REMOVE +#define MADV_REMOVE 0x5 /* remove these pages & resources */ +#endif + +int os_drop_memory(void *addr, int length) +{ + int err; + + err = madvise(addr, length, MADV_REMOVE); + if(err < 0) + err = -errno; + return err; +} + +int can_drop_memory(void) +{ + void *addr; + int fd; + + printk("Checking host MADV_REMOVE support..."); + fd = create_mem_file(UM_KERN_PAGE_SIZE); + if(fd < 0){ + printk("Creating test memory file failed, err = %d\n", -fd); + return 0; + } + + addr = mmap64(NULL, UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + if(addr == MAP_FAILED){ + printk("Mapping test memory file failed, err = %d\n", -errno); + return 0; + } + + if(madvise(addr, UM_KERN_PAGE_SIZE, MADV_REMOVE) != 0){ + printk("MADV_REMOVE failed, err = %d\n", -errno); + return 0; + } + + printk("OK\n"); + return 1; +} + void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) { int flags = 0, pages; diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 9ba942947146..00e9388e947a 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -304,8 +304,8 @@ out_clear_poll: .size = 0, .used = 0 }); out_free: - kfree(p); sigio_unlock(); + kfree(p); out_close2: close(l_sigio_private[0]); close(l_sigio_private[1]); diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c index fbb080c2fc26..b3c11cfa995a 100644 --- a/arch/um/os-Linux/skas/mem.c +++ b/arch/um/os-Linux/skas/mem.c @@ -82,8 +82,8 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) if (offset) { data = (unsigned long *)(mm_idp->stack + offset - UML_CONFIG_STUB_DATA); - printk("do_syscall_stub : ret = %d, offset = %d, " - "data = 0x%x\n", ret, offset, data); + printk("do_syscall_stub : ret = %ld, offset = %ld, " + "data = %p\n", ret, offset, data); syscall = (unsigned long *)((unsigned long)data + data[0]); printk("do_syscall_stub: syscall %ld failed, return value = " "0x%lx, expected return value = 0x%lx\n", diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index bbf34cb91ce1..045ae0037456 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -265,7 +265,7 @@ void userspace(union uml_pt_regs *regs) if(err) panic("userspace - could not resume userspace process, " "pid=%d, ptrace operation = %d, errno = %d\n", - op, errno); + pid, op, errno); CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if(err < 0) @@ -369,7 +369,7 @@ int copy_context_skas0(unsigned long new_stack, int pid) */ wait_stub_done(pid, -1, "copy_context_skas0"); if (child_data->err != UML_CONFIG_STUB_DATA) - panic("copy_context_skas0 - stub-child reports error %d\n", + panic("copy_context_skas0 - stub-child reports error %ld\n", child_data->err); if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 32753131f8d8..387e26af301a 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -470,25 +470,6 @@ int can_do_skas(void) } #endif -int have_devanon = 0; - -/* Runs on boot kernel stack - already safe to use printk. */ - -void check_devanon(void) -{ - int fd; - - printk("Checking for /dev/anon on the host..."); - fd = open("/dev/anon", O_RDWR); - if(fd < 0){ - printk("Not available (open failed with errno %d)\n", errno); - return; - } - - printk("OK\n"); - have_devanon = 1; -} - int __init parse_iomem(char *str, int *add) { struct iomem_region *new; @@ -664,6 +645,5 @@ void os_check_bugs(void) { check_ptrace(); check_sigio(); - check_devanon(); } diff --git a/arch/um/os-Linux/sys-i386/Makefile b/arch/um/os-Linux/sys-i386/Makefile index 340ef26f5944..b3213613c41c 100644 --- a/arch/um/os-Linux/sys-i386/Makefile +++ b/arch/um/os-Linux/sys-i386/Makefile @@ -3,7 +3,7 @@ # Licensed under the GPL # -obj-$(CONFIG_MODE_SKAS) = registers.o +obj-$(CONFIG_MODE_SKAS) = registers.o tls.o USER_OBJS := $(obj-y) diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c new file mode 100644 index 000000000000..120abbe4e3ce --- /dev/null +++ b/arch/um/os-Linux/sys-i386/tls.c @@ -0,0 +1,34 @@ +#include +#include +#include "sysdep/tls.h" +#include "user_util.h" + +static _syscall1(int, get_thread_area, user_desc_t *, u_info); + +/* Checks whether host supports TLS, and sets *tls_min according to the value + * valid on the host. + * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ +void check_host_supports_tls(int *supports_tls, int *tls_min) { + /* Values for x86 and x86_64.*/ + int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64}; + int i; + + for (i = 0; i < ARRAY_SIZE(val); i++) { + user_desc_t info; + info.entry_number = val[i]; + + if (get_thread_area(&info) == 0) { + *tls_min = val[i]; + *supports_tls = 1; + return; + } else { + if (errno == EINVAL) + continue; + else if (errno == ENOSYS) + *supports_tls = 0; + return; + } + } + + *supports_tls = 0; +} diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c new file mode 100644 index 000000000000..9cb09a45546b --- /dev/null +++ b/arch/um/os-Linux/tls.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include "sysdep/tls.h" +#include "uml-config.h" + +/* TLS support - we basically rely on the host's one.*/ + +/* In TT mode, this should be called only by the tracing thread, and makes sense + * only for PTRACE_SET_THREAD_AREA. In SKAS mode, it's used normally. + * + */ + +#ifndef PTRACE_GET_THREAD_AREA +#define PTRACE_GET_THREAD_AREA 25 +#endif + +#ifndef PTRACE_SET_THREAD_AREA +#define PTRACE_SET_THREAD_AREA 26 +#endif + +int os_set_thread_area(user_desc_t *info, int pid) +{ + int ret; + + ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number, + (unsigned long) info); + if (ret < 0) + ret = -errno; + return ret; +} + +#ifdef UML_CONFIG_MODE_SKAS + +int os_get_thread_area(user_desc_t *info, int pid) +{ + int ret; + + ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number, + (unsigned long) info); + if (ret < 0) + ret = -errno; + return ret; +} + +#endif + +#ifdef UML_CONFIG_MODE_TT +#include "linux/unistd.h" + +static _syscall1(int, get_thread_area, user_desc_t *, u_info); +static _syscall1(int, set_thread_area, user_desc_t *, u_info); + +int do_set_thread_area_tt(user_desc_t *info) +{ + int ret; + + ret = set_thread_area(info); + if (ret < 0) { + ret = -errno; + } + return ret; +} + +int do_get_thread_area_tt(user_desc_t *info) +{ + int ret; + + ret = get_thread_area(info); + if (ret < 0) { + ret = -errno; + } + return ret; +} + +#endif /* UML_CONFIG_MODE_TT */ diff --git a/arch/um/os-Linux/umid.c b/arch/um/os-Linux/umid.c index 198e59163288..34bfc1bb9e38 100644 --- a/arch/um/os-Linux/umid.c +++ b/arch/um/os-Linux/umid.c @@ -120,7 +120,8 @@ static int not_dead_yet(char *dir) dead = 0; fd = open(file, O_RDONLY); - if(fd < 0){ + if(fd < 0) { + fd = -errno; if(fd != -ENOENT){ printk("not_dead_yet : couldn't open pid file '%s', " "err = %d\n", file, -fd); @@ -130,9 +131,13 @@ static int not_dead_yet(char *dir) err = 0; n = read(fd, pid, sizeof(pid)); - if(n <= 0){ + if(n < 0){ printk("not_dead_yet : couldn't read pid file '%s', " - "err = %d\n", file, -n); + "err = %d\n", file, errno); + goto out_close; + } else if(n == 0){ + printk("not_dead_yet : couldn't read pid file '%s', " + "0-byte read\n", file); goto out_close; } @@ -155,9 +160,9 @@ static int not_dead_yet(char *dir) return err; - out_close: +out_close: close(fd); - out: +out: return 0; } diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 8da6ab31152a..2598158e1f53 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c @@ -18,14 +18,19 @@ extern void *memmove(void *, const void *, size_t); extern void *memset(void *, int, size_t); extern int printf(const char *, ...); +/* If they're not defined, the export is included in lib/string.c.*/ +#ifdef __HAVE_ARCH_STRLEN EXPORT_SYMBOL(strlen); +#endif +#ifdef __HAVE_ARCH_STRSTR +EXPORT_SYMBOL(strstr); +#endif + EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(printf); -EXPORT_SYMBOL(strstr); - /* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. * However, the modules will use the CRC defined *here*, no matter if it is * good; so the versions of these symbols will always match diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules index 2e41cabd3d93..5e7a9c310aa5 100644 --- a/arch/um/scripts/Makefile.rules +++ b/arch/um/scripts/Makefile.rules @@ -9,10 +9,8 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) $(USER_OBJS) $(USER_OBJS:.o=.i) $(USER_OBJS:.o=.s) $(USER_OBJS:.o=.lst): \ c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) $(CFLAGS_$(notdir $@)) -$(USER_OBJS): cmd_checksrc = -$(USER_OBJS): quiet_cmd_checksrc = -$(USER_OBJS): cmd_force_checksrc = -$(USER_OBJS): quiet_cmd_force_checksrc = +$(USER_OBJS) : CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ \ + -Dunix -D__unix__ -D__$(SUBARCH)__ # The stubs and unmap.o can't try to call mcount or update basic block data @@ -20,25 +18,7 @@ define unprofile $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1))) endef - -# cmd_make_link checks to see if the $(foo-dir) variable starts with a /. If -# so, it's considered to be a path relative to $(srcdir) rather than -# $(srcdir)/arch/$(SUBARCH). This is because x86_64 wants to get ldt.c from -# arch/um/sys-i386 rather than arch/i386 like the other borrowed files. So, -# it sets $(ldt.c-dir) to /arch/um/sys-i386. -quiet_cmd_make_link = SYMLINK $@ -cmd_make_link = rm -f $@; ln -sf $(srctree)$(if $(filter-out /%,$($(notdir $@)-dir)),/arch/$(SUBARCH))/$($(notdir $@)-dir)/$(notdir $@) $@ - -# this needs to be before the foreach, because targets does not accept -# complete paths like $(obj)/$(f). To make sure this works, use a := assignment -# or we will get $(obj)/$(f) in the "targets" value. -# Also, this forces you to use the := syntax when assigning to targets. -# Otherwise the line below will cause an infinite loop (if you don't know why, -# just do it). - -targets := $(targets) $(SYMLINKS) - -SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$(f)) - -$(SYMLINKS): FORCE - $(call if_changed,make_link) +ifdef subarch-obj-y +obj-y += subarch.o +subarch-y = $(addprefix ../../$(SUBARCH)/,$(subarch-obj-y)) +endif diff --git a/arch/um/scripts/Makefile.unmap b/arch/um/scripts/Makefile.unmap deleted file mode 100644 index b2165188d942..000000000000 --- a/arch/um/scripts/Makefile.unmap +++ /dev/null @@ -1,22 +0,0 @@ -clean-files += unmap_tmp.o unmap_fin.o unmap.o - -ifdef CONFIG_MODE_TT - -#Always build unmap_fin.o -extra-y += unmap_fin.o -#Do dependency tracking for unmap.o (it will be always built, but won't get the tracking unless we use this). -targets += unmap.o - -#XXX: partially copied from arch/um/scripts/Makefile.rules -$(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS)) - -quiet_cmd_wrapld = LD $@ -define cmd_wrapld - $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< ; \ - $(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo -endef - -$(obj)/unmap_fin.o : $(obj)/unmap.o FORCE - $(call if_changed,wrapld) - -endif diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index f5fd5b0156d0..98b20b7bba4f 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,23 +1,18 @@ -obj-y := bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ - ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \ - sys_call_table.o +obj-y = bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ + ptrace_user.o signal.o sigcontext.o syscalls.o sysrq.o \ + sys_call_table.o tls.o obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o -obj-$(CONFIG_HIGHMEM) += highmem.o -obj-$(CONFIG_MODULES) += module.o +subarch-obj-y = lib/bitops.o kernel/semaphore.o +subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem.o +subarch-obj-$(CONFIG_MODULES) += kernel/module.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o stub_segv.o -SYMLINKS = bitops.c semaphore.c highmem.c module.c - include arch/um/scripts/Makefile.rules -bitops.c-dir = lib -semaphore.c-dir = kernel -highmem.c-dir = mm -module.c-dir = kernel +extra-$(CONFIG_MODE_TT) += unmap.o -$(obj)/stub_segv.o : _c_flags = $(call unprofile,$(CFLAGS)) - -include arch/um/scripts/Makefile.unmap +$(obj)/stub_segv.o $(obj)/unmap.o: \ + _c_flags = $(call unprofile,$(CFLAGS)) diff --git a/arch/um/sys-i386/ksyms.c b/arch/um/sys-i386/ksyms.c index db524ab3f743..2a1eac1859ce 100644 --- a/arch/um/sys-i386/ksyms.c +++ b/arch/um/sys-i386/ksyms.c @@ -15,7 +15,3 @@ EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial); - -/* delay core functions */ -EXPORT_SYMBOL(__const_udelay); -EXPORT_SYMBOL(__udelay); diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index 8032a105949a..6028bc7cc01b 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c @@ -15,9 +15,22 @@ #include "sysdep/sigcontext.h" #include "sysdep/sc.h" -void arch_switch(void) +void arch_switch_to_tt(struct task_struct *from, struct task_struct *to) { - update_debugregs(current->thread.arch.debugregs_seq); + update_debugregs(to->thread.arch.debugregs_seq); + arch_switch_tls_tt(from, to); +} + +void arch_switch_to_skas(struct task_struct *from, struct task_struct *to) +{ + int err = arch_switch_tls_skas(from, to); + if (!err) + return; + + if (err != -EINVAL) + printk(KERN_WARNING "arch_switch_tls_skas failed, errno %d, not EINVAL\n", -err); + else + printk(KERN_WARNING "arch_switch_tls_skas failed, errno = EINVAL\n"); } int is_syscall(unsigned long addr) @@ -124,22 +137,22 @@ unsigned long getreg(struct task_struct *child, int regno) int peek_user(struct task_struct *child, long addr, long data) { /* read the word at location addr in the USER area. */ - unsigned long tmp; + unsigned long tmp; - if ((addr & 3) || addr < 0) - return -EIO; + if ((addr & 3) || addr < 0) + return -EIO; - tmp = 0; /* Default return condition */ - if(addr < MAX_REG_OFFSET){ - tmp = getreg(child, addr); - } - else if((addr >= offsetof(struct user, u_debugreg[0])) && - (addr <= offsetof(struct user, u_debugreg[7]))){ - addr -= offsetof(struct user, u_debugreg[0]); - addr = addr >> 2; - tmp = child->thread.arch.debugregs[addr]; - } - return put_user(tmp, (unsigned long *) data); + tmp = 0; /* Default return condition */ + if(addr < MAX_REG_OFFSET){ + tmp = getreg(child, addr); + } + else if((addr >= offsetof(struct user, u_debugreg[0])) && + (addr <= offsetof(struct user, u_debugreg[7]))){ + addr -= offsetof(struct user, u_debugreg[0]); + addr = addr >> 2; + tmp = child->thread.arch.debugregs[addr]; + } + return put_user(tmp, (unsigned long __user *) data); } struct i387_fxsave_struct { diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 7c376c95de50..40aa88531446 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -14,6 +14,7 @@ #include "sysdep/thread.h" #include "user.h" #include "os.h" +#include "uml-config.h" int ptrace_getregs(long pid, unsigned long *regs_out) { @@ -43,6 +44,7 @@ int ptrace_setfpregs(long pid, unsigned long *regs) return 0; } +/* All the below stuff is of interest for TT mode only */ static void write_debugregs(int pid, unsigned long *regs) { struct user *dummy; @@ -55,7 +57,7 @@ static void write_debugregs(int pid, unsigned long *regs) if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i], regs[i]) < 0) printk("write_debugregs - ptrace failed on " - "register %d, value = 0x%x, errno = %d\n", i, + "register %d, value = 0x%lx, errno = %d\n", i, regs[i], errno); } } @@ -75,7 +77,6 @@ static void read_debugregs(int pid, unsigned long *regs) /* Accessed only by the tracing thread */ static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; -static int debugregs_seq = 0; void arch_enter_kernel(void *task, int pid) { @@ -89,6 +90,11 @@ void arch_leave_kernel(void *task, int pid) write_debugregs(pid, TASK_DEBUGREGS(task)); } +#ifdef UML_CONFIG_PT_PROXY +/* Accessed only by the tracing thread */ +static int debugregs_seq; + +/* Only called by the ptrace proxy */ void ptrace_pokeuser(unsigned long addr, unsigned long data) { if((addr < offsetof(struct user, u_debugreg[0])) || @@ -109,6 +115,7 @@ static void update_debugregs_cb(void *arg) write_debugregs(pid, kernel_debugregs); } +/* Optimized out in its header when not defined */ void update_debugregs(int seq) { int me; @@ -118,6 +125,7 @@ void update_debugregs(int seq) me = os_getpid(); initial_thread_cb(update_debugregs_cb, &me); } +#endif /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c index 33a40f5ef0d2..618fd8594643 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c @@ -19,7 +19,7 @@ #include "skas.h" static int copy_sc_from_user_skas(struct pt_regs *regs, - struct sigcontext *from) + struct sigcontext __user *from) { struct sigcontext sc; unsigned long fpregs[HOST_FP_SIZE]; @@ -57,7 +57,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs, return(0); } -int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, +int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate __user *to_fp, struct pt_regs *regs, unsigned long sp) { struct sigcontext sc; @@ -92,7 +92,7 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, "errno = %d\n", err); return(1); } - to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1)); + to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1)); sc.fpstate = to_fp; if(err) @@ -113,10 +113,11 @@ int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, * saved pointer is in the kernel, but the sigcontext is in userspace, so we * copy_to_user it. */ -int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, +int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from, int fpsize) { - struct _fpstate *to_fp, *from_fp; + struct _fpstate *to_fp; + struct _fpstate __user *from_fp; unsigned long sigs; int err; @@ -131,13 +132,14 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, return(err); } -int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, +int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate __user *fp, struct sigcontext *from, int fpsize, unsigned long sp) { - struct _fpstate *to_fp, *from_fp; + struct _fpstate __user *to_fp; + struct _fpstate *from_fp; int err; - to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); + to_fp = (fp ? fp : (struct _fpstate __user *) (to + 1)); from_fp = from->fpstate; err = copy_to_user(to, from, sizeof(*to)); @@ -145,7 +147,7 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, * delivery. The sp passed in is the original, and this needs * to be restored, so we stick it in separately. */ - err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); + err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp)); if(from_fp != NULL){ err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); @@ -165,7 +167,7 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from) return(ret); } -static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, +static int copy_sc_to_user(struct sigcontext *to, struct _fpstate __user *fp, struct pt_regs *from, unsigned long sp) { return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), @@ -173,7 +175,7 @@ static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, copy_sc_to_user_skas(to, fp, from, sp))); } -static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, +static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp, sigset_t *set, unsigned long sp) { int err = 0; @@ -188,7 +190,7 @@ static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, struct sigframe { - char *pretcode; + char __user *pretcode; int sig; struct sigcontext sc; struct _fpstate fpstate; @@ -198,10 +200,10 @@ struct sigframe struct rt_sigframe { - char *pretcode; + char __user *pretcode; int sig; - struct siginfo *pinfo; - void *puc; + struct siginfo __user *pinfo; + void __user *puc; struct siginfo info; struct ucontext uc; struct _fpstate fpstate; @@ -213,16 +215,16 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig, sigset_t *mask) { struct sigframe __user *frame; - void *restorer; + void __user *restorer; unsigned long save_sp = PT_REGS_SP(regs); int err = 0; stack_top &= -8UL; - frame = (struct sigframe *) stack_top - 1; + frame = (struct sigframe __user *) stack_top - 1; if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return 1; - restorer = (void *) frame->retcode; + restorer = frame->retcode; if(ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; @@ -278,16 +280,16 @@ int setup_signal_stack_si(unsigned long stack_top, int sig, siginfo_t *info, sigset_t *mask) { struct rt_sigframe __user *frame; - void *restorer; + void __user *restorer; unsigned long save_sp = PT_REGS_SP(regs); int err = 0; stack_top &= -8UL; - frame = (struct rt_sigframe *) stack_top - 1; + frame = (struct rt_sigframe __user *) stack_top - 1; if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) return 1; - restorer = (void *) frame->retcode; + restorer = frame->retcode; if(ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; @@ -333,7 +335,7 @@ err: long sys_sigreturn(struct pt_regs regs) { unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct sigframe __user *frame = (struct sigframe *)(sp - 8); + struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); sigset_t set; struct sigcontext __user *sc = &frame->sc; unsigned long __user *oldmask = &sc->oldmask; @@ -365,8 +367,8 @@ long sys_sigreturn(struct pt_regs regs) long sys_rt_sigreturn(struct pt_regs regs) { - unsigned long __user sp = PT_REGS_SP(¤t->thread.regs); - struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4); + unsigned long sp = PT_REGS_SP(¤t->thread.regs); + struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (sp - 4); sigset_t set; struct ucontext __user *uc = &frame->uc; int sig_size = _NSIG_WORDS * sizeof(unsigned long); diff --git a/arch/um/sys-i386/sys_call_table.S b/arch/um/sys-i386/sys_call_table.S index ad75c27afe38..1ff61474b25c 100644 --- a/arch/um/sys-i386/sys_call_table.S +++ b/arch/um/sys-i386/sys_call_table.S @@ -6,8 +6,6 @@ #define sys_vm86old sys_ni_syscall #define sys_vm86 sys_ni_syscall -#define sys_set_thread_area sys_ni_syscall -#define sys_get_thread_area sys_ni_syscall #define sys_stime um_stime #define sys_time um_time diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c index 83e9be820a86..749dd1bfe60f 100644 --- a/arch/um/sys-i386/syscalls.c +++ b/arch/um/sys-i386/syscalls.c @@ -61,21 +61,27 @@ long old_select(struct sel_arg_struct __user *arg) return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); } -/* The i386 version skips reading from %esi, the fourth argument. So we must do - * this, too. +/* + * The prototype on i386 is: + * + * int clone(int flags, void * child_stack, int * parent_tidptr, struct user_desc * newtls, int * child_tidptr) + * + * and the "newtls" arg. on i386 is read by copy_thread directly from the + * register saved on the stack. */ long sys_clone(unsigned long clone_flags, unsigned long newsp, - int __user *parent_tid, int unused, int __user *child_tid) + int __user *parent_tid, void *newtls, int __user *child_tid) { long ret; if (!newsp) newsp = UPT_SP(¤t->thread.regs.regs); + current->thread.forking = 1; ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, child_tid); current->thread.forking = 0; - return(ret); + return ret; } /* @@ -104,7 +110,7 @@ long sys_ipc (uint call, int first, int second, union semun fourth; if (!ptr) return -EINVAL; - if (get_user(fourth.__pad, (void **) ptr)) + if (get_user(fourth.__pad, (void __user * __user *) ptr)) return -EFAULT; return sys_semctl (first, second, third, fourth); } diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c new file mode 100644 index 000000000000..71b9796258ef --- /dev/null +++ b/arch/um/sys-i386/tls.c @@ -0,0 +1,384 @@ +/* + * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso + * Licensed under the GPL + */ + +#include "linux/config.h" +#include "linux/kernel.h" +#include "linux/sched.h" +#include "linux/slab.h" +#include "linux/types.h" +#include "asm/uaccess.h" +#include "asm/ptrace.h" +#include "asm/segment.h" +#include "asm/smp.h" +#include "asm/desc.h" +#include "choose-mode.h" +#include "kern.h" +#include "kern_util.h" +#include "mode_kern.h" +#include "os.h" +#include "mode.h" + +#ifdef CONFIG_MODE_SKAS +#include "skas.h" +#endif + +/* If needed we can detect when it's uninitialized. */ +static int host_supports_tls = -1; +int host_gdt_entry_tls_min = -1; + +#ifdef CONFIG_MODE_SKAS +int do_set_thread_area_skas(struct user_desc *info) +{ + int ret; + u32 cpu; + + cpu = get_cpu(); + ret = os_set_thread_area(info, userspace_pid[cpu]); + put_cpu(); + return ret; +} + +int do_get_thread_area_skas(struct user_desc *info) +{ + int ret; + u32 cpu; + + cpu = get_cpu(); + ret = os_get_thread_area(info, userspace_pid[cpu]); + put_cpu(); + return ret; +} +#endif + +/* + * sys_get_thread_area: get a yet unused TLS descriptor index. + * XXX: Consider leaving one free slot for glibc usage at first place. This must + * be done here (and by changing GDT_ENTRY_TLS_* macros) and nowhere else. + * + * Also, this must be tested when compiling in SKAS mode with dinamic linking + * and running against NPTL. + */ +static int get_free_idx(struct task_struct* task) +{ + struct thread_struct *t = &task->thread; + int idx; + + if (!t->arch.tls_array) + return GDT_ENTRY_TLS_MIN; + + for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) + if (!t->arch.tls_array[idx].present) + return idx + GDT_ENTRY_TLS_MIN; + return -ESRCH; +} + +static inline void clear_user_desc(struct user_desc* info) +{ + /* Postcondition: LDT_empty(info) returns true. */ + memset(info, 0, sizeof(*info)); + + /* Check the LDT_empty or the i386 sys_get_thread_area code - we obtain + * indeed an empty user_desc. + */ + info->read_exec_only = 1; + info->seg_not_present = 1; +} + +#define O_FORCE 1 + +static int load_TLS(int flags, struct task_struct *to) +{ + int ret = 0; + int idx; + + for (idx = GDT_ENTRY_TLS_MIN; idx < GDT_ENTRY_TLS_MAX; idx++) { + struct uml_tls_struct* curr = &to->thread.arch.tls_array[idx - GDT_ENTRY_TLS_MIN]; + + /* Actually, now if it wasn't flushed it gets cleared and + * flushed to the host, which will clear it.*/ + if (!curr->present) { + if (!curr->flushed) { + clear_user_desc(&curr->tls); + curr->tls.entry_number = idx; + } else { + WARN_ON(!LDT_empty(&curr->tls)); + continue; + } + } + + if (!(flags & O_FORCE) && curr->flushed) + continue; + + ret = do_set_thread_area(&curr->tls); + if (ret) + goto out; + + curr->flushed = 1; + } +out: + return ret; +} + +/* Verify if we need to do a flush for the new process, i.e. if there are any + * present desc's, only if they haven't been flushed. + */ +static inline int needs_TLS_update(struct task_struct *task) +{ + int i; + int ret = 0; + + for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { + struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; + + /* Can't test curr->present, we may need to clear a descriptor + * which had a value. */ + if (curr->flushed) + continue; + ret = 1; + break; + } + return ret; +} + +/* On a newly forked process, the TLS descriptors haven't yet been flushed. So + * we mark them as such and the first switch_to will do the job. + */ +void clear_flushed_tls(struct task_struct *task) +{ + int i; + + for (i = GDT_ENTRY_TLS_MIN; i < GDT_ENTRY_TLS_MAX; i++) { + struct uml_tls_struct* curr = &task->thread.arch.tls_array[i - GDT_ENTRY_TLS_MIN]; + + /* Still correct to do this, if it wasn't present on the host it + * will remain as flushed as it was. */ + if (!curr->present) + continue; + + curr->flushed = 0; + } +} + +/* In SKAS0 mode, currently, multiple guest threads sharing the same ->mm have a + * common host process. So this is needed in SKAS0 too. + * + * However, if each thread had a different host process (and this was discussed + * for SMP support) this won't be needed. + * + * And this will not need be used when (and if) we'll add support to the host + * SKAS patch. */ + +int arch_switch_tls_skas(struct task_struct *from, struct task_struct *to) +{ + if (!host_supports_tls) + return 0; + + /* We have no need whatsoever to switch TLS for kernel threads; beyond + * that, that would also result in us calling os_set_thread_area with + * userspace_pid[cpu] == 0, which gives an error. */ + if (likely(to->mm)) + return load_TLS(O_FORCE, to); + + return 0; +} + +int arch_switch_tls_tt(struct task_struct *from, struct task_struct *to) +{ + if (!host_supports_tls) + return 0; + + if (needs_TLS_update(to)) + return load_TLS(0, to); + + return 0; +} + +static int set_tls_entry(struct task_struct* task, struct user_desc *info, + int idx, int flushed) +{ + struct thread_struct *t = &task->thread; + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls = *info; + t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present = 1; + t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed = flushed; + + return 0; +} + +int arch_copy_tls(struct task_struct *new) +{ + struct user_desc info; + int idx, ret = -EFAULT; + + if (copy_from_user(&info, + (void __user *) UPT_ESI(&new->thread.regs.regs), + sizeof(info))) + goto out; + + ret = -EINVAL; + if (LDT_empty(&info)) + goto out; + + idx = info.entry_number; + + ret = set_tls_entry(new, &info, idx, 0); +out: + return ret; +} + +/* XXX: use do_get_thread_area to read the host value? I'm not at all sure! */ +static int get_tls_entry(struct task_struct* task, struct user_desc *info, int idx) +{ + struct thread_struct *t = &task->thread; + + if (!t->arch.tls_array) + goto clear; + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + if (!t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].present) + goto clear; + + *info = t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].tls; + +out: + /* Temporary debugging check, to make sure that things have been + * flushed. This could be triggered if load_TLS() failed. + */ + if (unlikely(task == current && !t->arch.tls_array[idx - GDT_ENTRY_TLS_MIN].flushed)) { + printk(KERN_ERR "get_tls_entry: task with pid %d got here " + "without flushed TLS.", current->pid); + } + + return 0; +clear: + /* When the TLS entry has not been set, the values read to user in the + * tls_array are 0 (because it's cleared at boot, see + * arch/i386/kernel/head.S:cpu_gdt_table). Emulate that. + */ + clear_user_desc(info); + info->entry_number = idx; + goto out; +} + +asmlinkage int sys_set_thread_area(struct user_desc __user *user_desc) +{ + struct user_desc info; + int idx, ret; + + if (!host_supports_tls) + return -ENOSYS; + + if (copy_from_user(&info, user_desc, sizeof(info))) + return -EFAULT; + + idx = info.entry_number; + + if (idx == -1) { + idx = get_free_idx(current); + if (idx < 0) + return idx; + info.entry_number = idx; + /* Tell the user which slot we chose for him.*/ + if (put_user(idx, &user_desc->entry_number)) + return -EFAULT; + } + + ret = CHOOSE_MODE_PROC(do_set_thread_area_tt, do_set_thread_area_skas, &info); + if (ret) + return ret; + return set_tls_entry(current, &info, idx, 1); +} + +/* + * Perform set_thread_area on behalf of the traced child. + * Note: error handling is not done on the deferred load, and this differ from + * i386. However the only possible error are caused by bugs. + */ +int ptrace_set_thread_area(struct task_struct *child, int idx, + struct user_desc __user *user_desc) +{ + struct user_desc info; + + if (!host_supports_tls) + return -EIO; + + if (copy_from_user(&info, user_desc, sizeof(info))) + return -EFAULT; + + return set_tls_entry(child, &info, idx, 0); +} + +asmlinkage int sys_get_thread_area(struct user_desc __user *user_desc) +{ + struct user_desc info; + int idx, ret; + + if (!host_supports_tls) + return -ENOSYS; + + if (get_user(idx, &user_desc->entry_number)) + return -EFAULT; + + ret = get_tls_entry(current, &info, idx); + if (ret < 0) + goto out; + + if (copy_to_user(user_desc, &info, sizeof(info))) + ret = -EFAULT; + +out: + return ret; +} + +/* + * Perform get_thread_area on behalf of the traced child. + */ +int ptrace_get_thread_area(struct task_struct *child, int idx, + struct user_desc __user *user_desc) +{ + struct user_desc info; + int ret; + + if (!host_supports_tls) + return -EIO; + + ret = get_tls_entry(child, &info, idx); + if (ret < 0) + goto out; + + if (copy_to_user(user_desc, &info, sizeof(info))) + ret = -EFAULT; +out: + return ret; +} + + +/* XXX: This part is probably common to i386 and x86-64. Don't create a common + * file for now, do that when implementing x86-64 support.*/ +static int __init __setup_host_supports_tls(void) { + check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min); + if (host_supports_tls) { + printk(KERN_INFO "Host TLS support detected\n"); + printk(KERN_INFO "Detected host type: "); + switch (host_gdt_entry_tls_min) { + case GDT_ENTRY_TLS_MIN_I386: + printk("i386\n"); + break; + case GDT_ENTRY_TLS_MIN_X86_64: + printk("x86_64\n"); + break; + } + } else + printk(KERN_ERR " Host TLS support NOT detected! " + "TLS support inside UML will not work\n"); + return 0; +} + +__initcall(__setup_host_supports_tls); diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index a351091fbd99..b5fc22babddf 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile @@ -4,31 +4,23 @@ # Licensed under the GPL # -#XXX: why into lib-y? -lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o ldt.o mem.o memcpy.o \ - ptrace.o ptrace_user.o sigcontext.o signal.o syscalls.o \ - syscall_table.o sysrq.o thunk.o -lib-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o +obj-y = bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ + sigcontext.o signal.o syscalls.o syscall_table.o sysrq.o ksyms.o \ + tls.o -obj-y := ksyms.o -obj-$(CONFIG_MODULES) += module.o um_module.o +obj-$(CONFIG_MODE_SKAS) += stub.o stub_segv.o +obj-$(CONFIG_MODULES) += um_module.o + +subarch-obj-y = lib/bitops.o lib/csum-partial.o lib/memcpy.o lib/thunk.o +subarch-obj-$(CONFIG_MODULES) += kernel/module.o + +ldt-y = ../sys-i386/ldt.o USER_OBJS := ptrace_user.o sigcontext.o stub_segv.o -SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c ldt.c memcpy.S \ - thunk.S module.c - include arch/um/scripts/Makefile.rules -bitops.c-dir = lib -csum-copy.S-dir = lib -csum-partial.c-dir = lib -csum-wrappers.c-dir = lib -ldt.c-dir = /arch/um/sys-i386 -memcpy.S-dir = lib -thunk.S-dir = lib -module.c-dir = kernel +extra-$(CONFIG_MODE_TT) += unmap.o -$(obj)/stub_segv.o: _c_flags = $(call unprofile,$(CFLAGS)) - -include arch/um/scripts/Makefile.unmap +$(obj)/stub_segv.o $(obj)/unmap.o: \ + _c_flags = $(call unprofile,$(CFLAGS)) diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c index e75c4e1838b0..a4c46a8af008 100644 --- a/arch/um/sys-x86_64/signal.c +++ b/arch/um/sys-x86_64/signal.c @@ -137,7 +137,7 @@ int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, * delivery. The sp passed in is the original, and this needs * to be restored, so we stick it in separately. */ - err |= copy_to_user(&SC_SP(to), sp, sizeof(sp)); + err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp)); if(from_fp != NULL){ err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); diff --git a/arch/um/sys-x86_64/tls.c b/arch/um/sys-x86_64/tls.c new file mode 100644 index 000000000000..ce1bf1b81c43 --- /dev/null +++ b/arch/um/sys-x86_64/tls.c @@ -0,0 +1,14 @@ +#include "linux/sched.h" + +void debug_arch_force_load_TLS(void) +{ +} + +void clear_flushed_tls(struct task_struct *task) +{ +} + +int arch_copy_tls(struct task_struct *t) +{ + return 0; +} diff --git a/arch/v850/kernel/v850_ksyms.c b/arch/v850/kernel/v850_ksyms.c index 8ffc29c1c89d..6bcfcfe88384 100644 --- a/arch/v850/kernel/v850_ksyms.c +++ b/arch/v850/kernel/v850_ksyms.c @@ -43,7 +43,6 @@ EXPORT_SYMBOL (strncmp); EXPORT_SYMBOL (strchr); EXPORT_SYMBOL (strlen); EXPORT_SYMBOL (strnlen); -EXPORT_SYMBOL (strpbrk); EXPORT_SYMBOL (strrchr); EXPORT_SYMBOL (strstr); EXPORT_SYMBOL (memset); diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 4310b4a311a5..408d44a59756 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -136,6 +136,11 @@ config X86_L1_CACHE_SHIFT default "7" if GENERIC_CPU || MPSC default "6" if MK8 +config X86_INTERNODE_CACHE_BYTES + int + default "4096" if X86_VSMP + default X86_L1_CACHE_BYTES if !X86_VSMP + config X86_TSC bool default y @@ -283,6 +288,11 @@ config K8_NUMA Northbridge of Opteron. It is recommended to use X86_64_ACPI_NUMA instead, which also takes priority if both are compiled in. +config NODES_SHIFT + int + default "6" + depends on NEED_MULTIPLE_NODES + # Dummy CONFIG option to select ACPI_NUMA from drivers/acpi/Kconfig. config X86_64_ACPI_NUMA diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 585fd4a559c8..e573e2ab5510 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -24,37 +24,37 @@ LDFLAGS := -m elf_x86_64 OBJCOPYFLAGS := -O binary -R .note -R .comment -S LDFLAGS_vmlinux := - CHECKFLAGS += -D__x86_64__ -m64 +cflags-y := cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8) cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona) cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic) -CFLAGS += $(cflags-y) -CFLAGS += -m64 -CFLAGS += -mno-red-zone -CFLAGS += -mcmodel=kernel -CFLAGS += -pipe +cflags-y += -m64 +cflags-y += -mno-red-zone +cflags-y += -mcmodel=kernel +cflags-y += -pipe cflags-$(CONFIG_REORDER) += -ffunction-sections # this makes reading assembly source easier, but produces worse code # actually it makes the kernel smaller too. -CFLAGS += -fno-reorder-blocks -CFLAGS += -Wno-sign-compare +cflags-y += -fno-reorder-blocks +cflags-y += -Wno-sign-compare ifneq ($(CONFIG_UNWIND_INFO),y) -CFLAGS += -fno-asynchronous-unwind-tables +cflags-y += -fno-asynchronous-unwind-tables endif ifneq ($(CONFIG_DEBUG_INFO),y) # -fweb shrinks the kernel a bit, but the difference is very small # it also messes up debugging, so don't use it for now. -#CFLAGS += $(call cc-option,-fweb) +#cflags-y += $(call cc-option,-fweb) endif # -funit-at-a-time shrinks the kernel .text considerably # unfortunately it makes reading oopses harder. -CFLAGS += $(call cc-option,-funit-at-a-time) +cflags-y += $(call cc-option,-funit-at-a-time) # prevent gcc from generating any FP code by mistake -CFLAGS += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,) +cflags-y += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,) +CFLAGS += $(cflags-y) AFLAGS += -m64 head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S index 0587477c99f2..32327bb37aff 100644 --- a/arch/x86_64/boot/video.S +++ b/arch/x86_64/boot/video.S @@ -97,6 +97,7 @@ #define PARAM_VESAPM_OFF 0x30 #define PARAM_LFB_PAGES 0x32 #define PARAM_VESA_ATTRIB 0x34 +#define PARAM_CAPABILITIES 0x36 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ #ifdef CONFIG_VIDEO_RETAIN @@ -233,6 +234,10 @@ mopar_gr: movw 18(%di), %ax movl %eax, %fs:(PARAM_LFB_SIZE) +# store mode capabilities + movl 10(%di), %eax + movl %eax, %fs:(PARAM_CAPABILITIES) + # switching the DAC to 8-bit is for <= 8 bpp only movw %fs:(PARAM_LFB_DEPTH), %ax cmpw $8, %ax diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig index 566ecc97ee5a..69db0c0721d1 100644 --- a/arch/x86_64/defconfig +++ b/arch/x86_64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.16-git9 -# Sat Mar 25 15:18:40 2006 +# Linux kernel version: 2.6.17-rc1-git11 +# Sun Apr 16 07:22:36 2006 # CONFIG_X86_64=y CONFIG_64BIT=y @@ -9,6 +9,7 @@ CONFIG_X86=y CONFIG_SEMAPHORE_SLEEPERS=y CONFIG_MMU=y CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_X86_CMPXCHG=y CONFIG_EARLY_PRINTK=y @@ -55,11 +56,8 @@ CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_SHMEM=y -CONFIG_CC_ALIGN_FUNCTIONS=0 -CONFIG_CC_ALIGN_LABELS=0 -CONFIG_CC_ALIGN_LOOPS=0 -CONFIG_CC_ALIGN_JUMPS=0 CONFIG_SLAB=y +CONFIG_DOUBLEFAULT=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 # CONFIG_SLOB is not set @@ -70,7 +68,6 @@ CONFIG_BASE_SMALL=0 CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set # CONFIG_KMOD is not set @@ -81,6 +78,7 @@ CONFIG_STOP_MACHINE=y # CONFIG_LBD=y # CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set # # IO Schedulers @@ -105,6 +103,7 @@ CONFIG_X86_PC=y CONFIG_GENERIC_CPU=y CONFIG_X86_L1_CACHE_BYTES=128 CONFIG_X86_L1_CACHE_SHIFT=7 +CONFIG_X86_INTERNODE_CACHE_BYTES=128 CONFIG_X86_TSC=y CONFIG_X86_GOOD_APIC=y # CONFIG_MICROCODE is not set @@ -116,12 +115,14 @@ CONFIG_X86_LOCAL_APIC=y CONFIG_MTRR=y CONFIG_SMP=y CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set CONFIG_PREEMPT_BKL=y CONFIG_NUMA=y CONFIG_K8_NUMA=y +CONFIG_NODES_SHIFT=6 CONFIG_X86_64_ACPI_NUMA=y CONFIG_NUMA_EMU=y CONFIG_ARCH_DISCONTIGMEM_ENABLE=y @@ -138,6 +139,7 @@ CONFIG_NEED_MULTIPLE_NODES=y CONFIG_SPLIT_PTLOCK_CPUS=4 CONFIG_MIGRATION=y CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y +CONFIG_OUT_OF_LINE_PFN_TO_PAGE=y CONFIG_NR_CPUS=32 CONFIG_HOTPLUG_CPU=y CONFIG_HPET_TIMER=y @@ -289,6 +291,7 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set # CONFIG_INET_TUNNEL is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y @@ -300,6 +303,7 @@ CONFIG_IPV6=y # CONFIG_INET6_AH is not set # CONFIG_INET6_ESP is not set # CONFIG_INET6_IPCOMP is not set +# CONFIG_INET6_XFRM_TUNNEL is not set # CONFIG_INET6_TUNNEL is not set # CONFIG_IPV6_TUNNEL is not set # CONFIG_NETFILTER is not set @@ -542,7 +546,6 @@ CONFIG_SCSI_SATA_INTEL_COMBINED=y # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_IPR is not set -# CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_QLA_FC is not set # CONFIG_SCSI_LPFC is not set @@ -704,7 +707,6 @@ CONFIG_S2IO=m # Wireless LAN (non-hamradio) # # CONFIG_NET_RADIO is not set -# CONFIG_NET_WIRELESS_RTNETLINK is not set # # Wan interfaces @@ -791,7 +793,7 @@ CONFIG_HW_CONSOLE=y # CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y -# CONFIG_SERIAL_8250_ACPI is not set +CONFIG_SERIAL_8250_PCI=y CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_8250_RUNTIME_UARTS=4 # CONFIG_SERIAL_8250_EXTENDED is not set @@ -921,6 +923,7 @@ CONFIG_HWMON=y # Digital Video Broadcasting Devices # # CONFIG_DVB is not set +# CONFIG_USB_DABUSB is not set # # Graphics support @@ -932,6 +935,8 @@ CONFIG_VIDEO_SELECT=y # Console display driver support # CONFIG_VGA_CONSOLE=y +CONFIG_VGACON_SOFT_SCROLLBACK=y +CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=256 CONFIG_DUMMY_CONSOLE=y # @@ -1041,9 +1046,7 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_ACECAD is not set # CONFIG_USB_KBTAB is not set # CONFIG_USB_POWERMATE is not set -# CONFIG_USB_MTOUCH is not set -# CONFIG_USB_ITMTOUCH is not set -# CONFIG_USB_EGALAX is not set +# CONFIG_USB_TOUCHSCREEN is not set # CONFIG_USB_YEALINK is not set # CONFIG_USB_XPAD is not set # CONFIG_USB_ATI_REMOTE is not set @@ -1057,15 +1060,6 @@ CONFIG_USB_HIDINPUT=y # CONFIG_USB_MDC800 is not set # CONFIG_USB_MICROTEK is not set -# -# USB Multimedia devices -# -# CONFIG_USB_DABUSB is not set - -# -# Video4Linux support is needed for USB Multimedia device support -# - # # USB Network Adapters # @@ -1117,16 +1111,35 @@ CONFIG_USB_MON=y # # CONFIG_MMC is not set +# +# LED devices +# +# CONFIG_NEW_LEDS is not set + +# +# LED drivers +# + +# +# LED Triggers +# + # # InfiniBand support # # CONFIG_INFINIBAND is not set +# CONFIG_IPATH_CORE is not set # # EDAC - error detection and reporting (RAS) (EXPERIMENTAL) # # CONFIG_EDAC is not set +# +# Real Time Clock +# +# CONFIG_RTC_CLASS is not set + # # Firmware Drivers # diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 35b2faccdc6c..57fc37e0fb9c 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -15,6 +15,8 @@ #include #include +#define IA32_NR_syscalls ((ia32_syscall_end - ia32_sys_call_table)/8) + .macro IA32_ARG_FIXUP noebp=0 movl %edi,%r8d .if \noebp @@ -109,8 +111,8 @@ ENTRY(ia32_sysenter_target) CFI_REMEMBER_STATE jnz sysenter_tracesys sysenter_do_call: - cmpl $(IA32_NR_syscalls),%eax - jae ia32_badsys + cmpl $(IA32_NR_syscalls-1),%eax + ja ia32_badsys IA32_ARG_FIXUP 1 call *ia32_sys_call_table(,%rax,8) movq %rax,RAX-ARGOFFSET(%rsp) @@ -210,8 +212,8 @@ ENTRY(ia32_cstar_target) CFI_REMEMBER_STATE jnz cstar_tracesys cstar_do_call: - cmpl $IA32_NR_syscalls,%eax - jae ia32_badsys + cmpl $IA32_NR_syscalls-1,%eax + ja ia32_badsys IA32_ARG_FIXUP 1 call *ia32_sys_call_table(,%rax,8) movq %rax,RAX-ARGOFFSET(%rsp) @@ -296,8 +298,8 @@ ENTRY(ia32_syscall) testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),threadinfo_flags(%r10) jnz ia32_tracesys ia32_do_syscall: - cmpl $(IA32_NR_syscalls),%eax - jae ia32_badsys + cmpl $(IA32_NR_syscalls-1),%eax + ja ia32_badsys IA32_ARG_FIXUP call *ia32_sys_call_table(,%rax,8) # xxx: rip relative ia32_sysret: @@ -685,12 +687,12 @@ ia32_sys_call_table: .quad sys_readlinkat /* 305 */ .quad sys_fchmodat .quad sys_faccessat - .quad sys_ni_syscall /* pselect6 for now */ - .quad sys_ni_syscall /* ppoll for now */ + .quad quiet_ni_syscall /* pselect6 for now */ + .quad quiet_ni_syscall /* ppoll for now */ .quad sys_unshare /* 310 */ .quad compat_sys_set_robust_list .quad compat_sys_get_robust_list + .quad sys_splice + .quad sys_sync_file_range + .quad sys_tee ia32_syscall_end: - .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 - .quad ni_syscall - .endr diff --git a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86_64/ia32/vsyscall-sigreturn.S index d90321fe9bba..1384367cdbe1 100644 --- a/arch/x86_64/ia32/vsyscall-sigreturn.S +++ b/arch/x86_64/ia32/vsyscall-sigreturn.S @@ -32,9 +32,28 @@ __kernel_rt_sigreturn: .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn .section .eh_frame,"a",@progbits +.LSTARTFRAMES: + .long .LENDCIES-.LSTARTCIES +.LSTARTCIES: + .long 0 /* CIE ID */ + .byte 1 /* Version number */ + .string "zRS" /* NUL-terminated augmentation string */ + .uleb128 1 /* Code alignment factor */ + .sleb128 -4 /* Data alignment factor */ + .byte 8 /* Return address register column */ + .uleb128 1 /* Augmentation value length */ + .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ + .byte 0x0c /* DW_CFA_def_cfa */ + .uleb128 4 + .uleb128 4 + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .uleb128 1 + .align 4 +.LENDCIES: + .long .LENDFDE2-.LSTARTFDE2 /* Length FDE */ .LSTARTFDE2: - .long .LSTARTFDE2-.LSTARTFRAME /* CIE pointer */ + .long .LSTARTFDE2-.LSTARTFRAMES /* CIE pointer */ /* HACK: The dwarf2 unwind routines will subtract 1 from the return address to get an address in the middle of the presumed call instruction. Since we didn't get here via @@ -97,7 +116,7 @@ __kernel_rt_sigreturn: .long .LENDFDE3-.LSTARTFDE3 /* Length FDE */ .LSTARTFDE3: - .long .LSTARTFDE3-.LSTARTFRAME /* CIE pointer */ + .long .LSTARTFDE3-.LSTARTFRAMES /* CIE pointer */ /* HACK: See above wrt unwind library assumptions. */ .long .LSTART_rt_sigreturn-1-. /* PC-relative start address */ .long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1 diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile index a098a11e7755..059c88313f4e 100644 --- a/arch/x86_64/kernel/Makefile +++ b/arch/x86_64/kernel/Makefile @@ -8,7 +8,7 @@ obj-y := process.o signal.o entry.o traps.o irq.o \ ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \ - dmi_scan.o pci-dma.o pci-nommu.o + pci-dma.o pci-nommu.o obj-$(CONFIG_X86_MCE) += mce.o obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o @@ -49,5 +49,3 @@ intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o quirks-y += ../../i386/kernel/quirks.o i8237-y += ../../i386/kernel/i8237.o msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o -dmi_scan-y += ../../i386/kernel/dmi_scan.o - diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c index fffd6b0a2fab..70b9d21ed675 100644 --- a/arch/x86_64/kernel/aperture.c +++ b/arch/x86_64/kernel/aperture.c @@ -80,7 +80,7 @@ static int __init aperture_valid(char *name, u64 aper_base, u32 aper_size) printk("Aperture from %s beyond 4GB. Ignoring.\n",name); return 0; } - if (e820_mapped(aper_base, aper_base + aper_size, E820_RAM)) { + if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) { printk("Aperture from %s pointing to e820 RAM. Ignoring.\n",name); return 0; } diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index d54620147e8e..100a30c40044 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -615,7 +615,7 @@ static int __init apic_set_verbosity(char *str) printk(KERN_WARNING "APIC Verbosity level %s not recognised" " use apic=verbose or apic=debug", str); - return 0; + return 1; } __setup("apic=", apic_set_verbosity); @@ -1137,35 +1137,35 @@ int __init APIC_init_uniprocessor (void) static __init int setup_disableapic(char *str) { disable_apic = 1; - return 0; + return 1; } static __init int setup_nolapic(char *str) { disable_apic = 1; - return 0; + return 1; } static __init int setup_noapictimer(char *str) { if (str[0] != ' ' && str[0] != 0) - return -1; + return 0; disable_apic_timer = 1; - return 0; + return 1; } static __init int setup_apicmaintimer(char *str) { apic_runs_main_timer = 1; nohpet = 1; - return 0; + return 1; } __setup("apicmaintimer", setup_apicmaintimer); static __init int setup_noapicmaintimer(char *str) { apic_runs_main_timer = -1; - return 0; + return 1; } __setup("noapicmaintimer", setup_noapicmaintimer); diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index 293cd71a266a..62776c07cff1 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -80,7 +80,12 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size) return 0; } -int __init e820_mapped(unsigned long start, unsigned long end, unsigned type) +/* + * This function checks if any part of the range is mapped + * with type. + */ +int __meminit +e820_any_mapped(unsigned long start, unsigned long end, unsigned type) { int i; for (i = 0; i < e820.nr_map; i++) { @@ -94,6 +99,35 @@ int __init e820_mapped(unsigned long start, unsigned long end, unsigned type) return 0; } +/* + * This function checks if the entire range is mapped with type. + * + * Note: this function only works correct if the e820 table is sorted and + * not-overlapping, which is the case + */ +int __init e820_all_mapped(unsigned long start, unsigned long end, unsigned type) +{ + int i; + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + if (type && ei->type != type) + continue; + /* is the region (part) in overlap with the current region ?*/ + if (ei->addr >= end || ei->addr + ei->size <= start) + continue; + + /* if the region is at the beginning of we move + * start to the end of the region since it's ok until there + */ + if (ei->addr <= start) + start = ei->addr + ei->size; + /* if start is now at or beyond end, we're done, full coverage */ + if (start >= end) + return 1; /* we're done */ + } + return 0; +} + /* * Find a free area in a specific range. */ diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c index 13af920b6594..b93ef5b51980 100644 --- a/arch/x86_64/kernel/early_printk.c +++ b/arch/x86_64/kernel/early_printk.c @@ -221,7 +221,7 @@ int __init setup_early_printk(char *opt) char buf[256]; if (early_console_initialized) - return -1; + return 1; strlcpy(buf,opt,sizeof(buf)); space = strchr(buf, ' '); diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index 8538bfea30e6..c946e4fe67a7 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -180,6 +180,10 @@ rff_trace: * * XXX if we had a free scratch register we could save the RSP into the stack frame * and report it properly in ps. Unfortunately we haven't. + * + * When user can change the frames always force IRET. That is because + * it deals with uncanonical addresses better. SYSRET has trouble + * with them due to bugs in both AMD and Intel CPUs. */ ENTRY(system_call) @@ -254,7 +258,10 @@ sysret_signal: xorl %esi,%esi # oldset -> arg2 call ptregscall_common 1: movl $_TIF_NEED_RESCHED,%edi - jmp sysret_check + /* Use IRET because user could have changed frame. This + works because ptregscall_common has called FIXUP_TOP_OF_STACK. */ + cli + jmp int_with_check badsys: movq $-ENOSYS,RAX-ARGOFFSET(%rsp) @@ -280,7 +287,8 @@ tracesys: call syscall_trace_leave RESTORE_TOP_OF_STACK %rbx RESTORE_REST - jmp ret_from_sys_call + /* Use IRET because user could have changed frame */ + jmp int_ret_from_sys_call CFI_ENDPROC /* @@ -408,25 +416,9 @@ ENTRY(stub_execve) CFI_ADJUST_CFA_OFFSET -8 CFI_REGISTER rip, r11 SAVE_REST - movq %r11, %r15 - CFI_REGISTER rip, r15 FIXUP_TOP_OF_STACK %r11 call sys_execve - GET_THREAD_INFO(%rcx) - bt $TIF_IA32,threadinfo_flags(%rcx) - CFI_REMEMBER_STATE - jc exec_32bit RESTORE_TOP_OF_STACK %r11 - movq %r15, %r11 - CFI_REGISTER rip, r11 - RESTORE_REST - pushq %r11 - CFI_ADJUST_CFA_OFFSET 8 - CFI_REL_OFFSET rip, 0 - ret - -exec_32bit: - CFI_RESTORE_STATE movq %rax,RAX(%rsp) RESTORE_REST jmp int_ret_from_sys_call diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 04282ef9fbd4..6f0790e8b6d3 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -29,6 +29,8 @@ #define MISC_MCELOG_MINOR 227 #define NR_BANKS 6 +atomic_t mce_entry; + static int mce_dont_init; /* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic, @@ -172,10 +174,12 @@ void do_machine_check(struct pt_regs * regs, long error_code) int i; int panicm_found = 0; + atomic_inc(&mce_entry); + if (regs) notify_die(DIE_NMI, "machine check", regs, error_code, 18, SIGKILL); if (!banks) - return; + goto out2; memset(&m, 0, sizeof(struct mce)); m.cpu = safe_smp_processor_id(); @@ -266,6 +270,8 @@ void do_machine_check(struct pt_regs * regs, long error_code) out: /* Last thing done in the machine check exception to clear state. */ wrmsrl(MSR_IA32_MCG_STATUS, 0); + out2: + atomic_dec(&mce_entry); } /* @@ -501,7 +507,7 @@ static struct miscdevice mce_log_device = { static int __init mcheck_disable(char *str) { mce_dont_init = 1; - return 0; + return 1; } /* mce=off disables machine check. Note you can reenable it later @@ -521,7 +527,7 @@ static int __init mcheck_enable(char *str) get_option(&str, &tolerant); else printk("mce= argument %s ignored. Please use /sys", str); - return 0; + return 1; } __setup("nomce", mcheck_disable); diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index d9e4067faf05..4e6357fe0ec3 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -34,6 +34,7 @@ #include #include #include +#include /* * lapic_nmi_owner tracks the ownership of the lapic NMI hardware: @@ -480,6 +481,12 @@ void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) __get_cpu_var(nmi_touch) = 0; touched = 1; } +#ifdef CONFIG_X86_MCE + /* Could check oops_in_progress here too, but it's safer + not too */ + if (atomic_read(&mce_entry) > 0) + touched = 1; +#endif if (!touched && __get_cpu_var(last_irq_sum) == sum) { /* * Ayiee, looks like this CPU is stuck ... diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c index 03c9eeedb0f3..af035ede70cd 100644 --- a/arch/x86_64/kernel/pci-dma.c +++ b/arch/x86_64/kernel/pci-dma.c @@ -48,9 +48,11 @@ dma_alloc_pages(struct device *dev, gfp_t gfp, unsigned order) { struct page *page; int node; +#ifdef CONFIG_PCI if (dev->bus == &pci_bus_type) node = pcibus_to_node(to_pci_dev(dev)->bus); else +#endif node = numa_node_id(); page = alloc_pages_node(node, gfp, order); return page ? page_address(page) : NULL; diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c index ee5ee4891f3d..b0444a415bd6 100644 --- a/arch/x86_64/kernel/pmtimer.c +++ b/arch/x86_64/kernel/pmtimer.c @@ -121,7 +121,7 @@ unsigned int do_gettimeoffset_pm(void) static int __init nopmtimer_setup(char *s) { pmtmr_ioport = 0; - return 0; + return 1; } __setup("nopmtimer", nopmtimer_setup); diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 70dd8e5c6889..1c44b53cb15b 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -781,10 +781,16 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr) } case ARCH_GET_GS: { unsigned long base; + unsigned gsindex; if (task->thread.gsindex == GS_TLS_SEL) base = read_32bit_tls(task, GS_TLS); - else if (doit) - rdmsrl(MSR_KERNEL_GS_BASE, base); + else if (doit) { + asm("movl %%gs,%0" : "=r" (gsindex)); + if (gsindex) + rdmsrl(MSR_KERNEL_GS_BASE, base); + else + base = task->thread.gs; + } else base = task->thread.gs; ret = put_user(base, (unsigned long __user *)addr); diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index d44b2c1e63a6..da8e7903d817 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -274,11 +274,6 @@ static int putreg(struct task_struct *child, return -EIO; value &= 0xffff; break; - case offsetof(struct user_regs_struct, rip): - /* Check if the new RIP address is canonical */ - if (value >= TASK_SIZE_OF(child)) - return -EIO; - break; } put_stack_long(child, regno - sizeof(struct pt_regs), value); return 0; diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index d1f3e9272c05..c50b06765a80 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -353,8 +353,10 @@ static __init void parse_cmdline_early (char ** cmdline_p) if (fullarg(from, "enable_timer_pin_1")) disable_timer_pin_1 = -1; - if (fullarg(from, "nolapic") || fullarg(from, "disableapic")) + if (fullarg(from, "nolapic") || fullarg(from, "disableapic")) { + clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); disable_apic = 1; + } if (fullarg(from, "noapic")) skip_ioapic_setup = 1; @@ -540,7 +542,7 @@ void __init alternative_instructions(void) static int __init noreplacement_setup(char *s) { no_replacement = 1; - return 0; + return 1; } __setup("noreplacement", noreplacement_setup); diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c index eabdb63fec31..8a691fa6d393 100644 --- a/arch/x86_64/kernel/setup64.c +++ b/arch/x86_64/kernel/setup64.c @@ -55,7 +55,7 @@ int __init nonx_setup(char *str) do_not_nx = 1; __supported_pte_mask &= ~_PAGE_NX; } - return 0; + return 1; } __setup("noexec=", nonx_setup); /* parsed early actually */ @@ -74,7 +74,7 @@ static int __init nonx32_setup(char *str) force_personality32 &= ~READ_IMPLIES_EXEC; else if (!strcmp(str, "off")) force_personality32 |= READ_IMPLIES_EXEC; - return 0; + return 1; } __setup("noexec32=", nonx32_setup); diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c index ea48fa638070..71a7222cf9ce 100644 --- a/arch/x86_64/kernel/smpboot.c +++ b/arch/x86_64/kernel/smpboot.c @@ -353,7 +353,7 @@ static void __cpuinit tsc_sync_wait(void) static __init int notscsync_setup(char *s) { notscsync = 1; - return 0; + return 1; } __setup("notscsync", notscsync_setup); diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 473b514b66e4..7392570f975d 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -726,7 +726,7 @@ static __init int late_hpet_init(void) unsigned int ntimer; if (!vxtime.hpet_address) - return -1; + return 0; memset(&hd, 0, sizeof (hd)); @@ -917,6 +917,8 @@ void __init time_init(void) vxtime.hpet_address = 0; if (hpet_use_timer) { + /* set tick_nsec to use the proper rate for HPET */ + tick_nsec = TICK_NSEC_HPET; cpu_khz = hpet_calibrate_tsc(); timename = "HPET"; #ifdef CONFIG_X86_PM_TIMER @@ -1306,7 +1308,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) static int __init nohpet_setup(char *s) { nohpet = 1; - return 0; + return 1; } __setup("nohpet", nohpet_setup); @@ -1314,7 +1316,7 @@ __setup("nohpet", nohpet_setup); int __init notsc_setup(char *s) { notsc = 1; - return 0; + return 1; } __setup("notsc", notsc_setup); diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index edaa9fe654dc..2700b1375c1f 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -433,6 +434,8 @@ void __kprobes __die(const char * str, struct pt_regs * regs, long err) printk(KERN_ALERT "RIP "); printk_address(regs->rip); printk(" RSP <%016lx>\n", regs->rsp); + if (kexec_should_crash(current)) + crash_kexec(regs); } void die(const char * str, struct pt_regs * regs, long err) @@ -455,6 +458,8 @@ void __kprobes die_nmi(char *str, struct pt_regs *regs) */ printk(str, safe_smp_processor_id()); show_registers(regs); + if (kexec_should_crash(current)) + crash_kexec(regs); if (panic_on_timeout || panic_on_oops) panic("nmi watchdog"); printk("console shuts up ...\n"); @@ -973,14 +978,14 @@ void __init trap_init(void) static int __init oops_dummy(char *s) { panic_on_oops = 1; - return -1; + return 1; } __setup("oops=", oops_dummy); static int __init kstack_setup(char *s) { kstack_depth_to_print = simple_strtoul(s,NULL,0); - return 0; + return 1; } __setup("kstack=", kstack_setup); diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S index 39ff0708f803..b81f473c4a19 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -65,7 +65,7 @@ SECTIONS .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { *(.data.cacheline_aligned) } - . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES); .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) } diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c index d96a9348e5a2..1def21c9f7cd 100644 --- a/arch/x86_64/kernel/x8664_ksyms.c +++ b/arch/x86_64/kernel/x8664_ksyms.c @@ -102,8 +102,6 @@ EXPORT_SYMBOL(cpu_callout_map); EXPORT_SYMBOL(screen_info); #endif -EXPORT_SYMBOL(get_wchan); - EXPORT_SYMBOL(rtc_lock); EXPORT_SYMBOL_GPL(set_nmi_callback); @@ -114,7 +112,6 @@ EXPORT_SYMBOL_GPL(unset_nmi_callback); #undef memcpy #undef memset #undef memmove -#undef strlen extern void * memset(void *,int,__kernel_size_t); extern size_t strlen(const char *); @@ -123,8 +120,6 @@ extern void * memcpy(void *,const void *,__kernel_size_t); extern void * __memcpy(void *,const void *,__kernel_size_t); EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(__memcpy); diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c index 316c53de47bd..55250593d8c9 100644 --- a/arch/x86_64/mm/fault.c +++ b/arch/x86_64/mm/fault.c @@ -623,6 +623,6 @@ void vmalloc_sync_all(void) static int __init enable_pagefaulttrace(char *str) { page_fault_trace = 1; - return 0; + return 1; } __setup("pagefaulttrace", enable_pagefaulttrace); diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c index e5f7f1c34462..4ba34e95d835 100644 --- a/arch/x86_64/mm/init.c +++ b/arch/x86_64/mm/init.c @@ -305,7 +305,7 @@ static void __meminit phys_pud_init(pud_t *pud, unsigned long address, unsigned if (paddr >= end) break; - if (!after_bootmem && !e820_mapped(paddr, paddr+PUD_SIZE, 0)) { + if (!after_bootmem && !e820_any_mapped(paddr, paddr+PUD_SIZE, 0)) { set_pud(pud, __pud(0)); continue; } @@ -507,9 +507,8 @@ void __init clear_kernel_mapping(unsigned long address, unsigned long size) /* * Memory hotplug specific functions - * These are only for non-NUMA machines right now. */ -#ifdef CONFIG_MEMORY_HOTPLUG +#if defined(CONFIG_ACPI_HOTPLUG_MEMORY) || defined(CONFIG_ACPI_HOTPLUG_MEMORY_MODULE) void online_page(struct page *page) { @@ -520,6 +519,38 @@ void online_page(struct page *page) num_physpages++; } +#ifndef CONFIG_MEMORY_HOTPLUG +/* + * Memory Hotadd without sparsemem. The mem_maps have been allocated in advance, + * just online the pages. + */ +int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages) +{ + int err = -EIO; + unsigned long pfn; + unsigned long total = 0, mem = 0; + for (pfn = start_pfn; pfn < start_pfn + nr_pages; pfn++) { + if (pfn_valid(pfn)) { + online_page(pfn_to_page(pfn)); + err = 0; + mem++; + } + total++; + } + if (!err) { + z->spanned_pages += total; + z->present_pages += mem; + z->zone_pgdat->node_spanned_pages += total; + z->zone_pgdat->node_present_pages += mem; + } + return err; +} +#endif + +/* + * Memory is added always to NORMAL zone. This means you will never get + * additional DMA/DMA32 memory. + */ int add_memory(u64 start, u64 size) { struct pglist_data *pgdat = NODE_DATA(0); diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c index 4be82d6e2b48..cc02573a3271 100644 --- a/arch/x86_64/mm/numa.c +++ b/arch/x86_64/mm/numa.c @@ -100,11 +100,30 @@ int early_pfn_to_nid(unsigned long pfn) } #endif +static void * __init +early_node_mem(int nodeid, unsigned long start, unsigned long end, + unsigned long size) +{ + unsigned long mem = find_e820_area(start, end, size); + void *ptr; + if (mem != -1L) + return __va(mem); + ptr = __alloc_bootmem_nopanic(size, + SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS)); + if (ptr == 0) { + printk(KERN_ERR "Cannot find %lu bytes in node %d\n", + size, nodeid); + return NULL; + } + return ptr; +} + /* Initialize bootmem allocator for a node */ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long end) { unsigned long start_pfn, end_pfn, bootmap_pages, bootmap_size, bootmap_start; unsigned long nodedata_phys; + void *bootmap; const int pgdat_size = round_up(sizeof(pg_data_t), PAGE_SIZE); start = round_up(start, ZONE_ALIGN); @@ -114,13 +133,11 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en start_pfn = start >> PAGE_SHIFT; end_pfn = end >> PAGE_SHIFT; - nodedata_phys = find_e820_area(start, end, pgdat_size); - if (nodedata_phys == -1L) - panic("Cannot find memory pgdat in node %d\n", nodeid); + node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size); + if (node_data[nodeid] == NULL) + return; + nodedata_phys = __pa(node_data[nodeid]); - Dprintk("nodedata_phys %lx\n", nodedata_phys); - - node_data[nodeid] = phys_to_virt(nodedata_phys); memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t)); NODE_DATA(nodeid)->bdata = &plat_node_bdata[nodeid]; NODE_DATA(nodeid)->node_start_pfn = start_pfn; @@ -129,9 +146,15 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en /* Find a place for the bootmem map */ bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); bootmap_start = round_up(nodedata_phys + pgdat_size, PAGE_SIZE); - bootmap_start = find_e820_area(bootmap_start, end, bootmap_pages<= end) + free_bootmem((unsigned long)node_data[nodeid],pgdat_size); + node_data[nodeid] = NULL; + return; + } + bootmap_start = __pa(bootmap); Dprintk("bootmap start %lu pages %lu\n", bootmap_start, bootmap_pages); bootmap_size = init_bootmem_node(NODE_DATA(nodeid), @@ -142,6 +165,9 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size); reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start, bootmap_pages<> PAGE_SHIFT; + unsigned long e_pfn = end >> PAGE_SHIFT; + int changed = 0; + struct bootnode *nd = &nodes_add[node]; + + /* I had some trouble with strange memory hotadd regions breaking + the boot. Be very strict here and reject anything unexpected. + If you want working memory hotadd write correct SRATs. + + The node size check is a basic sanity check to guard against + mistakes */ + if ((signed long)(end - start) < NODE_MIN_SIZE) { + printk(KERN_ERR "SRAT: Hotplug area too small\n"); + return -1; + } + + /* This check might be a bit too strict, but I'm keeping it for now. */ + if (e820_hole_size(s_pfn, e_pfn) != e_pfn - s_pfn) { + printk(KERN_ERR "SRAT: Hotplug area has existing memory\n"); + return -1; + } + + if (!hotadd_enough_memory(&nodes_add[node])) { + printk(KERN_ERR "SRAT: Hotplug area too large\n"); + return -1; + } + + /* Looks good */ + + found_add_area = 1; + if (nd->start == nd->end) { + nd->start = start; + nd->end = end; + changed = 1; + } else { + if (nd->start == end) { + nd->start = start; + changed = 1; + } + if (nd->end == start) { + nd->end = end; + changed = 1; + } + if (!changed) + printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n"); + } + + if ((nd->end >> PAGE_SHIFT) > end_pfn) + end_pfn = nd->end >> PAGE_SHIFT; + + if (changed) + printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", nd->start, nd->end); + return 0; +} +#endif + /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */ void __init acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) { - struct bootnode *nd; + struct bootnode *nd, oldnode; unsigned long start, end; int node, pxm; int i; @@ -172,6 +292,8 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) } if (ma->flags.enabled == 0) return; + if (ma->flags.hot_pluggable && hotadd_percent == 0) + return; start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32); end = start + (ma->length_lo | ((u64)ma->length_hi << 32)); pxm = ma->proximity_domain; @@ -181,10 +303,6 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) bad_srat(); return; } - /* It is fine to add this area to the nodes data it will be used later*/ - if (ma->flags.hot_pluggable == 1) - printk(KERN_INFO "SRAT: hot plug zone found %lx - %lx \n", - start, end); i = conflicting_nodes(start, end); if (i == node) { printk(KERN_WARNING @@ -199,6 +317,7 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) return; } nd = &nodes[node]; + oldnode = *nd; if (!node_test_and_set(node, nodes_parsed)) { nd->start = start; nd->end = end; @@ -208,8 +327,19 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma) if (nd->end < end) nd->end = end; } + printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm, nd->start, nd->end); + +#ifdef RESERVE_HOTADD + if (ma->flags.hot_pluggable && reserve_hotadd(node, start, end) < 0) { + /* Ignore hotadd region. Undo damage */ + printk(KERN_NOTICE "SRAT: Hotplug region ignored\n"); + *nd = oldnode; + if ((nd->start | nd->end) == 0) + node_clear(node, nodes_parsed); + } +#endif } /* Sanity check to catch more bad SRATs (they are amazingly common). @@ -225,6 +355,9 @@ static int nodes_cover_memory(void) unsigned long e = nodes[i].end >> PAGE_SHIFT; pxmram += e - s; pxmram -= e820_hole_size(s, e); + pxmram -= nodes_add[i].end - nodes_add[i].start; + if ((long)pxmram < 0) + pxmram = 0; } e820ram = end_pfn - e820_hole_size(0, end_pfn); @@ -258,7 +391,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) /* First clean up the node list */ for (i = 0; i < MAX_NUMNODES; i++) { - cutoff_node(i, start, end); + cutoff_node(i, start, end); if ((nodes[i].end - nodes[i].start) < NODE_MIN_SIZE) unparse_node(i); } @@ -282,6 +415,12 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end) /* Finally register nodes */ for_each_node_mask(i, nodes_parsed) setup_node_bootmem(i, nodes[i].start, nodes[i].end); + /* Try again in case setup_node_bootmem missed one due + to missing bootmem */ + for_each_node_mask(i, nodes_parsed) + if (!node_online(i)) + setup_node_bootmem(i, nodes[i].start, nodes[i].end); + for (i = 0; i < NR_CPUS; i++) { if (cpu_to_node[i] == NUMA_NO_NODE) continue; @@ -303,6 +442,25 @@ static int node_to_pxm(int n) return 0; } +void __init srat_reserve_add_area(int nodeid) +{ + if (found_add_area && nodes_add[nodeid].end) { + u64 total_mb; + + printk(KERN_INFO "SRAT: Reserving hot-add memory space " + "for node %d at %Lx-%Lx\n", + nodeid, nodes_add[nodeid].start, nodes_add[nodeid].end); + total_mb = (nodes_add[nodeid].end - nodes_add[nodeid].start) + >> PAGE_SHIFT; + total_mb *= sizeof(struct page); + total_mb >>= 20; + printk(KERN_INFO "SRAT: This will cost you %Lu MB of " + "pre-allocated memory.\n", (unsigned long long)total_mb); + reserve_bootmem_node(NODE_DATA(nodeid), nodes_add[nodeid].start, + nodes_add[nodeid].end - nodes_add[nodeid].start); + } +} + int __node_distance(int a, int b) { int index; diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c index e616500207e4..a2060e4d5de6 100644 --- a/arch/x86_64/pci/mmconfig.c +++ b/arch/x86_64/pci/mmconfig.c @@ -9,11 +9,16 @@ #include #include #include +#include + #include "pci.h" #define MMCONFIG_APER_SIZE (256*1024*1024) +/* Verify the first 16 busses. We assume that systems with more busses + get MCFG right. */ +#define MAX_CHECK_BUS 16 -static DECLARE_BITMAP(fallback_slots, 32); +static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS); /* Static virtual mapping of the MMCONFIG aperture */ struct mmcfg_virt { @@ -55,7 +60,8 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus) static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) { char __iomem *addr; - if (seg == 0 && bus == 0 && test_bit(PCI_SLOT(devfn), fallback_slots)) + if (seg == 0 && bus < MAX_CHECK_BUS && + test_bit(32*bus + PCI_SLOT(devfn), fallback_slots)) return NULL; addr = get_virt(seg, bus); if (!addr) @@ -69,8 +75,10 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, char __iomem *addr; /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ - if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) + if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) { + *value = -1; return -EINVAL; + } addr = pci_dev_base(seg, bus, devfn); if (!addr) @@ -129,21 +137,26 @@ static struct pci_raw_ops pci_mmcfg = { Normally this can be expressed in the MCFG by not listing them and assigning suitable _SEGs, but this isn't implemented in some BIOS. Instead try to discover all devices on bus 0 that are unreachable using MM - and fallback for them. - We only do this for bus 0/seg 0 */ + and fallback for them. */ static __init void unreachable_devices(void) { - int i; - for (i = 0; i < 32; i++) { - u32 val1; - char __iomem *addr; + int i, k; + /* Use the max bus number from ACPI here? */ + for (k = 0; k < MAX_CHECK_BUS; k++) { + for (i = 0; i < 32; i++) { + u32 val1; + char __iomem *addr; - pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1); - if (val1 == 0xffffffff) - continue; - addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0)); - if (addr == NULL|| readl(addr) != val1) { - set_bit(i, fallback_slots); + pci_conf1_read(0, k, PCI_DEVFN(i,0), 0, 4, &val1); + if (val1 == 0xffffffff) + continue; + addr = pci_dev_base(0, k, PCI_DEVFN(i, 0)); + if (addr == NULL|| readl(addr) != val1) { + set_bit(i + 32*k, fallback_slots); + printk(KERN_NOTICE + "PCI: No mmconfig possible on device %x:%x\n", + k, i); + } } } } @@ -161,6 +174,14 @@ void __init pci_mmcfg_init(void) (pci_mmcfg_config[0].base_address == 0)) return; + if (!e820_all_mapped(pci_mmcfg_config[0].base_address, + pci_mmcfg_config[0].base_address + MMCONFIG_APER_SIZE, + E820_RESERVED)) { + printk(KERN_ERR "PCI: BIOS Bug: MCFG area is not E820-reserved\n"); + printk(KERN_ERR "PCI: Not using MMCONFIG.\n"); + return; + } + /* RED-PEN i386 doesn't do _nocache right now */ pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL); if (pci_mmcfg_virt == NULL) { diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index efae56a51475..a15b6e3e72c8 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -48,7 +48,6 @@ EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strrchr); @@ -113,8 +112,6 @@ EXPORT_SYMBOL(__xtensa_copy_user); // FIXME EXPORT_SYMBOL(screen_info); #endif -EXPORT_SYMBOL(get_wchan); - EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(outsw); EXPORT_SYMBOL(outsl); diff --git a/block/Kconfig b/block/Kconfig index 5536839886ff..b6f5f0a79655 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -27,10 +27,10 @@ config BLK_DEV_IO_TRACE config LSF bool "Support for Large Single Files" depends on X86 || (MIPS && 32BIT) || PPC32 || ARCH_S390_31 || SUPERH || UML - default n help - When CONFIG_LBD is disabled, say Y here if you want to - handle large file(bigger than 2TB), otherwise say N. - When CONFIG_LBD is enabled, Y is set automatically. + Say Y here if you want to be able to handle very large files (bigger + than 2TB), otherwise say N. + + If unsure, say Y. source block/Kconfig.iosched diff --git a/block/as-iosched.c b/block/as-iosched.c index 296708ceceb2..e25a5d79ab27 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -1844,9 +1844,10 @@ static void __exit as_exit(void) DECLARE_COMPLETION(all_gone); elv_unregister(&iosched_as); ioc_gone = &all_gone; - barrier(); + /* ioc_gone's update must be visible before reading ioc_count */ + smp_wmb(); if (atomic_read(&ioc_count)) - complete(ioc_gone); + wait_for_completion(ioc_gone); synchronize_rcu(); kmem_cache_destroy(arq_pool); } diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 67d446de0227..2540dfaa3e38 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1472,19 +1472,37 @@ out: return cfqq; } +static void +cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic) +{ + read_lock(&cfq_exit_lock); + rb_erase(&cic->rb_node, &ioc->cic_root); + read_unlock(&cfq_exit_lock); + kmem_cache_free(cfq_ioc_pool, cic); + atomic_dec(&ioc_count); +} + static struct cfq_io_context * cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc) { - struct rb_node *n = ioc->cic_root.rb_node; + struct rb_node *n; struct cfq_io_context *cic; - void *key = cfqd; + void *k, *key = cfqd; +restart: + n = ioc->cic_root.rb_node; while (n) { cic = rb_entry(n, struct cfq_io_context, rb_node); + /* ->key must be copied to avoid race with cfq_exit_queue() */ + k = cic->key; + if (unlikely(!k)) { + cfq_drop_dead_cic(ioc, cic); + goto restart; + } - if (key < cic->key) + if (key < k) n = n->rb_left; - else if (key > cic->key) + else if (key > k) n = n->rb_right; else return cic; @@ -1497,29 +1515,37 @@ static inline void cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc, struct cfq_io_context *cic) { - struct rb_node **p = &ioc->cic_root.rb_node; - struct rb_node *parent = NULL; + struct rb_node **p; + struct rb_node *parent; struct cfq_io_context *__cic; - - read_lock(&cfq_exit_lock); + void *k; cic->ioc = ioc; cic->key = cfqd; ioc->set_ioprio = cfq_ioc_set_ioprio; - +restart: + parent = NULL; + p = &ioc->cic_root.rb_node; while (*p) { parent = *p; __cic = rb_entry(parent, struct cfq_io_context, rb_node); + /* ->key must be copied to avoid race with cfq_exit_queue() */ + k = __cic->key; + if (unlikely(!k)) { + cfq_drop_dead_cic(ioc, cic); + goto restart; + } - if (cic->key < __cic->key) + if (cic->key < k) p = &(*p)->rb_left; - else if (cic->key > __cic->key) + else if (cic->key > k) p = &(*p)->rb_right; else BUG(); } + read_lock(&cfq_exit_lock); rb_link_node(&cic->rb_node, parent, p); rb_insert_color(&cic->rb_node, &ioc->cic_root); list_add(&cic->queue_list, &cfqd->cic_list); @@ -2439,9 +2465,10 @@ static void __exit cfq_exit(void) DECLARE_COMPLETION(all_gone); elv_unregister(&iosched_cfq); ioc_gone = &all_gone; - barrier(); + /* ioc_gone's update must be visible before reading ioc_count */ + smp_wmb(); if (atomic_read(&ioc_count)) - complete(ioc_gone); + wait_for_completion(ioc_gone); synchronize_rcu(); cfq_slab_kill(); } diff --git a/block/elevator.c b/block/elevator.c index 56c2ed06a9e2..0d6be03d929e 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -145,7 +145,7 @@ static int __init elevator_setup(char *str) strcpy(chosen_elevator, "anticipatory"); else strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1); - return 0; + return 1; } __setup("elevator=", elevator_setup); diff --git a/block/genhd.c b/block/genhd.c index db4c60c802d6..5a8d3bf02f17 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -17,8 +17,6 @@ #include #include -#define MAX_PROBE_HASH 255 /* random */ - static struct subsystem block_subsys; static DEFINE_MUTEX(block_subsys_lock); @@ -31,108 +29,29 @@ static struct blk_major_name { struct blk_major_name *next; int major; char name[16]; -} *major_names[MAX_PROBE_HASH]; +} *major_names[BLKDEV_MAJOR_HASH_SIZE]; /* index in the above - for now: assume no multimajor ranges */ static inline int major_to_index(int major) { - return major % MAX_PROBE_HASH; + return major % BLKDEV_MAJOR_HASH_SIZE; } -struct blkdev_info { - int index; - struct blk_major_name *bd; -}; +#ifdef CONFIG_PROC_FS -/* - * iterate over a list of blkdev_info structures. allows - * the major_names array to be iterated over from outside this file - * must be called with the block_subsys_lock held - */ -void *get_next_blkdev(void *dev) +void blkdev_show(struct seq_file *f, off_t offset) { - struct blkdev_info *info; + struct blk_major_name *dp; - if (dev == NULL) { - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) - goto out; - info->index=0; - info->bd = major_names[info->index]; - if (info->bd) - goto out; - } else { - info = dev; - } - - while (info->index < ARRAY_SIZE(major_names)) { - if (info->bd) - info->bd = info->bd->next; - if (info->bd) - goto out; - /* - * No devices on this chain, move to the next - */ - info->index++; - info->bd = (info->index < ARRAY_SIZE(major_names)) ? - major_names[info->index] : NULL; - if (info->bd) - goto out; - } - -out: - return info; -} - -void *acquire_blkdev_list(void) -{ - mutex_lock(&block_subsys_lock); - return get_next_blkdev(NULL); -} - -void release_blkdev_list(void *dev) -{ - mutex_unlock(&block_subsys_lock); - kfree(dev); -} - - -/* - * Count the number of records in the blkdev_list. - * must be called with the block_subsys_lock held - */ -int count_blkdev_list(void) -{ - struct blk_major_name *n; - int i, count; - - count = 0; - - for (i = 0; i < ARRAY_SIZE(major_names); i++) { - for (n = major_names[i]; n; n = n->next) - count++; + if (offset < BLKDEV_MAJOR_HASH_SIZE) { + mutex_lock(&block_subsys_lock); + for (dp = major_names[offset]; dp; dp = dp->next) + seq_printf(f, "%3d %s\n", dp->major, dp->name); + mutex_unlock(&block_subsys_lock); } - - return count; -} - -/* - * extract the major and name values from a blkdev_info struct - * passed in as a void to *dev. Must be called with - * block_subsys_lock held - */ -int get_blkdev_info(void *dev, int *major, char **name) -{ - struct blkdev_info *info = dev; - - if (info->bd == NULL) - return 1; - - *major = info->bd->major; - *name = info->bd->name; - return 0; } +#endif /* CONFIG_PROC_FS */ int register_blkdev(unsigned int major, const char *name) { diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 5b26af8597f3..e112d1a5dab6 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1740,7 +1740,7 @@ EXPORT_SYMBOL(blk_run_queue); /** * blk_cleanup_queue: - release a &request_queue_t when it is no longer needed - * @q: the request queue to be released + * @kobj: the kobj belonging of the request queue to be released * * Description: * blk_cleanup_queue is the pair to blk_init_queue() or diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 24f7af9d0abc..b33eda26e205 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -350,16 +350,51 @@ out: return ret; } +/** + * sg_scsi_ioctl -- handle deprecated SCSI_IOCTL_SEND_COMMAND ioctl + * @file: file this ioctl operates on (optional) + * @q: request queue to send scsi commands down + * @disk: gendisk to operate on (option) + * @sic: userspace structure describing the command to perform + * + * Send down the scsi command described by @sic to the device below + * the request queue @q. If @file is non-NULL it's used to perform + * fine-grained permission checks that allow users to send down + * non-destructive SCSI commands. If the caller has a struct gendisk + * available it should be passed in as @disk to allow the low level + * driver to use the information contained in it. A non-NULL @disk + * is only allowed if the caller knows that the low level driver doesn't + * need it (e.g. in the scsi subsystem). + * + * Notes: + * - This interface is deprecated - users should use the SG_IO + * interface instead, as this is a more flexible approach to + * performing SCSI commands on a device. + * - The SCSI command length is determined by examining the 1st byte + * of the given command. There is no way to override this. + * - Data transfers are limited to PAGE_SIZE + * - The length (x + y) must be at least OMAX_SB_LEN bytes long to + * accommodate the sense buffer when an error occurs. + * The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that + * old code will not be surprised. + * - If a Unix error occurs (e.g. ENOMEM) then the user will receive + * a negative return and the Unix error code in 'errno'. + * If the SCSI command succeeds then 0 is returned. + * Positive numbers returned are the compacted SCSI error codes (4 + * bytes in one int) where the lowest byte is the SCSI status. + */ #define OMAX_SB_LEN 16 /* For backward compatibility */ - -static int sg_scsi_ioctl(struct file *file, request_queue_t *q, - struct gendisk *bd_disk, Scsi_Ioctl_Command __user *sic) +int sg_scsi_ioctl(struct file *file, struct request_queue *q, + struct gendisk *disk, struct scsi_ioctl_command __user *sic) { struct request *rq; int err; unsigned int in_len, out_len, bytes, opcode, cmdlen; char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE]; + if (!sic) + return -EINVAL; + /* * get in an out lengths, verify they don't exceed a page worth of data */ @@ -393,45 +428,53 @@ static int sg_scsi_ioctl(struct file *file, request_queue_t *q, if (copy_from_user(rq->cmd, sic->data, cmdlen)) goto error; - if (copy_from_user(buffer, sic->data + cmdlen, in_len)) + if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) goto error; err = verify_command(file, rq->cmd); if (err) goto error; + /* default. possible overriden later */ + rq->retries = 5; + switch (opcode) { - case SEND_DIAGNOSTIC: - case FORMAT_UNIT: - rq->timeout = FORMAT_UNIT_TIMEOUT; - break; - case START_STOP: - rq->timeout = START_STOP_TIMEOUT; - break; - case MOVE_MEDIUM: - rq->timeout = MOVE_MEDIUM_TIMEOUT; - break; - case READ_ELEMENT_STATUS: - rq->timeout = READ_ELEMENT_STATUS_TIMEOUT; - break; - case READ_DEFECT_DATA: - rq->timeout = READ_DEFECT_DATA_TIMEOUT; - break; - default: - rq->timeout = BLK_DEFAULT_TIMEOUT; - break; + case SEND_DIAGNOSTIC: + case FORMAT_UNIT: + rq->timeout = FORMAT_UNIT_TIMEOUT; + rq->retries = 1; + break; + case START_STOP: + rq->timeout = START_STOP_TIMEOUT; + break; + case MOVE_MEDIUM: + rq->timeout = MOVE_MEDIUM_TIMEOUT; + break; + case READ_ELEMENT_STATUS: + rq->timeout = READ_ELEMENT_STATUS_TIMEOUT; + break; + case READ_DEFECT_DATA: + rq->timeout = READ_DEFECT_DATA_TIMEOUT; + rq->retries = 1; + break; + default: + rq->timeout = BLK_DEFAULT_TIMEOUT; + break; + } + + if (bytes && blk_rq_map_kern(q, rq, buffer, bytes, __GFP_WAIT)) { + err = DRIVER_ERROR << 24; + goto out; } memset(sense, 0, sizeof(sense)); rq->sense = sense; rq->sense_len = 0; - - rq->data = buffer; - rq->data_len = bytes; rq->flags |= REQ_BLOCK_PC; - rq->retries = 0; - blk_execute_rq(q, bd_disk, rq, 0); + blk_execute_rq(q, disk, rq, 0); + +out: err = rq->errors & 0xff; /* only 8 bit SCSI status */ if (err) { if (rq->sense_len && rq->sense) { @@ -450,7 +493,7 @@ error: blk_put_request(rq); return err; } - +EXPORT_SYMBOL_GPL(sg_scsi_ioctl); /* Send basic block requests */ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int cmd, int data) diff --git a/drivers/Kconfig b/drivers/Kconfig index 9f5c0da57c90..5c91d6afb117 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -64,6 +64,8 @@ source "drivers/usb/Kconfig" source "drivers/mmc/Kconfig" +source "drivers/leds/Kconfig" + source "drivers/infiniband/Kconfig" source "drivers/sn/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 424955274e60..447d8e68887a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -25,9 +25,6 @@ obj-$(CONFIG_CONNECTOR) += connector/ obj-$(CONFIG_FB_I810) += video/i810/ obj-$(CONFIG_FB_INTEL) += video/intelfb/ -# we also need input/serio early so serio bus is initialized by the time -# serial drivers start registering their serio ports -obj-$(CONFIG_SERIO) += input/serio/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ mfd/ net/ media/ @@ -53,6 +50,7 @@ obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_PCI) += usb/ obj-$(CONFIG_USB_GADGET) += usb/gadget/ +obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_I2O) += message/ @@ -69,7 +67,9 @@ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_MMC) += mmc/ +obj-$(CONFIG_NEW_LEDS) += leds/ obj-$(CONFIG_INFINIBAND) += infiniband/ +obj-$(CONFIG_IPATH_CORE) += infiniband/ obj-$(CONFIG_SGI_SN) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 5cb96300eb0f..c24652d31bf9 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -329,7 +329,7 @@ config ACPI_CONTAINER config ACPI_HOTPLUG_MEMORY tristate "Memory Hotplug" depends on ACPI - depends on MEMORY_HOTPLUG + depends on MEMORY_HOTPLUG || X86_64 default n help This driver adds supports for ACPI Memory Hotplug. This driver diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 79b09d76c180..eee0864ba300 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1572,7 +1572,7 @@ static void __exit acpi_ec_exit(void) static int __init acpi_fake_ecdt_setup(char *str) { acpi_fake_ecdt_enabled = 1; - return 0; + return 1; } __setup("acpi_fake_ecdt", acpi_fake_ecdt_setup); @@ -1591,7 +1591,7 @@ static int __init acpi_ec_set_intr_mode(char *str) acpi_ec_driver.ops.add = acpi_ec_poll_add; } printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling"); - return 0; + return 1; } __setup("ec_intr=", acpi_ec_set_intr_mode); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 48718b7f4fa0..76656acd00d4 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -188,6 +188,11 @@ static ssize_t driver_bind(struct device_driver *drv, up(&dev->sem); if (dev->parent) up(&dev->parent->sem); + + if (err > 0) /* success */ + err = count; + else if (err == 0) /* driver didn't accept device */ + err = -ENODEV; } put_device(dev); put_bus(bus); diff --git a/drivers/base/class.c b/drivers/base/class.c index df7fdabd0730..0e71dff327cd 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -562,14 +562,13 @@ int class_device_add(struct class_device *class_dev) kobject_uevent(&class_dev->kobj, KOBJ_ADD); /* notify any interfaces this device is now here */ - if (parent_class) { - down(&parent_class->sem); - list_add_tail(&class_dev->node, &parent_class->children); - list_for_each_entry(class_intf, &parent_class->interfaces, node) - if (class_intf->add) - class_intf->add(class_dev, class_intf); - up(&parent_class->sem); + down(&parent_class->sem); + list_add_tail(&class_dev->node, &parent_class->children); + list_for_each_entry(class_intf, &parent_class->interfaces, node) { + if (class_intf->add) + class_intf->add(class_dev, class_intf); } + up(&parent_class->sem); register_done: if (error) { diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 730a9ce0a14a..889c71111239 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -209,7 +209,7 @@ static void __device_release_driver(struct device * dev) sysfs_remove_link(&dev->kobj, "driver"); klist_remove(&dev->knode_driver); - if (dev->bus->remove) + if (dev->bus && dev->bus->remove) dev->bus->remove(dev); else if (drv->remove) drv->remove(dev); diff --git a/drivers/base/node.c b/drivers/base/node.c index 16c513aa4d48..c80c3aeed004 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -106,7 +106,7 @@ static ssize_t node_read_numastat(struct sys_device * dev, char * buf) other_node = 0; for (i = 0; i < MAX_NR_ZONES; i++) { struct zone *z = &pg->node_zones[i]; - for (cpu = 0; cpu < NR_CPUS; cpu++) { + for_each_online_cpu(cpu) { struct per_cpu_pageset *ps = zone_pcp(z,cpu); numa_hit += ps->numa_hit; numa_miss += ps->numa_miss; diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c index bdb60663f2ef..662209d3f42d 100644 --- a/drivers/base/power/suspend.c +++ b/drivers/base/power/suspend.c @@ -10,6 +10,8 @@ #include #include +#include +#include #include "../base.h" #include "power.h" @@ -58,6 +60,7 @@ int suspend_device(struct device * dev, pm_message_t state) if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) { dev_dbg(dev, "suspending\n"); error = dev->bus->suspend(dev, state); + suspend_report_result(dev->bus->suspend, error); } up(&dev->sem); return error; @@ -169,3 +172,12 @@ int device_power_down(pm_message_t state) EXPORT_SYMBOL_GPL(device_power_down); +void __suspend_report_result(const char *function, void *fn, int ret) +{ + if (ret) { + printk(KERN_ERR "%s(): ", function); + print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); + printk("%d\n", ret); + } +} +EXPORT_SYMBOL_GPL(__suspend_report_result); diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index b6e290956214..2a8af685926f 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1850,6 +1850,7 @@ static int __init amiga_floppy_setup (char *str) return 0; printk (KERN_INFO "amiflop: Setting default df0 to %x\n", n); fd_def_df0 = n; + return 1; } __setup("floppy=", amiga_floppy_setup); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 1b0fd31c57c3..1319d8f20640 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1180,6 +1180,53 @@ static int revalidate_allvol(ctlr_info_t *host) return 0; } +static inline void complete_buffers(struct bio *bio, int status) +{ + while (bio) { + struct bio *xbh = bio->bi_next; + int nr_sectors = bio_sectors(bio); + + bio->bi_next = NULL; + blk_finished_io(len); + bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); + bio = xbh; + } + +} + +static void cciss_softirq_done(struct request *rq) +{ + CommandList_struct *cmd = rq->completion_data; + ctlr_info_t *h = hba[cmd->ctlr]; + unsigned long flags; + u64bit temp64; + int i, ddir; + + if (cmd->Request.Type.Direction == XFER_READ) + ddir = PCI_DMA_FROMDEVICE; + else + ddir = PCI_DMA_TODEVICE; + + /* command did not need to be retried */ + /* unmap the DMA mapping for all the scatter gather elements */ + for(i=0; iHeader.SGList; i++) { + temp64.val32.lower = cmd->SG[i].Addr.lower; + temp64.val32.upper = cmd->SG[i].Addr.upper; + pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); + } + + complete_buffers(rq->bio, rq->errors); + +#ifdef CCISS_DEBUG + printk("Done with %p\n", rq); +#endif /* CCISS_DEBUG */ + + spin_lock_irqsave(&h->lock, flags); + end_that_request_last(rq, rq->errors); + cmd_free(h, cmd,1); + spin_unlock_irqrestore(&h->lock, flags); +} + /* This function will check the usage_count of the drive to be updated/added. * If the usage_count is zero then the drive information will be updated and * the disk will be re-registered with the kernel. If not then it will be @@ -1248,6 +1295,8 @@ static void cciss_update_drive_info(int ctlr, int drv_index) blk_queue_max_sectors(disk->queue, 512); + blk_queue_softirq_done(disk->queue, cciss_softirq_done); + disk->queue->queuedata = hba[ctlr]; blk_queue_hardsect_size(disk->queue, @@ -2147,20 +2196,6 @@ static void start_io( ctlr_info_t *h) addQ (&(h->cmpQ), c); } } - -static inline void complete_buffers(struct bio *bio, int status) -{ - while (bio) { - struct bio *xbh = bio->bi_next; - int nr_sectors = bio_sectors(bio); - - bio->bi_next = NULL; - blk_finished_io(len); - bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO); - bio = xbh; - } - -} /* Assumes that CCISS_LOCK(h->ctlr) is held. */ /* Zeros out the error record and then resends the command back */ /* to the controller */ @@ -2178,39 +2213,6 @@ static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c) start_io(h); } -static void cciss_softirq_done(struct request *rq) -{ - CommandList_struct *cmd = rq->completion_data; - ctlr_info_t *h = hba[cmd->ctlr]; - unsigned long flags; - u64bit temp64; - int i, ddir; - - if (cmd->Request.Type.Direction == XFER_READ) - ddir = PCI_DMA_FROMDEVICE; - else - ddir = PCI_DMA_TODEVICE; - - /* command did not need to be retried */ - /* unmap the DMA mapping for all the scatter gather elements */ - for(i=0; iHeader.SGList; i++) { - temp64.val32.lower = cmd->SG[i].Addr.lower; - temp64.val32.upper = cmd->SG[i].Addr.upper; - pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); - } - - complete_buffers(rq->bio, rq->errors); - -#ifdef CCISS_DEBUG - printk("Done with %p\n", rq); -#endif /* CCISS_DEBUG */ - - spin_lock_irqsave(&h->lock, flags); - end_that_request_last(rq, rq->errors); - cmd_free(h, cmd,1); - spin_unlock_irqrestore(&h->lock, flags); -} - /* checks the status of the job and calls complete buffers to mark all * buffers for the completed job. Note that this function does not need * to hold the hba/queue lock. diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 9888bc151755..473a13b22b29 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -65,7 +65,7 @@ MODULE_LICENSE("GPL"); typedef struct bluecard_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct hci_dev *hdev; @@ -85,8 +85,8 @@ typedef struct bluecard_info_t { } bluecard_info_t; -static void bluecard_config(dev_link_t *link); -static void bluecard_release(dev_link_t *link); +static int bluecard_config(struct pcmcia_device *link); +static void bluecard_release(struct pcmcia_device *link); static void bluecard_detach(struct pcmcia_device *p_dev); @@ -162,7 +162,7 @@ static void bluecard_detach(struct pcmcia_device *p_dev); static void bluecard_activity_led_timeout(u_long arg) { bluecard_info_t *info = (bluecard_info_t *)arg; - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) return; @@ -179,7 +179,7 @@ static void bluecard_activity_led_timeout(u_long arg) static void bluecard_enable_activity_led(bluecard_info_t *info) { - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; if (!test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) return; @@ -235,7 +235,7 @@ static void bluecard_write_wakeup(bluecard_info_t *info) } do { - register unsigned int iobase = info->link.io.BasePort1; + register unsigned int iobase = info->p_dev->io.BasePort1; register unsigned int offset; register unsigned char command; register unsigned long ready_bit; @@ -244,7 +244,7 @@ static void bluecard_write_wakeup(bluecard_info_t *info) clear_bit(XMIT_WAKEUP, &(info->tx_state)); - if (!(info->link.state & DEV_PRESENT)) + if (!pcmcia_dev_present(info->p_dev)) return; if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { @@ -382,7 +382,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset) return; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; if (test_bit(XMIT_SENDING_READY, &(info->tx_state))) bluecard_enable_activity_led(info); @@ -512,7 +512,7 @@ static irqreturn_t bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *r if (!test_bit(CARD_READY, &(info->hw_state))) return IRQ_HANDLED; - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; spin_lock(&(info->lock)); @@ -626,7 +626,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev) static int bluecard_hci_open(struct hci_dev *hdev) { bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); @@ -646,7 +646,7 @@ static int bluecard_hci_open(struct hci_dev *hdev) static int bluecard_hci_close(struct hci_dev *hdev) { bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) return 0; @@ -713,7 +713,7 @@ static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned l static int bluecard_open(bluecard_info_t *info) { - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; struct hci_dev *hdev; unsigned char id; @@ -831,7 +831,7 @@ static int bluecard_open(bluecard_info_t *info) static int bluecard_close(bluecard_info_t *info) { - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; struct hci_dev *hdev = info->hdev; if (!hdev) @@ -856,17 +856,16 @@ static int bluecard_close(bluecard_info_t *info) return 0; } -static int bluecard_attach(struct pcmcia_device *p_dev) +static int bluecard_probe(struct pcmcia_device *link) { bluecard_info_t *info; - dev_link_t *link; /* Create new info device */ info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - link = &info->link; + info->p_dev = link; link->priv = info; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; @@ -878,32 +877,22 @@ static int bluecard_attach(struct pcmcia_device *p_dev) link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - bluecard_config(link); - - return 0; + return bluecard_config(link); } -static void bluecard_detach(struct pcmcia_device *p_dev) +static void bluecard_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); bluecard_info_t *info = link->priv; - if (link->state & DEV_CONFIG) - bluecard_release(link); - + bluecard_release(link); kfree(info); } -static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i; @@ -918,14 +907,12 @@ static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse return pcmcia_parse_tuple(handle, tuple, parse); } -static void bluecard_config(dev_link_t *link) +static int bluecard_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; bluecard_info_t *info = link->priv; tuple_t tuple; u_short buf[256]; cisparse_t parse; - config_info_t config; int i, n, last_ret, last_fn; tuple.TupleData = (cisdata_t *)buf; @@ -935,7 +922,7 @@ static void bluecard_config(dev_link_t *link) /* Get configuration register information */ tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(handle, &tuple, &parse); + last_ret = first_tuple(link, &tuple, &parse); if (last_ret != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; @@ -943,36 +930,31 @@ static void bluecard_config(dev_link_t *link) link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - i = pcmcia_get_configuration_info(handle, &config); - link->conf.Vcc = config.Vcc; - link->conf.ConfigIndex = 0x20; link->io.NumPorts1 = 64; link->io.IOAddrLines = 6; for (n = 0; n < 0x400; n += 0x40) { link->io.BasePort1 = n ^ 0x300; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); goto failed; } - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); + cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); + cs_error(link, RequestConfiguration, i); goto failed; } @@ -980,57 +962,28 @@ static void bluecard_config(dev_link_t *link) goto failed; strcpy(info->node.dev_name, info->hdev->name); - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &info->node; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: bluecard_release(link); + return -ENODEV; } -static void bluecard_release(dev_link_t *link) +static void bluecard_release(struct pcmcia_device *link) { bluecard_info_t *info = link->priv; - if (link->state & DEV_PRESENT) - bluecard_close(info); + bluecard_close(info); del_timer(&(info->timer)); - link->dev = NULL; - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; -} - -static int bluecard_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int bluecard_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (DEV_OK(link)) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; + pcmcia_disable_device(link); } static struct pcmcia_device_id bluecard_ids[] = { @@ -1046,11 +999,9 @@ static struct pcmcia_driver bluecard_driver = { .drv = { .name = "bluecard_cs", }, - .probe = bluecard_attach, + .probe = bluecard_probe, .remove = bluecard_detach, .id_table = bluecard_ids, - .suspend = bluecard_suspend, - .resume = bluecard_resume, }; static int __init init_bluecard_cs(void) diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 7e21b1ff27c4..b94ac2f9f7ba 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -72,7 +72,7 @@ MODULE_LICENSE("GPL"); typedef struct bt3c_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct hci_dev *hdev; @@ -88,8 +88,8 @@ typedef struct bt3c_info_t { } bt3c_info_t; -static void bt3c_config(dev_link_t *link); -static void bt3c_release(dev_link_t *link); +static int bt3c_config(struct pcmcia_device *link); +static void bt3c_release(struct pcmcia_device *link); static void bt3c_detach(struct pcmcia_device *p_dev); @@ -191,11 +191,11 @@ static void bt3c_write_wakeup(bt3c_info_t *info) return; do { - register unsigned int iobase = info->link.io.BasePort1; + register unsigned int iobase = info->p_dev->io.BasePort1; register struct sk_buff *skb; register int len; - if (!(info->link.state & DEV_PRESENT)) + if (!pcmcia_dev_present(info->p_dev)) break; @@ -229,7 +229,7 @@ static void bt3c_receive(bt3c_info_t *info) return; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; avail = bt3c_read(iobase, 0x7006); //printk("bt3c_cs: receiving %d bytes\n", avail); @@ -350,7 +350,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) return IRQ_NONE; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; spin_lock(&(info->lock)); @@ -481,7 +481,7 @@ static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int co unsigned int iobase, size, addr, fcs, tmp; int i, err = 0; - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; /* Reset */ bt3c_io_write(iobase, 0x8040, 0x0404); @@ -562,7 +562,6 @@ static int bt3c_open(bt3c_info_t *info) { const struct firmware *firmware; struct hci_dev *hdev; - client_handle_t handle; int err; spin_lock_init(&(info->lock)); @@ -594,10 +593,8 @@ static int bt3c_open(bt3c_info_t *info) hdev->owner = THIS_MODULE; - handle = info->link.handle; - /* Load firmware */ - err = request_firmware(&firmware, "BT3CPCC.bin", &handle_to_dev(handle)); + err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev); if (err < 0) { BT_ERR("Firmware request failed"); goto error; @@ -648,17 +645,16 @@ static int bt3c_close(bt3c_info_t *info) return 0; } -static int bt3c_attach(struct pcmcia_device *p_dev) +static int bt3c_probe(struct pcmcia_device *link) { bt3c_info_t *info; - dev_link_t *link; /* Create new info device */ info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - link = &info->link; + info->p_dev = link; link->priv = info; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; @@ -670,31 +666,21 @@ static int bt3c_attach(struct pcmcia_device *p_dev) link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - bt3c_config(link); - - return 0; + return bt3c_config(link); } -static void bt3c_detach(struct pcmcia_device *p_dev) +static void bt3c_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); bt3c_info_t *info = link->priv; - if (link->state & DEV_CONFIG) - bt3c_release(link); - + bt3c_release(link); kfree(info); } -static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i; @@ -705,30 +691,28 @@ static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) return pcmcia_parse_tuple(handle, tuple, parse); } -static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) return CS_NO_MORE_ITEMS; return get_tuple(handle, tuple, parse); } -static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) return CS_NO_MORE_ITEMS; return get_tuple(handle, tuple, parse); } -static void bt3c_config(dev_link_t *link) +static int bt3c_config(struct pcmcia_device *link) { static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; - client_handle_t handle = link->handle; bt3c_info_t *info = link->priv; tuple_t tuple; u_short buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; - config_info_t config; int i, j, try, last_ret, last_fn; tuple.TupleData = (cisdata_t *)buf; @@ -738,7 +722,7 @@ static void bt3c_config(dev_link_t *link) /* Get configuration register information */ tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(handle, &tuple, &parse); + last_ret = first_tuple(link, &tuple, &parse); if (last_ret != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; @@ -746,11 +730,6 @@ static void bt3c_config(dev_link_t *link) link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - i = pcmcia_get_configuration_info(handle, &config); - link->conf.Vcc = config.Vcc; - /* First pass: look for a config entry that looks normal. */ tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; @@ -759,59 +738,59 @@ static void bt3c_config(dev_link_t *link) tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; /* Two tries: without IO aliases, then with aliases */ for (try = 0; try < 2; try++) { - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); while (i != CS_NO_MORE_ITEMS) { if (i != CS_SUCCESS) goto next_entry; if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; + link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } next_entry: - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(link, &tuple, &parse); } } /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { link->conf.ConfigIndex = cf->index; for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; link->io.IOAddrLines = base[j] ? 16 : 3; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(link, &tuple, &parse); } found_port: if (i != CS_SUCCESS) { BT_ERR("No usable port range found"); - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); goto failed; } - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); + cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); + cs_error(link, RequestConfiguration, i); goto failed; } @@ -819,55 +798,26 @@ found_port: goto failed; strcpy(info->node.dev_name, info->hdev->name); - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &info->node; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: bt3c_release(link); + return -ENODEV; } -static void bt3c_release(dev_link_t *link) +static void bt3c_release(struct pcmcia_device *link) { bt3c_info_t *info = link->priv; - if (link->state & DEV_PRESENT) - bt3c_close(info); + bt3c_close(info); - link->dev = NULL; - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; -} - -static int bt3c_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int bt3c_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (DEV_OK(link)) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; + pcmcia_disable_device(link); } @@ -882,11 +832,9 @@ static struct pcmcia_driver bt3c_driver = { .drv = { .name = "bt3c_cs", }, - .probe = bt3c_attach, + .probe = bt3c_probe, .remove = bt3c_detach, .id_table = bt3c_ids, - .suspend = bt3c_suspend, - .resume = bt3c_resume, }; static int __init init_bt3c_cs(void) diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 7b4bff4cfa2d..9ce4c93467e5 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -68,7 +68,7 @@ MODULE_LICENSE("GPL"); typedef struct btuart_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct hci_dev *hdev; @@ -84,8 +84,8 @@ typedef struct btuart_info_t { } btuart_info_t; -static void btuart_config(dev_link_t *link); -static void btuart_release(dev_link_t *link); +static int btuart_config(struct pcmcia_device *link); +static void btuart_release(struct pcmcia_device *link); static void btuart_detach(struct pcmcia_device *p_dev); @@ -146,13 +146,13 @@ static void btuart_write_wakeup(btuart_info_t *info) } do { - register unsigned int iobase = info->link.io.BasePort1; + register unsigned int iobase = info->p_dev->io.BasePort1; register struct sk_buff *skb; register int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); - if (!(info->link.state & DEV_PRESENT)) + if (!pcmcia_dev_present(info->p_dev)) return; if (!(skb = skb_dequeue(&(info->txq)))) @@ -187,7 +187,7 @@ static void btuart_receive(btuart_info_t *info) return; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; do { info->hdev->stat.byte_rx++; @@ -301,7 +301,7 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *reg return IRQ_NONE; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; spin_lock(&(info->lock)); @@ -357,7 +357,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed) return; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; spin_lock_irqsave(&(info->lock), flags); @@ -481,7 +481,7 @@ static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned lon static int btuart_open(btuart_info_t *info) { unsigned long flags; - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; struct hci_dev *hdev; spin_lock_init(&(info->lock)); @@ -550,7 +550,7 @@ static int btuart_open(btuart_info_t *info) static int btuart_close(btuart_info_t *info) { unsigned long flags; - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; struct hci_dev *hdev = info->hdev; if (!hdev) @@ -576,17 +576,16 @@ static int btuart_close(btuart_info_t *info) return 0; } -static int btuart_attach(struct pcmcia_device *p_dev) +static int btuart_probe(struct pcmcia_device *link) { btuart_info_t *info; - dev_link_t *link; /* Create new info device */ info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - link = &info->link; + info->p_dev = link; link->priv = info; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; @@ -598,31 +597,21 @@ static int btuart_attach(struct pcmcia_device *p_dev) link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - btuart_config(link); - - return 0; + return btuart_config(link); } -static void btuart_detach(struct pcmcia_device *p_dev) +static void btuart_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); btuart_info_t *info = link->priv; - if (link->state & DEV_CONFIG) - btuart_release(link); - + btuart_release(link); kfree(info); } -static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i; @@ -633,30 +622,28 @@ static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) return pcmcia_parse_tuple(handle, tuple, parse); } -static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) return CS_NO_MORE_ITEMS; return get_tuple(handle, tuple, parse); } -static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) return CS_NO_MORE_ITEMS; return get_tuple(handle, tuple, parse); } -static void btuart_config(dev_link_t *link) +static int btuart_config(struct pcmcia_device *link) { static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; - client_handle_t handle = link->handle; btuart_info_t *info = link->priv; tuple_t tuple; u_short buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; - config_info_t config; int i, j, try, last_ret, last_fn; tuple.TupleData = (cisdata_t *)buf; @@ -666,7 +653,7 @@ static void btuart_config(dev_link_t *link) /* Get configuration register information */ tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(handle, &tuple, &parse); + last_ret = first_tuple(link, &tuple, &parse); if (last_ret != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; @@ -674,11 +661,6 @@ static void btuart_config(dev_link_t *link) link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - i = pcmcia_get_configuration_info(handle, &config); - link->conf.Vcc = config.Vcc; - /* First pass: look for a config entry that looks normal. */ tuple.TupleData = (cisdata_t *) buf; tuple.TupleOffset = 0; @@ -687,29 +669,29 @@ static void btuart_config(dev_link_t *link) tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; /* Two tries: without IO aliases, then with aliases */ for (try = 0; try < 2; try++) { - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); while (i != CS_NO_MORE_ITEMS) { if (i != CS_SUCCESS) goto next_entry; if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; + link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } next_entry: - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(link, &tuple, &parse); } } /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { @@ -717,30 +699,30 @@ next_entry: for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; link->io.IOAddrLines = base[j] ? 16 : 3; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(link, &tuple, &parse); } found_port: if (i != CS_SUCCESS) { BT_ERR("No usable port range found"); - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); goto failed; } - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); + cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); + cs_error(link, RequestConfiguration, i); goto failed; } @@ -748,58 +730,28 @@ found_port: goto failed; strcpy(info->node.dev_name, info->hdev->name); - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &info->node; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: btuart_release(link); + return -ENODEV; } -static void btuart_release(dev_link_t *link) +static void btuart_release(struct pcmcia_device *link) { btuart_info_t *info = link->priv; - if (link->state & DEV_PRESENT) - btuart_close(info); + btuart_close(info); - link->dev = NULL; - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } -static int btuart_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int btuart_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (DEV_OK(link)) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; -} - - static struct pcmcia_device_id btuart_ids[] = { /* don't use this driver. Use serial_cs + hci_uart instead */ PCMCIA_DEVICE_NULL @@ -811,11 +763,9 @@ static struct pcmcia_driver btuart_driver = { .drv = { .name = "btuart_cs", }, - .probe = btuart_attach, + .probe = btuart_probe, .remove = btuart_detach, .id_table = btuart_ids, - .suspend = btuart_suspend, - .resume = btuart_resume, }; static int __init init_btuart_cs(void) diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 0449bc45ae5e..a71a240611e0 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -68,7 +68,7 @@ MODULE_LICENSE("GPL"); typedef struct dtl1_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct hci_dev *hdev; @@ -87,8 +87,8 @@ typedef struct dtl1_info_t { } dtl1_info_t; -static void dtl1_config(dev_link_t *link); -static void dtl1_release(dev_link_t *link); +static int dtl1_config(struct pcmcia_device *link); +static void dtl1_release(struct pcmcia_device *link); static void dtl1_detach(struct pcmcia_device *p_dev); @@ -153,13 +153,13 @@ static void dtl1_write_wakeup(dtl1_info_t *info) } do { - register unsigned int iobase = info->link.io.BasePort1; + register unsigned int iobase = info->p_dev->io.BasePort1; register struct sk_buff *skb; register int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); - if (!(info->link.state & DEV_PRESENT)) + if (!pcmcia_dev_present(info->p_dev)) return; if (!(skb = skb_dequeue(&(info->txq)))) @@ -218,7 +218,7 @@ static void dtl1_receive(dtl1_info_t *info) return; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; do { info->hdev->stat.byte_rx++; @@ -305,7 +305,7 @@ static irqreturn_t dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) return IRQ_NONE; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->io.BasePort1; spin_lock(&(info->lock)); @@ -458,7 +458,7 @@ static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long static int dtl1_open(dtl1_info_t *info) { unsigned long flags; - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; struct hci_dev *hdev; spin_lock_init(&(info->lock)); @@ -504,7 +504,7 @@ static int dtl1_open(dtl1_info_t *info) outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); - info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; + info->ri_latch = inb(info->p_dev->io.BasePort1 + UART_MSR) & UART_MSR_RI; /* Turn on interrupts */ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); @@ -529,7 +529,7 @@ static int dtl1_open(dtl1_info_t *info) static int dtl1_close(dtl1_info_t *info) { unsigned long flags; - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->io.BasePort1; struct hci_dev *hdev = info->hdev; if (!hdev) @@ -555,17 +555,16 @@ static int dtl1_close(dtl1_info_t *info) return 0; } -static int dtl1_attach(struct pcmcia_device *p_dev) +static int dtl1_probe(struct pcmcia_device *link) { dtl1_info_t *info; - dev_link_t *link; /* Create new info device */ info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - link = &info->link; + info->p_dev = link; link->priv = info; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; @@ -577,31 +576,22 @@ static int dtl1_attach(struct pcmcia_device *p_dev) link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - dtl1_config(link); - - return 0; + return dtl1_config(link); } -static void dtl1_detach(struct pcmcia_device *p_dev) +static void dtl1_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); dtl1_info_t *info = link->priv; - if (link->state & DEV_CONFIG) - dtl1_release(link); + dtl1_release(link); kfree(info); } -static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i; @@ -612,29 +602,27 @@ static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) return pcmcia_parse_tuple(handle, tuple, parse); } -static int first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) return CS_NO_MORE_ITEMS; return get_tuple(handle, tuple, parse); } -static int next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) return CS_NO_MORE_ITEMS; return get_tuple(handle, tuple, parse); } -static void dtl1_config(dev_link_t *link) +static int dtl1_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; dtl1_info_t *info = link->priv; tuple_t tuple; u_short buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; - config_info_t config; int i, last_ret, last_fn; tuple.TupleData = (cisdata_t *)buf; @@ -644,7 +632,7 @@ static void dtl1_config(dev_link_t *link) /* Get configuration register information */ tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(handle, &tuple, &parse); + last_ret = first_tuple(link, &tuple, &parse); if (last_ret != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; @@ -652,11 +640,6 @@ static void dtl1_config(dev_link_t *link) link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - i = pcmcia_get_configuration_info(handle, &config); - link->conf.Vcc = config.Vcc; - tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; @@ -665,34 +648,34 @@ static void dtl1_config(dev_link_t *link) /* Look for a generic full-sized window */ link->io.NumPorts1 = 8; - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.NumPorts1 = cf->io.win[0].len; /*yo */ link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(link, &tuple, &parse); } if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); goto failed; } - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); + cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); + cs_error(link, RequestConfiguration, i); goto failed; } @@ -700,55 +683,26 @@ static void dtl1_config(dev_link_t *link) goto failed; strcpy(info->node.dev_name, info->hdev->name); - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &info->node; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: dtl1_release(link); + return -ENODEV; } -static void dtl1_release(dev_link_t *link) +static void dtl1_release(struct pcmcia_device *link) { dtl1_info_t *info = link->priv; - if (link->state & DEV_PRESENT) - dtl1_close(info); + dtl1_close(info); - link->dev = NULL; - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; -} - -static int dtl1_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int dtl1_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (DEV_OK(link)) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; + pcmcia_disable_device(link); } @@ -765,11 +719,9 @@ static struct pcmcia_driver dtl1_driver = { .drv = { .name = "dtl1_cs", }, - .probe = dtl1_attach, + .probe = dtl1_probe, .remove = dtl1_detach, .id_table = dtl1_ids, - .suspend = dtl1_suspend, - .resume = dtl1_resume, }; static int __init init_dtl1_cs(void) diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index ce4a1ce59d6a..ec004897b634 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -1763,7 +1763,7 @@ static int __init aztcd_init(void) release_region(azt_port, 4); } } - if ((azt_port_auto[i] == 0) || (i == 16)) { + if ((i == 16) || (azt_port_auto[i] == 0)) { printk(KERN_INFO "aztcd: no AZTECH CD-ROM drive found\n"); return -EIO; } diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 73d30bf01582..402296670d3a 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -561,14 +561,31 @@ config TIPAR If unsure, say N. +config HVC_DRIVER + bool + help + Users of pSeries machines that want to utilize the hvc console front-end + module for their backend console driver should select this option. + It will automatically be selected if one of the back-end console drivers + is selected. + + config HVC_CONSOLE bool "pSeries Hypervisor Virtual Console support" depends on PPC_PSERIES + select HVC_DRIVER help pSeries machines when partitioned support a hypervisor virtual console. This driver allows each pSeries partition to have a console which is accessed via the HMC. +config HVC_RTAS + bool "IBM RTAS Console support" + depends on PPC_RTAS + select HVC_DRIVER + help + IBM Console device driver which makes use of RTAS + config HVCS tristate "IBM Hypervisor Virtual Console Server support" depends on PPC_PSERIES @@ -788,10 +805,6 @@ config S3C2410_RTC Samsung S3C2410. This can provide periodic interrupt rates from 1Hz to 64Hz for user programs, and wakeup from Alarm. -config RTC_VR41XX - tristate "NEC VR4100 series Real Time Clock Support" - depends on CPU_VR41XX - config COBALT_LCD bool "Support for Cobalt LCD" depends on MIPS_COBALT diff --git a/drivers/char/Makefile b/drivers/char/Makefile index b2a11245fa95..f5b01c6d498e 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -41,7 +41,9 @@ obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_SX) += sx.o generic_serial.o obj-$(CONFIG_RIO) += rio/ generic_serial.o -obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvc_vio.o hvsi.o +obj-$(CONFIG_HVC_DRIVER) += hvc_console.o +obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o +obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MMTIMER) += mmtimer.o @@ -65,7 +67,6 @@ obj-$(CONFIG_SGI_DS1286) += ds1286.o obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o obj-$(CONFIG_DS1302) += ds1302.o obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o -obj-$(CONFIG_RTC_VR41XX) += vr41xx_rtc.o ifeq ($(CONFIG_GENERIC_NVRAM),y) obj-$(CONFIG_NVRAM) += generic_nvram.o else diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index fed0a87448d8..86a966b65236 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -64,6 +64,12 @@ static struct gatt_mask efficeon_generic_masks[] = {.mask = 0x00000001, .type = 0} }; +/* This function does the same thing as mask_memory() for this chipset... */ +static inline unsigned long efficeon_mask_memory(unsigned long addr) +{ + return addr | 0x00000001; +} + static struct aper_size_info_lvl2 efficeon_generic_sizes[4] = { {256, 65536, 0}, @@ -251,7 +257,7 @@ static int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int t last_page = NULL; for (i = 0; i < count; i++) { int index = pg_start + i; - unsigned long insert = mem->memory[i]; + unsigned long insert = efficeon_mask_memory(mem->memory[i]); page = (unsigned int *) efficeon_private.l1_table[index >> 10]; diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 927a5bbe112c..a370e7a0bad5 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -142,7 +142,7 @@ static int ac_register_board(unsigned long physloc, void __iomem *loc, if (!boardno) boardno = readb(loc + NUMCARD_OWNER_TO_PC); - if (!boardno && boardno > MAX_BOARD) { + if (!boardno || boardno > MAX_BOARD) { printk(KERN_WARNING "Board #%d (at 0x%lx) is out of range (1 <= x <= %d).\n", boardno, physloc, MAX_BOARD); return 0; diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index 107df9fdba4e..e1aadae00623 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -357,6 +357,12 @@ typedef struct drm_freelist { spinlock_t lock; } drm_freelist_t; +typedef struct drm_dma_handle { + dma_addr_t busaddr; + void *vaddr; + size_t size; +} drm_dma_handle_t; + /** * Buffer entry. There is one of this for each buffer size order. */ @@ -366,7 +372,7 @@ typedef struct drm_buf_entry { drm_buf_t *buflist; /**< buffer list */ int seg_count; int page_order; - unsigned long *seglist; + drm_dma_handle_t **seglist; drm_freelist_t freelist; } drm_buf_entry_t; @@ -483,12 +489,6 @@ typedef struct drm_sigdata { drm_hw_lock_t *lock; } drm_sigdata_t; -typedef struct drm_dma_handle { - dma_addr_t busaddr; - void *vaddr; - size_t size; -} drm_dma_handle_t; - /** * Mappings list */ @@ -813,12 +813,8 @@ extern void drm_mem_init(void); extern int drm_mem_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area); -extern unsigned long drm_alloc_pages(int order, int area); -extern void drm_free_pages(unsigned long address, int order, int area); extern void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t * dev); -extern void *drm_ioremap_nocache(unsigned long offset, unsigned long size, - drm_device_t * dev); extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev); extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type); @@ -1024,11 +1020,13 @@ static __inline__ void drm_core_ioremap(struct drm_map *map, map->handle = drm_ioremap(map->offset, map->size, dev); } +#if 0 static __inline__ void drm_core_ioremap_nocache(struct drm_map *map, struct drm_device *dev) { map->handle = drm_ioremap_nocache(map->offset, map->size, dev); } +#endif /* 0 */ static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev) diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c index e2637b4d51de..8a9cf12e6183 100644 --- a/drivers/char/drm/drm_bufs.c +++ b/drivers/char/drm/drm_bufs.c @@ -474,8 +474,7 @@ static void drm_cleanup_buf_error(drm_device_t * dev, drm_buf_entry_t * entry) if (entry->seg_count) { for (i = 0; i < entry->seg_count; i++) { if (entry->seglist[i]) { - drm_free_pages(entry->seglist[i], - entry->page_order, DRM_MEM_DMA); + drm_pci_free(dev, entry->seglist[i]); } } drm_free(entry->seglist, @@ -678,7 +677,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) int total; int page_order; drm_buf_entry_t *entry; - unsigned long page; + drm_dma_handle_t *dmah; drm_buf_t *buf; int alignment; unsigned long offset; @@ -781,8 +780,10 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) page_count = 0; while (entry->buf_count < count) { - page = drm_alloc_pages(page_order, DRM_MEM_DMA); - if (!page) { + + dmah = drm_pci_alloc(dev, PAGE_SIZE << page_order, 0x1000, 0xfffffffful); + + if (!dmah) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; entry->seg_count = count; @@ -794,13 +795,13 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) atomic_dec(&dev->buf_alloc); return -ENOMEM; } - entry->seglist[entry->seg_count++] = page; + entry->seglist[entry->seg_count++] = dmah; for (i = 0; i < (1 << page_order); i++) { DRM_DEBUG("page %d @ 0x%08lx\n", dma->page_count + page_count, - page + PAGE_SIZE * i); + (unsigned long)dmah->vaddr + PAGE_SIZE * i); temp_pagelist[dma->page_count + page_count++] - = page + PAGE_SIZE * i; + = (unsigned long)dmah->vaddr + PAGE_SIZE * i; } for (offset = 0; offset + size <= total && entry->buf_count < count; @@ -811,7 +812,8 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) buf->order = order; buf->used = 0; buf->offset = (dma->byte_count + byte_count + offset); - buf->address = (void *)(page + offset); + buf->address = (void *)(dmah->vaddr + offset); + buf->bus_address = dmah->busaddr + offset; buf->next = NULL; buf->waiting = 0; buf->pending = 0; diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c index 2afab95ca036..892db7096986 100644 --- a/drivers/char/drm/drm_dma.c +++ b/drivers/char/drm/drm_dma.c @@ -85,9 +85,7 @@ void drm_dma_takedown(drm_device_t * dev) dma->bufs[i].seg_count); for (j = 0; j < dma->bufs[i].seg_count; j++) { if (dma->bufs[i].seglist[j]) { - drm_free_pages(dma->bufs[i].seglist[j], - dma->bufs[i].page_order, - DRM_MEM_DMA); + drm_pci_free(dev, dma->bufs[i].seglist[j]); } } drm_free(dma->bufs[i].seglist, diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c index dc6bbe8a18dc..3c0b882a8e72 100644 --- a/drivers/char/drm/drm_drv.c +++ b/drivers/char/drm/drm_drv.c @@ -75,8 +75,8 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX)] = {drm_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX)] = {drm_getsareactx, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, - [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = {drm_addctx, DRM_AUTH|DRM_ROOT_ONLY}, + [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = {drm_rmctx, DRM_AUTH|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = {drm_modctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = {drm_getctx, DRM_AUTH}, [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = {drm_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c index 8074771e348f..7e3318e1d1c6 100644 --- a/drivers/char/drm/drm_memory.c +++ b/drivers/char/drm/drm_memory.c @@ -79,66 +79,72 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) return pt; } -/** - * Allocate pages. - * - * \param order size order. - * \param area memory area. (Not used.) - * \return page address on success, or zero on failure. - * - * Allocate and reserve free pages. - */ -unsigned long drm_alloc_pages(int order, int area) -{ - unsigned long address; - unsigned long bytes = PAGE_SIZE << order; - unsigned long addr; - unsigned int sz; - - address = __get_free_pages(GFP_KERNEL|__GFP_COMP, order); - if (!address) - return 0; - - /* Zero */ - memset((void *)address, 0, bytes); - - /* Reserve */ - for (addr = address, sz = bytes; - sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { - SetPageReserved(virt_to_page(addr)); - } - - return address; -} - -/** - * Free pages. - * - * \param address address of the pages to free. - * \param order size order. - * \param area memory area. (Not used.) - * - * Unreserve and free pages allocated by alloc_pages(). - */ -void drm_free_pages(unsigned long address, int order, int area) -{ - unsigned long bytes = PAGE_SIZE << order; - unsigned long addr; - unsigned int sz; - - if (!address) - return; - - /* Unreserve */ - for (addr = address, sz = bytes; - sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { - ClearPageReserved(virt_to_page(addr)); - } - - free_pages(address, order); -} - #if __OS_HAS_AGP +/* + * Find the drm_map that covers the range [offset, offset+size). + */ +static drm_map_t *drm_lookup_map(unsigned long offset, + unsigned long size, drm_device_t * dev) +{ + struct list_head *list; + drm_map_list_t *r_list; + drm_map_t *map; + + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *) list; + map = r_list->map; + if (!map) + continue; + if (map->offset <= offset + && (offset + size) <= (map->offset + map->size)) + return map; + } + return NULL; +} + +static void *agp_remap(unsigned long offset, unsigned long size, + drm_device_t * dev) +{ + unsigned long *phys_addr_map, i, num_pages = + PAGE_ALIGN(size) / PAGE_SIZE; + struct drm_agp_mem *agpmem; + struct page **page_map; + void *addr; + + size = PAGE_ALIGN(size); + +#ifdef __alpha__ + offset -= dev->hose->mem_space->start; +#endif + + for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) + if (agpmem->bound <= offset + && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >= + (offset + size)) + break; + if (!agpmem) + return NULL; + + /* + * OK, we're mapping AGP space on a chipset/platform on which memory accesses by + * the CPU do not get remapped by the GART. We fix this by using the kernel's + * page-table instead (that's probably faster anyhow...). + */ + /* note: use vmalloc() because num_pages could be large... */ + page_map = vmalloc(num_pages * sizeof(struct page *)); + if (!page_map) + return NULL; + + phys_addr_map = + agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE; + for (i = 0; i < num_pages; ++i) + page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT); + addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); + vfree(page_map); + + return addr; +} + /** Wrapper around agp_allocate_memory() */ DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type) { @@ -162,5 +168,74 @@ int drm_unbind_agp(DRM_AGP_MEM * handle) { return drm_agp_unbind_memory(handle); } + +#else /* __OS_HAS_AGP */ + +static inline drm_map_t *drm_lookup_map(unsigned long offset, + unsigned long size, drm_device_t * dev) +{ + return NULL; +} + +static inline void *agp_remap(unsigned long offset, unsigned long size, + drm_device_t * dev) +{ + return NULL; +} + #endif /* agp */ + +void *drm_ioremap(unsigned long offset, unsigned long size, + drm_device_t * dev) +{ + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { + drm_map_t *map = drm_lookup_map(offset, size, dev); + + if (map && map->type == _DRM_AGP) + return agp_remap(offset, size, dev); + } + return ioremap(offset, size); +} +EXPORT_SYMBOL(drm_ioremap); + +#if 0 +void *drm_ioremap_nocache(unsigned long offset, + unsigned long size, drm_device_t * dev) +{ + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { + drm_map_t *map = drm_lookup_map(offset, size, dev); + + if (map && map->type == _DRM_AGP) + return agp_remap(offset, size, dev); + } + return ioremap_nocache(offset, size); +} +#endif /* 0 */ + +void drm_ioremapfree(void *pt, unsigned long size, + drm_device_t * dev) +{ + /* + * This is a bit ugly. It would be much cleaner if the DRM API would use separate + * routines for handling mappings in the AGP space. Hopefully this can be done in + * a future revision of the interface... + */ + if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture + && ((unsigned long)pt >= VMALLOC_START + && (unsigned long)pt < VMALLOC_END)) { + unsigned long offset; + drm_map_t *map; + + offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK); + map = drm_lookup_map(offset, size, dev); + if (map && map->type == _DRM_AGP) { + vunmap(pt); + return; + } + } + + iounmap(pt); +} +EXPORT_SYMBOL(drm_ioremapfree); + #endif /* debug_memory */ diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h index 3732a61c3762..714d9aedcff5 100644 --- a/drivers/char/drm/drm_memory.h +++ b/drivers/char/drm/drm_memory.h @@ -57,71 +57,6 @@ # endif #endif -/* - * Find the drm_map that covers the range [offset, offset+size). - */ -static inline drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - struct list_head *list; - drm_map_list_t *r_list; - drm_map_t *map; - - list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *) list; - map = r_list->map; - if (!map) - continue; - if (map->offset <= offset - && (offset + size) <= (map->offset + map->size)) - return map; - } - return NULL; -} - -static inline void *agp_remap(unsigned long offset, unsigned long size, - drm_device_t * dev) -{ - unsigned long *phys_addr_map, i, num_pages = - PAGE_ALIGN(size) / PAGE_SIZE; - struct drm_agp_mem *agpmem; - struct page **page_map; - void *addr; - - size = PAGE_ALIGN(size); - -#ifdef __alpha__ - offset -= dev->hose->mem_space->start; -#endif - - for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) - if (agpmem->bound <= offset - && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >= - (offset + size)) - break; - if (!agpmem) - return NULL; - - /* - * OK, we're mapping AGP space on a chipset/platform on which memory accesses by - * the CPU do not get remapped by the GART. We fix this by using the kernel's - * page-table instead (that's probably faster anyhow...). - */ - /* note: use vmalloc() because num_pages could be large... */ - page_map = vmalloc(num_pages * sizeof(struct page *)); - if (!page_map) - return NULL; - - phys_addr_map = - agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE; - for (i = 0; i < num_pages; ++i) - page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT); - addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); - vfree(page_map); - - return addr; -} - static inline unsigned long drm_follow_page(void *vaddr) { pgd_t *pgd = pgd_offset_k((unsigned long)vaddr); @@ -133,18 +68,6 @@ static inline unsigned long drm_follow_page(void *vaddr) #else /* __OS_HAS_AGP */ -static inline drm_map_t *drm_lookup_map(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - return NULL; -} - -static inline void *agp_remap(unsigned long offset, unsigned long size, - drm_device_t * dev) -{ - return NULL; -} - static inline unsigned long drm_follow_page(void *vaddr) { return 0; @@ -152,51 +75,8 @@ static inline unsigned long drm_follow_page(void *vaddr) #endif -static inline void *drm_ioremap(unsigned long offset, unsigned long size, - drm_device_t * dev) -{ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { - drm_map_t *map = drm_lookup_map(offset, size, dev); +void *drm_ioremap(unsigned long offset, unsigned long size, + drm_device_t * dev); - if (map && map->type == _DRM_AGP) - return agp_remap(offset, size, dev); - } - return ioremap(offset, size); -} - -static inline void *drm_ioremap_nocache(unsigned long offset, - unsigned long size, drm_device_t * dev) -{ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) { - drm_map_t *map = drm_lookup_map(offset, size, dev); - - if (map && map->type == _DRM_AGP) - return agp_remap(offset, size, dev); - } - return ioremap_nocache(offset, size); -} - -static inline void drm_ioremapfree(void *pt, unsigned long size, - drm_device_t * dev) -{ - /* - * This is a bit ugly. It would be much cleaner if the DRM API would use separate - * routines for handling mappings in the AGP space. Hopefully this can be done in - * a future revision of the interface... - */ - if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture - && ((unsigned long)pt >= VMALLOC_START - && (unsigned long)pt < VMALLOC_END)) { - unsigned long offset; - drm_map_t *map; - - offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK); - map = drm_lookup_map(offset, size, dev); - if (map && map->type == _DRM_AGP) { - vunmap(pt); - return; - } - } - - iounmap(pt); -} +void drm_ioremapfree(void *pt, unsigned long size, + drm_device_t * dev); diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h index e84605fc54af..6543b9a14c42 100644 --- a/drivers/char/drm/drm_memory_debug.h +++ b/drivers/char/drm/drm_memory_debug.h @@ -206,76 +206,6 @@ void drm_free (void *pt, size_t size, int area) { } } -unsigned long drm_alloc_pages (int order, int area) { - unsigned long address; - unsigned long bytes = PAGE_SIZE << order; - unsigned long addr; - unsigned int sz; - - spin_lock(&drm_mem_lock); - if ((drm_ram_used >> PAGE_SHIFT) - > (DRM_RAM_PERCENT * drm_ram_available) / 100) { - spin_unlock(&drm_mem_lock); - return 0; - } - spin_unlock(&drm_mem_lock); - - address = __get_free_pages(GFP_KERNEL|__GFP_COMP, order); - if (!address) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[area].fail_count; - spin_unlock(&drm_mem_lock); - return 0; - } - spin_lock(&drm_mem_lock); - ++drm_mem_stats[area].succeed_count; - drm_mem_stats[area].bytes_allocated += bytes; - drm_ram_used += bytes; - spin_unlock(&drm_mem_lock); - - /* Zero outside the lock */ - memset((void *)address, 0, bytes); - - /* Reserve */ - for (addr = address, sz = bytes; - sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { - SetPageReserved(virt_to_page(addr)); - } - - return address; -} - -void drm_free_pages (unsigned long address, int order, int area) { - unsigned long bytes = PAGE_SIZE << order; - int alloc_count; - int free_count; - unsigned long addr; - unsigned int sz; - - if (!address) { - DRM_MEM_ERROR(area, "Attempt to free address 0\n"); - } else { - /* Unreserve */ - for (addr = address, sz = bytes; - sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { - ClearPageReserved(virt_to_page(addr)); - } - free_pages(address, order); - } - - spin_lock(&drm_mem_lock); - free_count = ++drm_mem_stats[area].free_count; - alloc_count = drm_mem_stats[area].succeed_count; - drm_mem_stats[area].bytes_freed += bytes; - drm_ram_used -= bytes; - spin_unlock(&drm_mem_lock); - if (free_count > alloc_count) { - DRM_MEM_ERROR(area, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } -} - void *drm_ioremap (unsigned long offset, unsigned long size, drm_device_t * dev) { void *pt; @@ -299,6 +229,7 @@ void *drm_ioremap (unsigned long offset, unsigned long size, return pt; } +#if 0 void *drm_ioremap_nocache (unsigned long offset, unsigned long size, drm_device_t * dev) { void *pt; @@ -321,6 +252,7 @@ void *drm_ioremap_nocache (unsigned long offset, unsigned long size, spin_unlock(&drm_mem_lock); return pt; } +#endif /* 0 */ void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) { int alloc_count; diff --git a/drivers/char/drm/drm_pci.c b/drivers/char/drm/drm_pci.c index 1fd7ff164817..86a0f1c22091 100644 --- a/drivers/char/drm/drm_pci.c +++ b/drivers/char/drm/drm_pci.c @@ -37,6 +37,7 @@ */ #include +#include #include "drmP.h" /**********************************************************************/ @@ -50,6 +51,10 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align, dma_addr_t maxaddr) { drm_dma_handle_t *dmah; +#if 1 + unsigned long addr; + size_t sz; +#endif #ifdef DRM_DEBUG_MEMORY int area = DRM_MEM_DMA; @@ -79,7 +84,7 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align, return NULL; dmah->size = size; - dmah->vaddr = pci_alloc_consistent(dev->pdev, size, &dmah->busaddr); + dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP); #ifdef DRM_DEBUG_MEMORY if (dmah->vaddr == NULL) { @@ -104,18 +109,29 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align, memset(dmah->vaddr, 0, size); + /* XXX - Is virt_to_page() legal for consistent mem? */ + /* Reserve */ + for (addr = (unsigned long)dmah->vaddr, sz = size; + sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { + SetPageReserved(virt_to_page(addr)); + } + return dmah; } EXPORT_SYMBOL(drm_pci_alloc); /** - * \brief Free a PCI consistent memory block with freeing its descriptor. + * \brief Free a PCI consistent memory block without freeing its descriptor. * * This function is for internal use in the Linux-specific DRM core code. */ void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah) { +#if 1 + unsigned long addr; + size_t sz; +#endif #ifdef DRM_DEBUG_MEMORY int area = DRM_MEM_DMA; int alloc_count; @@ -127,8 +143,14 @@ void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah) DRM_MEM_ERROR(area, "Attempt to free address 0\n"); #endif } else { - pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr, - dmah->busaddr); + /* XXX - Is virt_to_page() legal for consistent mem? */ + /* Unreserve */ + for (addr = (unsigned long)dmah->vaddr, sz = dmah->size; + sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + } + dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr, + dmah->busaddr); } #ifdef DRM_DEBUG_MEMORY diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 2c17e88a8847..b1bb3c7b568d 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -3,49 +3,69 @@ Please contact dri-devel@lists.sf.net to add new cards to this list */ #define radeon_PCI_IDS \ - {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350},\ + {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \ + {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \ {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \ {0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ + {0x1002, 0x4148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x4149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x414A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x414B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ {0x1002, 0x4150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ {0x1002, 0x4151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ {0x1002, 0x4152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ {0x1002, 0x4153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ {0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ {0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ - {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS250|CHIP_IS_IGP}, \ + {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \ {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ {0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ - {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS250|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ - {0x1002, 0x4964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \ - {0x1002, 0x4965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \ - {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \ - {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250}, \ - {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \ - {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \ + {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ + {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ + {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ + {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \ {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \ {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \ {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \ - {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \ - {0x1002, 0x4C65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \ - {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \ - {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R250|CHIP_IS_MOBILITY}, \ + {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \ + {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \ + {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \ {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ - {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ {0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ - {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ + {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ {0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ + {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ + {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \ {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ @@ -53,44 +73,66 @@ {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \ {0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x5149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x514A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x514B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ {0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ {0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x514E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x514F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ {0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \ {0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \ {0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ {0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ {0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ - {0x1002, 0x5168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x5169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x516A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x516B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x516C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ - {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ - {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ + {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \ + {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \ + {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \ + {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \ - {0x1002, 0x5836, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \ - {0x1002, 0x5837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \ {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ - {0x1002, 0x5963, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ - {0x1002, 0x5968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ + {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ - {0x1002, 0x596A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ - {0x1002, 0x596B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ + {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \ {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \ - {0x1002, 0x5c62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \ - {0x1002, 0x5c64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ - {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ - {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420}, \ + {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \ + {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \ {0, 0, 0} #define r128_PCI_IDS \ diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index 1ff4c7ca0bff..9f4b8ce4c05e 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -495,8 +495,6 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev, } } - dev_priv->sarea_priv->last_enqueue = dev_priv->counter++; - i915_emit_breadcrumb(dev); return 0; diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index d3879ac9970f..a752afd86ab8 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -53,6 +53,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); + if (temp & USER_INT_FLAG) DRM_WAKEUP(&dev_priv->irq_queue); diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c index c08fa5076f05..b108c7f913b2 100644 --- a/drivers/char/drm/r300_cmdbuf.c +++ b/drivers/char/drm/r300_cmdbuf.c @@ -214,13 +214,13 @@ void r300_init_reg_flags(void) ADD_RANGE(0x4F54, 1); ADD_RANGE(R300_TX_FILTER_0, 16); - ADD_RANGE(R300_TX_UNK1_0, 16); + ADD_RANGE(R300_TX_FILTER1_0, 16); ADD_RANGE(R300_TX_SIZE_0, 16); ADD_RANGE(R300_TX_FORMAT_0, 16); ADD_RANGE(R300_TX_PITCH_0, 16); /* Texture offset is dangerous and needs more checking */ ADD_RANGE_MARK(R300_TX_OFFSET_0, 16, MARK_CHECK_OFFSET); - ADD_RANGE(R300_TX_UNK4_0, 16); + ADD_RANGE(R300_TX_CHROMA_KEY_0, 16); ADD_RANGE(R300_TX_BORDER_COLOR_0, 16); /* Sporadic registers used as primitives are emitted */ @@ -242,8 +242,10 @@ static __inline__ int r300_check_range(unsigned reg, int count) return 0; } - /* we expect offsets passed to the framebuffer to be either within video memory or - within AGP space */ +/* + * we expect offsets passed to the framebuffer to be either within video + * memory or within AGP space + */ static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv, u32 offset) { @@ -251,11 +253,11 @@ static __inline__ int r300_check_offset(drm_radeon_private_t *dev_priv, but this value is not being kept. This code is correct for now (does the same thing as the code that sets MC_FB_LOCATION) in radeon_cp.c */ - if ((offset >= dev_priv->fb_location) && - (offset < dev_priv->gart_vm_start)) + if (offset >= dev_priv->fb_location && + offset < (dev_priv->fb_location + dev_priv->fb_size)) return 0; - if ((offset >= dev_priv->gart_vm_start) && - (offset < dev_priv->gart_vm_start + dev_priv->gart_size)) + if (offset >= dev_priv->gart_vm_start && + offset < (dev_priv->gart_vm_start + dev_priv->gart_size)) return 0; return 1; } @@ -490,6 +492,7 @@ static __inline__ int r300_emit_3d_load_vbpntr(drm_radeon_private_t *dev_priv, return 0; } + static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, drm_radeon_kcmd_buffer_t *cmdbuf) { @@ -701,6 +704,64 @@ static void r300_discard_buffer(drm_device_t * dev, drm_buf_t * buf) buf->used = 0; } +static int r300_scratch(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf, + drm_r300_cmd_header_t header) +{ + u32 *ref_age_base; + u32 i, buf_idx, h_pending; + RING_LOCALS; + + if (cmdbuf->bufsz < + (sizeof(u64) + header.scratch.n_bufs * sizeof(buf_idx))) { + return DRM_ERR(EINVAL); + } + + if (header.scratch.reg >= 5) { + return DRM_ERR(EINVAL); + } + + dev_priv->scratch_ages[header.scratch.reg]++; + + ref_age_base = *(u32 **)cmdbuf->buf; + + cmdbuf->buf += sizeof(u64); + cmdbuf->bufsz -= sizeof(u64); + + for (i=0; i < header.scratch.n_bufs; i++) { + buf_idx = *(u32 *)cmdbuf->buf; + buf_idx *= 2; /* 8 bytes per buf */ + + if (DRM_COPY_TO_USER(ref_age_base + buf_idx, &dev_priv->scratch_ages[header.scratch.reg], sizeof(u32))) { + return DRM_ERR(EINVAL); + } + + if (DRM_COPY_FROM_USER(&h_pending, ref_age_base + buf_idx + 1, sizeof(u32))) { + return DRM_ERR(EINVAL); + } + + if (h_pending == 0) { + return DRM_ERR(EINVAL); + } + + h_pending--; + + if (DRM_COPY_TO_USER(ref_age_base + buf_idx + 1, &h_pending, sizeof(u32))) { + return DRM_ERR(EINVAL); + } + + cmdbuf->buf += sizeof(buf_idx); + cmdbuf->bufsz -= sizeof(buf_idx); + } + + BEGIN_RING(2); + OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0)); + OUT_RING(dev_priv->scratch_ages[header.scratch.reg]); + ADVANCE_RING(); + + return 0; +} + /** * Parses and validates a user-supplied command buffer and emits appropriate * commands on the DMA ring buffer. @@ -838,6 +899,15 @@ int r300_do_cp_cmdbuf(drm_device_t *dev, } break; + case R300_CMD_SCRATCH: + DRM_DEBUG("R300_CMD_SCRATCH\n"); + ret = r300_scratch(dev_priv, cmdbuf, header); + if (ret) { + DRM_ERROR("r300_scratch failed\n"); + goto cleanup; + } + break; + default: DRM_ERROR("bad cmd_type %i at %p\n", header.header.cmd_type, diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h index d1e19954406b..a881f96c983e 100644 --- a/drivers/char/drm/r300_reg.h +++ b/drivers/char/drm/r300_reg.h @@ -711,8 +711,22 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_TX_MAX_ANISO_16_TO_1 (8 << 21) # define R300_TX_MAX_ANISO_MASK (14 << 21) -#define R300_TX_UNK1_0 0x4440 +#define R300_TX_FILTER1_0 0x4440 +# define R300_CHROMA_KEY_MODE_DISABLE 0 +# define R300_CHROMA_KEY_FORCE 1 +# define R300_CHROMA_KEY_BLEND 2 +# define R300_MC_ROUND_NORMAL (0<<2) +# define R300_MC_ROUND_MPEG4 (1<<2) # define R300_LOD_BIAS_MASK 0x1fff +# define R300_EDGE_ANISO_EDGE_DIAG (0<<13) +# define R300_EDGE_ANISO_EDGE_ONLY (1<<13) +# define R300_MC_COORD_TRUNCATE_DISABLE (0<<14) +# define R300_MC_COORD_TRUNCATE_MPEG (1<<14) +# define R300_TX_TRI_PERF_0_8 (0<<15) +# define R300_TX_TRI_PERF_1_8 (1<<15) +# define R300_TX_TRI_PERF_1_4 (2<<15) +# define R300_TX_TRI_PERF_3_8 (3<<15) +# define R300_ANISO_THRESHOLD_MASK (7<<17) #define R300_TX_SIZE_0 0x4480 # define R300_TX_WIDTHMASK_SHIFT 0 @@ -722,6 +736,8 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_TX_UNK23 (1 << 23) # define R300_TX_SIZE_SHIFT 26 /* largest of width, height */ # define R300_TX_SIZE_MASK (15 << 26) +# define R300_TX_SIZE_PROJECTED (1<<30) +# define R300_TX_SIZE_TXPITCH_EN (1<<31) #define R300_TX_FORMAT_0 0x44C0 /* The interpretation of the format word by Wladimir van der Laan */ /* The X, Y, Z and W refer to the layout of the components. @@ -750,7 +766,8 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_TX_FORMAT_B8G8_B8G8 0x14 /* no swizzle */ # define R300_TX_FORMAT_G8R8_G8B8 0x15 /* no swizzle */ /* 0x16 - some 16 bit green format.. ?? */ -# define R300_TX_FORMAT_UNK25 (1 << 25) /* no swizzle */ +# define R300_TX_FORMAT_UNK25 (1 << 25) /* no swizzle */ +# define R300_TX_FORMAT_CUBIC_MAP (1 << 26) /* gap */ /* Floating point formats */ @@ -800,18 +817,20 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_TX_FORMAT_YUV_MODE 0x00800000 -#define R300_TX_PITCH_0 0x4500 +#define R300_TX_PITCH_0 0x4500 /* obvious missing in gap */ #define R300_TX_OFFSET_0 0x4540 /* BEGIN: Guess from R200 */ # define R300_TXO_ENDIAN_NO_SWAP (0 << 0) # define R300_TXO_ENDIAN_BYTE_SWAP (1 << 0) # define R300_TXO_ENDIAN_WORD_SWAP (2 << 0) # define R300_TXO_ENDIAN_HALFDW_SWAP (3 << 0) +# define R300_TXO_MACRO_TILE (1 << 2) +# define R300_TXO_MICRO_TILE (1 << 3) # define R300_TXO_OFFSET_MASK 0xffffffe0 # define R300_TXO_OFFSET_SHIFT 5 /* END */ -#define R300_TX_UNK4_0 0x4580 -#define R300_TX_BORDER_COLOR_0 0x45C0 //ff00ff00 == { 0, 1.0, 0, 1.0 } +#define R300_TX_CHROMA_KEY_0 0x4580 /* 32 bit chroma key */ +#define R300_TX_BORDER_COLOR_0 0x45C0 //ff00ff00 == { 0, 1.0, 0, 1.0 } /* END */ @@ -868,7 +887,9 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_PFS_NODE_TEX_OFFSET_MASK (31 << 12) # define R300_PFS_NODE_TEX_END_SHIFT 17 # define R300_PFS_NODE_TEX_END_MASK (31 << 17) -# define R300_PFS_NODE_LAST_NODE (1 << 22) +/*# define R300_PFS_NODE_LAST_NODE (1 << 22) */ +# define R300_PFS_NODE_OUTPUT_COLOR (1 << 22) +# define R300_PFS_NODE_OUTPUT_DEPTH (1 << 23) /* TEX // As far as I can tell, texture instructions cannot write into output @@ -887,6 +908,7 @@ I am fairly certain that they are correct unless stated otherwise in comments. */ # define R300_FPITX_OPCODE_SHIFT 15 # define R300_FPITX_OP_TEX 1 +# define R300_FPITX_OP_KIL 2 # define R300_FPITX_OP_TXP 3 # define R300_FPITX_OP_TXB 4 @@ -962,9 +984,11 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_FPI1_SRC2C_CONST (1 << 17) # define R300_FPI1_DSTC_SHIFT 18 # define R300_FPI1_DSTC_MASK (31 << 18) +# define R300_FPI1_DSTC_REG_MASK_SHIFT 23 # define R300_FPI1_DSTC_REG_X (1 << 23) # define R300_FPI1_DSTC_REG_Y (1 << 24) # define R300_FPI1_DSTC_REG_Z (1 << 25) +# define R300_FPI1_DSTC_OUTPUT_MASK_SHIFT 26 # define R300_FPI1_DSTC_OUTPUT_X (1 << 26) # define R300_FPI1_DSTC_OUTPUT_Y (1 << 27) # define R300_FPI1_DSTC_OUTPUT_Z (1 << 28) @@ -983,6 +1007,7 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_FPI3_DSTA_MASK (31 << 18) # define R300_FPI3_DSTA_REG (1 << 23) # define R300_FPI3_DSTA_OUTPUT (1 << 24) +# define R300_FPI3_DSTA_DEPTH (1 << 27) #define R300_PFS_INSTR0_0 0x48C0 # define R300_FPI0_ARGC_SRC0C_XYZ 0 @@ -1036,7 +1061,7 @@ I am fairly certain that they are correct unless stated otherwise in comments. # define R300_FPI0_OUTC_FRC (9 << 23) # define R300_FPI0_OUTC_REPL_ALPHA (10 << 23) # define R300_FPI0_OUTC_SAT (1 << 30) -# define R300_FPI0_UNKNOWN_31 (1 << 31) +# define R300_FPI0_INSERT_NOP (1 << 31) #define R300_PFS_INSTR2_0 0x49C0 # define R300_FPI2_ARGA_SRC0C_X 0 diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 9bb8ae0c1c27..7f949c9c9691 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -1118,14 +1118,20 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, { u32 ring_start, cur_read_ptr; u32 tmp; - - /* Initialize the memory controller */ - RADEON_WRITE(RADEON_MC_FB_LOCATION, - ((dev_priv->gart_vm_start - 1) & 0xffff0000) - | (dev_priv->fb_location >> 16)); + + /* Initialize the memory controller. With new memory map, the fb location + * is not changed, it should have been properly initialized already. Part + * of the problem is that the code below is bogus, assuming the GART is + * always appended to the fb which is not necessarily the case + */ + if (!dev_priv->new_memmap) + RADEON_WRITE(RADEON_MC_FB_LOCATION, + ((dev_priv->gart_vm_start - 1) & 0xffff0000) + | (dev_priv->fb_location >> 16)); #if __OS_HAS_AGP if (dev_priv->flags & CHIP_IS_AGP) { + RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); RADEON_WRITE(RADEON_MC_AGP_LOCATION, (((dev_priv->gart_vm_start - 1 + dev_priv->gart_size) & 0xffff0000) | @@ -1153,8 +1159,6 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, #if __OS_HAS_AGP if (dev_priv->flags & CHIP_IS_AGP) { - /* set RADEON_AGP_BASE here instead of relying on X from user space */ - RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset - dev->agp->base + dev_priv->gart_vm_start); @@ -1174,6 +1178,17 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, entry->handle + tmp_ofs); } + /* Set ring buffer size */ +#ifdef __BIG_ENDIAN + RADEON_WRITE(RADEON_CP_RB_CNTL, + dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT); +#else + RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw); +#endif + + /* Start with assuming that writeback doesn't work */ + dev_priv->writeback_works = 0; + /* Initialize the scratch register pointer. This will cause * the scratch register values to be written out to memory * whenever they are updated. @@ -1190,7 +1205,38 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, RADEON_WRITE(RADEON_SCRATCH_UMSK, 0x7); - /* Writeback doesn't seem to work everywhere, test it first */ + /* Turn on bus mastering */ + tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; + RADEON_WRITE(RADEON_BUS_CNTL, tmp); + + dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; + RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); + + dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0; + RADEON_WRITE(RADEON_LAST_DISPATCH_REG, + dev_priv->sarea_priv->last_dispatch); + + dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; + RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); + + radeon_do_wait_for_idle(dev_priv); + + /* Sync everything up */ + RADEON_WRITE(RADEON_ISYNC_CNTL, + (RADEON_ISYNC_ANY2D_IDLE3D | + RADEON_ISYNC_ANY3D_IDLE2D | + RADEON_ISYNC_WAIT_IDLEGUI | + RADEON_ISYNC_CPSCRATCH_IDLEGUI)); + +} + +static void radeon_test_writeback(drm_radeon_private_t * dev_priv) +{ + u32 tmp; + + /* Writeback doesn't seem to work everywhere, test it here and possibly + * enable it if it appears to work + */ DRM_WRITE32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0); RADEON_WRITE(RADEON_SCRATCH_REG1, 0xdeadbeef); @@ -1203,46 +1249,15 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, if (tmp < dev_priv->usec_timeout) { dev_priv->writeback_works = 1; - DRM_DEBUG("writeback test succeeded, tmp=%d\n", tmp); + DRM_INFO("writeback test succeeded in %d usecs\n", tmp); } else { dev_priv->writeback_works = 0; - DRM_DEBUG("writeback test failed\n"); + DRM_INFO("writeback test failed\n"); } if (radeon_no_wb == 1) { dev_priv->writeback_works = 0; - DRM_DEBUG("writeback forced off\n"); + DRM_INFO("writeback forced off\n"); } - - dev_priv->sarea_priv->last_frame = dev_priv->scratch[0] = 0; - RADEON_WRITE(RADEON_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame); - - dev_priv->sarea_priv->last_dispatch = dev_priv->scratch[1] = 0; - RADEON_WRITE(RADEON_LAST_DISPATCH_REG, - dev_priv->sarea_priv->last_dispatch); - - dev_priv->sarea_priv->last_clear = dev_priv->scratch[2] = 0; - RADEON_WRITE(RADEON_LAST_CLEAR_REG, dev_priv->sarea_priv->last_clear); - - /* Set ring buffer size */ -#ifdef __BIG_ENDIAN - RADEON_WRITE(RADEON_CP_RB_CNTL, - dev_priv->ring.size_l2qw | RADEON_BUF_SWAP_32BIT); -#else - RADEON_WRITE(RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw); -#endif - - radeon_do_wait_for_idle(dev_priv); - - /* Turn on bus mastering */ - tmp = RADEON_READ(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS; - RADEON_WRITE(RADEON_BUS_CNTL, tmp); - - /* Sync everything up */ - RADEON_WRITE(RADEON_ISYNC_CNTL, - (RADEON_ISYNC_ANY2D_IDLE3D | - RADEON_ISYNC_ANY3D_IDLE2D | - RADEON_ISYNC_WAIT_IDLEGUI | - RADEON_ISYNC_CPSCRATCH_IDLEGUI)); } /* Enable or disable PCI-E GART on the chip */ @@ -1317,6 +1332,14 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) DRM_DEBUG("\n"); + /* if we require new memory map but we don't have it fail */ + if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap) + { + DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX\n"); + radeon_do_cleanup_cp(dev); + return DRM_ERR(EINVAL); + } + if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP)) { DRM_DEBUG("Forcing AGP card to PCI mode\n"); @@ -1496,6 +1519,9 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev_priv->fb_location = (RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff) << 16; + dev_priv->fb_size = + ((RADEON_READ(RADEON_MC_FB_LOCATION) & 0xffff0000u) + 0x10000) + - dev_priv->fb_location; dev_priv->front_pitch_offset = (((dev_priv->front_pitch / 64) << 22) | ((dev_priv->front_offset @@ -1510,8 +1536,46 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) + dev_priv->fb_location) >> 10)); dev_priv->gart_size = init->gart_size; - dev_priv->gart_vm_start = dev_priv->fb_location - + RADEON_READ(RADEON_CONFIG_APER_SIZE); + + /* New let's set the memory map ... */ + if (dev_priv->new_memmap) { + u32 base = 0; + + DRM_INFO("Setting GART location based on new memory map\n"); + + /* If using AGP, try to locate the AGP aperture at the same + * location in the card and on the bus, though we have to + * align it down. + */ +#if __OS_HAS_AGP + if (dev_priv->flags & CHIP_IS_AGP) { + base = dev->agp->base; + /* Check if valid */ + if ((base + dev_priv->gart_size) > dev_priv->fb_location && + base < (dev_priv->fb_location + dev_priv->fb_size)) { + DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n", + dev->agp->base); + base = 0; + } + } +#endif + /* If not or if AGP is at 0 (Macs), try to put it elsewhere */ + if (base == 0) { + base = dev_priv->fb_location + dev_priv->fb_size; + if (((base + dev_priv->gart_size) & 0xfffffffful) + < base) + base = dev_priv->fb_location + - dev_priv->gart_size; + } + dev_priv->gart_vm_start = base & 0xffc00000u; + if (dev_priv->gart_vm_start != base) + DRM_INFO("GART aligned down from 0x%08x to 0x%08x\n", + base, dev_priv->gart_vm_start); + } else { + DRM_INFO("Setting GART location based on old memory map\n"); + dev_priv->gart_vm_start = dev_priv->fb_location + + RADEON_READ(RADEON_CONFIG_APER_SIZE); + } #if __OS_HAS_AGP if (dev_priv->flags & CHIP_IS_AGP) @@ -1596,6 +1660,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev_priv->last_buf = 0; radeon_do_engine_reset(dev); + radeon_test_writeback(dev_priv); return 0; } diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h index 9c177a6b2a4c..c8e279e89c2e 100644 --- a/drivers/char/drm/radeon_drm.h +++ b/drivers/char/drm/radeon_drm.h @@ -222,6 +222,7 @@ typedef union { # define R300_WAIT_3D 0x2 # define R300_WAIT_2D_CLEAN 0x3 # define R300_WAIT_3D_CLEAN 0x4 +#define R300_CMD_SCRATCH 8 typedef union { unsigned int u; @@ -247,6 +248,9 @@ typedef union { struct { unsigned char cmd_type, flags, pad0, pad1; } wait; + struct { + unsigned char cmd_type, reg, n_bufs, flags; + } scratch; } drm_r300_cmd_header_t; #define RADEON_FRONT 0x1 @@ -697,6 +701,7 @@ typedef struct drm_radeon_setparam { #define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ #define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */ #define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */ +#define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */ /* 1.14: Clients can allocate/free a surface */ diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h index 1f7d2ab8c4fc..78345cee8f8e 100644 --- a/drivers/char/drm/radeon_drv.h +++ b/drivers/char/drm/radeon_drv.h @@ -38,7 +38,7 @@ #define DRIVER_NAME "radeon" #define DRIVER_DESC "ATI Radeon" -#define DRIVER_DATE "20051229" +#define DRIVER_DATE "20060225" /* Interface history: * @@ -91,9 +91,11 @@ * 1.20- Add support for r300 texrect * 1.21- Add support for card type getparam * 1.22- Add support for texture cache flushes (R300_TX_CNTL) + * 1.23- Add new radeon memory map work from benh + * 1.24- Add general-purpose packet for manipulating scratch registers (r300) */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 22 +#define DRIVER_MINOR 24 #define DRIVER_PATCHLEVEL 0 /* @@ -101,20 +103,21 @@ */ enum radeon_family { CHIP_R100, - CHIP_RS100, CHIP_RV100, + CHIP_RS100, CHIP_RV200, - CHIP_R200, CHIP_RS200, - CHIP_R250, - CHIP_RS250, + CHIP_R200, CHIP_RV250, + CHIP_RS300, CHIP_RV280, CHIP_R300, - CHIP_RS300, CHIP_R350, CHIP_RV350, + CHIP_RV380, CHIP_R420, + CHIP_RV410, + CHIP_RS400, CHIP_LAST, }; @@ -136,9 +139,11 @@ enum radeon_chip_flags { CHIP_IS_AGP = 0x00080000UL, CHIP_HAS_HIERZ = 0x00100000UL, CHIP_IS_PCIE = 0x00200000UL, + CHIP_NEW_MEMMAP = 0x00400000UL, }; -#define GET_RING_HEAD(dev_priv) DRM_READ32( (dev_priv)->ring_rptr, 0 ) +#define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ + DRM_READ32( (dev_priv)->ring_rptr, 0 ) : RADEON_READ(RADEON_CP_RB_RPTR)) #define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) typedef struct drm_radeon_freelist { @@ -199,6 +204,8 @@ typedef struct drm_radeon_private { drm_radeon_sarea_t *sarea_priv; u32 fb_location; + u32 fb_size; + int new_memmap; int gart_size; u32 gart_vm_start; @@ -272,6 +279,8 @@ typedef struct drm_radeon_private { unsigned long pcigart_offset; drm_ati_pcigart_info gart_info; + u32 scratch_ages[5]; + /* starting from here on, data is preserved accross an open */ uint32_t flags; /* see radeon_chip_flags */ } drm_radeon_private_t; diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c index 7bc27516d425..c5b8f774a599 100644 --- a/drivers/char/drm/radeon_state.c +++ b/drivers/char/drm/radeon_state.c @@ -45,22 +45,53 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * u32 off = *offset; struct drm_radeon_driver_file_fields *radeon_priv; - if (off >= dev_priv->fb_location && - off < (dev_priv->gart_vm_start + dev_priv->gart_size)) + /* Hrm ... the story of the offset ... So this function converts + * the various ideas of what userland clients might have for an + * offset in the card address space into an offset into the card + * address space :) So with a sane client, it should just keep + * the value intact and just do some boundary checking. However, + * not all clients are sane. Some older clients pass us 0 based + * offsets relative to the start of the framebuffer and some may + * assume the AGP aperture it appended to the framebuffer, so we + * try to detect those cases and fix them up. + * + * Note: It might be a good idea here to make sure the offset lands + * in some "allowed" area to protect things like the PCIE GART... + */ + + /* First, the best case, the offset already lands in either the + * framebuffer or the GART mapped space + */ + if ((off >= dev_priv->fb_location && + off < (dev_priv->fb_location + dev_priv->fb_size)) || + (off >= dev_priv->gart_vm_start && + off < (dev_priv->gart_vm_start + dev_priv->gart_size))) return 0; - radeon_priv = filp_priv->driver_priv; - off += radeon_priv->radeon_fb_delta; + /* Ok, that didn't happen... now check if we have a zero based + * offset that fits in the framebuffer + gart space, apply the + * magic offset we get from SETPARAM or calculated from fb_location + */ + if (off < (dev_priv->fb_size + dev_priv->gart_size)) { + radeon_priv = filp_priv->driver_priv; + off += radeon_priv->radeon_fb_delta; + } - DRM_DEBUG("offset fixed up to 0x%x\n", off); + /* Finally, assume we aimed at a GART offset if beyond the fb */ + if (off > (dev_priv->fb_location + dev_priv->fb_size)) + off = off - (dev_priv->fb_location + dev_priv->fb_size) + + dev_priv->gart_vm_start; - if (off < dev_priv->fb_location || - off >= (dev_priv->gart_vm_start + dev_priv->gart_size)) - return DRM_ERR(EINVAL); - - *offset = off; - - return 0; + /* Now recheck and fail if out of bounds */ + if ((off >= dev_priv->fb_location && + off < (dev_priv->fb_location + dev_priv->fb_size)) || + (off >= dev_priv->gart_vm_start && + off < (dev_priv->gart_vm_start + dev_priv->gart_size))) { + DRM_DEBUG("offset fixed up to 0x%x\n", off); + *offset = off; + return 0; + } + return DRM_ERR(EINVAL); } static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * @@ -1939,11 +1970,6 @@ static int radeon_surface_alloc(DRM_IOCTL_ARGS) drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_surface_alloc_t alloc; - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); - } - DRM_COPY_FROM_USER_IOCTL(alloc, (drm_radeon_surface_alloc_t __user *) data, sizeof(alloc)); @@ -1960,12 +1986,7 @@ static int radeon_surface_free(DRM_IOCTL_ARGS) drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_surface_free_t memfree; - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); - } - - DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data, + DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data, sizeof(memfree)); if (free_surface(filp, dev_priv, memfree.address)) @@ -2100,11 +2121,6 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS) LOCK_TEST_WITH_RETURN(dev, filp); - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); - } - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data, @@ -2189,11 +2205,6 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS) LOCK_TEST_WITH_RETURN(dev, filp); - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); - } - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data, @@ -2340,11 +2351,6 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS) LOCK_TEST_WITH_RETURN(dev, filp); - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); - } - DRM_COPY_FROM_USER_IOCTL(indirect, (drm_radeon_indirect_t __user *) data, sizeof(indirect)); @@ -2417,11 +2423,6 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS) LOCK_TEST_WITH_RETURN(dev, filp); - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); - } - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data, @@ -2738,11 +2739,6 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS) LOCK_TEST_WITH_RETURN(dev, filp); - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); - } - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); DRM_COPY_FROM_USER_IOCTL(cmdbuf, @@ -2897,11 +2893,6 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS) drm_radeon_getparam_t param; int value; - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); - } - DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data, sizeof(param)); @@ -2981,11 +2972,6 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) drm_radeon_setparam_t sp; struct drm_radeon_driver_file_fields *radeon_priv; - if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); - return DRM_ERR(EINVAL); - } - DRM_GET_PRIV_WITH_RETURN(filp_priv, filp); DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data, @@ -3012,6 +2998,9 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS) case RADEON_SETPARAM_PCIGART_LOCATION: dev_priv->pcigart_offset = sp.value; break; + case RADEON_SETPARAM_NEW_MEMMAP: + dev_priv->new_memmap = sp.value; + break; default: DRM_DEBUG("Invalid parameter %d\n", sp.param); return DRM_ERR(EINVAL); diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c index 6774d2fe3452..5e9936bc307f 100644 --- a/drivers/char/drm/sis_mm.c +++ b/drivers/char/drm/sis_mm.c @@ -110,7 +110,7 @@ static int sis_fb_alloc(DRM_IOCTL_ARGS) DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb)); - DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset); + DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset); return retval; } diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c index 6152415644e9..c33d068cde19 100644 --- a/drivers/char/drm/via_irq.c +++ b/drivers/char/drm/via_irq.c @@ -196,9 +196,9 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; unsigned int cur_irq_sequence; - drm_via_irq_t *cur_irq = dev_priv->via_irqs; + drm_via_irq_t *cur_irq; int ret = 0; - maskarray_t *masks = dev_priv->irq_masks; + maskarray_t *masks; int real_irq; DRM_DEBUG("%s\n", __FUNCTION__); @@ -221,8 +221,9 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, __FUNCTION__, irq); return DRM_ERR(EINVAL); } - - cur_irq += real_irq; + + masks = dev_priv->irq_masks; + cur_irq = dev_priv->via_irqs + real_irq; if (masks[real_irq][2] && !force_sequence) { DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ, @@ -247,11 +248,12 @@ void via_driver_irq_preinstall(drm_device_t * dev) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; u32 status; - drm_via_irq_t *cur_irq = dev_priv->via_irqs; + drm_via_irq_t *cur_irq; int i; DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv); if (dev_priv) { + cur_irq = dev_priv->via_irqs; dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE; dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING; diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index a229915ce1b2..87dcaa237f07 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -490,7 +490,7 @@ for (i = 0; i < 10; i++) \ release_region(dtlk_portlist[i], DTLK_IO_EXTENT); } - printk(KERN_INFO "\nDoubleTalk PC - not found\n"); + printk(KERN_INFO "DoubleTalk PC - not found\n"); return -ENODEV; } diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c index 1b5e01e6e129..43ff59816511 100644 --- a/drivers/char/generic_nvram.c +++ b/drivers/char/generic_nvram.c @@ -22,6 +22,9 @@ #include #include #include +#ifdef CONFIG_PPC_PMAC +#include +#endif #define NVRAM_SIZE 8192 @@ -92,7 +95,7 @@ static int nvram_ioctl(struct inode *inode, struct file *file, case IOC_NVRAM_GET_OFFSET: { int part, offset; - if (_machine != _MACH_Pmac) + if (!machine_is(powermac)) return -EINVAL; if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0) return -EFAULT; diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index f65b2e14a485..2b6a56b2bf35 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -39,8 +39,10 @@ #include #include #include + #include -#include + +#include "hvc_console.h" #define HVC_MAJOR 229 #define HVC_MINOR 0 @@ -54,17 +56,14 @@ #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ /* - * The Linux TTY code does not support dynamic addition of tty derived devices - * so we need to know how many tty devices we might need when space is allocated - * for the tty device. Since this driver supports hotplug of vty adapters we - * need to make sure we have enough allocated. + * These sizes are most efficient for vio, because they are the + * native transfer size. We could make them selectable in the + * future to better deal with backends that want other buffer sizes. */ -#define HVC_ALLOC_TTY_ADAPTERS 8 - #define N_OUTBUF 16 #define N_INBUF 16 -#define __ALIGNED__ __attribute__((__aligned__(8))) +#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) static struct tty_driver *hvc_driver; static struct task_struct *hvc_task; @@ -154,7 +153,7 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = void hvc_console_print(struct console *co, const char *b, unsigned count) { - char c[16] __ALIGNED__; + char c[N_OUTBUF] __ALIGNED__; unsigned i = 0, n = 0; int r, donecr = 0, index = co->index; @@ -473,8 +472,10 @@ static void hvc_push(struct hvc_struct *hp) n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); if (n <= 0) { - if (n == 0) + if (n == 0) { + hp->do_wakeup = 1; return; + } /* throw away output on error; this happens when there is no session connected to the vterm. */ hp->n_outbuf = 0; @@ -486,12 +487,19 @@ static void hvc_push(struct hvc_struct *hp) hp->do_wakeup = 1; } -static inline int __hvc_write_kernel(struct hvc_struct *hp, - const unsigned char *buf, int count) +static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) { + struct hvc_struct *hp = tty->driver_data; unsigned long flags; int rsize, written = 0; + /* This write was probably executed during a tty close. */ + if (!hp) + return -EPIPE; + + if (hp->count <= 0) + return -EIO; + spin_lock_irqsave(&hp->lock, flags); /* Push pending writes */ @@ -510,26 +518,8 @@ static inline int __hvc_write_kernel(struct hvc_struct *hp, } spin_unlock_irqrestore(&hp->lock, flags); - return written; -} -static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - struct hvc_struct *hp = tty->driver_data; - int written; - - /* This write was probably executed during a tty close. */ - if (!hp) - return -EPIPE; - - if (hp->count <= 0) - return -EIO; - - written = __hvc_write_kernel(hp, buf, count); - /* * Racy, but harmless, kick thread if there is still pending data. - * There really is nothing wrong with kicking the thread, even if there - * is no buffered data. */ if (hp->n_outbuf) hvc_kick(); @@ -614,6 +604,13 @@ static int hvc_poll(struct hvc_struct *hp) spin_unlock_irqrestore(&hp->lock, flags); tty_hangup(tty); spin_lock_irqsave(&hp->lock, flags); + } else if ( n == -EAGAIN ) { + /* + * Some back-ends can only ensure a certain min + * num of bytes read, which may be > 'count'. + * Let the tty clear the flip buff to make room. + */ + poll_mask |= HVC_POLL_READ; } break; } @@ -635,16 +632,7 @@ static int hvc_poll(struct hvc_struct *hp) tty_insert_flip_char(tty, buf[i], 0); } - /* - * Account for the total amount read in one loop, and if above - * 64 bytes, we do a quick schedule loop to let the tty grok - * the data and eventually throttle us. - */ read_total += n; - if (read_total >= 64) { - poll_mask |= HVC_POLL_QUICK; - break; - } } throttled: /* Wakeup write queue if necessary */ @@ -767,7 +755,8 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, * see if this vterm id matches one registered for console. */ for (i=0; i < MAX_NR_HVC_CONSOLES; i++) - if (vtermnos[i] == hp->vtermno) + if (vtermnos[i] == hp->vtermno && + cons_ops[i] == hp->ops) break; /* no matching slot, just use a counter */ @@ -823,34 +812,38 @@ EXPORT_SYMBOL(hvc_remove); * interfaces start to become available. */ int __init hvc_init(void) { + struct tty_driver *drv; + /* We need more than hvc_count adapters due to hotplug additions. */ - hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); - if (!hvc_driver) + drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); + if (!drv) return -ENOMEM; - hvc_driver->owner = THIS_MODULE; - hvc_driver->devfs_name = "hvc/"; - hvc_driver->driver_name = "hvc"; - hvc_driver->name = "hvc"; - hvc_driver->major = HVC_MAJOR; - hvc_driver->minor_start = HVC_MINOR; - hvc_driver->type = TTY_DRIVER_TYPE_SYSTEM; - hvc_driver->init_termios = tty_std_termios; - hvc_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(hvc_driver, &hvc_ops); + drv->owner = THIS_MODULE; + drv->devfs_name = "hvc/"; + drv->driver_name = "hvc"; + drv->name = "hvc"; + drv->major = HVC_MAJOR; + drv->minor_start = HVC_MINOR; + drv->type = TTY_DRIVER_TYPE_SYSTEM; + drv->init_termios = tty_std_termios; + drv->flags = TTY_DRIVER_REAL_RAW; + tty_set_operations(drv, &hvc_ops); /* Always start the kthread because there can be hotplug vty adapters * added later. */ hvc_task = kthread_run(khvcd, NULL, "khvcd"); if (IS_ERR(hvc_task)) { panic("Couldn't create kthread for console.\n"); - put_tty_driver(hvc_driver); + put_tty_driver(drv); return -EIO; } - if (tty_register_driver(hvc_driver)) + if (tty_register_driver(drv)) panic("Couldn't register hvc console driver\n"); + mb(); + hvc_driver = drv; return 0; } module_init(hvc_init); diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h new file mode 100644 index 000000000000..96b7401319c1 --- /dev/null +++ b/drivers/char/hvc_console.h @@ -0,0 +1,63 @@ +/* + * hvc_console.h + * Copyright (C) 2005 IBM Corporation + * + * Author(s): + * Ryan S. Arnold + * + * hvc_console header information: + * moved here from include/asm-powerpc/hvconsole.h + * and drivers/char/hvc_console.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 + */ + +#ifndef HVC_CONSOLE_H +#define HVC_CONSOLE_H + +/* + * This is the max number of console adapters that can/will be found as + * console devices on first stage console init. Any number beyond this range + * can't be used as a console device but is still a valid tty device. + */ +#define MAX_NR_HVC_CONSOLES 16 + +/* + * The Linux TTY code does not support dynamic addition of tty derived devices + * so we need to know how many tty devices we might need when space is allocated + * for the tty device. Since this driver supports hotplug of vty adapters we + * need to make sure we have enough allocated. + */ +#define HVC_ALLOC_TTY_ADAPTERS 8 + + +/* implemented by a low level driver */ +struct hv_ops { + int (*get_chars)(uint32_t vtermno, char *buf, int count); + int (*put_chars)(uint32_t vtermno, const char *buf, int count); +}; + +struct hvc_struct; + +/* Register a vterm and a slot index for use as a console (console_init) */ +extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); + +/* register a vterm for hvc tty operation (module_init or hotplug add) */ +extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq, + struct hv_ops *ops); +/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ +extern int __devexit hvc_remove(struct hvc_struct *hp); + +#endif // HVC_CONSOLE_H diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c new file mode 100644 index 000000000000..83364ea63cba --- /dev/null +++ b/drivers/char/hvc_rtas.c @@ -0,0 +1,138 @@ +/* + * IBM RTAS driver interface to hvc_console.c + * + * (C) Copyright IBM Corporation 2001-2005 + * (C) Copyright Red Hat, Inc. 2005 + * + * Author(s): Maximino Augilar + * : Ryan S. Arnold + * : Utz Bacher + * : David Woodhouse + * + * inspired by drivers/char/hvc_console.c + * written by Anton Blanchard and Paul Mackerras + * + * 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 "hvc_console.h" + +#define hvc_rtas_cookie 0x67781e15 +struct hvc_struct *hvc_rtas_dev; + +#define RTASCONS_PUT_ATTEMPTS 16 + +static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE; +static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE; +static int rtascons_put_delay = 100; +module_param_named(put_delay, rtascons_put_delay, int, 0644); + +static inline int hvc_rtas_write_console(uint32_t vtermno, const char *buf, int count) +{ + int done; + + /* if there is more than one character to be displayed, wait a bit */ + for (done = 0; done < count; done++) { + int result; + result = rtas_call(rtascons_put_char_token, 1, 1, NULL, buf[done]); + if (result) + break; + } + /* the calling routine expects to receive the number of bytes sent */ + return done; +} + +static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) +{ + int i; + + for (i = 0; i < count; i++) { + int c, err; + + err = rtas_call(rtascons_get_char_token, 0, 2, &c); + if (err) + break; + + buf[i] = c; + } + + return i; +} + +static struct hv_ops hvc_rtas_get_put_ops = { + .get_chars = hvc_rtas_read_console, + .put_chars = hvc_rtas_write_console, +}; + +static int hvc_rtas_init(void) +{ + struct hvc_struct *hp; + + if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) + rtascons_put_char_token = rtas_token("put-term-char"); + if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) + return -EIO; + + if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) + rtascons_get_char_token = rtas_token("get-term-char"); + if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) + return -EIO; + + BUG_ON(hvc_rtas_dev); + + /* Allocate an hvc_struct for the console device we instantiated + * earlier. Save off hp so that we can return it on exit */ + hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops); + if (IS_ERR(hp)) + return PTR_ERR(hp); + hvc_rtas_dev = hp; + return 0; +} +module_init(hvc_rtas_init); + +/* This will tear down the tty portion of the driver */ +static void __exit hvc_rtas_exit(void) +{ + /* Really the fun isn't over until the worker thread breaks down and the + * tty cleans up */ + if (hvc_rtas_dev) + hvc_remove(hvc_rtas_dev); +} +module_exit(hvc_rtas_exit); + +/* This will happen prior to module init. There is no tty at this time? */ +static int hvc_rtas_console_init(void) +{ + rtascons_put_char_token = rtas_token("put-term-char"); + if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE) + return -EIO; + rtascons_get_char_token = rtas_token("get-term-char"); + if (rtascons_get_char_token == RTAS_UNKNOWN_SERVICE) + return -EIO; + + hvc_instantiate(hvc_rtas_cookie, 0, &hvc_rtas_get_put_ops ); + add_preferred_console("hvc", 0, NULL); + return 0; +} +console_initcall(hvc_rtas_console_init); diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index f5212eb2b41d..9add81ceb440 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -31,10 +31,13 @@ #include #include + #include #include #include +#include "hvc_console.h" + char hvc_driver_name[] = "hvc_console"; static struct vio_device_id hvc_driver_table[] __devinitdata = { @@ -48,6 +51,14 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count) unsigned long got; int i; + /* + * Vio firmware will read up to SIZE_VIO_GET_CHARS at its own discretion + * so we play safe and avoid the situation where got > count which could + * overload the flip buffer. + */ + if (count < SIZE_VIO_GET_CHARS) + return -EAGAIN; + got = hvc_get_chars(vtermno, buf, count); /* diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index f7ac31856572..8d97b3911293 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -439,7 +439,6 @@ static int hvcs_io(struct hvcs_struct *hvcsd) char buf[HVCS_BUFF_LEN] __ALIGNED__; unsigned long flags; int got = 0; - int i; spin_lock_irqsave(&hvcsd->lock, flags); @@ -905,7 +904,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, * It is possible the vty-server was removed after the irq was * requested but before we have time to enable interrupts. */ - if (vio_enable_interrupts(vdev) == H_Success) + if (vio_enable_interrupts(vdev) == H_SUCCESS) return 0; else { printk(KERN_ERR "HVCS: int enable failed for" diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 932feedda262..e1c95374984c 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include @@ -55,7 +55,7 @@ struct ipmi_file_private struct file *file; struct fasync_struct *fasync_queue; wait_queue_head_t wait; - struct semaphore recv_sem; + struct mutex recv_mutex; int default_retries; unsigned int default_retry_time_ms; }; @@ -141,7 +141,7 @@ static int ipmi_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&(priv->recv_msgs)); init_waitqueue_head(&priv->wait); priv->fasync_queue = NULL; - sema_init(&(priv->recv_sem), 1); + mutex_init(&priv->recv_mutex); /* Use the low-level defaults. */ priv->default_retries = -1; @@ -285,15 +285,15 @@ static int ipmi_ioctl(struct inode *inode, break; } - /* We claim a semaphore because we don't want two + /* We claim a mutex because we don't want two users getting something from the queue at a time. Since we have to release the spinlock before we can copy the data to the user, it's possible another user will grab something from the queue, too. Then the messages might get out of order if something fails and the message gets put back onto the - queue. This semaphore prevents that problem. */ - down(&(priv->recv_sem)); + queue. This mutex prevents that problem. */ + mutex_lock(&priv->recv_mutex); /* Grab the message off the list. */ spin_lock_irqsave(&(priv->recv_msg_lock), flags); @@ -352,7 +352,7 @@ static int ipmi_ioctl(struct inode *inode, goto recv_putback_on_err; } - up(&(priv->recv_sem)); + mutex_unlock(&priv->recv_mutex); ipmi_free_recv_msg(msg); break; @@ -362,11 +362,11 @@ static int ipmi_ioctl(struct inode *inode, spin_lock_irqsave(&(priv->recv_msg_lock), flags); list_add(entry, &(priv->recv_msgs)); spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); - up(&(priv->recv_sem)); + mutex_unlock(&priv->recv_mutex); break; recv_err: - up(&(priv->recv_sem)); + mutex_unlock(&priv->recv_mutex); break; } diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index da1554194d3d..2062675f9e99 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -227,7 +227,7 @@ static inline int check_ibf(struct si_sm_data *kcs, unsigned char status, static inline int check_obf(struct si_sm_data *kcs, unsigned char status, long time) { - if (! GET_STATUS_OBF(status)) { + if (!GET_STATUS_OBF(status)) { kcs->obf_timeout -= time; if (kcs->obf_timeout < 0) { start_error_recovery(kcs, "OBF not ready in time"); @@ -407,7 +407,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) } if (state == KCS_READ_STATE) { - if (! check_obf(kcs, status, time)) + if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; read_next_byte(kcs); } else { @@ -447,7 +447,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) "Not in read state for error2"); break; } - if (! check_obf(kcs, status, time)) + if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; clear_obf(kcs, status); @@ -462,7 +462,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) break; } - if (! check_obf(kcs, status, time)) + if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; clear_obf(kcs, status); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 40eb005b9d77..9f2f8fdec69a 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -234,7 +235,7 @@ struct ipmi_smi /* The list of command receivers that are registered for commands on this interface. */ - struct semaphore cmd_rcvrs_lock; + struct mutex cmd_rcvrs_mutex; struct list_head cmd_rcvrs; /* Events that were queues because no one was there to receive @@ -387,10 +388,10 @@ static void clean_up_interface_data(ipmi_smi_t intf) /* Wholesale remove all the entries from the list in the * interface and wait for RCU to know that none are in use. */ - down(&intf->cmd_rcvrs_lock); + mutex_lock(&intf->cmd_rcvrs_mutex); list_add_rcu(&list, &intf->cmd_rcvrs); list_del_rcu(&intf->cmd_rcvrs); - up(&intf->cmd_rcvrs_lock); + mutex_unlock(&intf->cmd_rcvrs_mutex); synchronize_rcu(); list_for_each_entry_safe(rcvr, rcvr2, &list, link) @@ -557,7 +558,7 @@ unsigned int ipmi_addr_length(int addr_type) static void deliver_response(struct ipmi_recv_msg *msg) { - if (! msg->user) { + if (!msg->user) { ipmi_smi_t intf = msg->user_msg_data; unsigned long flags; @@ -598,11 +599,11 @@ static int intf_next_seq(ipmi_smi_t intf, (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; i = (i+1)%IPMI_IPMB_NUM_SEQ) { - if (! intf->seq_table[i].inuse) + if (!intf->seq_table[i].inuse) break; } - if (! intf->seq_table[i].inuse) { + if (!intf->seq_table[i].inuse) { intf->seq_table[i].recv_msg = recv_msg; /* Start with the maximum timeout, when the send response @@ -763,7 +764,7 @@ int ipmi_create_user(unsigned int if_num, } new_user = kmalloc(sizeof(*new_user), GFP_KERNEL); - if (! new_user) + if (!new_user) return -ENOMEM; spin_lock_irqsave(&interfaces_lock, flags); @@ -819,14 +820,13 @@ static void free_user(struct kref *ref) int ipmi_destroy_user(ipmi_user_t user) { - int rv = -ENODEV; ipmi_smi_t intf = user->intf; int i; unsigned long flags; struct cmd_rcvr *rcvr; struct cmd_rcvr *rcvrs = NULL; - user->valid = 1; + user->valid = 0; /* Remove the user from the interface's sequence table. */ spin_lock_irqsave(&intf->seq_lock, flags); @@ -847,7 +847,7 @@ int ipmi_destroy_user(ipmi_user_t user) * since other things may be using it till we do * synchronize_rcu()) then free everything in that list. */ - down(&intf->cmd_rcvrs_lock); + mutex_lock(&intf->cmd_rcvrs_mutex); list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { if (rcvr->user == user) { list_del_rcu(&rcvr->link); @@ -855,7 +855,7 @@ int ipmi_destroy_user(ipmi_user_t user) rcvrs = rcvr; } } - up(&intf->cmd_rcvrs_lock); + mutex_unlock(&intf->cmd_rcvrs_mutex); synchronize_rcu(); while (rcvrs) { rcvr = rcvrs; @@ -871,7 +871,7 @@ int ipmi_destroy_user(ipmi_user_t user) kref_put(&user->refcount, free_user); - return rv; + return 0; } void ipmi_get_version(ipmi_user_t user, @@ -936,10 +936,12 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) if (val) { /* Deliver any queued events. */ - list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) { + list_for_each_entry_safe(msg, msg2, &intf->waiting_events, + link) { list_del(&msg->link); list_add_tail(&msg->link, &msgs); } + intf->waiting_events_count = 0; } /* Hold the events lock while doing this to preserve order. */ @@ -978,13 +980,13 @@ int ipmi_register_for_cmd(ipmi_user_t user, rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL); - if (! rcvr) + if (!rcvr) return -ENOMEM; rcvr->cmd = cmd; rcvr->netfn = netfn; rcvr->user = user; - down(&intf->cmd_rcvrs_lock); + mutex_lock(&intf->cmd_rcvrs_mutex); /* Make sure the command/netfn is not already registered. */ entry = find_cmd_rcvr(intf, netfn, cmd); if (entry) { @@ -995,7 +997,7 @@ int ipmi_register_for_cmd(ipmi_user_t user, list_add_rcu(&rcvr->link, &intf->cmd_rcvrs); out_unlock: - up(&intf->cmd_rcvrs_lock); + mutex_unlock(&intf->cmd_rcvrs_mutex); if (rv) kfree(rcvr); @@ -1009,17 +1011,17 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, ipmi_smi_t intf = user->intf; struct cmd_rcvr *rcvr; - down(&intf->cmd_rcvrs_lock); + mutex_lock(&intf->cmd_rcvrs_mutex); /* Make sure the command/netfn is not already registered. */ rcvr = find_cmd_rcvr(intf, netfn, cmd); if ((rcvr) && (rcvr->user == user)) { list_del_rcu(&rcvr->link); - up(&intf->cmd_rcvrs_lock); + mutex_unlock(&intf->cmd_rcvrs_mutex); synchronize_rcu(); kfree(rcvr); return 0; } else { - up(&intf->cmd_rcvrs_lock); + mutex_unlock(&intf->cmd_rcvrs_mutex); return -ENOENT; } } @@ -1514,7 +1516,7 @@ int ipmi_request_settime(ipmi_user_t user, unsigned char saddr, lun; int rv; - if (! user) + if (!user) return -EINVAL; rv = check_addr(user->intf, addr, &saddr, &lun); if (rv) @@ -1545,7 +1547,7 @@ int ipmi_request_supply_msgs(ipmi_user_t user, unsigned char saddr, lun; int rv; - if (! user) + if (!user) return -EINVAL; rv = check_addr(user->intf, addr, &saddr, &lun); if (rv) @@ -1570,7 +1572,7 @@ static int ipmb_file_read_proc(char *page, char **start, off_t off, char *out = (char *) page; ipmi_smi_t intf = data; int i; - int rv= 0; + int rv = 0; for (i = 0; i < IPMI_MAX_CHANNELS; i++) rv += sprintf(out+rv, "%x ", intf->channels[i].address); @@ -1989,7 +1991,7 @@ static int ipmi_bmc_register(ipmi_smi_t intf) } else { bmc->dev = platform_device_alloc("ipmi_bmc", bmc->id.device_id); - if (! bmc->dev) { + if (!bmc->dev) { printk(KERN_ERR "ipmi_msghandler:" " Unable to allocate platform device\n"); @@ -2305,8 +2307,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, void *send_info, struct ipmi_device_id *device_id, struct device *si_dev, - unsigned char slave_addr, - ipmi_smi_t *new_intf) + unsigned char slave_addr) { int i, j; int rv; @@ -2366,7 +2367,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, spin_lock_init(&intf->events_lock); INIT_LIST_HEAD(&intf->waiting_events); intf->waiting_events_count = 0; - init_MUTEX(&intf->cmd_rcvrs_lock); + mutex_init(&intf->cmd_rcvrs_mutex); INIT_LIST_HEAD(&intf->cmd_rcvrs); init_waitqueue_head(&intf->waitq); @@ -2388,9 +2389,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, if (rv) goto out; - /* FIXME - this is an ugly kludge, this sets the intf for the - caller before sending any messages with it. */ - *new_intf = intf; + rv = handlers->start_processing(send_info, intf); + if (rv) + goto out; get_guid(intf); @@ -2622,7 +2623,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, spin_unlock_irqrestore(&intf->counter_lock, flags); recv_msg = ipmi_alloc_recv_msg(); - if (! recv_msg) { + if (!recv_msg) { /* We couldn't allocate memory for the message, so requeue it for handling later. */ @@ -2777,7 +2778,7 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, spin_unlock_irqrestore(&intf->counter_lock, flags); recv_msg = ipmi_alloc_recv_msg(); - if (! recv_msg) { + if (!recv_msg) { /* We couldn't allocate memory for the message, so requeue it for handling later. */ @@ -2869,13 +2870,14 @@ static int handle_read_event_rsp(ipmi_smi_t intf, events. */ rcu_read_lock(); list_for_each_entry_rcu(user, &intf->users, link) { - if (! user->gets_events) + if (!user->gets_events) continue; recv_msg = ipmi_alloc_recv_msg(); - if (! recv_msg) { + if (!recv_msg) { rcu_read_unlock(); - list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) { + list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, + link) { list_del(&recv_msg->link); ipmi_free_recv_msg(recv_msg); } @@ -2905,7 +2907,7 @@ static int handle_read_event_rsp(ipmi_smi_t intf, /* No one to receive the message, put it in queue if there's not already too many things in the queue. */ recv_msg = ipmi_alloc_recv_msg(); - if (! recv_msg) { + if (!recv_msg) { /* We couldn't allocate memory for the message, so requeue it for handling later. */ @@ -2915,6 +2917,7 @@ static int handle_read_event_rsp(ipmi_smi_t intf, copy_event_into_recv_msg(recv_msg, msg); list_add_tail(&(recv_msg->link), &(intf->waiting_events)); + intf->waiting_events_count++; } else { /* There's too many things in the queue, discard this message. */ @@ -3190,7 +3193,7 @@ void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) rcu_read_lock(); list_for_each_entry_rcu(user, &intf->users, link) { - if (! user->handler->ipmi_watchdog_pretimeout) + if (!user->handler->ipmi_watchdog_pretimeout) continue; user->handler->ipmi_watchdog_pretimeout(user->handler_data); @@ -3278,7 +3281,7 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot, ent->seqid); - if (! smi_msg) + if (!smi_msg) return; spin_unlock_irqrestore(&intf->seq_lock, *flags); @@ -3314,8 +3317,9 @@ static void ipmi_timeout_handler(long timeout_period) /* See if any waiting messages need to be processed. */ spin_lock_irqsave(&intf->waiting_msgs_lock, flags); - list_for_each_entry_safe(smi_msg, smi_msg2, &intf->waiting_msgs, link) { - if (! handle_new_recv_msg(intf, smi_msg)) { + list_for_each_entry_safe(smi_msg, smi_msg2, + &intf->waiting_msgs, link) { + if (!handle_new_recv_msg(intf, smi_msg)) { list_del(&smi_msg->link); ipmi_free_smi_msg(smi_msg); } else { diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 786a2802ca34..d0b5c08e7b4e 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -346,7 +346,7 @@ static int ipmi_dell_chassis_detect (ipmi_user_t user) { const char ipmi_version_major = ipmi_version & 0xF; const char ipmi_version_minor = (ipmi_version >> 4) & 0xF; - const char mfr[3]=DELL_IANA_MFR_ID; + const char mfr[3] = DELL_IANA_MFR_ID; if (!memcmp(mfr, &mfg_id, sizeof(mfr)) && ipmi_version_major <= 1 && ipmi_version_minor < 5) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 35fbd4d8ed4b..a86c0f29953e 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -803,7 +803,7 @@ static int ipmi_thread(void *data) set_user_nice(current, 19); while (!kthread_should_stop()) { spin_lock_irqsave(&(smi_info->si_lock), flags); - smi_result=smi_event_handler(smi_info, 0); + smi_result = smi_event_handler(smi_info, 0); spin_unlock_irqrestore(&(smi_info->si_lock), flags); if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { /* do nothing */ @@ -972,10 +972,37 @@ static irqreturn_t si_bt_irq_handler(int irq, void *data, struct pt_regs *regs) return si_irq_handler(irq, data, regs); } +static int smi_start_processing(void *send_info, + ipmi_smi_t intf) +{ + struct smi_info *new_smi = send_info; + + new_smi->intf = intf; + + /* Set up the timer that drives the interface. */ + setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi); + new_smi->last_timeout_jiffies = jiffies; + mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES); + + if (new_smi->si_type != SI_BT) { + new_smi->thread = kthread_run(ipmi_thread, new_smi, + "kipmi%d", new_smi->intf_num); + if (IS_ERR(new_smi->thread)) { + printk(KERN_NOTICE "ipmi_si_intf: Could not start" + " kernel thread due to error %ld, only using" + " timers to drive the interface\n", + PTR_ERR(new_smi->thread)); + new_smi->thread = NULL; + } + } + + return 0; +} static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, + .start_processing = smi_start_processing, .sender = sender, .request_events = request_events, .set_run_to_completion = set_run_to_completion, @@ -987,7 +1014,7 @@ static struct ipmi_smi_handlers handlers = #define SI_MAX_PARMS 4 static LIST_HEAD(smi_infos); -static DECLARE_MUTEX(smi_infos_lock); +static DEFINE_MUTEX(smi_infos_lock); static int smi_num; /* Used to sequence the SMIs */ #define DEFAULT_REGSPACING 1 @@ -2162,9 +2189,13 @@ static void setup_xaction_handlers(struct smi_info *smi_info) static inline void wait_for_timer_and_thread(struct smi_info *smi_info) { - if (smi_info->thread != NULL && smi_info->thread != ERR_PTR(-ENOMEM)) - kthread_stop(smi_info->thread); - del_timer_sync(&smi_info->si_timer); + if (smi_info->intf) { + /* The timer and thread are only running if the + interface has been started up and registered. */ + if (smi_info->thread != NULL) + kthread_stop(smi_info->thread); + del_timer_sync(&smi_info->si_timer); + } } static struct ipmi_default_vals @@ -2245,7 +2276,7 @@ static int try_smi_init(struct smi_info *new_smi) new_smi->slave_addr, new_smi->irq); } - down(&smi_infos_lock); + mutex_lock(&smi_infos_lock); if (!is_new_interface(new_smi)) { printk(KERN_WARNING "ipmi_si: duplicate interface\n"); rv = -EBUSY; @@ -2341,21 +2372,6 @@ static int try_smi_init(struct smi_info *new_smi) if (new_smi->irq) new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ; - /* The ipmi_register_smi() code does some operations to - determine the channel information, so we must be ready to - handle operations before it is called. This means we have - to stop the timer if we get an error after this point. */ - init_timer(&(new_smi->si_timer)); - new_smi->si_timer.data = (long) new_smi; - new_smi->si_timer.function = smi_timeout; - new_smi->last_timeout_jiffies = jiffies; - new_smi->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; - - add_timer(&(new_smi->si_timer)); - if (new_smi->si_type != SI_BT) - new_smi->thread = kthread_run(ipmi_thread, new_smi, - "kipmi%d", new_smi->intf_num); - if (!new_smi->dev) { /* If we don't already have a device from something * else (like PCI), then register a new one. */ @@ -2365,7 +2381,7 @@ static int try_smi_init(struct smi_info *new_smi) printk(KERN_ERR "ipmi_si_intf:" " Unable to allocate platform device\n"); - goto out_err_stop_timer; + goto out_err; } new_smi->dev = &new_smi->pdev->dev; new_smi->dev->driver = &ipmi_driver; @@ -2377,7 +2393,7 @@ static int try_smi_init(struct smi_info *new_smi) " Unable to register system interface device:" " %d\n", rv); - goto out_err_stop_timer; + goto out_err; } new_smi->dev_registered = 1; } @@ -2386,8 +2402,7 @@ static int try_smi_init(struct smi_info *new_smi) new_smi, &new_smi->device_id, new_smi->dev, - new_smi->slave_addr, - &(new_smi->intf)); + new_smi->slave_addr); if (rv) { printk(KERN_ERR "ipmi_si: Unable to register device: error %d\n", @@ -2417,7 +2432,7 @@ static int try_smi_init(struct smi_info *new_smi) list_add_tail(&new_smi->link, &smi_infos); - up(&smi_infos_lock); + mutex_unlock(&smi_infos_lock); printk(" IPMI %s interface initialized\n",si_to_str[new_smi->si_type]); @@ -2454,7 +2469,7 @@ static int try_smi_init(struct smi_info *new_smi) kfree(new_smi); - up(&smi_infos_lock); + mutex_unlock(&smi_infos_lock); return rv; } @@ -2512,26 +2527,26 @@ static __devinit int init_ipmi_si(void) #endif if (si_trydefaults) { - down(&smi_infos_lock); + mutex_lock(&smi_infos_lock); if (list_empty(&smi_infos)) { /* No BMC was found, try defaults. */ - up(&smi_infos_lock); + mutex_unlock(&smi_infos_lock); default_find_bmc(); } else { - up(&smi_infos_lock); + mutex_unlock(&smi_infos_lock); } } - down(&smi_infos_lock); + mutex_lock(&smi_infos_lock); if (list_empty(&smi_infos)) { - up(&smi_infos_lock); + mutex_unlock(&smi_infos_lock); #ifdef CONFIG_PCI pci_unregister_driver(&ipmi_pci_driver); #endif printk("ipmi_si: Unable to find any System Interface(s)\n"); return -ENODEV; } else { - up(&smi_infos_lock); + mutex_unlock(&smi_infos_lock); return 0; } } @@ -2607,10 +2622,10 @@ static __exit void cleanup_ipmi_si(void) pci_unregister_driver(&ipmi_pci_driver); #endif - down(&smi_infos_lock); + mutex_lock(&smi_infos_lock); list_for_each_entry_safe(e, tmp_e, &smi_infos, link) cleanup_one_si(e); - up(&smi_infos_lock); + mutex_unlock(&smi_infos_lock); driver_unregister(&ipmi_driver); } diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 7ece9f3c8f70..2d11ddd99e55 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -303,21 +304,22 @@ static int ipmi_heartbeat(void); static void panic_halt_ipmi_heartbeat(void); -/* We use a semaphore to make sure that only one thing can send a set +/* We use a mutex to make sure that only one thing can send a set timeout at one time, because we only have one copy of the data. - The semaphore is claimed when the set_timeout is sent and freed + The mutex is claimed when the set_timeout is sent and freed when both messages are free. */ static atomic_t set_timeout_tofree = ATOMIC_INIT(0); -static DECLARE_MUTEX(set_timeout_lock); +static DEFINE_MUTEX(set_timeout_lock); +static DECLARE_COMPLETION(set_timeout_wait); static void set_timeout_free_smi(struct ipmi_smi_msg *msg) { if (atomic_dec_and_test(&set_timeout_tofree)) - up(&set_timeout_lock); + complete(&set_timeout_wait); } static void set_timeout_free_recv(struct ipmi_recv_msg *msg) { if (atomic_dec_and_test(&set_timeout_tofree)) - up(&set_timeout_lock); + complete(&set_timeout_wait); } static struct ipmi_smi_msg set_timeout_smi_msg = { @@ -399,7 +401,7 @@ static int ipmi_set_timeout(int do_heartbeat) /* We can only send one of these at a time. */ - down(&set_timeout_lock); + mutex_lock(&set_timeout_lock); atomic_set(&set_timeout_tofree, 2); @@ -407,16 +409,21 @@ static int ipmi_set_timeout(int do_heartbeat) &set_timeout_recv_msg, &send_heartbeat_now); if (rv) { - up(&set_timeout_lock); - } else { - if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) - || ((send_heartbeat_now) - && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) - { - rv = ipmi_heartbeat(); - } + mutex_unlock(&set_timeout_lock); + goto out; } + wait_for_completion(&set_timeout_wait); + + if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) + || ((send_heartbeat_now) + && (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) + { + rv = ipmi_heartbeat(); + } + mutex_unlock(&set_timeout_lock); + +out: return rv; } @@ -458,17 +465,17 @@ static void panic_halt_ipmi_set_timeout(void) The semaphore is claimed when the set_timeout is sent and freed when both messages are free. */ static atomic_t heartbeat_tofree = ATOMIC_INIT(0); -static DECLARE_MUTEX(heartbeat_lock); -static DECLARE_MUTEX_LOCKED(heartbeat_wait_lock); +static DEFINE_MUTEX(heartbeat_lock); +static DECLARE_COMPLETION(heartbeat_wait); static void heartbeat_free_smi(struct ipmi_smi_msg *msg) { if (atomic_dec_and_test(&heartbeat_tofree)) - up(&heartbeat_wait_lock); + complete(&heartbeat_wait); } static void heartbeat_free_recv(struct ipmi_recv_msg *msg) { if (atomic_dec_and_test(&heartbeat_tofree)) - up(&heartbeat_wait_lock); + complete(&heartbeat_wait); } static struct ipmi_smi_msg heartbeat_smi_msg = { @@ -511,14 +518,14 @@ static int ipmi_heartbeat(void) return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); } - down(&heartbeat_lock); + mutex_lock(&heartbeat_lock); atomic_set(&heartbeat_tofree, 2); /* Don't reset the timer if we have the timer turned off, that re-enables the watchdog. */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) { - up(&heartbeat_lock); + mutex_unlock(&heartbeat_lock); return 0; } @@ -539,14 +546,14 @@ static int ipmi_heartbeat(void) &heartbeat_recv_msg, 1); if (rv) { - up(&heartbeat_lock); + mutex_unlock(&heartbeat_lock); printk(KERN_WARNING PFX "heartbeat failure: %d\n", rv); return rv; } /* Wait for the heartbeat to be sent. */ - down(&heartbeat_wait_lock); + wait_for_completion(&heartbeat_wait); if (heartbeat_recv_msg.msg.data[0] != 0) { /* Got an error in the heartbeat response. It was already @@ -555,7 +562,7 @@ static int ipmi_heartbeat(void) rv = -EINVAL; } - up(&heartbeat_lock); + mutex_unlock(&heartbeat_lock); return rv; } @@ -589,7 +596,7 @@ static void panic_halt_ipmi_heartbeat(void) 1); } -static struct watchdog_info ident= +static struct watchdog_info ident = { .options = 0, /* WDIOF_SETTIMEOUT, */ .firmware_version = 1, @@ -790,13 +797,13 @@ static int ipmi_fasync(int fd, struct file *file, int on) static int ipmi_close(struct inode *ino, struct file *filep) { - if (iminor(ino)==WATCHDOG_MINOR) - { + if (iminor(ino) == WATCHDOG_MINOR) { if (expect_close == 42) { ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); } else { - printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + printk(KERN_CRIT PFX + "Unexpected close, not stopping watchdog!\n"); ipmi_heartbeat(); } clear_bit(0, &ipmi_wdog_open); diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index e5247f85a446..ef20c1fc9c4c 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -706,7 +706,6 @@ static int stli_portcmdstats(stliport_t *portp); static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp); static int stli_getportstruct(stliport_t __user *arg); static int stli_getbrdstruct(stlibrd_t __user *arg); -static void *stli_memalloc(int len); static stlibrd_t *stli_allocbrd(void); static void stli_ecpinit(stlibrd_t *brdp); @@ -997,17 +996,6 @@ static int stli_parsebrd(stlconf_t *confp, char **argp) /*****************************************************************************/ -/* - * Local driver kernel malloc routine. - */ - -static void *stli_memalloc(int len) -{ - return((void *) kmalloc(len, GFP_KERNEL)); -} - -/*****************************************************************************/ - static int stli_open(struct tty_struct *tty, struct file *filp) { stlibrd_t *brdp; @@ -3227,13 +3215,12 @@ static int stli_initports(stlibrd_t *brdp) #endif for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) { - portp = (stliport_t *) stli_memalloc(sizeof(stliport_t)); - if (portp == (stliport_t *) NULL) { + portp = kzalloc(sizeof(stliport_t), GFP_KERNEL); + if (!portp) { printk("STALLION: failed to allocate port structure\n"); continue; } - memset(portp, 0, sizeof(stliport_t)); portp->magic = STLI_PORTMAGIC; portp->portnr = i; portp->brdnr = brdp->brdnr; @@ -4610,14 +4597,13 @@ static stlibrd_t *stli_allocbrd(void) { stlibrd_t *brdp; - brdp = (stlibrd_t *) stli_memalloc(sizeof(stlibrd_t)); - if (brdp == (stlibrd_t *) NULL) { + brdp = kzalloc(sizeof(stlibrd_t), GFP_KERNEL); + if (!brdp) { printk(KERN_ERR "STALLION: failed to allocate memory " "(size=%d)\n", sizeof(stlibrd_t)); - return((stlibrd_t *) NULL); + return NULL; } - memset(brdp, 0, sizeof(stlibrd_t)); brdp->magic = STLI_BOARDMAGIC; return(brdp); } @@ -5210,12 +5196,12 @@ int __init stli_init(void) /* * Allocate a temporary write buffer. */ - stli_tmpwritebuf = (char *) stli_memalloc(STLI_TXBUFSIZE); - if (stli_tmpwritebuf == (char *) NULL) + stli_tmpwritebuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL); + if (!stli_tmpwritebuf) printk(KERN_ERR "STALLION: failed to allocate memory " "(size=%d)\n", STLI_TXBUFSIZE); - stli_txcookbuf = stli_memalloc(STLI_TXBUFSIZE); - if (stli_txcookbuf == (char *) NULL) + stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL); + if (!stli_txcookbuf) printk(KERN_ERR "STALLION: failed to allocate memory " "(size=%d)\n", STLI_TXBUFSIZE); diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 8b603b2d1c42..935670a3cd98 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -74,7 +74,7 @@ void compute_shiftstate(void); k_self, k_fn, k_spec, k_pad,\ k_dead, k_cons, k_cur, k_shift,\ k_meta, k_ascii, k_lock, k_lowercase,\ - k_slock, k_dead2, k_ignore, k_ignore + k_slock, k_dead2, k_brl, k_ignore typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs); @@ -100,7 +100,7 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; const int max_vals[] = { 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, - 255, NR_LOCK - 1, 255 + 255, NR_LOCK - 1, 255, NR_BRL - 1 }; const int NR_TYPES = ARRAY_SIZE(max_vals); @@ -126,7 +126,7 @@ static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static int dead_key_next; static int npadch = -1; /* -1 or number assembled on pad */ -static unsigned char diacr; +static unsigned int diacr; static char rep; /* flag telling character repeat */ static unsigned char ledstate = 0xff; /* undefined */ @@ -394,22 +394,30 @@ void compute_shiftstate(void) * Otherwise, conclude that DIACR was not combining after all, * queue it and return CH. */ -static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) +static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) { - int d = diacr; + unsigned int d = diacr; unsigned int i; diacr = 0; - for (i = 0; i < accent_table_size; i++) { - if (accent_table[i].diacr == d && accent_table[i].base == ch) - return accent_table[i].result; + if ((d & ~0xff) == BRL_UC_ROW) { + if ((ch & ~0xff) == BRL_UC_ROW) + return d | ch; + } else { + for (i = 0; i < accent_table_size; i++) + if (accent_table[i].diacr == d && accent_table[i].base == ch) + return accent_table[i].result; } - if (ch == ' ' || ch == d) + if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d) return d; - put_queue(vc, d); + if (kbd->kbdmode == VC_UNICODE) + to_utf8(vc, d); + else if (d < 0x100) + put_queue(vc, d); + return ch; } @@ -419,7 +427,10 @@ static unsigned char handle_diacr(struct vc_data *vc, unsigned char ch) static void fn_enter(struct vc_data *vc, struct pt_regs *regs) { if (diacr) { - put_queue(vc, diacr); + if (kbd->kbdmode == VC_UNICODE) + to_utf8(vc, diacr); + else if (diacr < 0x100) + put_queue(vc, diacr); diacr = 0; } put_queue(vc, 13); @@ -615,7 +626,7 @@ static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag, s printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n"); } -static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs) { if (up_flag) return; /* no action, if this is a key release */ @@ -628,7 +639,10 @@ static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct diacr = value; return; } - put_queue(vc, value); + if (kbd->kbdmode == VC_UNICODE) + to_utf8(vc, value); + else if (value < 0x100) + put_queue(vc, value); } /* @@ -636,13 +650,23 @@ static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct * dead keys modifying the same character. Very useful * for Vietnamese. */ -static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs) { if (up_flag) return; diacr = (diacr ? handle_diacr(vc, value) : value); } +static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +{ + k_unicode(vc, value, up_flag, regs); +} + +static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +{ + k_deadunicode(vc, value, up_flag, regs); +} + /* * Obsolete - for backwards compatibility only */ @@ -650,7 +674,7 @@ static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct { static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' }; value = ret_diacr[value]; - k_dead2(vc, value, up_flag, regs); + k_deadunicode(vc, value, up_flag, regs); } static void k_cons(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) @@ -835,6 +859,62 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struc } } +/* by default, 300ms interval for combination release */ +static long brl_timeout = 300; +MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for combination on first release, < 0 for dead characters)"); +module_param(brl_timeout, long, 0644); +static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) +{ + static unsigned pressed,committing; + static unsigned long releasestart; + + if (kbd->kbdmode != VC_UNICODE) { + if (!up_flag) + printk("keyboard mode must be unicode for braille patterns\n"); + return; + } + + if (!value) { + k_unicode(vc, BRL_UC_ROW, up_flag, regs); + return; + } + + if (value > 8) + return; + + if (brl_timeout < 0) { + k_deadunicode(vc, BRL_UC_ROW | (1 << (value - 1)), up_flag, regs); + return; + } + + if (up_flag) { + if (brl_timeout) { + if (!committing || + jiffies - releasestart > (brl_timeout * HZ) / 1000) { + committing = pressed; + releasestart = jiffies; + } + pressed &= ~(1 << (value - 1)); + if (!pressed) { + if (committing) { + k_unicode(vc, BRL_UC_ROW | committing, 0, regs); + committing = 0; + } + } + } else { + if (committing) { + k_unicode(vc, BRL_UC_ROW | committing, 0, regs); + committing = 0; + } + pressed &= ~(1 << (value - 1)); + } + } else { + pressed |= 1 << (value - 1); + if (!brl_timeout) + committing = pressed; + } +} + /* * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, * or (ii) whatever pattern of lights people want to show using KDSETLED, @@ -1125,9 +1205,13 @@ static void kbd_keycode(unsigned int keycode, int down, } if (keycode > NR_KEYS) - return; + if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) + keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1); + else + return; + else + keysym = key_map[keycode]; - keysym = key_map[keycode]; type = KTYP(keysym); if (type < 0xf0) { diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 5fdf18515433..02114a0bd0d9 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -46,7 +46,7 @@ /* #define ATR_CSUM */ #ifdef PCMCIA_DEBUG -#define reader_to_dev(x) (&handle_to_dev(x->link.handle)) +#define reader_to_dev(x) (&handle_to_dev(x->p_dev->handle)) static int pc_debug = PCMCIA_DEBUG; module_param(pc_debug, int, 0600); #define DEBUGP(n, rdr, x, args...) do { \ @@ -67,7 +67,7 @@ static char *version = "cm4000_cs.c v2.4.0gm6 - All bugs added by Harald Welte"; #define T_100MSEC msecs_to_jiffies(100) #define T_500MSEC msecs_to_jiffies(500) -static void cm4000_release(dev_link_t *link); +static void cm4000_release(struct pcmcia_device *link); static int major; /* major number we get from the kernel */ @@ -106,7 +106,7 @@ static int major; /* major number we get from the kernel */ #define REG_STOPBITS(x) (x + 7) struct cm4000_dev { - dev_link_t link; /* pcmcia link */ + struct pcmcia_device *p_dev; dev_node_t node; /* OS node (major,minor) */ unsigned char atr[MAX_ATR]; @@ -149,14 +149,14 @@ struct cm4000_dev { #define ZERO_DEV(dev) \ memset(&dev->atr_csum,0, \ sizeof(struct cm4000_dev) - \ - /*link*/ sizeof(dev_link_t) - \ + /*link*/ sizeof(struct pcmcia_device) - \ /*node*/ sizeof(dev_node_t) - \ /*atr*/ MAX_ATR*sizeof(char) - \ /*rbuf*/ 512*sizeof(char) - \ /*sbuf*/ 512*sizeof(char) - \ /*queue*/ 4*sizeof(wait_queue_head_t)) -static dev_link_t *dev_table[CM4000_MAX_DEV]; +static struct pcmcia_device *dev_table[CM4000_MAX_DEV]; static struct class *cmm_class; /* This table doesn't use spaces after the comma between fields and thus @@ -454,7 +454,7 @@ static struct card_fixup card_fixups[] = { static void set_cardparameter(struct cm4000_dev *dev) { int i; - ioaddr_t iobase = dev->link.io.BasePort1; + ioaddr_t iobase = dev->p_dev->io.BasePort1; u_int8_t stopbits = 0x02; /* ISO default */ DEBUGP(3, dev, "-> set_cardparameter\n"); @@ -487,7 +487,7 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq) unsigned short num_bytes_read; unsigned char pts_reply[4]; ssize_t rc; - ioaddr_t iobase = dev->link.io.BasePort1; + ioaddr_t iobase = dev->p_dev->io.BasePort1; rc = 0; @@ -699,7 +699,7 @@ static void terminate_monitor(struct cm4000_dev *dev) static void monitor_card(unsigned long p) { struct cm4000_dev *dev = (struct cm4000_dev *) p; - ioaddr_t iobase = dev->link.io.BasePort1; + ioaddr_t iobase = dev->p_dev->io.BasePort1; unsigned short s; struct ptsreq ptsreq; int i, atrc; @@ -962,7 +962,7 @@ static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count, loff_t *ppos) { struct cm4000_dev *dev = filp->private_data; - ioaddr_t iobase = dev->link.io.BasePort1; + ioaddr_t iobase = dev->p_dev->io.BasePort1; ssize_t rc; int i, j, k; @@ -971,7 +971,7 @@ static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count, if (count == 0) /* according to manpage */ return 0; - if ((dev->link.state & DEV_PRESENT) == 0 || /* socket removed */ + if (!pcmcia_dev_present(dev->p_dev) || /* device removed */ test_bit(IS_CMM_ABSENT, &dev->flags)) return -ENODEV; @@ -1083,7 +1083,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data; - ioaddr_t iobase = dev->link.io.BasePort1; + ioaddr_t iobase = dev->p_dev->io.BasePort1; unsigned short s; unsigned char tmp; unsigned char infolen; @@ -1108,7 +1108,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf, sendT0 = dev->proto ? 0 : nr > 5 ? 0x08 : 0; - if ((dev->link.state & DEV_PRESENT) == 0 || /* socket removed */ + if (!pcmcia_dev_present(dev->p_dev) || /* device removed */ test_bit(IS_CMM_ABSENT, &dev->flags)) return -ENODEV; @@ -1440,8 +1440,8 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct cm4000_dev *dev = filp->private_data; - ioaddr_t iobase = dev->link.io.BasePort1; - dev_link_t *link; + ioaddr_t iobase = dev->p_dev->io.BasePort1; + struct pcmcia_device *link; int size; int rc; void __user *argp = (void __user *)arg; @@ -1458,7 +1458,7 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, iminor(inode), ioctl_names[_IOC_NR(cmd)]); link = dev_table[iminor(inode)]; - if (!(DEV_OK(link))) { + if (!pcmcia_dev_present(link)) { DEBUGP(4, dev, "DEV_OK false\n"); return -ENODEV; } @@ -1660,14 +1660,14 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, static int cmm_open(struct inode *inode, struct file *filp) { struct cm4000_dev *dev; - dev_link_t *link; + struct pcmcia_device *link; int rc, minor = iminor(inode); if (minor >= CM4000_MAX_DEV) return -ENODEV; link = dev_table[minor]; - if (link == NULL || !(DEV_OK(link))) + if (link == NULL || !pcmcia_dev_present(link)) return -ENODEV; if (link->open) @@ -1709,7 +1709,7 @@ static int cmm_open(struct inode *inode, struct file *filp) static int cmm_close(struct inode *inode, struct file *filp) { struct cm4000_dev *dev; - dev_link_t *link; + struct pcmcia_device *link; int minor = iminor(inode); if (minor >= CM4000_MAX_DEV) @@ -1735,7 +1735,7 @@ static int cmm_close(struct inode *inode, struct file *filp) return 0; } -static void cmm_cm4000_release(dev_link_t * link) +static void cmm_cm4000_release(struct pcmcia_device * link) { struct cm4000_dev *dev = link->priv; @@ -1759,13 +1759,11 @@ static void cmm_cm4000_release(dev_link_t * link) /*==== Interface to PCMCIA Layer =======================================*/ -static void cm4000_config(dev_link_t * link, int devno) +static int cm4000_config(struct pcmcia_device * link, int devno) { - client_handle_t handle = link->handle; struct cm4000_dev *dev; tuple_t tuple; cisparse_t parse; - config_info_t conf; u_char buf[64]; int fail_fn, fail_rc; int rc; @@ -1777,41 +1775,34 @@ static void cm4000_config(dev_link_t * link, int devno) tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) { + if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) { fail_fn = GetFirstTuple; goto cs_failed; } - if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) { + if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) { fail_fn = GetTupleData; goto cs_failed; } if ((fail_rc = - pcmcia_parse_tuple(handle, &tuple, &parse)) != CS_SUCCESS) { + pcmcia_parse_tuple(link, &tuple, &parse)) != CS_SUCCESS) { fail_fn = ParseTuple; goto cs_failed; } - if ((fail_rc = - pcmcia_get_configuration_info(handle, &conf)) != CS_SUCCESS) { - fail_fn = GetConfigurationInfo; - goto cs_failed; - } - link->state |= DEV_CONFIG; link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - link->conf.Vcc = conf.Vcc; link->io.BasePort2 = 0; link->io.NumPorts2 = 0; link->io.Attributes2 = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - for (rc = pcmcia_get_first_tuple(handle, &tuple); - rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(handle, &tuple)) { + for (rc = pcmcia_get_first_tuple(link, &tuple); + rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(link, &tuple)) { - rc = pcmcia_get_tuple_data(handle, &tuple); + rc = pcmcia_get_tuple_data(link, &tuple); if (rc != CS_SUCCESS) continue; - rc = pcmcia_parse_tuple(handle, &tuple, &parse); + rc = pcmcia_parse_tuple(link, &tuple, &parse); if (rc != CS_SUCCESS) continue; @@ -1831,7 +1822,7 @@ static void cm4000_config(dev_link_t * link, int devno) link->io.IOAddrLines = parse.cftable_entry.io.flags & CISTPL_IO_LINES_MASK; - rc = pcmcia_request_io(handle, &link->io); + rc = pcmcia_request_io(link, &link->io); if (rc == CS_SUCCESS) break; /* we are done */ } @@ -1841,7 +1832,7 @@ static void cm4000_config(dev_link_t * link, int devno) link->conf.IntType = 00000002; if ((fail_rc = - pcmcia_request_configuration(handle, &link->conf)) != CS_SUCCESS) { + pcmcia_request_configuration(link, &link->conf)) != CS_SUCCESS) { fail_fn = RequestConfiguration; goto cs_release; } @@ -1851,63 +1842,48 @@ static void cm4000_config(dev_link_t * link, int devno) dev->node.major = major; dev->node.minor = devno; dev->node.next = NULL; - link->dev = &dev->node; - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &dev->node; - return; + return 0; cs_failed: - cs_error(handle, fail_fn, fail_rc); + cs_error(link, fail_fn, fail_rc); cs_release: cm4000_release(link); - - link->state &= ~DEV_CONFIG_PENDING; + return -ENODEV; } -static int cm4000_suspend(struct pcmcia_device *p_dev) +static int cm4000_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct cm4000_dev *dev; dev = link->priv; - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); stop_monitor(dev); return 0; } -static int cm4000_resume(struct pcmcia_device *p_dev) +static int cm4000_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct cm4000_dev *dev; dev = link->priv; - - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) start_monitor(dev); return 0; } -static void cm4000_release(dev_link_t *link) +static void cm4000_release(struct pcmcia_device *link) { cmm_cm4000_release(link->priv); /* delay release until device closed */ - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); + pcmcia_disable_device(link); } -static int cm4000_attach(struct pcmcia_device *p_dev) +static int cm4000_probe(struct pcmcia_device *link) { struct cm4000_dev *dev; - dev_link_t *link; - int i; + int i, ret; for (i = 0; i < CM4000_MAX_DEV; i++) if (dev_table[i] == NULL) @@ -1923,7 +1899,7 @@ static int cm4000_attach(struct pcmcia_device *p_dev) if (dev == NULL) return -ENOMEM; - link = &dev->link; + dev->p_dev = link; link->priv = dev; link->conf.IntType = INT_MEMORY_AND_IO; dev_table[i] = link; @@ -1933,11 +1909,9 @@ static int cm4000_attach(struct pcmcia_device *p_dev) init_waitqueue_head(&dev->atrq); init_waitqueue_head(&dev->readq); - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - cm4000_config(link, i); + ret = cm4000_config(link, i); + if (ret) + return ret; class_device_create(cmm_class, NULL, MKDEV(major, i), NULL, "cmm%d", i); @@ -1945,9 +1919,8 @@ static int cm4000_attach(struct pcmcia_device *p_dev) return 0; } -static void cm4000_detach(struct pcmcia_device *p_dev) +static void cm4000_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct cm4000_dev *dev = link->priv; int devno; @@ -1958,11 +1931,9 @@ static void cm4000_detach(struct pcmcia_device *p_dev) if (devno == CM4000_MAX_DEV) return; - link->state &= ~DEV_PRESENT; stop_monitor(dev); - if (link->state & DEV_CONFIG) - cm4000_release(link); + cm4000_release(link); dev_table[devno] = NULL; kfree(dev); @@ -1993,7 +1964,7 @@ static struct pcmcia_driver cm4000_driver = { .drv = { .name = "cm4000_cs", }, - .probe = cm4000_attach, + .probe = cm4000_probe, .remove = cm4000_detach, .suspend = cm4000_suspend, .resume = cm4000_resume, diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 466e33bab029..29efa64580a8 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -41,7 +41,7 @@ #ifdef PCMCIA_DEBUG -#define reader_to_dev(x) (&handle_to_dev(x->link.handle)) +#define reader_to_dev(x) (&handle_to_dev(x->p_dev->handle)) static int pc_debug = PCMCIA_DEBUG; module_param(pc_debug, int, 0600); #define DEBUGP(n, rdr, x, args...) do { \ @@ -65,7 +65,7 @@ static char *version = /* how often to poll for fifo status change */ #define POLL_PERIOD msecs_to_jiffies(10) -static void reader_release(dev_link_t *link); +static void reader_release(struct pcmcia_device *link); static int major; static struct class *cmx_class; @@ -74,7 +74,7 @@ static struct class *cmx_class; #define BS_WRITABLE 0x02 struct reader_dev { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; wait_queue_head_t devq; wait_queue_head_t poll_wait; @@ -87,7 +87,7 @@ struct reader_dev { struct timer_list poll_timer; }; -static dev_link_t *dev_table[CM_MAX_DEV]; +static struct pcmcia_device *dev_table[CM_MAX_DEV]; #ifndef PCMCIA_DEBUG #define xoutb outb @@ -116,7 +116,7 @@ static inline unsigned char xinb(unsigned short port) static void cm4040_do_poll(unsigned long dummy) { struct reader_dev *dev = (struct reader_dev *) dummy; - unsigned int obs = xinb(dev->link.io.BasePort1 + unsigned int obs = xinb(dev->p_dev->io.BasePort1 + REG_OFFSET_BUFFER_STATUS); if ((obs & BSR_BULK_IN_FULL)) { @@ -147,7 +147,7 @@ static void cm4040_stop_poll(struct reader_dev *dev) static int wait_for_bulk_out_ready(struct reader_dev *dev) { int i, rc; - int iobase = dev->link.io.BasePort1; + int iobase = dev->p_dev->io.BasePort1; for (i = 0; i < POLL_LOOP_COUNT; i++) { if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) @@ -177,7 +177,7 @@ static int wait_for_bulk_out_ready(struct reader_dev *dev) /* Write to Sync Control Register */ static int write_sync_reg(unsigned char val, struct reader_dev *dev) { - int iobase = dev->link.io.BasePort1; + int iobase = dev->p_dev->io.BasePort1; int rc; rc = wait_for_bulk_out_ready(dev); @@ -195,7 +195,7 @@ static int write_sync_reg(unsigned char val, struct reader_dev *dev) static int wait_for_bulk_in_ready(struct reader_dev *dev) { int i, rc; - int iobase = dev->link.io.BasePort1; + int iobase = dev->p_dev->io.BasePort1; for (i = 0; i < POLL_LOOP_COUNT; i++) { if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) @@ -225,7 +225,7 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct reader_dev *dev = filp->private_data; - int iobase = dev->link.io.BasePort1; + int iobase = dev->p_dev->io.BasePort1; size_t bytes_to_read; unsigned long i; size_t min_bytes_to_read; @@ -246,7 +246,7 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, return -EAGAIN; } - if ((dev->link.state & DEV_PRESENT)==0) + if (!pcmcia_dev_present(dev->p_dev)) return -ENODEV; for (i = 0; i < 5; i++) { @@ -328,7 +328,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { struct reader_dev *dev = filp->private_data; - int iobase = dev->link.io.BasePort1; + int iobase = dev->p_dev->io.BasePort1; ssize_t rc; int i; unsigned int bytes_to_write; @@ -351,7 +351,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, return -EAGAIN; } - if ((dev->link.state & DEV_PRESENT) == 0) + if (!pcmcia_dev_present(dev->p_dev)) return -ENODEV; bytes_to_write = count; @@ -445,14 +445,14 @@ static unsigned int cm4040_poll(struct file *filp, poll_table *wait) static int cm4040_open(struct inode *inode, struct file *filp) { struct reader_dev *dev; - dev_link_t *link; + struct pcmcia_device *link; int minor = iminor(inode); if (minor >= CM_MAX_DEV) return -ENODEV; link = dev_table[minor]; - if (link == NULL || !(DEV_OK(link))) + if (link == NULL || !pcmcia_dev_present(link)) return -ENODEV; if (link->open) @@ -478,7 +478,7 @@ static int cm4040_open(struct inode *inode, struct file *filp) static int cm4040_close(struct inode *inode, struct file *filp) { struct reader_dev *dev = filp->private_data; - dev_link_t *link; + struct pcmcia_device *link; int minor = iminor(inode); DEBUGP(2, dev, "-> cm4040_close(maj/min=%d.%d)\n", imajor(inode), @@ -500,7 +500,7 @@ static int cm4040_close(struct inode *inode, struct file *filp) return 0; } -static void cm4040_reader_release(dev_link_t *link) +static void cm4040_reader_release(struct pcmcia_device *link) { struct reader_dev *dev = link->priv; @@ -514,60 +514,49 @@ static void cm4040_reader_release(dev_link_t *link) return; } -static void reader_config(dev_link_t *link, int devno) +static int reader_config(struct pcmcia_device *link, int devno) { - client_handle_t handle; struct reader_dev *dev; tuple_t tuple; cisparse_t parse; - config_info_t conf; u_char buf[64]; int fail_fn, fail_rc; int rc; - handle = link->handle; - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if ((fail_rc = pcmcia_get_first_tuple(handle, &tuple)) != CS_SUCCESS) { + if ((fail_rc = pcmcia_get_first_tuple(link, &tuple)) != CS_SUCCESS) { fail_fn = GetFirstTuple; goto cs_failed; } - if ((fail_rc = pcmcia_get_tuple_data(handle, &tuple)) != CS_SUCCESS) { + if ((fail_rc = pcmcia_get_tuple_data(link, &tuple)) != CS_SUCCESS) { fail_fn = GetTupleData; goto cs_failed; } - if ((fail_rc = pcmcia_parse_tuple(handle, &tuple, &parse)) + if ((fail_rc = pcmcia_parse_tuple(link, &tuple, &parse)) != CS_SUCCESS) { fail_fn = ParseTuple; goto cs_failed; } - if ((fail_rc = pcmcia_get_configuration_info(handle, &conf)) - != CS_SUCCESS) { - fail_fn = GetConfigurationInfo; - goto cs_failed; - } - link->state |= DEV_CONFIG; link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - link->conf.Vcc = conf.Vcc; link->io.BasePort2 = 0; link->io.NumPorts2 = 0; link->io.Attributes2 = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - for (rc = pcmcia_get_first_tuple(handle, &tuple); + for (rc = pcmcia_get_first_tuple(link, &tuple); rc == CS_SUCCESS; - rc = pcmcia_get_next_tuple(handle, &tuple)) { - rc = pcmcia_get_tuple_data(handle, &tuple); + rc = pcmcia_get_next_tuple(link, &tuple)) { + rc = pcmcia_get_tuple_data(link, &tuple); if (rc != CS_SUCCESS) continue; - rc = pcmcia_parse_tuple(handle, &tuple, &parse); + rc = pcmcia_parse_tuple(link, &tuple, &parse); if (rc != CS_SUCCESS) continue; @@ -585,13 +574,13 @@ static void reader_config(dev_link_t *link, int devno) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.IOAddrLines = parse.cftable_entry.io.flags & CISTPL_IO_LINES_MASK; - rc = pcmcia_request_io(handle, &link->io); + rc = pcmcia_request_io(link, &link->io); - dev_printk(KERN_INFO, &handle_to_dev(handle), "foo"); + dev_printk(KERN_INFO, &handle_to_dev(link), "foo"); if (rc == CS_SUCCESS) break; else - dev_printk(KERN_INFO, &handle_to_dev(handle), + dev_printk(KERN_INFO, &handle_to_dev(link), "pcmcia_request_io failed 0x%x\n", rc); } if (rc != CS_SUCCESS) @@ -599,10 +588,10 @@ static void reader_config(dev_link_t *link, int devno) link->conf.IntType = 00000002; - if ((fail_rc = pcmcia_request_configuration(handle,&link->conf)) + if ((fail_rc = pcmcia_request_configuration(link,&link->conf)) !=CS_SUCCESS) { fail_fn = RequestConfiguration; - dev_printk(KERN_INFO, &handle_to_dev(handle), + dev_printk(KERN_INFO, &handle_to_dev(link), "pcmcia_request_configuration failed 0x%x\n", fail_rc); goto cs_release; @@ -612,57 +601,31 @@ static void reader_config(dev_link_t *link, int devno) sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno); dev->node.major = major; dev->node.minor = devno; - dev->node.next = NULL; - link->dev = &dev->node; - link->state &= ~DEV_CONFIG_PENDING; + dev->node.next = &dev->node; DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4x-0x%.4x\n", devno, link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1); DEBUGP(2, dev, "<- reader_config (succ)\n"); - return; + return 0; cs_failed: - cs_error(handle, fail_fn, fail_rc); + cs_error(link, fail_fn, fail_rc); cs_release: reader_release(link); - link->state &= ~DEV_CONFIG_PENDING; + return -ENODEV; } -static int reader_suspend(struct pcmcia_device *p_dev) -{ - dev_link_t *link = dev_to_instance(p_dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int reader_resume(struct pcmcia_device *p_dev) -{ - dev_link_t *link = dev_to_instance(p_dev); - - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; -} - -static void reader_release(dev_link_t *link) +static void reader_release(struct pcmcia_device *link) { cm4040_reader_release(link->priv); - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); + pcmcia_disable_device(link); } -static int reader_attach(struct pcmcia_device *p_dev) +static int reader_probe(struct pcmcia_device *link) { struct reader_dev *dev; - dev_link_t *link; - int i; + int i, ret; for (i = 0; i < CM_MAX_DEV; i++) { if (dev_table[i] == NULL) @@ -679,8 +642,8 @@ static int reader_attach(struct pcmcia_device *p_dev) dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; dev->buffer_status = 0; - link = &dev->link; link->priv = dev; + dev->p_dev = link; link->conf.IntType = INT_MEMORY_AND_IO; dev_table[i] = link; @@ -692,11 +655,9 @@ static int reader_attach(struct pcmcia_device *p_dev) init_timer(&dev->poll_timer); dev->poll_timer.function = &cm4040_do_poll; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - reader_config(link, i); + ret = reader_config(link, i); + if (ret) + return ret; class_device_create(cmx_class, NULL, MKDEV(major, i), NULL, "cmx%d", i); @@ -704,9 +665,8 @@ static int reader_attach(struct pcmcia_device *p_dev) return 0; } -static void reader_detach(struct pcmcia_device *p_dev) +static void reader_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct reader_dev *dev = link->priv; int devno; @@ -718,10 +678,7 @@ static void reader_detach(struct pcmcia_device *p_dev) if (devno == CM_MAX_DEV) return; - link->state &= ~DEV_PRESENT; - - if (link->state & DEV_CONFIG) - reader_release(link); + reader_release(link); dev_table[devno] = NULL; kfree(dev); @@ -753,10 +710,8 @@ static struct pcmcia_driver reader_driver = { .drv = { .name = "cm4040_cs", }, - .probe = reader_attach, + .probe = reader_probe, .remove = reader_detach, - .suspend = reader_suspend, - .resume = reader_resume, .id_table = cm4040_ids, }; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index e6b714b6390d..07213454c458 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -228,7 +228,7 @@ typedef struct _mgslpc_info { struct _input_signal_events input_signal_events; /* PCMCIA support */ - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; int stop; @@ -484,7 +484,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); /* PCMCIA prototypes */ -static void mgslpc_config(dev_link_t *link); +static int mgslpc_config(struct pcmcia_device *link); static void mgslpc_release(u_long arg); static void mgslpc_detach(struct pcmcia_device *p_dev); @@ -533,14 +533,14 @@ static void ldisc_receive_buf(struct tty_struct *tty, } } -static int mgslpc_attach(struct pcmcia_device *p_dev) +static int mgslpc_probe(struct pcmcia_device *link) { MGSLPC_INFO *info; - dev_link_t *link; - + int ret; + if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_attach\n"); - + info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); if (!info) { printk("Error can't allocate device instance data\n"); @@ -565,25 +565,22 @@ static int mgslpc_attach(struct pcmcia_device *p_dev) info->imrb_value = 0xffff; info->pim_value = 0xff; - link = &info->link; + info->p_dev = link; link->priv = info; - - /* Initialize the dev_link_t structure */ + + /* Initialize the struct pcmcia_device structure */ /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = NULL; - + link->conf.Attributes = 0; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - mgslpc_config(link); + ret = mgslpc_config(link); + if (ret) + return ret; mgslpc_add_device(info); @@ -596,15 +593,13 @@ static int mgslpc_attach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void mgslpc_config(dev_link_t *link) +static int mgslpc_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; MGSLPC_INFO *info = link->priv; tuple_t tuple; cisparse_t parse; int last_fn, last_ret; u_char buf[64]; - config_info_t conf; cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg; @@ -617,27 +612,20 @@ static void mgslpc_config(dev_link_t *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - - /* Configure card */ - link->state |= DEV_CONFIG; - - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; /* get CIS configuration entry */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); cfg = &(parse.cftable_entry); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) @@ -658,11 +646,10 @@ static void mgslpc_config(dev_link_t *link) link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; link->io.BasePort1 = io->win[0].base; link->io.NumPorts1 = io->win[0].len; - CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); + CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); } link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 8; link->conf.Present = PRESENT_OPTION; @@ -670,9 +657,9 @@ static void mgslpc_config(dev_link_t *link) link->irq.Attributes |= IRQ_HANDLE_PRESENT; link->irq.Handler = mgslpc_isr; link->irq.Instance = info; - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); info->io_base = link->io.BasePort1; info->irq_level = link->irq.AssignedIRQ; @@ -680,7 +667,7 @@ static void mgslpc_config(dev_link_t *link) /* add to linked list of devices */ sprintf(info->node.dev_name, "mgslpc0"); info->node.major = info->node.minor = 0; - link->dev = &info->node; + link->dev_node = &info->node; printk(KERN_INFO "%s: index 0x%02x:", info->node.dev_name, link->conf.ConfigIndex); @@ -690,13 +677,12 @@ static void mgslpc_config(dev_link_t *link) printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); printk("\n"); - - link->state &= ~DEV_CONFIG_PENDING; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); mgslpc_release((u_long)link); + return -ENODEV; } /* Card has been removed. @@ -705,58 +691,38 @@ cs_failed: */ static void mgslpc_release(u_long arg) { - dev_link_t *link = (dev_link_t *)arg; + struct pcmcia_device *link = (struct pcmcia_device *)arg; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_release(0x%p)\n", link); + if (debug_level >= DEBUG_LEVEL_INFO) + printk("mgslpc_release(0x%p)\n", link); - /* Unlink the device chain */ - link->dev = NULL; - link->state &= ~DEV_CONFIG; - - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - if (link->irq.AssignedIRQ) - pcmcia_release_irq(link->handle, &link->irq); + pcmcia_disable_device(link); } -static void mgslpc_detach(struct pcmcia_device *p_dev) +static void mgslpc_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); + if (debug_level >= DEBUG_LEVEL_INFO) + printk("mgslpc_detach(0x%p)\n", link); - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_detach(0x%p)\n", link); + ((MGSLPC_INFO *)link->priv)->stop = 1; + mgslpc_release((u_long)link); - if (link->state & DEV_CONFIG) { - ((MGSLPC_INFO *)link->priv)->stop = 1; - mgslpc_release((u_long)link); - } - - mgslpc_remove_device((MGSLPC_INFO *)link->priv); + mgslpc_remove_device((MGSLPC_INFO *)link->priv); } -static int mgslpc_suspend(struct pcmcia_device *dev) +static int mgslpc_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); MGSLPC_INFO *info = link->priv; - link->state |= DEV_SUSPEND; info->stop = 1; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); return 0; } -static int mgslpc_resume(struct pcmcia_device *dev) +static int mgslpc_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); MGSLPC_INFO *info = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); info->stop = 0; return 0; @@ -1280,7 +1246,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs) if (!info) return IRQ_NONE; - if (!(info->link.state & DEV_CONFIG)) + if (!(info->p_dev->_locked)) return IRQ_HANDLED; spin_lock(&info->lock); @@ -3033,7 +2999,7 @@ static struct pcmcia_driver mgslpc_driver = { .drv = { .name = "synclink_cs", }, - .probe = mgslpc_attach, + .probe = mgslpc_probe, .remove = mgslpc_detach, .id_table = mgslpc_ids, .suspend = mgslpc_suspend, diff --git a/drivers/char/random.c b/drivers/char/random.c index 86be04b241e1..58f3512c52e1 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1584,7 +1584,6 @@ u32 secure_ipv6_port_ephemeral(const __u32 *saddr, const __u32 *daddr, __u16 dpo return twothirdsMD4Transform(daddr, hash); } -EXPORT_SYMBOL(secure_ipv6_port_ephemeral); #endif #if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 3f5d6077f39c..a9c5a7230f89 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -504,7 +504,6 @@ static int stl_echmcaintr(stlbrd_t *brdp); static int stl_echpciintr(stlbrd_t *brdp); static int stl_echpci64intr(stlbrd_t *brdp); static void stl_offintr(void *private); -static void *stl_memalloc(int len); static stlbrd_t *stl_allocbrd(void); static stlport_t *stl_getport(int brdnr, int panelnr, int portnr); @@ -939,17 +938,6 @@ static int stl_parsebrd(stlconf_t *confp, char **argp) /*****************************************************************************/ -/* - * Local driver kernel memory allocation routine. - */ - -static void *stl_memalloc(int len) -{ - return (void *) kmalloc(len, GFP_KERNEL); -} - -/*****************************************************************************/ - /* * Allocate a new board structure. Fill out the basic info in it. */ @@ -958,14 +946,13 @@ static stlbrd_t *stl_allocbrd(void) { stlbrd_t *brdp; - brdp = (stlbrd_t *) stl_memalloc(sizeof(stlbrd_t)); - if (brdp == (stlbrd_t *) NULL) { + brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL); + if (!brdp) { printk("STALLION: failed to allocate memory (size=%d)\n", sizeof(stlbrd_t)); - return (stlbrd_t *) NULL; + return NULL; } - memset(brdp, 0, sizeof(stlbrd_t)); brdp->magic = STL_BOARDMAGIC; return brdp; } @@ -1017,9 +1004,9 @@ static int stl_open(struct tty_struct *tty, struct file *filp) portp->refcount++; if ((portp->flags & ASYNC_INITIALIZED) == 0) { - if (portp->tx.buf == (char *) NULL) { - portp->tx.buf = (char *) stl_memalloc(STL_TXBUFSIZE); - if (portp->tx.buf == (char *) NULL) + if (!portp->tx.buf) { + portp->tx.buf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL); + if (!portp->tx.buf) return -ENOMEM; portp->tx.head = portp->tx.buf; portp->tx.tail = portp->tx.buf; @@ -2178,13 +2165,12 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp) * each ports data structures. */ for (i = 0; (i < panelp->nrports); i++) { - portp = (stlport_t *) stl_memalloc(sizeof(stlport_t)); - if (portp == (stlport_t *) NULL) { + portp = kzalloc(sizeof(stlport_t), GFP_KERNEL); + if (!portp) { printk("STALLION: failed to allocate memory " "(size=%d)\n", sizeof(stlport_t)); break; } - memset(portp, 0, sizeof(stlport_t)); portp->magic = STL_PORTMAGIC; portp->portnr = i; @@ -2315,13 +2301,12 @@ static inline int stl_initeio(stlbrd_t *brdp) * can complete the setup. */ - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { + panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); + if (!panelp) { printk(KERN_WARNING "STALLION: failed to allocate memory " "(size=%d)\n", sizeof(stlpanel_t)); - return(-ENOMEM); + return -ENOMEM; } - memset(panelp, 0, sizeof(stlpanel_t)); panelp->magic = STL_PANELMAGIC; panelp->brdnr = brdp->brdnr; @@ -2490,13 +2475,12 @@ static inline int stl_initech(stlbrd_t *brdp) status = inb(ioaddr + ECH_PNLSTATUS); if ((status & ECH_PNLIDMASK) != nxtid) break; - panelp = (stlpanel_t *) stl_memalloc(sizeof(stlpanel_t)); - if (panelp == (stlpanel_t *) NULL) { + panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL); + if (!panelp) { printk("STALLION: failed to allocate memory " "(size=%d)\n", sizeof(stlpanel_t)); break; } - memset(panelp, 0, sizeof(stlpanel_t)); panelp->magic = STL_PANELMAGIC; panelp->brdnr = brdp->brdnr; panelp->panelnr = panelnr; @@ -3074,8 +3058,8 @@ static int __init stl_init(void) /* * Allocate a temporary write buffer. */ - stl_tmpwritebuf = (char *) stl_memalloc(STL_TXBUFSIZE); - if (stl_tmpwritebuf == (char *) NULL) + stl_tmpwritebuf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL); + if (!stl_tmpwritebuf) printk("STALLION: failed to allocate memory (size=%d)\n", STL_TXBUFSIZE); diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 2546637a55c0..f58ad7f68267 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -327,7 +327,7 @@ static ssize_t store_received_ref_clk3a(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(received_ref_clk3a, S_IWUGO, NULL, +static DEVICE_ATTR(received_ref_clk3a, (S_IWUSR|S_IWGRP), NULL, store_received_ref_clk3a); @@ -349,7 +349,7 @@ static ssize_t store_received_ref_clk3b(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(received_ref_clk3b, S_IWUGO, NULL, +static DEVICE_ATTR(received_ref_clk3b, (S_IWUSR|S_IWGRP), NULL, store_received_ref_clk3b); @@ -371,7 +371,7 @@ static ssize_t store_enable_clk3b_output(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(enable_clk3b_output, S_IWUGO, NULL, +static DEVICE_ATTR(enable_clk3b_output, (S_IWUSR|S_IWGRP), NULL, store_enable_clk3b_output); static ssize_t store_enable_clk3a_output(struct device *d, @@ -392,7 +392,7 @@ static ssize_t store_enable_clk3a_output(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(enable_clk3a_output, S_IWUGO, NULL, +static DEVICE_ATTR(enable_clk3a_output, (S_IWUSR|S_IWGRP), NULL, store_enable_clk3a_output); static ssize_t store_enable_clkb1_output(struct device *d, @@ -413,7 +413,7 @@ static ssize_t store_enable_clkb1_output(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(enable_clkb1_output, S_IWUGO, NULL, +static DEVICE_ATTR(enable_clkb1_output, (S_IWUSR|S_IWGRP), NULL, store_enable_clkb1_output); @@ -435,7 +435,7 @@ static ssize_t store_enable_clka1_output(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(enable_clka1_output, S_IWUGO, NULL, +static DEVICE_ATTR(enable_clka1_output, (S_IWUSR|S_IWGRP), NULL, store_enable_clka1_output); static ssize_t store_enable_clkb0_output(struct device *d, @@ -456,7 +456,7 @@ static ssize_t store_enable_clkb0_output(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(enable_clkb0_output, S_IWUGO, NULL, +static DEVICE_ATTR(enable_clkb0_output, (S_IWUSR|S_IWGRP), NULL, store_enable_clkb0_output); static ssize_t store_enable_clka0_output(struct device *d, @@ -477,7 +477,7 @@ static ssize_t store_enable_clka0_output(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(enable_clka0_output, S_IWUGO, NULL, +static DEVICE_ATTR(enable_clka0_output, (S_IWUSR|S_IWGRP), NULL, store_enable_clka0_output); static ssize_t store_select_amcb2_transmit_clock(struct device *d, @@ -519,7 +519,7 @@ static ssize_t store_select_amcb2_transmit_clock(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(select_amcb2_transmit_clock, S_IWUGO, NULL, +static DEVICE_ATTR(select_amcb2_transmit_clock, (S_IWUSR|S_IWGRP), NULL, store_select_amcb2_transmit_clock); static ssize_t store_select_amcb1_transmit_clock(struct device *d, @@ -560,7 +560,7 @@ static ssize_t store_select_amcb1_transmit_clock(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(select_amcb1_transmit_clock, S_IWUGO, NULL, +static DEVICE_ATTR(select_amcb1_transmit_clock, (S_IWUSR|S_IWGRP), NULL, store_select_amcb1_transmit_clock); static ssize_t store_select_redundant_clock(struct device *d, @@ -581,7 +581,7 @@ static ssize_t store_select_redundant_clock(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(select_redundant_clock, S_IWUGO, NULL, +static DEVICE_ATTR(select_redundant_clock, (S_IWUSR|S_IWGRP), NULL, store_select_redundant_clock); static ssize_t store_select_ref_frequency(struct device *d, @@ -602,7 +602,7 @@ static ssize_t store_select_ref_frequency(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(select_ref_frequency, S_IWUGO, NULL, +static DEVICE_ATTR(select_ref_frequency, (S_IWUSR|S_IWGRP), NULL, store_select_ref_frequency); static ssize_t store_filter_select(struct device *d, @@ -623,7 +623,7 @@ static ssize_t store_filter_select(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(filter_select, S_IWUGO, NULL, store_filter_select); +static DEVICE_ATTR(filter_select, (S_IWUSR|S_IWGRP), NULL, store_filter_select); static ssize_t store_hardware_switching_mode(struct device *d, struct device_attribute *attr, const char *buf, size_t count) @@ -643,7 +643,7 @@ static ssize_t store_hardware_switching_mode(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(hardware_switching_mode, S_IWUGO, NULL, +static DEVICE_ATTR(hardware_switching_mode, (S_IWUSR|S_IWGRP), NULL, store_hardware_switching_mode); static ssize_t store_hardware_switching(struct device *d, @@ -664,7 +664,7 @@ static ssize_t store_hardware_switching(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(hardware_switching, S_IWUGO, NULL, +static DEVICE_ATTR(hardware_switching, (S_IWUSR|S_IWGRP), NULL, store_hardware_switching); static ssize_t store_refalign (struct device *d, @@ -684,7 +684,7 @@ static ssize_t store_refalign (struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(refalign, S_IWUGO, NULL, store_refalign); +static DEVICE_ATTR(refalign, (S_IWUSR|S_IWGRP), NULL, store_refalign); static ssize_t store_mode_select (struct device *d, struct device_attribute *attr, const char *buf, size_t count) @@ -704,7 +704,7 @@ static ssize_t store_mode_select (struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(mode_select, S_IWUGO, NULL, store_mode_select); +static DEVICE_ATTR(mode_select, (S_IWUSR|S_IWGRP), NULL, store_mode_select); static ssize_t store_reset (struct device *d, struct device_attribute *attr, const char *buf, size_t count) @@ -724,7 +724,7 @@ static ssize_t store_reset (struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(reset, S_IWUGO, NULL, store_reset); +static DEVICE_ATTR(reset, (S_IWUSR|S_IWGRP), NULL, store_reset); static struct attribute *tlclk_sysfs_entries[] = { &dev_attr_current_ref.attr, diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 0bfd1b63662e..841f0bd3eaaf 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -351,10 +351,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size) spin_unlock_irqrestore(&tty->buf.lock, flags); return size; } - EXPORT_SYMBOL_GPL(tty_buffer_request_room); -int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, size_t size) +int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, + size_t size) { int copied = 0; do { @@ -368,17 +368,16 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, s tb->used += space; copied += space; chars += space; -/* printk("Flip insert %d.\n", space); */ } /* There is a small chance that we need to split the data over several buffers. If this is the case we must loop */ while (unlikely(size > copied)); return copied; } +EXPORT_SYMBOL(tty_insert_flip_string); -EXPORT_SYMBOL_GPL(tty_insert_flip_string); - -int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size) +int tty_insert_flip_string_flags(struct tty_struct *tty, + const unsigned char *chars, const char *flags, size_t size) { int copied = 0; do { @@ -399,9 +398,20 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *ch while (unlikely(size > copied)); return copied; } - EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags); +void tty_schedule_flip(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + if (tty->buf.tail != NULL) { + tty->buf.tail->active = 0; + tty->buf.tail->commit = tty->buf.tail->used; + } + spin_unlock_irqrestore(&tty->buf.lock, flags); + schedule_delayed_work(&tty->buf.work, 1); +} +EXPORT_SYMBOL(tty_schedule_flip); /* * Prepare a block of space in the buffer for data. Returns the length @@ -1730,7 +1740,7 @@ static void release_dev(struct file * filp) { struct tty_struct *tty, *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; - int devpts_master, devpts; + int devpts; int idx; char buf[64]; unsigned long flags; @@ -1747,7 +1757,6 @@ static void release_dev(struct file * filp) pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; - devpts_master = pty_master && devpts; o_tty = tty->link; #ifdef TTY_PARANOIA_CHECK @@ -2185,6 +2194,7 @@ static int ptmx_open(struct inode * inode, struct file * filp) return 0; out1: release_dev(filp); + return retval; out: down(&allocated_ptys_lock); idr_remove(&allocated_ptys, index); @@ -2724,7 +2734,7 @@ static void __do_SAK(void *arg) printk(KERN_NOTICE "SAK: killed process %d" " (%s): fd#%d opened to the tty\n", p->pid, p->comm, i); - send_sig(SIGKILL, p, 1); + force_sig(SIGKILL, p); break; } } diff --git a/drivers/char/vt.c b/drivers/char/vt.c index ca4844c527da..acc5d47844eb 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -2328,6 +2328,10 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) case TIOCL_SETVESABLANK: set_vesa_blanking(p); break; + case TIOCL_GETKMSGREDIRECT: + data = kmsg_redirect; + ret = __put_user(data, p); + break; case TIOCL_SETKMSGREDIRECT: if (!capable(CAP_SYS_ADMIN)) { ret = -EPERM; diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 16e99db2e12d..d53f664a4dd8 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -60,6 +60,13 @@ config SOFT_WATCHDOG # ARM Architecture +config AT91_WATCHDOG + tristate "AT91RM9200 watchdog" + depends on WATCHDOG && ARCH_AT91RM9200 + help + Watchdog timer embedded into AT91RM9200 chips. This will reboot your + system when the timeout is reached. + config 21285_WATCHDOG tristate "DC21285 watchdog" depends on WATCHDOG && FOOTBRIDGE diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index d6f27fde9905..6ab77b61a643 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o # ARM Architecture +obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91_wdt.c new file mode 100644 index 000000000000..ac83bc4b019a --- /dev/null +++ b/drivers/char/watchdog/at91_wdt.c @@ -0,0 +1,228 @@ +/* + * Watchdog driver for Atmel AT91RM9200 (Thunder) + * + * Copyright (C) 2003 SAN People (Pty) Ltd + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define WDT_DEFAULT_TIME 5 /* 5 seconds */ +#define WDT_MAX_TIME 256 /* 256 seconds */ + +static int wdt_time = WDT_DEFAULT_TIME; +static int nowayout = WATCHDOG_NOWAYOUT; + +module_param(wdt_time, int, 0); +MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + + +static unsigned long at91wdt_busy; + +/* ......................................................................... */ + +/* + * Disable the watchdog. + */ +static void inline at91_wdt_stop(void) +{ + at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN); +} + +/* + * Enable and reset the watchdog. + */ +static void inline at91_wdt_start(void) +{ + at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV)); + at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); +} + +/* + * Reload the watchdog timer. (ie, pat the watchdog) + */ +static void inline at91_wdt_reload(void) +{ + at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); +} + +/* ......................................................................... */ + +/* + * Watchdog device is opened, and watchdog starts running. + */ +static int at91_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &at91wdt_busy)) + return -EBUSY; + + at91_wdt_start(); + return nonseekable_open(inode, file); +} + +/* + * Close the watchdog device. + * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also + * disabled. + */ +static int at91_wdt_close(struct inode *inode, struct file *file) +{ + if (!nowayout) + at91_wdt_stop(); /* Disable the watchdog when file is closed */ + + clear_bit(0, &at91wdt_busy); + return 0; +} + +/* + * Change the watchdog time interval. + */ +static int at91_wdt_settimeout(int new_time) +{ + /* + * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz + * + * Since WDV is a 16-bit counter, the maximum period is + * 65536 / 0.256 = 256 seconds. + */ + if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) + return -EINVAL; + + /* Set new watchdog time. It will be used when at91_wdt_start() is called. */ + wdt_time = new_time; + return 0; +} + +static struct watchdog_info at91_wdt_info = { + .identity = "at91 watchdog", + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, +}; + +/* + * Handle commands from user-space. + */ +static int at91_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int new_value; + + switch(cmd) { + case WDIOC_KEEPALIVE: + at91_wdt_reload(); /* pat the watchdog */ + return 0; + + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_value, p)) + return -EFAULT; + + if (at91_wdt_settimeout(new_value)) + return -EINVAL; + + /* Enable new time value */ + at91_wdt_start(); + + /* Return current value */ + return put_user(wdt_time, p); + + case WDIOC_GETTIMEOUT: + return put_user(wdt_time, p); + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + + case WDIOC_SETOPTIONS: + if (get_user(new_value, p)) + return -EFAULT; + + if (new_value & WDIOS_DISABLECARD) + at91_wdt_stop(); + if (new_value & WDIOS_ENABLECARD) + at91_wdt_start(); + return 0; + + default: + return -ENOIOCTLCMD; + } +} + +/* + * Pat the watchdog whenever device is written to. + */ +static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + at91_wdt_reload(); /* pat the watchdog */ + return len; +} + +/* ......................................................................... */ + +static struct file_operations at91wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = at91_wdt_ioctl, + .open = at91_wdt_open, + .release = at91_wdt_close, + .write = at91_wdt_write, +}; + +static struct miscdevice at91wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &at91wdt_fops, +}; + +static int __init at91_wdt_init(void) +{ + int res; + + /* Check that the heartbeat value is within range; if not reset to the default */ + if (at91_wdt_settimeout(wdt_time)) { + at91_wdt_settimeout(WDT_DEFAULT_TIME); + printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time); + } + + res = misc_register(&at91wdt_miscdev); + if (res) + return res; + + printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout); + return 0; +} + +static void __exit at91_wdt_exit(void) +{ + misc_deregister(&at91wdt_miscdev); +} + +module_init(at91_wdt_init); +module_exit(at91_wdt_exit); + +MODULE_AUTHOR("Andrew Victor"); +MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c index 8d6b249ad66b..6d44ca68312d 100644 --- a/drivers/char/watchdog/pcwd.c +++ b/drivers/char/watchdog/pcwd.c @@ -66,15 +66,13 @@ #include /* For file operations */ #include /* For io-port access */ #include /* For spin_lock/spin_unlock/... */ -#include /* TASK_INTERRUPTIBLE, set_current_state() and friends */ -#include /* For kmalloc */ #include /* For copy_to_user/put_user/... */ #include /* For inb/outb/... */ /* Module and version information */ -#define WATCHDOG_VERSION "1.16" -#define WATCHDOG_DATE "03 Jan 2006" +#define WATCHDOG_VERSION "1.17" +#define WATCHDOG_DATE "12 Feb 2006" #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog" #define WATCHDOG_NAME "pcwd" #define PFX WATCHDOG_NAME ": " @@ -96,15 +94,19 @@ * PCI-PC Watchdog card. */ /* Port 1 : Control Status #1 for the PC Watchdog card, revision A. */ -#define WD_WDRST 0x01 /* Previously reset state */ -#define WD_T110 0x02 /* Temperature overheat sense */ -#define WD_HRTBT 0x04 /* Heartbeat sense */ -#define WD_RLY2 0x08 /* External relay triggered */ -#define WD_SRLY2 0x80 /* Software external relay triggered */ +#define WD_WDRST 0x01 /* Previously reset state */ +#define WD_T110 0x02 /* Temperature overheat sense */ +#define WD_HRTBT 0x04 /* Heartbeat sense */ +#define WD_RLY2 0x08 /* External relay triggered */ +#define WD_SRLY2 0x80 /* Software external relay triggered */ /* Port 1 : Control Status #1 for the PC Watchdog card, revision C. */ -#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ -#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ -#define WD_REVC_TTRP 0x04 /* Temperature Trip status */ +#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ +#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ +#define WD_REVC_TTRP 0x04 /* Temperature Trip status */ +#define WD_REVC_RL2A 0x08 /* Relay 2 activated by on-board processor */ +#define WD_REVC_RL1A 0x10 /* Relay 1 active */ +#define WD_REVC_R2DS 0x40 /* Relay 2 disable */ +#define WD_REVC_RLY2 0x80 /* Relay 2 activated? */ /* Port 2 : Control Status #2 */ #define WD_WDIS 0x10 /* Watchdog Disabled */ #define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */ @@ -122,9 +124,14 @@ #define CMD_ISA_VERSION_HUNDRETH 0x03 #define CMD_ISA_VERSION_MINOR 0x04 #define CMD_ISA_SWITCH_SETTINGS 0x05 +#define CMD_ISA_RESET_PC 0x06 +#define CMD_ISA_ARM_0 0x07 +#define CMD_ISA_ARM_30 0x08 +#define CMD_ISA_ARM_60 0x09 #define CMD_ISA_DELAY_TIME_2SECS 0x0A #define CMD_ISA_DELAY_TIME_4SECS 0x0B #define CMD_ISA_DELAY_TIME_8SECS 0x0C +#define CMD_ISA_RESET_RELAYS 0x0D /* * We are using an kernel timer to do the pinging of the watchdog @@ -142,6 +149,7 @@ static atomic_t open_allowed = ATOMIC_INIT(1); static char expect_close; static int temp_panic; static struct { /* this is private data for each ISA-PC watchdog card */ + char fw_ver_str[6]; /* The cards firmware version */ int revision; /* The card's revision */ int supports_temp; /* Wether or not the card has a temperature device */ int command_mode; /* Wether or not the card is in command mode */ @@ -153,6 +161,13 @@ static struct { /* this is private data for each ISA-PC watchdog card */ } pcwd_private; /* module parameters */ +#define QUIET 0 /* Default */ +#define VERBOSE 1 /* Verbose */ +#define DEBUG 2 /* print fancy stuff too */ +static int debug = QUIET; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); + #define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */ static int heartbeat = WATCHDOG_HEARTBEAT; module_param(heartbeat, int, 0); @@ -172,6 +187,10 @@ static int send_isa_command(int cmd) int control_status; int port0, last_port0; /* Double read for stabilising */ + if (debug >= DEBUG) + printk(KERN_DEBUG PFX "sending following data cmd=0x%02x\n", + cmd); + /* The WCMD bit must be 1 and the command is only 4 bits in size */ control_status = (cmd & 0x0F) | WD_WCMD; outb_p(control_status, pcwd_private.io_addr + 2); @@ -188,6 +207,10 @@ static int send_isa_command(int cmd) udelay (250); } + if (debug >= DEBUG) + printk(KERN_DEBUG PFX "received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n", + cmd, port0, last_port0); + return port0; } @@ -214,6 +237,10 @@ static int set_command_mode(void) spin_unlock(&pcwd_private.io_lock); pcwd_private.command_mode = found; + if (debug >= DEBUG) + printk(KERN_DEBUG PFX "command_mode=%d\n", + pcwd_private.command_mode); + return(found); } @@ -226,6 +253,10 @@ static void unset_command_mode(void) spin_unlock(&pcwd_private.io_lock); pcwd_private.command_mode = 0; + + if (debug >= DEBUG) + printk(KERN_DEBUG PFX "command_mode=%d\n", + pcwd_private.command_mode); } static inline void pcwd_check_temperature_support(void) @@ -234,27 +265,22 @@ static inline void pcwd_check_temperature_support(void) pcwd_private.supports_temp = 1; } -static inline char *get_firmware(void) +static inline void pcwd_get_firmware(void) { int one, ten, hund, minor; - char *ret; - ret = kmalloc(6, GFP_KERNEL); - if(ret == NULL) - return NULL; + strcpy(pcwd_private.fw_ver_str, "ERROR"); if (set_command_mode()) { one = send_isa_command(CMD_ISA_VERSION_INTEGER); ten = send_isa_command(CMD_ISA_VERSION_TENTH); hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH); minor = send_isa_command(CMD_ISA_VERSION_MINOR); - sprintf(ret, "%c.%c%c%c", one, ten, hund, minor); + sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", one, ten, hund, minor); } - else - sprintf(ret, "ERROR"); - unset_command_mode(); - return(ret); + + return; } static inline int pcwd_get_option_switches(void) @@ -272,17 +298,15 @@ static inline int pcwd_get_option_switches(void) static void pcwd_show_card_info(void) { - char *firmware; int option_switches; /* Get some extra info from the hardware (in command/debug/diag mode) */ if (pcwd_private.revision == PCWD_REVISION_A) printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr); else if (pcwd_private.revision == PCWD_REVISION_C) { - firmware = get_firmware(); + pcwd_get_firmware(); printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n", - pcwd_private.io_addr, firmware); - kfree(firmware); + pcwd_private.io_addr, pcwd_private.fw_ver_str); option_switches = pcwd_get_option_switches(); printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n", option_switches, @@ -362,6 +386,10 @@ static int pcwd_start(void) return -EIO; } } + + if (debug >= VERBOSE) + printk(KERN_DEBUG PFX "Watchdog started\n"); + return 0; } @@ -386,6 +414,10 @@ static int pcwd_stop(void) return -EIO; } } + + if (debug >= VERBOSE) + printk(KERN_DEBUG PFX "Watchdog stopped\n"); + return 0; } @@ -393,6 +425,10 @@ static int pcwd_keepalive(void) { /* user land ping */ pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ); + + if (debug >= DEBUG) + printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n"); + return 0; } @@ -402,12 +438,17 @@ static int pcwd_set_heartbeat(int t) return -EINVAL; heartbeat = t; + + if (debug >= VERBOSE) + printk(KERN_DEBUG PFX "New heartbeat: %d\n", + heartbeat); + return 0; } static int pcwd_get_status(int *status) { - int card_status; + int control_status; *status=0; spin_lock(&pcwd_private.io_lock); @@ -415,37 +456,39 @@ static int pcwd_get_status(int *status) /* Rev A cards return status information from * the base register, which is used for the * temperature in other cards. */ - card_status = inb(pcwd_private.io_addr); + control_status = inb(pcwd_private.io_addr); else { /* Rev C cards return card status in the base * address + 1 register. And use different bits * to indicate a card initiated reset, and an * over-temperature condition. And the reboot * status can be reset. */ - card_status = inb(pcwd_private.io_addr + 1); + control_status = inb(pcwd_private.io_addr + 1); } spin_unlock(&pcwd_private.io_lock); if (pcwd_private.revision == PCWD_REVISION_A) { - if (card_status & WD_WDRST) + if (control_status & WD_WDRST) *status |= WDIOF_CARDRESET; - if (card_status & WD_T110) { + if (control_status & WD_T110) { *status |= WDIOF_OVERHEAT; if (temp_panic) { printk (KERN_INFO PFX "Temperature overheat trip!\n"); kernel_power_off(); + /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ } } } else { - if (card_status & WD_REVC_WTRP) + if (control_status & WD_REVC_WTRP) *status |= WDIOF_CARDRESET; - if (card_status & WD_REVC_TTRP) { + if (control_status & WD_REVC_TTRP) { *status |= WDIOF_OVERHEAT; if (temp_panic) { printk (KERN_INFO PFX "Temperature overheat trip!\n"); kernel_power_off(); + /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ } } } @@ -455,9 +498,25 @@ static int pcwd_get_status(int *status) static int pcwd_clear_status(void) { + int control_status; + if (pcwd_private.revision == PCWD_REVISION_C) { spin_lock(&pcwd_private.io_lock); - outb_p(0x00, pcwd_private.io_addr + 1); /* clear reset status */ + + if (debug >= VERBOSE) + printk(KERN_INFO PFX "clearing watchdog trip status\n"); + + control_status = inb_p(pcwd_private.io_addr + 1); + + if (debug >= DEBUG) { + printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status); + printk(KERN_DEBUG PFX "sending: 0x%02x\n", + (control_status & WD_REVC_R2DS)); + } + + /* clear reset status & Keep Relay 2 disable state as it is */ + outb_p((control_status & WD_REVC_R2DS), pcwd_private.io_addr + 1); + spin_unlock(&pcwd_private.io_lock); } return 0; @@ -481,6 +540,11 @@ static int pcwd_get_temperature(int *temperature) *temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32; spin_unlock(&pcwd_private.io_lock); + if (debug >= DEBUG) { + printk(KERN_DEBUG PFX "temperature is: %d F\n", + *temperature); + } + return 0; } @@ -599,6 +663,8 @@ static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len, static int pcwd_open(struct inode *inode, struct file *file) { if (!atomic_dec_and_test(&open_allowed) ) { + if (debug >= VERBOSE) + printk(KERN_ERR PFX "Attempt to open already opened device.\n"); atomic_inc( &open_allowed ); return -EBUSY; } @@ -922,7 +988,8 @@ static void __exit pcwd_cleanup_module(void) { if (pcwd_private.io_addr) pcwatchdog_exit(); - return; + + printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); } module_init(pcwd_init_module); diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c index 2700c5c45b8a..3fdfda9324fa 100644 --- a/drivers/char/watchdog/pcwd_usb.c +++ b/drivers/char/watchdog/pcwd_usb.c @@ -705,7 +705,8 @@ err_out_misc_deregister: err_out_unregister_reboot: unregister_reboot_notifier(&usb_pcwd_notifier); error: - usb_pcwd_delete (usb_pcwd); + if (usb_pcwd) + usb_pcwd_delete(usb_pcwd); usb_pcwd_device = NULL; return retval; } diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index b582d0cdc24f..4f0898400c6d 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -71,7 +71,7 @@ config EDAC_E7XXX config EDAC_E752X tristate "Intel e752x (e7520, e7525, e7320)" - depends on EDAC_MM_EDAC && PCI && X86 + depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG help Support for error detection and correction on the Intel E7520, E7525, E7320 server chipsets. diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 85429979d0db..98e395f4bb29 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -1,7 +1,8 @@ # # Makefile for the linux kernel. # -obj-$(CONFIG_EDD) += edd.o +obj-$(CONFIG_DMI) += dmi_scan.o +obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_PCDP) += pcdp.o obj-$(CONFIG_DELL_RBU) += dell_rbu.o diff --git a/arch/i386/kernel/dmi_scan.c b/drivers/firmware/dmi_scan.c similarity index 98% rename from arch/i386/kernel/dmi_scan.c rename to drivers/firmware/dmi_scan.c index 5efceebc48dc..948bd7e1445a 100644 --- a/arch/i386/kernel/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -27,7 +27,7 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s) else printk(KERN_ERR "dmi_string: out of memory.\n"); } - } + } return str; } @@ -41,7 +41,7 @@ static int __init dmi_table(u32 base, int len, int num, { u8 *buf, *data; int i = 0; - + buf = dmi_ioremap(base, len); if (buf == NULL) return -1; @@ -49,9 +49,9 @@ static int __init dmi_table(u32 base, int len, int num, data = buf; /* - * Stop when we see all the items the table claimed to have - * OR we run off the end of the table (also happens) - */ + * Stop when we see all the items the table claimed to have + * OR we run off the end of the table (also happens) + */ while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { struct dmi_header *dm = (struct dmi_header *)data; /* @@ -75,7 +75,7 @@ static int __init dmi_checksum(u8 *buf) { u8 sum = 0; int a; - + for (a = 0; a < 15; a++) sum += buf[a]; diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index 7636c1a58f9c..1659f6c41458 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ @@ -71,10 +70,10 @@ static u8 km_activity; static int rest_x; static int rest_y; -static DEFINE_MUTEX(hdaps_mutex); +static DECLARE_MUTEX(hdaps_sem); /* - * __get_latch - Get the value from a given port. Callers must hold hdaps_mutex. + * __get_latch - Get the value from a given port. Callers must hold hdaps_sem. */ static inline u8 __get_latch(u16 port) { @@ -83,7 +82,7 @@ static inline u8 __get_latch(u16 port) /* * __check_latch - Check a port latch for a given value. Returns zero if the - * port contains the given value. Callers must hold hdaps_mutex. + * port contains the given value. Callers must hold hdaps_sem. */ static inline int __check_latch(u16 port, u8 val) { @@ -94,7 +93,7 @@ static inline int __check_latch(u16 port, u8 val) /* * __wait_latch - Wait up to 100us for a port latch to get a certain value, - * returning zero if the value is obtained. Callers must hold hdaps_mutex. + * returning zero if the value is obtained. Callers must hold hdaps_sem. */ static int __wait_latch(u16 port, u8 val) { @@ -111,7 +110,7 @@ static int __wait_latch(u16 port, u8 val) /* * __device_refresh - request a refresh from the accelerometer. Does not wait - * for refresh to complete. Callers must hold hdaps_mutex. + * for refresh to complete. Callers must hold hdaps_sem. */ static void __device_refresh(void) { @@ -125,7 +124,7 @@ static void __device_refresh(void) /* * __device_refresh_sync - request a synchronous refresh from the * accelerometer. We wait for the refresh to complete. Returns zero if - * successful and nonzero on error. Callers must hold hdaps_mutex. + * successful and nonzero on error. Callers must hold hdaps_sem. */ static int __device_refresh_sync(void) { @@ -135,7 +134,7 @@ static int __device_refresh_sync(void) /* * __device_complete - indicate to the accelerometer that we are done reading - * data, and then initiate an async refresh. Callers must hold hdaps_mutex. + * data, and then initiate an async refresh. Callers must hold hdaps_sem. */ static inline void __device_complete(void) { @@ -153,7 +152,7 @@ static int hdaps_readb_one(unsigned int port, u8 *val) { int ret; - mutex_lock(&hdaps_mutex); + down(&hdaps_sem); /* do a sync refresh -- we need to be sure that we read fresh data */ ret = __device_refresh_sync(); @@ -164,7 +163,7 @@ static int hdaps_readb_one(unsigned int port, u8 *val) __device_complete(); out: - mutex_unlock(&hdaps_mutex); + up(&hdaps_sem); return ret; } @@ -199,9 +198,9 @@ static int hdaps_read_pair(unsigned int port1, unsigned int port2, { int ret; - mutex_lock(&hdaps_mutex); + down(&hdaps_sem); ret = __hdaps_read_pair(port1, port2, val1, val2); - mutex_unlock(&hdaps_mutex); + up(&hdaps_sem); return ret; } @@ -214,7 +213,7 @@ static int hdaps_device_init(void) { int total, ret = -ENXIO; - mutex_lock(&hdaps_mutex); + down(&hdaps_sem); outb(0x13, 0x1610); outb(0x01, 0x161f); @@ -280,7 +279,7 @@ static int hdaps_device_init(void) } out: - mutex_unlock(&hdaps_mutex); + up(&hdaps_sem); return ret; } @@ -314,7 +313,7 @@ static struct platform_driver hdaps_driver = { }; /* - * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_mutex. + * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_sem. */ static void hdaps_calibrate(void) { @@ -326,7 +325,7 @@ static void hdaps_mousedev_poll(unsigned long unused) int x, y; /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ - if (!mutex_trylock(&hdaps_mutex)) { + if (down_trylock(&hdaps_sem)) { mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD); return; } @@ -341,7 +340,7 @@ static void hdaps_mousedev_poll(unsigned long unused) mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD); out: - mutex_unlock(&hdaps_mutex); + up(&hdaps_sem); } @@ -421,9 +420,9 @@ static ssize_t hdaps_calibrate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - mutex_lock(&hdaps_mutex); + down(&hdaps_sem); hdaps_calibrate(); - mutex_unlock(&hdaps_mutex); + up(&hdaps_sem); return count; } @@ -510,12 +509,22 @@ static int hdaps_dmi_match_invert(struct dmi_system_id *id) } \ } +#define HDAPS_DMI_MATCH_LENOVO(model) { \ + .ident = "Lenovo " model, \ + .callback = hdaps_dmi_match_invert, \ + .matches = { \ + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), \ + DMI_MATCH(DMI_PRODUCT_VERSION, model) \ + } \ +} + static int __init hdaps_init(void) { int ret; /* Note that DMI_MATCH(...,"ThinkPad T42") will match "ThinkPad T42p" */ struct dmi_system_id hdaps_whitelist[] = { + HDAPS_DMI_MATCH_NORMAL("ThinkPad H"), HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"), HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"), HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"), @@ -525,15 +534,17 @@ static int __init hdaps_init(void) HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"), HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"), HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"), + HDAPS_DMI_MATCH_LENOVO("ThinkPad T60p"), HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"), HDAPS_DMI_MATCH_NORMAL("ThinkPad X41 Tablet"), HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"), + HDAPS_DMI_MATCH_LENOVO("ThinkPad X60"), { .ident = NULL } }; if (!dmi_check_system(hdaps_whitelist)) { printk(KERN_WARNING "hdaps: supported laptop not found!\n"); - ret = -ENXIO; + ret = -ENODEV; goto out; } diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 6865c64d8a51..958602e28412 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -1161,7 +1161,7 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) bank. */ if (kind < 0) { if (w83792d_read_value(client, W83792D_REG_CONFIG) & 0x80) { - dev_warn(dev, "Detection failed at step 3\n"); + dev_dbg(dev, "Detection failed at step 1\n"); goto ERROR1; } val1 = w83792d_read_value(client, W83792D_REG_BANK); @@ -1170,6 +1170,7 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) if (!(val1 & 0x07)) { /* is Bank0 */ if (((!(val1 & 0x80)) && (val2 != 0xa3)) || ((val1 & 0x80) && (val2 != 0x5c))) { + dev_dbg(dev, "Detection failed at step 2\n"); goto ERROR1; } } @@ -1177,7 +1178,7 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) should match */ if (w83792d_read_value(client, W83792D_REG_I2C_ADDR) != address) { - dev_warn(dev, "Detection failed at step 5\n"); + dev_dbg(dev, "Detection failed at step 3\n"); goto ERROR1; } } diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 089c6f5b24de..d6d44946a283 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -286,7 +286,10 @@ config I2C_PARPORT This driver is a replacement for (and was inspired by) an older driver named i2c-philips-par. The new driver supports more devices, and makes it easier to add support for new devices. - + + An adapter type parameter is now mandatory. Please read the file + Documentation/i2c/busses/i2c-parport for details. + Another driver exists, named i2c-parport-light, which doesn't depend on the parport driver. This is meant for embedded systems. Don't say Y here if you intend to say Y or M there. diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index c63025a4c861..e09ebbb2f9f0 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -121,9 +121,14 @@ static struct i2c_adapter parport_adapter = { static int __init i2c_parport_init(void) { - if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) { + if (type < 0) { + printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); + return -ENODEV; + } + + if (type >= ARRAY_SIZE(adapter_parm)) { printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); - type = 0; + return -ENODEV; } if (base == 0) { diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 7e2e8cd1c14a..934bd55bae15 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -241,9 +241,14 @@ static struct parport_driver i2c_parport_driver = { static int __init i2c_parport_init(void) { - if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) { + if (type < 0) { + printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); + return -ENODEV; + } + + if (type >= ARRAY_SIZE(adapter_parm)) { printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); - type = 0; + return -ENODEV; } return parport_register_driver(&i2c_parport_driver); diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h index d702e5e0388d..9ddd816d5d0f 100644 --- a/drivers/i2c/busses/i2c-parport.h +++ b/drivers/i2c/busses/i2c-parport.h @@ -90,7 +90,7 @@ static struct adapter_parm adapter_parm[] = { }, }; -static int type; +static int type = -1; module_param(type, int, 0); MODULE_PARM_DESC(type, "Type of adapter:\n" diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 3024907cdafe..1a73c0532fc7 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -43,13 +43,6 @@ #include #include -/* - HISTORY: - 2003-05-11 1.0.0 Updated from lm_sensors project for kernel 2.5 - (was i2c-sis645.c from lm_sensors 2.7.0) -*/ -#define SIS96x_VERSION "1.0.0" - /* base address register in PCI config space */ #define SIS96x_BAR 0x04 @@ -337,7 +330,6 @@ static struct pci_driver sis96x_driver = { static int __init i2c_sis96x_init(void) { - printk(KERN_INFO "i2c-sis96x version %s\n", SIS96x_VERSION); return pci_register_driver(&sis96x_driver); } diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c index 03d09ed5ec2c..4630f1969a09 100644 --- a/drivers/i2c/chips/ds1374.c +++ b/drivers/i2c/chips/ds1374.c @@ -27,6 +27,7 @@ #include #include #include +#include #define DS1374_REG_TOD0 0x00 #define DS1374_REG_TOD1 0x01 @@ -139,7 +140,7 @@ ulong ds1374_get_rtc_time(void) return t1; } -static void ds1374_set_tlet(ulong arg) +static void ds1374_set_work(void *arg) { ulong t1, t2; int limit = 10; /* arbitrary retry limit */ @@ -168,17 +169,18 @@ static void ds1374_set_tlet(ulong arg) static ulong new_time; -static DECLARE_TASKLET_DISABLED(ds1374_tasklet, ds1374_set_tlet, - (ulong) & new_time); +static struct workqueue_struct *ds1374_workqueue; + +static DECLARE_WORK(ds1374_work, ds1374_set_work, &new_time); int ds1374_set_rtc_time(ulong nowtime) { new_time = nowtime; if (in_interrupt()) - tasklet_schedule(&ds1374_tasklet); + queue_work(ds1374_workqueue, &ds1374_work); else - ds1374_set_tlet((ulong) & new_time); + ds1374_set_work(&new_time); return 0; } @@ -204,6 +206,8 @@ static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) client->adapter = adap; client->driver = &ds1374_driver; + ds1374_workqueue = create_singlethread_workqueue("ds1374"); + if ((rc = i2c_attach_client(client)) != 0) { kfree(client); return rc; @@ -227,7 +231,7 @@ static int ds1374_detach(struct i2c_client *client) if ((rc = i2c_detach_client(client)) == 0) { kfree(i2c_get_clientdata(client)); - tasklet_kill(&ds1374_tasklet); + destroy_workqueue(ds1374_workqueue); } return rc; } diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c index b5aabe7cf792..27fc9ff2961a 100644 --- a/drivers/i2c/chips/m41t00.c +++ b/drivers/i2c/chips/m41t00.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -111,7 +112,7 @@ m41t00_get_rtc_time(void) } static void -m41t00_set_tlet(ulong arg) +m41t00_set(void *arg) { struct rtc_time tm; ulong nowtime = *(ulong *)arg; @@ -145,9 +146,9 @@ m41t00_set_tlet(ulong arg) return; } -static ulong new_time; - -DECLARE_TASKLET_DISABLED(m41t00_tasklet, m41t00_set_tlet, (ulong)&new_time); +static ulong new_time; +static struct workqueue_struct *m41t00_wq; +static DECLARE_WORK(m41t00_work, m41t00_set, &new_time); int m41t00_set_rtc_time(ulong nowtime) @@ -155,9 +156,9 @@ m41t00_set_rtc_time(ulong nowtime) new_time = nowtime; if (in_interrupt()) - tasklet_schedule(&m41t00_tasklet); + queue_work(m41t00_wq, &m41t00_work); else - m41t00_set_tlet((ulong)&new_time); + m41t00_set(&new_time); return 0; } @@ -189,6 +190,7 @@ m41t00_probe(struct i2c_adapter *adap, int addr, int kind) return rc; } + m41t00_wq = create_singlethread_workqueue("m41t00"); save_client = client; return 0; } @@ -206,7 +208,7 @@ m41t00_detach(struct i2c_client *client) if ((rc = i2c_detach_client(client)) == 0) { kfree(client); - tasklet_kill(&m41t00_tasklet); + destroy_workqueue(m41t00_wq); } return rc; } diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index ccf528d733bf..a5017de72da5 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -61,6 +61,7 @@ #include #include #include +#include #define _IDE_DISK @@ -317,6 +318,8 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s return ide_stopped; } + ledtrig_ide_activity(); + pr_debug("%s: %sing: block=%llu, sectors=%lu, buffer=0x%08lx\n", drive->name, rq_data_dir(rq) == READ ? "read" : "writ", (unsigned long long)block, rq->nr_sectors, diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 0606bd2f6020..9233b8109a0f 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -375,7 +375,13 @@ static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) } } - ide_end_request(drive, 1, rq->hard_nr_sectors); + if (rq->rq_disk) { + ide_driver_t *drv; + + drv = *(ide_driver_t **)rq->rq_disk->private_data;; + drv->end_request(drive, 1, rq->hard_nr_sectors); + } else + ide_end_request(drive, 1, rq->hard_nr_sectors); } /* diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 6213bd3caee5..4961f1e764a7 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -81,14 +81,14 @@ static const char ide_major[] = { }; typedef struct ide_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; int ndev; dev_node_t node; int hd; } ide_info_t; -static void ide_release(dev_link_t *); -static void ide_config(dev_link_t *); +static void ide_release(struct pcmcia_device *); +static int ide_config(struct pcmcia_device *); static void ide_detach(struct pcmcia_device *p_dev); @@ -103,10 +103,9 @@ static void ide_detach(struct pcmcia_device *p_dev); ======================================================================*/ -static int ide_attach(struct pcmcia_device *p_dev) +static int ide_probe(struct pcmcia_device *link) { ide_info_t *info; - dev_link_t *link; DEBUG(0, "ide_attach()\n"); @@ -114,7 +113,9 @@ static int ide_attach(struct pcmcia_device *p_dev) info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - link = &info->link; link->priv = info; + + info->p_dev = link; + link->priv = info; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; @@ -122,16 +123,9 @@ static int ide_attach(struct pcmcia_device *p_dev) link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - ide_config(link); - - return 0; + return ide_config(link); } /* ide_attach */ /*====================================================================== @@ -143,14 +137,11 @@ static int ide_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void ide_detach(struct pcmcia_device *p_dev) +static void ide_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - DEBUG(0, "ide_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) - ide_release(link); + ide_release(link); kfree(link->priv); } /* ide_detach */ @@ -177,9 +168,8 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void ide_config(dev_link_t *link) +static int ide_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; ide_info_t *info = link->priv; tuple_t tuple; struct { @@ -203,34 +193,30 @@ static void ide_config(dev_link_t *link) tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &stk->parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &stk->parse)); link->conf.ConfigBase = stk->parse.config.base; link->conf.Present = stk->parse.config.rmask[0]; tuple.DesiredTuple = CISTPL_MANFID; - if (!pcmcia_get_first_tuple(handle, &tuple) && - !pcmcia_get_tuple_data(handle, &tuple) && - !pcmcia_parse_tuple(handle, &tuple, &stk->parse)) + if (!pcmcia_get_first_tuple(link, &tuple) && + !pcmcia_get_tuple_data(link, &tuple) && + !pcmcia_parse_tuple(link, &tuple, &stk->parse)) is_kme = ((stk->parse.manfid.manf == MANFID_KME) && ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) || (stk->parse.manfid.card == PRODID_KME_KXLC005_B))); - /* Configure card */ - link->state |= DEV_CONFIG; - /* Not sure if this is right... look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &stk->conf)); - link->conf.Vcc = stk->conf.Vcc; + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf)); pass = io_base = ctl_base = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { - if (pcmcia_get_tuple_data(handle, &tuple) != 0) goto next_entry; - if (pcmcia_parse_tuple(handle, &tuple, &stk->parse) != 0) goto next_entry; + if (pcmcia_get_tuple_data(link, &tuple) != 0) goto next_entry; + if (pcmcia_parse_tuple(link, &tuple, &stk->parse) != 0) goto next_entry; /* Check for matching Vcc, unless we're desperate */ if (!pass) { @@ -244,10 +230,10 @@ static void ide_config(dev_link_t *link) } if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) { @@ -261,14 +247,14 @@ static void ide_config(dev_link_t *link) link->io.NumPorts1 = 8; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = (is_kme) ? 2 : 1; - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; io_base = link->io.BasePort1; ctl_base = link->io.BasePort2; } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { link->io.NumPorts1 = io->win[0].len; link->io.NumPorts2 = 0; - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; io_base = link->io.BasePort1; ctl_base = link->io.BasePort1 + 0x0e; @@ -281,16 +267,16 @@ static void ide_config(dev_link_t *link) if (cfg->flags & CISTPL_CFTABLE_DEFAULT) memcpy(&stk->dflt, cfg, sizeof(stk->dflt)); if (pass) { - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); - } else if (pcmcia_get_next_tuple(handle, &tuple) != 0) { - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); + } else if (pcmcia_get_next_tuple(link, &tuple) != 0) { + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); memset(&stk->dflt, 0, sizeof(stk->dflt)); pass++; } } - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); /* disable drive interrupts during IDE probe */ outb(0x02, ctl_base); @@ -301,12 +287,12 @@ static void ide_config(dev_link_t *link) /* retry registration in case device is still spinning up */ for (hd = -1, i = 0; i < 10; i++) { - hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, handle); + hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link); if (hd >= 0) break; if (link->io.NumPorts1 == 0x20) { outb(0x02, ctl_base + 0x10); hd = idecs_register(io_base + 0x10, ctl_base + 0x10, - link->irq.AssignedIRQ, handle); + link->irq.AssignedIRQ, link); if (hd >= 0) { io_base += 0x10; ctl_base += 0x10; @@ -328,25 +314,23 @@ static void ide_config(dev_link_t *link) info->node.major = ide_major[hd]; info->node.minor = 0; info->hd = hd; - link->dev = &info->node; - printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n", - info->node.dev_name, link->conf.Vcc / 10, link->conf.Vcc % 10, - link->conf.Vpp1 / 10, link->conf.Vpp1 % 10); + link->dev_node = &info->node; + printk(KERN_INFO "ide-cs: %s: Vpp = %d.%d\n", + info->node.dev_name, link->conf.Vpp / 10, link->conf.Vpp % 10); - link->state &= ~DEV_CONFIG_PENDING; kfree(stk); - return; + return 0; err_mem: printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n"); goto failed; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: kfree(stk); ide_release(link); - link->state &= ~DEV_CONFIG_PENDING; + return -ENODEV; } /* ide_config */ /*====================================================================== @@ -357,7 +341,7 @@ failed: ======================================================================*/ -void ide_release(dev_link_t *link) +void ide_release(struct pcmcia_device *link) { ide_info_t *info = link->priv; @@ -369,37 +353,10 @@ void ide_release(dev_link_t *link) ide_unregister(info->hd); } info->ndev = 0; - link->dev = NULL; - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } /* ide_release */ -static int ide_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int ide_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (DEV_OK(link)) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; -} /*====================================================================== @@ -459,11 +416,9 @@ static struct pcmcia_driver ide_cs_driver = { .drv = { .name = "ide-cs", }, - .probe = ide_attach, + .probe = ide_probe, .remove = ide_detach, .id_table = ide_ids, - .suspend = ide_suspend, - .resume = ide_resume, }; static int __init init_ide_cs(void) diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index c85b87cb59d1..3e677c4f8c28 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -440,7 +440,7 @@ static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif) #if defined(CONFIG_PPC_CHRP) && defined(CONFIG_PPC32) - if(_machine == _MACH_chrp && _chrp_type == _CHRP_Pegasos) { + if(machine_is(chrp) && _chrp_type == _CHRP_Pegasos) { hwif->irq = hwif->channel ? 15 : 14; } #endif diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 5013b1285e22..78e30f803671 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -1677,7 +1677,7 @@ MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match); void __init pmac_ide_probe(void) { - if (_machine != _MACH_Pmac) + if (!machine_is(powermac)) return; #ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index a86beeb6af5d..19222878aae9 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -3529,7 +3529,7 @@ static void ohci1394_pci_remove(struct pci_dev *pdev) static int ohci1394_pci_resume (struct pci_dev *pdev) { #ifdef CONFIG_PPC_PMAC - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { struct device_node *of_node; /* Re-enable 1394 */ @@ -3548,7 +3548,7 @@ static int ohci1394_pci_resume (struct pci_dev *pdev) static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state) { #ifdef CONFIG_PPC_PMAC - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { struct device_node *of_node; /* Disable 1394 */ diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 2c765ca5aa50..f4206604db03 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -496,22 +496,17 @@ static struct sbp2_command_info *sbp2util_find_command_for_orb( /* * This function finds the sbp2_command for a given outstanding SCpnt. * Only looks at the inuse list. + * Must be called with scsi_id->sbp2_command_orb_lock held. */ -static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt) +static struct sbp2_command_info *sbp2util_find_command_for_SCpnt( + struct scsi_id_instance_data *scsi_id, void *SCpnt) { struct sbp2_command_info *command; - unsigned long flags; - spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); - if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) { - list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) { - if (command->Current_SCpnt == SCpnt) { - spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); + if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) + list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) + if (command->Current_SCpnt == SCpnt) return command; - } - } - } - spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return NULL; } @@ -580,17 +575,15 @@ static void sbp2util_free_command_dma(struct sbp2_command_info *command) /* * This function moves a command to the completed orb list. + * Must be called with scsi_id->sbp2_command_orb_lock held. */ -static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id, - struct sbp2_command_info *command) +static void sbp2util_mark_command_completed( + struct scsi_id_instance_data *scsi_id, + struct sbp2_command_info *command) { - unsigned long flags; - - spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); list_del(&command->list); sbp2util_free_command_dma(command); list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed); - spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); } /* @@ -2148,7 +2141,9 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest * Matched status with command, now grab scsi command pointers and check status */ SCpnt = command->Current_SCpnt; + spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); sbp2util_mark_command_completed(scsi_id, command); + spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); if (SCpnt) { @@ -2484,6 +2479,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) (struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0]; struct sbp2scsi_host_info *hi = scsi_id->hi; struct sbp2_command_info *command; + unsigned long flags; SBP2_ERR("aborting sbp2 command"); scsi_print_command(SCpnt); @@ -2494,6 +2490,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) * Right now, just return any matching command structures * to the free pool. */ + spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt); if (command) { SBP2_DEBUG("Found command to abort"); @@ -2511,6 +2508,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt) command->Current_done(command->Current_SCpnt); } } + spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); /* * Initiate a fetch agent reset. diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index bdf0891a92dd..afc612b8577d 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -30,6 +30,7 @@ config INFINIBAND_USER_ACCESS . source "drivers/infiniband/hw/mthca/Kconfig" +source "drivers/infiniband/hw/ipath/Kconfig" source "drivers/infiniband/ulp/ipoib/Kconfig" diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile index a43fb34cca94..eea27322a22d 100644 --- a/drivers/infiniband/Makefile +++ b/drivers/infiniband/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_INFINIBAND) += core/ obj-$(CONFIG_INFINIBAND_MTHCA) += hw/mthca/ +obj-$(CONFIG_IPATH_CORE) += hw/ipath/ obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/ obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/ diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index c57a3871184c..50364c0b090c 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -302,7 +302,7 @@ static void ib_cache_setup_one(struct ib_device *device) kmalloc(sizeof *device->cache.pkey_cache * (end_port(device) - start_port(device) + 1), GFP_KERNEL); device->cache.gid_cache = - kmalloc(sizeof *device->cache.pkey_cache * + kmalloc(sizeof *device->cache.gid_cache * (end_port(device) - start_port(device) + 1), GFP_KERNEL); if (!device->cache.pkey_cache || !device->cache.gid_cache) { diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index f7854b65fd55..3a702da83e41 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -227,6 +227,14 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, if (!is_vendor_oui(mad_reg_req->oui)) goto error1; } + /* Make sure class supplied is consistent with RMPP */ + if (ib_is_mad_class_rmpp(mad_reg_req->mgmt_class)) { + if (!rmpp_version) + goto error1; + } else { + if (rmpp_version) + goto error1; + } /* Make sure class supplied is consistent with QP type */ if (qp_type == IB_QPT_SMI) { if ((mad_reg_req->mgmt_class != @@ -890,6 +898,35 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, } EXPORT_SYMBOL(ib_create_send_mad); +int ib_get_mad_data_offset(u8 mgmt_class) +{ + if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM) + return IB_MGMT_SA_HDR; + else if ((mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) || + (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) || + (mgmt_class == IB_MGMT_CLASS_BIS)) + return IB_MGMT_DEVICE_HDR; + else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && + (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) + return IB_MGMT_VENDOR_HDR; + else + return IB_MGMT_MAD_HDR; +} +EXPORT_SYMBOL(ib_get_mad_data_offset); + +int ib_is_mad_class_rmpp(u8 mgmt_class) +{ + if ((mgmt_class == IB_MGMT_CLASS_SUBN_ADM) || + (mgmt_class == IB_MGMT_CLASS_DEVICE_MGMT) || + (mgmt_class == IB_MGMT_CLASS_DEVICE_ADM) || + (mgmt_class == IB_MGMT_CLASS_BIS) || + ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && + (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END))) + return 1; + return 0; +} +EXPORT_SYMBOL(ib_is_mad_class_rmpp); + void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num) { struct ib_mad_send_wr_private *mad_send_wr; @@ -1022,6 +1059,13 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf, goto error; } + if (!ib_is_mad_class_rmpp(((struct ib_mad_hdr *) send_buf->mad)->mgmt_class)) { + if (mad_agent_priv->agent.rmpp_version) { + ret = -EINVAL; + goto error; + } + } + /* * Save pointer to next work request to post in case the * current one completes, and the user modifies the work @@ -1618,14 +1662,59 @@ static int is_data_mad(struct ib_mad_agent_private *mad_agent_priv, (rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA); } +static inline int rcv_has_same_class(struct ib_mad_send_wr_private *wr, + struct ib_mad_recv_wc *rwc) +{ + return ((struct ib_mad *)(wr->send_buf.mad))->mad_hdr.mgmt_class == + rwc->recv_buf.mad->mad_hdr.mgmt_class; +} + +static inline int rcv_has_same_gid(struct ib_mad_send_wr_private *wr, + struct ib_mad_recv_wc *rwc ) +{ + struct ib_ah_attr attr; + u8 send_resp, rcv_resp; + + send_resp = ((struct ib_mad *)(wr->send_buf.mad))-> + mad_hdr.method & IB_MGMT_METHOD_RESP; + rcv_resp = rwc->recv_buf.mad->mad_hdr.method & IB_MGMT_METHOD_RESP; + + if (!send_resp && rcv_resp) + /* is request/response. GID/LIDs are both local (same). */ + return 1; + + if (send_resp == rcv_resp) + /* both requests, or both responses. GIDs different */ + return 0; + + if (ib_query_ah(wr->send_buf.ah, &attr)) + /* Assume not equal, to avoid false positives. */ + return 0; + + if (!(attr.ah_flags & IB_AH_GRH) && !(rwc->wc->wc_flags & IB_WC_GRH)) + return attr.dlid == rwc->wc->slid; + else if ((attr.ah_flags & IB_AH_GRH) && + (rwc->wc->wc_flags & IB_WC_GRH)) + return memcmp(attr.grh.dgid.raw, + rwc->recv_buf.grh->sgid.raw, 16) == 0; + else + /* one has GID, other does not. Assume different */ + return 0; +} struct ib_mad_send_wr_private* -ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid) +ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_recv_wc *mad_recv_wc) { struct ib_mad_send_wr_private *mad_send_wr; + struct ib_mad *mad; + + mad = (struct ib_mad *)mad_recv_wc->recv_buf.mad; list_for_each_entry(mad_send_wr, &mad_agent_priv->wait_list, agent_list) { - if (mad_send_wr->tid == tid) + if ((mad_send_wr->tid == mad->mad_hdr.tid) && + rcv_has_same_class(mad_send_wr, mad_recv_wc) && + rcv_has_same_gid(mad_send_wr, mad_recv_wc)) return mad_send_wr; } @@ -1636,7 +1725,10 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid) list_for_each_entry(mad_send_wr, &mad_agent_priv->send_list, agent_list) { if (is_data_mad(mad_agent_priv, mad_send_wr->send_buf.mad) && - mad_send_wr->tid == tid && mad_send_wr->timeout) { + mad_send_wr->tid == mad->mad_hdr.tid && + mad_send_wr->timeout && + rcv_has_same_class(mad_send_wr, mad_recv_wc) && + rcv_has_same_gid(mad_send_wr, mad_recv_wc)) { /* Verify request has not been canceled */ return (mad_send_wr->status == IB_WC_SUCCESS) ? mad_send_wr : NULL; @@ -1661,7 +1753,6 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, struct ib_mad_send_wr_private *mad_send_wr; struct ib_mad_send_wc mad_send_wc; unsigned long flags; - __be64 tid; INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); @@ -1677,9 +1768,8 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, /* Complete corresponding request */ if (response_mad(mad_recv_wc->recv_buf.mad)) { - tid = mad_recv_wc->recv_buf.mad->mad_hdr.tid; spin_lock_irqsave(&mad_agent_priv->lock, flags); - mad_send_wr = ib_find_send_mad(mad_agent_priv, tid); + mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc); if (!mad_send_wr) { spin_unlock_irqrestore(&mad_agent_priv->lock, flags); ib_free_recv_mad(mad_recv_wc); @@ -2221,6 +2311,7 @@ static void local_completions(void *data) local = list_entry(mad_agent_priv->local_list.next, struct ib_mad_local_private, completion_list); + list_del(&local->completion_list); spin_unlock_irqrestore(&mad_agent_priv->lock, flags); if (local->mad_priv) { recv_mad_agent = local->recv_mad_agent; @@ -2272,7 +2363,6 @@ local_send_completion: &mad_send_wc); spin_lock_irqsave(&mad_agent_priv->lock, flags); - list_del(&local->completion_list); atomic_dec(&mad_agent_priv->refcount); if (!recv) kmem_cache_free(ib_mad_cache, local->mad_priv); @@ -2408,11 +2498,11 @@ static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, } } sg_list.addr = dma_map_single(qp_info->port_priv-> - device->dma_device, - &mad_priv->grh, - sizeof *mad_priv - - sizeof mad_priv->header, - DMA_FROM_DEVICE); + device->dma_device, + &mad_priv->grh, + sizeof *mad_priv - + sizeof mad_priv->header, + DMA_FROM_DEVICE); pci_unmap_addr_set(&mad_priv->header, mapping, sg_list.addr); recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list; mad_priv->header.mad_list.mad_queue = recv_queue; diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index a7125d4b5ccf..6c9c133d71ef 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -216,7 +216,8 @@ extern kmem_cache_t *ib_mad_cache; int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr); struct ib_mad_send_wr_private * -ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, __be64 tid); +ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv, + struct ib_mad_recv_wc *mad_recv_wc); void ib_mad_complete_send_wr(struct ib_mad_send_wr_private *mad_send_wr, struct ib_mad_send_wc *mad_send_wc); diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index bacfdd5bddad..dfd4e588ce03 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2005 Intel Inc. All rights reserved. - * Copyright (c) 2005 Voltaire, Inc. All rights reserved. + * Copyright (c) 2005-2006 Voltaire, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -100,17 +100,6 @@ void ib_cancel_rmpp_recvs(struct ib_mad_agent_private *agent) } } -static int data_offset(u8 mgmt_class) -{ - if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM) - return IB_MGMT_SA_HDR; - else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && - (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) - return IB_MGMT_VENDOR_HDR; - else - return IB_MGMT_RMPP_HDR; -} - static void format_ack(struct ib_mad_send_buf *msg, struct ib_rmpp_mad *data, struct mad_rmpp_recv *rmpp_recv) @@ -137,7 +126,7 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv, struct ib_mad_send_buf *msg; int ret, hdr_len; - hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class); + hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class); msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp, recv_wc->wc->pkey_index, 1, hdr_len, 0, GFP_KERNEL); @@ -163,7 +152,7 @@ static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent, if (IS_ERR(ah)) return (void *) ah; - hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class); + hdr_len = ib_get_mad_data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class); msg = ib_create_send_mad(agent, recv_wc->wc->src_qp, recv_wc->wc->pkey_index, 1, hdr_len, 0, GFP_KERNEL); @@ -408,7 +397,7 @@ static inline int get_mad_len(struct mad_rmpp_recv *rmpp_recv) rmpp_mad = (struct ib_rmpp_mad *)rmpp_recv->cur_seg_buf->mad; - hdr_size = data_offset(rmpp_mad->mad_hdr.mgmt_class); + hdr_size = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class); data_size = sizeof(struct ib_rmpp_mad) - hdr_size; pad = IB_MGMT_RMPP_DATA - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); if (pad > IB_MGMT_RMPP_DATA || pad < 0) @@ -562,15 +551,15 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) return ib_send_mad(mad_send_wr); } -static void abort_send(struct ib_mad_agent_private *agent, __be64 tid, - u8 rmpp_status) +static void abort_send(struct ib_mad_agent_private *agent, + struct ib_mad_recv_wc *mad_recv_wc, u8 rmpp_status) { struct ib_mad_send_wr_private *mad_send_wr; struct ib_mad_send_wc wc; unsigned long flags; spin_lock_irqsave(&agent->lock, flags); - mad_send_wr = ib_find_send_mad(agent, tid); + mad_send_wr = ib_find_send_mad(agent, mad_recv_wc); if (!mad_send_wr) goto out; /* Unmatched send */ @@ -612,8 +601,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; if (rmpp_mad->rmpp_hdr.rmpp_status) { - abort_send(agent, rmpp_mad->mad_hdr.tid, - IB_MGMT_RMPP_STATUS_BAD_STATUS); + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); return; } @@ -621,14 +609,13 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, seg_num = be32_to_cpu(rmpp_mad->rmpp_hdr.seg_num); newwin = be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); if (newwin < seg_num) { - abort_send(agent, rmpp_mad->mad_hdr.tid, - IB_MGMT_RMPP_STATUS_W2S); + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S); nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_W2S); return; } spin_lock_irqsave(&agent->lock, flags); - mad_send_wr = ib_find_send_mad(agent, rmpp_mad->mad_hdr.tid); + mad_send_wr = ib_find_send_mad(agent, mad_recv_wc); if (!mad_send_wr) goto out; /* Unmatched ACK */ @@ -639,8 +626,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, if (seg_num > mad_send_wr->send_buf.seg_count || seg_num > mad_send_wr->newwin) { spin_unlock_irqrestore(&agent->lock, flags); - abort_send(agent, rmpp_mad->mad_hdr.tid, - IB_MGMT_RMPP_STATUS_S2B); + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B); nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_S2B); return; } @@ -728,12 +714,10 @@ static void process_rmpp_stop(struct ib_mad_agent_private *agent, rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad; if (rmpp_mad->rmpp_hdr.rmpp_status != IB_MGMT_RMPP_STATUS_RESX) { - abort_send(agent, rmpp_mad->mad_hdr.tid, - IB_MGMT_RMPP_STATUS_BAD_STATUS); + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); } else - abort_send(agent, rmpp_mad->mad_hdr.tid, - rmpp_mad->rmpp_hdr.rmpp_status); + abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status); } static void process_rmpp_abort(struct ib_mad_agent_private *agent, @@ -745,12 +729,10 @@ static void process_rmpp_abort(struct ib_mad_agent_private *agent, if (rmpp_mad->rmpp_hdr.rmpp_status < IB_MGMT_RMPP_STATUS_ABORT_MIN || rmpp_mad->rmpp_hdr.rmpp_status > IB_MGMT_RMPP_STATUS_ABORT_MAX) { - abort_send(agent, rmpp_mad->mad_hdr.tid, - IB_MGMT_RMPP_STATUS_BAD_STATUS); + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BAD_STATUS); } else - abort_send(agent, rmpp_mad->mad_hdr.tid, - rmpp_mad->rmpp_hdr.rmpp_status); + abort_send(agent, mad_recv_wc, rmpp_mad->rmpp_hdr.rmpp_status); } struct ib_mad_recv_wc * @@ -764,8 +746,7 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent, return mad_recv_wc; if (rmpp_mad->rmpp_hdr.rmpp_version != IB_MGMT_RMPP_VERSION) { - abort_send(agent, rmpp_mad->mad_hdr.tid, - IB_MGMT_RMPP_STATUS_UNV); + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV); nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_UNV); goto out; } @@ -783,8 +764,7 @@ ib_process_rmpp_recv_wc(struct ib_mad_agent_private *agent, process_rmpp_abort(agent, mad_recv_wc); break; default: - abort_send(agent, rmpp_mad->mad_hdr.tid, - IB_MGMT_RMPP_STATUS_BADT); + abort_send(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT); nack_recv(agent, mad_recv_wc, IB_MGMT_RMPP_STATUS_BADT); break; } diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index fb6cd42601f9..afe70a549c2f 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -177,17 +177,6 @@ static int queue_packet(struct ib_umad_file *file, return ret; } -static int data_offset(u8 mgmt_class) -{ - if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM) - return IB_MGMT_SA_HDR; - else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && - (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) - return IB_MGMT_VENDOR_HDR; - else - return IB_MGMT_RMPP_HDR; -} - static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *send_wc) { @@ -283,7 +272,7 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, */ return -ENOSPC; } - offset = data_offset(recv_buf->mad->mad_hdr.mgmt_class); + offset = ib_get_mad_data_offset(recv_buf->mad->mad_hdr.mgmt_class); max_seg_payload = sizeof (struct ib_mad) - offset; for (left = packet->length - seg_payload, buf += seg_payload; @@ -441,21 +430,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, } rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data; - if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { - hdr_len = IB_MGMT_SA_HDR; - copy_offset = IB_MGMT_RMPP_HDR; - rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & - IB_MGMT_RMPP_FLAG_ACTIVE; - } else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START && - rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) { - hdr_len = IB_MGMT_VENDOR_HDR; - copy_offset = IB_MGMT_RMPP_HDR; - rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & - IB_MGMT_RMPP_FLAG_ACTIVE; - } else { - hdr_len = IB_MGMT_MAD_HDR; + hdr_len = ib_get_mad_data_offset(rmpp_mad->mad_hdr.mgmt_class); + if (!ib_is_mad_class_rmpp(rmpp_mad->mad_hdr.mgmt_class)) { copy_offset = IB_MGMT_MAD_HDR; rmpp_active = 0; + } else { + copy_offset = IB_MGMT_RMPP_HDR; + rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & + IB_MGMT_RMPP_FLAG_ACTIVE; } data_len = count - sizeof (struct ib_user_mad) - hdr_len; diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index cae0845f472a..b78e7dc69330 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -45,6 +45,40 @@ #include #include +int ib_rate_to_mult(enum ib_rate rate) +{ + switch (rate) { + case IB_RATE_2_5_GBPS: return 1; + case IB_RATE_5_GBPS: return 2; + case IB_RATE_10_GBPS: return 4; + case IB_RATE_20_GBPS: return 8; + case IB_RATE_30_GBPS: return 12; + case IB_RATE_40_GBPS: return 16; + case IB_RATE_60_GBPS: return 24; + case IB_RATE_80_GBPS: return 32; + case IB_RATE_120_GBPS: return 48; + default: return -1; + } +} +EXPORT_SYMBOL(ib_rate_to_mult); + +enum ib_rate mult_to_ib_rate(int mult) +{ + switch (mult) { + case 1: return IB_RATE_2_5_GBPS; + case 2: return IB_RATE_5_GBPS; + case 4: return IB_RATE_10_GBPS; + case 8: return IB_RATE_20_GBPS; + case 12: return IB_RATE_30_GBPS; + case 16: return IB_RATE_40_GBPS; + case 24: return IB_RATE_60_GBPS; + case 32: return IB_RATE_80_GBPS; + case 48: return IB_RATE_120_GBPS; + default: return IB_RATE_PORT_CURRENT; + } +} +EXPORT_SYMBOL(mult_to_ib_rate); + /* Protection domains */ struct ib_pd *ib_alloc_pd(struct ib_device *device) diff --git a/drivers/infiniband/hw/ipath/Kconfig b/drivers/infiniband/hw/ipath/Kconfig new file mode 100644 index 000000000000..9ea67c409b6d --- /dev/null +++ b/drivers/infiniband/hw/ipath/Kconfig @@ -0,0 +1,16 @@ +config IPATH_CORE + tristate "PathScale InfiniPath Driver" + depends on 64BIT && PCI_MSI && NET + ---help--- + This is a low-level driver for PathScale InfiniPath host channel + adapters (HCAs) based on the HT-400 and PE-800 chips. + +config INFINIBAND_IPATH + tristate "PathScale InfiniPath Verbs Driver" + depends on IPATH_CORE && INFINIBAND + ---help--- + This is a driver that provides InfiniBand verbs support for + PathScale InfiniPath host channel adapters (HCAs). This + allows these devices to be used with both kernel upper level + protocols such as IP-over-InfiniBand as well as with userspace + applications (in conjunction with InfiniBand userspace access). diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile new file mode 100644 index 000000000000..b4d084abfd22 --- /dev/null +++ b/drivers/infiniband/hw/ipath/Makefile @@ -0,0 +1,36 @@ +EXTRA_CFLAGS += -DIPATH_IDSTR='"PathScale kernel.org driver"' \ + -DIPATH_KERN_TYPE=0 + +obj-$(CONFIG_IPATH_CORE) += ipath_core.o +obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o + +ipath_core-y := \ + ipath_diag.o \ + ipath_driver.o \ + ipath_eeprom.o \ + ipath_file_ops.o \ + ipath_fs.o \ + ipath_ht400.o \ + ipath_init_chip.o \ + ipath_intr.o \ + ipath_layer.o \ + ipath_pe800.o \ + ipath_stats.o \ + ipath_sysfs.o \ + ipath_user_pages.o + +ipath_core-$(CONFIG_X86_64) += ipath_wc_x86_64.o + +ib_ipath-y := \ + ipath_cq.o \ + ipath_keys.o \ + ipath_mad.o \ + ipath_mr.o \ + ipath_qp.o \ + ipath_rc.o \ + ipath_ruc.o \ + ipath_srq.o \ + ipath_uc.o \ + ipath_ud.o \ + ipath_verbs.o \ + ipath_verbs_mcast.o diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h new file mode 100644 index 000000000000..48a55247b832 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_common.h @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _IPATH_COMMON_H +#define _IPATH_COMMON_H + +/* + * This file contains defines, structures, etc. that are used + * to communicate between kernel and user code. + */ + +/* This is the IEEE-assigned OUI for PathScale, Inc. */ +#define IPATH_SRC_OUI_1 0x00 +#define IPATH_SRC_OUI_2 0x11 +#define IPATH_SRC_OUI_3 0x75 + +/* version of protocol header (known to chip also). In the long run, + * we should be able to generate and accept a range of version numbers; + * for now we only accept one, and it's compiled in. + */ +#define IPS_PROTO_VERSION 2 + +/* + * These are compile time constants that you may want to enable or disable + * if you are trying to debug problems with code or performance. + * IPATH_VERBOSE_TRACING define as 1 if you want additional tracing in + * fastpath code + * IPATH_TRACE_REGWRITES define as 1 if you want register writes to be + * traced in faspath code + * _IPATH_TRACING define as 0 if you want to remove all tracing in a + * compilation unit + * _IPATH_DEBUGGING define as 0 if you want to remove debug prints + */ + +/* + * The value in the BTH QP field that InfiniPath uses to differentiate + * an infinipath protocol IB packet vs standard IB transport + */ +#define IPATH_KD_QP 0x656b79 + +/* + * valid states passed to ipath_set_linkstate() user call + */ +#define IPATH_IB_LINKDOWN 0 +#define IPATH_IB_LINKARM 1 +#define IPATH_IB_LINKACTIVE 2 +#define IPATH_IB_LINKINIT 3 +#define IPATH_IB_LINKDOWN_SLEEP 4 +#define IPATH_IB_LINKDOWN_DISABLE 5 + +/* + * stats maintained by the driver. For now, at least, this is global + * to all minor devices. + */ +struct infinipath_stats { + /* number of interrupts taken */ + __u64 sps_ints; + /* number of interrupts for errors */ + __u64 sps_errints; + /* number of errors from chip (not incl. packet errors or CRC) */ + __u64 sps_errs; + /* number of packet errors from chip other than CRC */ + __u64 sps_pkterrs; + /* number of packets with CRC errors (ICRC and VCRC) */ + __u64 sps_crcerrs; + /* number of hardware errors reported (parity, etc.) */ + __u64 sps_hwerrs; + /* number of times IB link changed state unexpectedly */ + __u64 sps_iblink; + /* no longer used; left for compatibility */ + __u64 sps_unused3; + /* number of kernel (port0) packets received */ + __u64 sps_port0pkts; + /* number of "ethernet" packets sent by driver */ + __u64 sps_ether_spkts; + /* number of "ethernet" packets received by driver */ + __u64 sps_ether_rpkts; + /* number of SMA packets sent by driver */ + __u64 sps_sma_spkts; + /* number of SMA packets received by driver */ + __u64 sps_sma_rpkts; + /* number of times all ports rcvhdrq was full and packet dropped */ + __u64 sps_hdrqfull; + /* number of times all ports egrtid was full and packet dropped */ + __u64 sps_etidfull; + /* + * number of times we tried to send from driver, but no pio buffers + * avail + */ + __u64 sps_nopiobufs; + /* number of ports currently open */ + __u64 sps_ports; + /* list of pkeys (other than default) accepted (0 means not set) */ + __u16 sps_pkeys[4]; + /* lids for up to 4 infinipaths, indexed by infinipath # */ + __u16 sps_lid[4]; + /* number of user ports per chip (not IB ports) */ + __u32 sps_nports; + /* not our interrupt, or already handled */ + __u32 sps_nullintr; + /* max number of packets handled per receive call */ + __u32 sps_maxpkts_call; + /* avg number of packets handled per receive call */ + __u32 sps_avgpkts_call; + /* total number of pages locked */ + __u64 sps_pagelocks; + /* total number of pages unlocked */ + __u64 sps_pageunlocks; + /* + * Number of packets dropped in kernel other than errors (ether + * packets if ipath not configured, sma/mad, etc.) + */ + __u64 sps_krdrops; + /* mlids for up to 4 infinipaths, indexed by infinipath # */ + __u16 sps_mlid[4]; + /* pad for future growth */ + __u64 __sps_pad[45]; +}; + +/* + * These are the status bits readable (in ascii form, 64bit value) + * from the "status" sysfs file. + */ +#define IPATH_STATUS_INITTED 0x1 /* basic initialization done */ +#define IPATH_STATUS_DISABLED 0x2 /* hardware disabled */ +/* Device has been disabled via admin request */ +#define IPATH_STATUS_ADMIN_DISABLED 0x4 +#define IPATH_STATUS_OIB_SMA 0x8 /* ipath_mad kernel SMA running */ +#define IPATH_STATUS_SMA 0x10 /* user SMA running */ +/* Chip has been found and initted */ +#define IPATH_STATUS_CHIP_PRESENT 0x20 +/* IB link is at ACTIVE, usable for data traffic */ +#define IPATH_STATUS_IB_READY 0x40 +/* link is configured, LID, MTU, etc. have been set */ +#define IPATH_STATUS_IB_CONF 0x80 +/* no link established, probably no cable */ +#define IPATH_STATUS_IB_NOCABLE 0x100 +/* A Fatal hardware error has occurred. */ +#define IPATH_STATUS_HWERROR 0x200 + +/* + * The list of usermode accessible registers. Also see Reg_* later in file. + */ +typedef enum _ipath_ureg { + /* (RO) DMA RcvHdr to be used next. */ + ur_rcvhdrtail = 0, + /* (RW) RcvHdr entry to be processed next by host. */ + ur_rcvhdrhead = 1, + /* (RO) Index of next Eager index to use. */ + ur_rcvegrindextail = 2, + /* (RW) Eager TID to be processed next */ + ur_rcvegrindexhead = 3, + /* For internal use only; max register number. */ + _IPATH_UregMax +} ipath_ureg; + +/* bit values for spi_runtime_flags */ +#define IPATH_RUNTIME_HT 0x1 +#define IPATH_RUNTIME_PCIE 0x2 +#define IPATH_RUNTIME_FORCE_WC_ORDER 0x4 +#define IPATH_RUNTIME_RCVHDR_COPY 0x8 + +/* + * This structure is returned by ipath_userinit() immediately after + * open to get implementation-specific info, and info specific to this + * instance. + * + * This struct must have explict pad fields where type sizes + * may result in different alignments between 32 and 64 bit + * programs, since the 64 bit * bit kernel requires the user code + * to have matching offsets + */ +struct ipath_base_info { + /* version of hardware, for feature checking. */ + __u32 spi_hw_version; + /* version of software, for feature checking. */ + __u32 spi_sw_version; + /* InfiniPath port assigned, goes into sent packets */ + __u32 spi_port; + /* + * IB MTU, packets IB data must be less than this. + * The MTU is in bytes, and will be a multiple of 4 bytes. + */ + __u32 spi_mtu; + /* + * Size of a PIO buffer. Any given packet's total size must be less + * than this (in words). Included is the starting control word, so + * if 513 is returned, then total pkt size is 512 words or less. + */ + __u32 spi_piosize; + /* size of the TID cache in infinipath, in entries */ + __u32 spi_tidcnt; + /* size of the TID Eager list in infinipath, in entries */ + __u32 spi_tidegrcnt; + /* size of a single receive header queue entry. */ + __u32 spi_rcvhdrent_size; + /* + * Count of receive header queue entries allocated. + * This may be less than the spu_rcvhdrcnt passed in!. + */ + __u32 spi_rcvhdr_cnt; + + /* per-chip and other runtime features bitmap (IPATH_RUNTIME_*) */ + __u32 spi_runtime_flags; + + /* address where receive buffer queue is mapped into */ + __u64 spi_rcvhdr_base; + + /* user program. */ + + /* base address of eager TID receive buffers. */ + __u64 spi_rcv_egrbufs; + + /* Allocated by initialization code, not by protocol. */ + + /* + * Size of each TID buffer in host memory, starting at + * spi_rcv_egrbufs. The buffers are virtually contiguous. + */ + __u32 spi_rcv_egrbufsize; + /* + * The special QP (queue pair) value that identifies an infinipath + * protocol packet from standard IB packets. More, probably much + * more, to be added. + */ + __u32 spi_qpair; + + /* + * User register base for init code, not to be used directly by + * protocol or applications. + */ + __u64 __spi_uregbase; + /* + * Maximum buffer size in bytes that can be used in a single TID + * entry (assuming the buffer is aligned to this boundary). This is + * the minimum of what the hardware and software support Guaranteed + * to be a power of 2. + */ + __u32 spi_tid_maxsize; + /* + * alignment of each pio send buffer (byte count + * to add to spi_piobufbase to get to second buffer) + */ + __u32 spi_pioalign; + /* + * The index of the first pio buffer available to this process; + * needed to do lookup in spi_pioavailaddr; not added to + * spi_piobufbase. + */ + __u32 spi_pioindex; + /* number of buffers mapped for this process */ + __u32 spi_piocnt; + + /* + * Base address of writeonly pio buffers for this process. + * Each buffer has spi_piosize words, and is aligned on spi_pioalign + * boundaries. spi_piocnt buffers are mapped from this address + */ + __u64 spi_piobufbase; + + /* + * Base address of readonly memory copy of the pioavail registers. + * There are 2 bits for each buffer. + */ + __u64 spi_pioavailaddr; + + /* + * Address where driver updates a copy of the interface and driver + * status (IPATH_STATUS_*) as a 64 bit value. It's followed by a + * string indicating hardware error, if there was one. + */ + __u64 spi_status; + + /* number of chip ports available to user processes */ + __u32 spi_nports; + /* unit number of chip we are using */ + __u32 spi_unit; + /* num bufs in each contiguous set */ + __u32 spi_rcv_egrperchunk; + /* size in bytes of each contiguous set */ + __u32 spi_rcv_egrchunksize; + /* total size of mmap to cover full rcvegrbuffers */ + __u32 spi_rcv_egrbuftotlen; +} __attribute__ ((aligned(8))); + + +/* + * This version number is given to the driver by the user code during + * initialization in the spu_userversion field of ipath_user_info, so + * the driver can check for compatibility with user code. + * + * The major version changes when data structures + * change in an incompatible way. The driver must be the same or higher + * for initialization to succeed. In some cases, a higher version + * driver will not interoperate with older software, and initialization + * will return an error. + */ +#define IPATH_USER_SWMAJOR 1 + +/* + * Minor version differences are always compatible + * a within a major version, however if if user software is larger + * than driver software, some new features and/or structure fields + * may not be implemented; the user code must deal with this if it + * cares, or it must abort after initialization reports the difference + */ +#define IPATH_USER_SWMINOR 2 + +#define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR) + +#define IPATH_KERN_TYPE 0 + +/* + * Similarly, this is the kernel version going back to the user. It's + * slightly different, in that we want to tell if the driver was built as + * part of a PathScale release, or from the driver from OpenIB, kernel.org, + * or a standard distribution, for support reasons. The high bit is 0 for + * non-PathScale, and 1 for PathScale-built/supplied. + * + * It's returned by the driver to the user code during initialization in the + * spi_sw_version field of ipath_base_info, so the user code can in turn + * check for compatibility with the kernel. +*/ +#define IPATH_KERN_SWVERSION ((IPATH_KERN_TYPE<<31) | IPATH_USER_SWVERSION) + +/* + * This structure is passed to ipath_userinit() to tell the driver where + * user code buffers are, sizes, etc. The offsets and sizes of the + * fields must remain unchanged, for binary compatibility. It can + * be extended, if userversion is changed so user code can tell, if needed + */ +struct ipath_user_info { + /* + * version of user software, to detect compatibility issues. + * Should be set to IPATH_USER_SWVERSION. + */ + __u32 spu_userversion; + + /* desired number of receive header queue entries */ + __u32 spu_rcvhdrcnt; + + /* size of struct base_info to write to */ + __u32 spu_base_info_size; + + /* + * number of words in KD protocol header + * This tells InfiniPath how many words to copy to rcvhdrq. If 0, + * kernel uses a default. Once set, attempts to set any other value + * are an error (EAGAIN) until driver is reloaded. + */ + __u32 spu_rcvhdrsize; + + /* + * cache line aligned (64 byte) user address to + * which the rcvhdrtail register will be written by infinipath + * whenever it changes, so that no chip registers are read in + * the performance path. + */ + __u64 spu_rcvhdraddr; + + /* + * address of struct base_info to write to + */ + __u64 spu_base_info; + +} __attribute__ ((aligned(8))); + +/* User commands. */ + +#define IPATH_CMD_MIN 16 + +#define IPATH_CMD_USER_INIT 16 /* set up userspace */ +#define IPATH_CMD_PORT_INFO 17 /* find out what resources we got */ +#define IPATH_CMD_RECV_CTRL 18 /* control receipt of packets */ +#define IPATH_CMD_TID_UPDATE 19 /* update expected TID entries */ +#define IPATH_CMD_TID_FREE 20 /* free expected TID entries */ +#define IPATH_CMD_SET_PART_KEY 21 /* add partition key */ + +#define IPATH_CMD_MAX 21 + +struct ipath_port_info { + __u32 num_active; /* number of active units */ + __u32 unit; /* unit (chip) assigned to caller */ + __u32 port; /* port on unit assigned to caller */ +}; + +struct ipath_tid_info { + __u32 tidcnt; + /* make structure same size in 32 and 64 bit */ + __u32 tid__unused; + /* virtual address of first page in transfer */ + __u64 tidvaddr; + /* pointer (same size 32/64 bit) to __u16 tid array */ + __u64 tidlist; + + /* + * pointer (same size 32/64 bit) to bitmap of TIDs used + * for this call; checked for being large enough at open + */ + __u64 tidmap; +}; + +struct ipath_cmd { + __u32 type; /* command type */ + union { + struct ipath_tid_info tid_info; + struct ipath_user_info user_info; + /* address in userspace of struct ipath_port_info to + write result to */ + __u64 port_info; + /* enable/disable receipt of packets */ + __u32 recv_ctrl; + /* partition key to set */ + __u16 part_key; + } cmd; +}; + +struct ipath_iovec { + /* Pointer to data, but same size 32 and 64 bit */ + __u64 iov_base; + + /* + * Length of data; don't need 64 bits, but want + * ipath_sendpkt to remain same size as before 32 bit changes, so... + */ + __u64 iov_len; +}; + +/* + * Describes a single packet for send. Each packet can have one or more + * buffers, but the total length (exclusive of IB headers) must be less + * than the MTU, and if using the PIO method, entire packet length, + * including IB headers, must be less than the ipath_piosize value (words). + * Use of this necessitates including sys/uio.h + */ +struct __ipath_sendpkt { + __u32 sps_flags; /* flags for packet (TBD) */ + __u32 sps_cnt; /* number of entries to use in sps_iov */ + /* array of iov's describing packet. TEMPORARY */ + struct ipath_iovec sps_iov[4]; +}; + +/* Passed into SMA special file's ->read and ->write methods. */ +struct ipath_sma_pkt +{ + __u32 unit; /* unit on which to send packet */ + __u64 data; /* address of payload in userspace */ + __u32 len; /* length of payload */ +}; + +/* + * Data layout in I2C flash (for GUID, etc.) + * All fields are little-endian binary unless otherwise stated + */ +#define IPATH_FLASH_VERSION 1 +struct ipath_flash { + /* flash layout version (IPATH_FLASH_VERSION) */ + __u8 if_fversion; + /* checksum protecting if_length bytes */ + __u8 if_csum; + /* + * valid length (in use, protected by if_csum), including + * if_fversion and if_sum themselves) + */ + __u8 if_length; + /* the GUID, in network order */ + __u8 if_guid[8]; + /* number of GUIDs to use, starting from if_guid */ + __u8 if_numguid; + /* the board serial number, in ASCII */ + char if_serial[12]; + /* board mfg date (YYYYMMDD ASCII) */ + char if_mfgdate[8]; + /* last board rework/test date (YYYYMMDD ASCII) */ + char if_testdate[8]; + /* logging of error counts, TBD */ + __u8 if_errcntp[4]; + /* powered on hours, updated at driver unload */ + __u8 if_powerhour[2]; + /* ASCII free-form comment field */ + char if_comment[32]; + /* 78 bytes used, min flash size is 128 bytes */ + __u8 if_future[50]; +}; + +/* + * These are the counters implemented in the chip, and are listed in order. + * The InterCaps naming is taken straight from the chip spec. + */ +struct infinipath_counters { + __u64 LBIntCnt; + __u64 LBFlowStallCnt; + __u64 Reserved1; + __u64 TxUnsupVLErrCnt; + __u64 TxDataPktCnt; + __u64 TxFlowPktCnt; + __u64 TxDwordCnt; + __u64 TxLenErrCnt; + __u64 TxMaxMinLenErrCnt; + __u64 TxUnderrunCnt; + __u64 TxFlowStallCnt; + __u64 TxDroppedPktCnt; + __u64 RxDroppedPktCnt; + __u64 RxDataPktCnt; + __u64 RxFlowPktCnt; + __u64 RxDwordCnt; + __u64 RxLenErrCnt; + __u64 RxMaxMinLenErrCnt; + __u64 RxICRCErrCnt; + __u64 RxVCRCErrCnt; + __u64 RxFlowCtrlErrCnt; + __u64 RxBadFormatCnt; + __u64 RxLinkProblemCnt; + __u64 RxEBPCnt; + __u64 RxLPCRCErrCnt; + __u64 RxBufOvflCnt; + __u64 RxTIDFullErrCnt; + __u64 RxTIDValidErrCnt; + __u64 RxPKeyMismatchCnt; + __u64 RxP0HdrEgrOvflCnt; + __u64 RxP1HdrEgrOvflCnt; + __u64 RxP2HdrEgrOvflCnt; + __u64 RxP3HdrEgrOvflCnt; + __u64 RxP4HdrEgrOvflCnt; + __u64 RxP5HdrEgrOvflCnt; + __u64 RxP6HdrEgrOvflCnt; + __u64 RxP7HdrEgrOvflCnt; + __u64 RxP8HdrEgrOvflCnt; + __u64 Reserved6; + __u64 Reserved7; + __u64 IBStatusChangeCnt; + __u64 IBLinkErrRecoveryCnt; + __u64 IBLinkDownedCnt; + __u64 IBSymbolErrCnt; +}; + +/* + * The next set of defines are for packet headers, and chip register + * and memory bits that are visible to and/or used by user-mode software + * The other bits that are used only by the driver or diags are in + * ipath_registers.h + */ + +/* RcvHdrFlags bits */ +#define INFINIPATH_RHF_LENGTH_MASK 0x7FF +#define INFINIPATH_RHF_LENGTH_SHIFT 0 +#define INFINIPATH_RHF_RCVTYPE_MASK 0x7 +#define INFINIPATH_RHF_RCVTYPE_SHIFT 11 +#define INFINIPATH_RHF_EGRINDEX_MASK 0x7FF +#define INFINIPATH_RHF_EGRINDEX_SHIFT 16 +#define INFINIPATH_RHF_H_ICRCERR 0x80000000 +#define INFINIPATH_RHF_H_VCRCERR 0x40000000 +#define INFINIPATH_RHF_H_PARITYERR 0x20000000 +#define INFINIPATH_RHF_H_LENERR 0x10000000 +#define INFINIPATH_RHF_H_MTUERR 0x08000000 +#define INFINIPATH_RHF_H_IHDRERR 0x04000000 +#define INFINIPATH_RHF_H_TIDERR 0x02000000 +#define INFINIPATH_RHF_H_MKERR 0x01000000 +#define INFINIPATH_RHF_H_IBERR 0x00800000 +#define INFINIPATH_RHF_L_SWA 0x00008000 +#define INFINIPATH_RHF_L_SWB 0x00004000 + +/* infinipath header fields */ +#define INFINIPATH_I_VERS_MASK 0xF +#define INFINIPATH_I_VERS_SHIFT 28 +#define INFINIPATH_I_PORT_MASK 0xF +#define INFINIPATH_I_PORT_SHIFT 24 +#define INFINIPATH_I_TID_MASK 0x7FF +#define INFINIPATH_I_TID_SHIFT 13 +#define INFINIPATH_I_OFFSET_MASK 0x1FFF +#define INFINIPATH_I_OFFSET_SHIFT 0 + +/* K_PktFlags bits */ +#define INFINIPATH_KPF_INTR 0x1 + +/* SendPIO per-buffer control */ +#define INFINIPATH_SP_LENGTHP1_MASK 0x3FF +#define INFINIPATH_SP_LENGTHP1_SHIFT 0 +#define INFINIPATH_SP_INTR 0x80000000 +#define INFINIPATH_SP_TEST 0x40000000 +#define INFINIPATH_SP_TESTEBP 0x20000000 + +/* SendPIOAvail bits */ +#define INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT 1 +#define INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT 0 + +#endif /* _IPATH_COMMON_H */ diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c new file mode 100644 index 000000000000..7ece1135ddfe --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_cq.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "ipath_verbs.h" + +/** + * ipath_cq_enter - add a new entry to the completion queue + * @cq: completion queue + * @entry: work completion entry to add + * @sig: true if @entry is a solicitated entry + * + * This may be called with one of the qp->s_lock or qp->r_rq.lock held. + */ +void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited) +{ + unsigned long flags; + u32 next; + + spin_lock_irqsave(&cq->lock, flags); + + if (cq->head == cq->ibcq.cqe) + next = 0; + else + next = cq->head + 1; + if (unlikely(next == cq->tail)) { + spin_unlock_irqrestore(&cq->lock, flags); + if (cq->ibcq.event_handler) { + struct ib_event ev; + + ev.device = cq->ibcq.device; + ev.element.cq = &cq->ibcq; + ev.event = IB_EVENT_CQ_ERR; + cq->ibcq.event_handler(&ev, cq->ibcq.cq_context); + } + return; + } + cq->queue[cq->head] = *entry; + cq->head = next; + + if (cq->notify == IB_CQ_NEXT_COMP || + (cq->notify == IB_CQ_SOLICITED && solicited)) { + cq->notify = IB_CQ_NONE; + cq->triggered++; + /* + * This will cause send_complete() to be called in + * another thread. + */ + tasklet_hi_schedule(&cq->comptask); + } + + spin_unlock_irqrestore(&cq->lock, flags); + + if (entry->status != IB_WC_SUCCESS) + to_idev(cq->ibcq.device)->n_wqe_errs++; +} + +/** + * ipath_poll_cq - poll for work completion entries + * @ibcq: the completion queue to poll + * @num_entries: the maximum number of entries to return + * @entry: pointer to array where work completions are placed + * + * Returns the number of completion entries polled. + * + * This may be called from interrupt context. Also called by ib_poll_cq() + * in the generic verbs code. + */ +int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) +{ + struct ipath_cq *cq = to_icq(ibcq); + unsigned long flags; + int npolled; + + spin_lock_irqsave(&cq->lock, flags); + + for (npolled = 0; npolled < num_entries; ++npolled, ++entry) { + if (cq->tail == cq->head) + break; + *entry = cq->queue[cq->tail]; + if (cq->tail == cq->ibcq.cqe) + cq->tail = 0; + else + cq->tail++; + } + + spin_unlock_irqrestore(&cq->lock, flags); + + return npolled; +} + +static void send_complete(unsigned long data) +{ + struct ipath_cq *cq = (struct ipath_cq *)data; + + /* + * The completion handler will most likely rearm the notification + * and poll for all pending entries. If a new completion entry + * is added while we are in this routine, tasklet_hi_schedule() + * won't call us again until we return so we check triggered to + * see if we need to call the handler again. + */ + for (;;) { + u8 triggered = cq->triggered; + + cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); + + if (cq->triggered == triggered) + return; + } +} + +/** + * ipath_create_cq - create a completion queue + * @ibdev: the device this completion queue is attached to + * @entries: the minimum size of the completion queue + * @context: unused by the InfiniPath driver + * @udata: unused by the InfiniPath driver + * + * Returns a pointer to the completion queue or negative errno values + * for failure. + * + * Called by ib_create_cq() in the generic verbs code. + */ +struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct ipath_cq *cq; + struct ib_wc *wc; + struct ib_cq *ret; + + /* + * Need to use vmalloc() if we want to support large #s of + * entries. + */ + cq = kmalloc(sizeof(*cq), GFP_KERNEL); + if (!cq) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + /* + * Need to use vmalloc() if we want to support large #s of entries. + */ + wc = vmalloc(sizeof(*wc) * (entries + 1)); + if (!wc) { + kfree(cq); + ret = ERR_PTR(-ENOMEM); + goto bail; + } + /* + * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe. + * The number of entries should be >= the number requested or return + * an error. + */ + cq->ibcq.cqe = entries; + cq->notify = IB_CQ_NONE; + cq->triggered = 0; + spin_lock_init(&cq->lock); + tasklet_init(&cq->comptask, send_complete, (unsigned long)cq); + cq->head = 0; + cq->tail = 0; + cq->queue = wc; + + ret = &cq->ibcq; + +bail: + return ret; +} + +/** + * ipath_destroy_cq - destroy a completion queue + * @ibcq: the completion queue to destroy. + * + * Returns 0 for success. + * + * Called by ib_destroy_cq() in the generic verbs code. + */ +int ipath_destroy_cq(struct ib_cq *ibcq) +{ + struct ipath_cq *cq = to_icq(ibcq); + + tasklet_kill(&cq->comptask); + vfree(cq->queue); + kfree(cq); + + return 0; +} + +/** + * ipath_req_notify_cq - change the notification type for a completion queue + * @ibcq: the completion queue + * @notify: the type of notification to request + * + * Returns 0 for success. + * + * This may be called from interrupt context. Also called by + * ib_req_notify_cq() in the generic verbs code. + */ +int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify) +{ + struct ipath_cq *cq = to_icq(ibcq); + unsigned long flags; + + spin_lock_irqsave(&cq->lock, flags); + /* + * Don't change IB_CQ_NEXT_COMP to IB_CQ_SOLICITED but allow + * any other transitions. + */ + if (cq->notify != IB_CQ_NEXT_COMP) + cq->notify = notify; + spin_unlock_irqrestore(&cq->lock, flags); + return 0; +} + +int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) +{ + struct ipath_cq *cq = to_icq(ibcq); + struct ib_wc *wc, *old_wc; + u32 n; + int ret; + + /* + * Need to use vmalloc() if we want to support large #s of entries. + */ + wc = vmalloc(sizeof(*wc) * (cqe + 1)); + if (!wc) { + ret = -ENOMEM; + goto bail; + } + + spin_lock_irq(&cq->lock); + if (cq->head < cq->tail) + n = cq->ibcq.cqe + 1 + cq->head - cq->tail; + else + n = cq->head - cq->tail; + if (unlikely((u32)cqe < n)) { + spin_unlock_irq(&cq->lock); + vfree(wc); + ret = -EOVERFLOW; + goto bail; + } + for (n = 0; cq->tail != cq->head; n++) { + wc[n] = cq->queue[cq->tail]; + if (cq->tail == cq->ibcq.cqe) + cq->tail = 0; + else + cq->tail++; + } + cq->ibcq.cqe = cqe; + cq->head = n; + cq->tail = 0; + old_wc = cq->queue; + cq->queue = wc; + spin_unlock_irq(&cq->lock); + + vfree(old_wc); + + ret = 0; + +bail: + return ret; +} diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h new file mode 100644 index 000000000000..593e28969c69 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_debug.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _IPATH_DEBUG_H +#define _IPATH_DEBUG_H + +#ifndef _IPATH_DEBUGGING /* debugging enabled or not */ +#define _IPATH_DEBUGGING 1 +#endif + +#if _IPATH_DEBUGGING + +/* + * Mask values for debugging. The scheme allows us to compile out any + * of the debug tracing stuff, and if compiled in, to enable or disable + * dynamically. This can be set at modprobe time also: + * modprobe infinipath.ko infinipath_debug=7 + */ + +#define __IPATH_INFO 0x1 /* generic low verbosity stuff */ +#define __IPATH_DBG 0x2 /* generic debug */ +#define __IPATH_TRSAMPLE 0x8 /* generate trace buffer sample entries */ +/* leave some low verbosity spots open */ +#define __IPATH_VERBDBG 0x40 /* very verbose debug */ +#define __IPATH_PKTDBG 0x80 /* print packet data */ +/* print process startup (init)/exit messages */ +#define __IPATH_PROCDBG 0x100 +/* print mmap/nopage stuff, not using VDBG any more */ +#define __IPATH_MMDBG 0x200 +#define __IPATH_USER_SEND 0x1000 /* use user mode send */ +#define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */ +#define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */ +#define __IPATH_SMADBG 0x8000 /* sma packet debug */ +#define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) general debug on */ +#define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings on */ +#define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors on */ +#define __IPATH_IPATHPD 0x80000 /* Ethernet (IPATH) packet dump on */ +#define __IPATH_IPATHTABLE 0x100000 /* Ethernet (IPATH) table dump on */ + +#else /* _IPATH_DEBUGGING */ + +/* + * define all of these even with debugging off, for the few places that do + * if(infinipath_debug & _IPATH_xyzzy), but in a way that will make the + * compiler eliminate the code + */ + +#define __IPATH_INFO 0x0 /* generic low verbosity stuff */ +#define __IPATH_DBG 0x0 /* generic debug */ +#define __IPATH_TRSAMPLE 0x0 /* generate trace buffer sample entries */ +#define __IPATH_VERBDBG 0x0 /* very verbose debug */ +#define __IPATH_PKTDBG 0x0 /* print packet data */ +#define __IPATH_PROCDBG 0x0 /* print process startup (init)/exit messages */ +/* print mmap/nopage stuff, not using VDBG any more */ +#define __IPATH_MMDBG 0x0 +#define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */ +#define __IPATH_SMADBG 0x0 /* print process startup (init)/exit messages */#define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */ +#define __IPATH_IPATHWARN 0x0 /* Ethernet (IPATH) warnings on */ +#define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */ +#define __IPATH_IPATHPD 0x0 /* Ethernet (IPATH) packet dump on */ +#define __IPATH_IPATHTABLE 0x0 /* Ethernet (IPATH) packet dump on */ + +#endif /* _IPATH_DEBUGGING */ + +#define __IPATH_VERBOSEDBG __IPATH_VERBDBG + +#endif /* _IPATH_DEBUG_H */ diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c new file mode 100644 index 000000000000..cd533cf951c2 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_diag.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This file contains support for diagnostic functions. It is accessed by + * opening the ipath_diag device, normally minor number 129. Diagnostic use + * of the InfiniPath chip may render the chip or board unusable until the + * driver is unloaded, or in some cases, until the system is rebooted. + * + * Accesses to the chip through this interface are not similar to going + * through the /sys/bus/pci resource mmap interface. + */ + +#include +#include + +#include "ipath_common.h" +#include "ipath_kernel.h" +#include "ips_common.h" +#include "ipath_layer.h" + +int ipath_diag_inuse; +static int diag_set_link; + +static int ipath_diag_open(struct inode *in, struct file *fp); +static int ipath_diag_release(struct inode *in, struct file *fp); +static ssize_t ipath_diag_read(struct file *fp, char __user *data, + size_t count, loff_t *off); +static ssize_t ipath_diag_write(struct file *fp, const char __user *data, + size_t count, loff_t *off); + +static struct file_operations diag_file_ops = { + .owner = THIS_MODULE, + .write = ipath_diag_write, + .read = ipath_diag_read, + .open = ipath_diag_open, + .release = ipath_diag_release +}; + +static struct cdev *diag_cdev; +static struct class_device *diag_class_dev; + +int ipath_diag_init(void) +{ + return ipath_cdev_init(IPATH_DIAG_MINOR, "ipath_diag", + &diag_file_ops, &diag_cdev, &diag_class_dev); +} + +void ipath_diag_cleanup(void) +{ + ipath_cdev_cleanup(&diag_cdev, &diag_class_dev); +} + +/** + * ipath_read_umem64 - read a 64-bit quantity from the chip into user space + * @dd: the infinipath device + * @uaddr: the location to store the data in user memory + * @caddr: the source chip address (full pointer, not offset) + * @count: number of bytes to copy (multiple of 32 bits) + * + * This function also localizes all chip memory accesses. + * The copy should be written such that we read full cacheline packets + * from the chip. This is usually used for a single qword + * + * NOTE: This assumes the chip address is 64-bit aligned. + */ +static int ipath_read_umem64(struct ipath_devdata *dd, void __user *uaddr, + const void __iomem *caddr, size_t count) +{ + const u64 __iomem *reg_addr = caddr; + const u64 __iomem *reg_end = reg_addr + (count / sizeof(u64)); + int ret; + + /* not very efficient, but it works for now */ + if (reg_addr < dd->ipath_kregbase || + reg_end > dd->ipath_kregend) { + ret = -EINVAL; + goto bail; + } + while (reg_addr < reg_end) { + u64 data = readq(reg_addr); + if (copy_to_user(uaddr, &data, sizeof(u64))) { + ret = -EFAULT; + goto bail; + } + reg_addr++; + uaddr++; + } + ret = 0; +bail: + return ret; +} + +/** + * ipath_write_umem64 - write a 64-bit quantity to the chip from user space + * @dd: the infinipath device + * @caddr: the destination chip address (full pointer, not offset) + * @uaddr: the source of the data in user memory + * @count: the number of bytes to copy (multiple of 32 bits) + * + * This is usually used for a single qword + * NOTE: This assumes the chip address is 64-bit aligned. + */ + +static int ipath_write_umem64(struct ipath_devdata *dd, void __iomem *caddr, + const void __user *uaddr, size_t count) +{ + u64 __iomem *reg_addr = caddr; + const u64 __iomem *reg_end = reg_addr + (count / sizeof(u64)); + int ret; + + /* not very efficient, but it works for now */ + if (reg_addr < dd->ipath_kregbase || + reg_end > dd->ipath_kregend) { + ret = -EINVAL; + goto bail; + } + while (reg_addr < reg_end) { + u64 data; + if (copy_from_user(&data, uaddr, sizeof(data))) { + ret = -EFAULT; + goto bail; + } + writeq(data, reg_addr); + + reg_addr++; + uaddr++; + } + ret = 0; +bail: + return ret; +} + +/** + * ipath_read_umem32 - read a 32-bit quantity from the chip into user space + * @dd: the infinipath device + * @uaddr: the location to store the data in user memory + * @caddr: the source chip address (full pointer, not offset) + * @count: number of bytes to copy + * + * read 32 bit values, not 64 bit; for memories that only + * support 32 bit reads; usually a single dword. + */ +static int ipath_read_umem32(struct ipath_devdata *dd, void __user *uaddr, + const void __iomem *caddr, size_t count) +{ + const u32 __iomem *reg_addr = caddr; + const u32 __iomem *reg_end = reg_addr + (count / sizeof(u32)); + int ret; + + if (reg_addr < (u32 __iomem *) dd->ipath_kregbase || + reg_end > (u32 __iomem *) dd->ipath_kregend) { + ret = -EINVAL; + goto bail; + } + /* not very efficient, but it works for now */ + while (reg_addr < reg_end) { + u32 data = readl(reg_addr); + if (copy_to_user(uaddr, &data, sizeof(data))) { + ret = -EFAULT; + goto bail; + } + + reg_addr++; + uaddr++; + } + ret = 0; +bail: + return ret; +} + +/** + * ipath_write_umem32 - write a 32-bit quantity to the chip from user space + * @dd: the infinipath device + * @caddr: the destination chip address (full pointer, not offset) + * @uaddr: the source of the data in user memory + * @count: number of bytes to copy + * + * write 32 bit values, not 64 bit; for memories that only + * support 32 bit write; usually a single dword. + */ + +static int ipath_write_umem32(struct ipath_devdata *dd, void __iomem *caddr, + const void __user *uaddr, size_t count) +{ + u32 __iomem *reg_addr = caddr; + const u32 __iomem *reg_end = reg_addr + (count / sizeof(u32)); + int ret; + + if (reg_addr < (u32 __iomem *) dd->ipath_kregbase || + reg_end > (u32 __iomem *) dd->ipath_kregend) { + ret = -EINVAL; + goto bail; + } + while (reg_addr < reg_end) { + u32 data; + if (copy_from_user(&data, uaddr, sizeof(data))) { + ret = -EFAULT; + goto bail; + } + writel(data, reg_addr); + + reg_addr++; + uaddr++; + } + ret = 0; +bail: + return ret; +} + +static int ipath_diag_open(struct inode *in, struct file *fp) +{ + struct ipath_devdata *dd; + int unit = 0; /* XXX this is bogus */ + unsigned long flags; + int ret; + + dd = ipath_lookup(unit); + + mutex_lock(&ipath_mutex); + spin_lock_irqsave(&ipath_devs_lock, flags); + + if (ipath_diag_inuse) { + ret = -EBUSY; + goto bail; + } + + list_for_each_entry(dd, &ipath_dev_list, ipath_list) { + /* + * we need at least one infinipath device to be present + * (don't use INITTED, because we want to be able to open + * even if device is in freeze mode, which cleared INITTED). + * There is a small amount of risk to this, which is why we + * also verify kregbase is set. + */ + + if (!(dd->ipath_flags & IPATH_PRESENT) || + !dd->ipath_kregbase) + continue; + + ipath_diag_inuse = 1; + diag_set_link = 0; + ret = 0; + goto bail; + } + + ret = -ENODEV; + +bail: + spin_unlock_irqrestore(&ipath_devs_lock, flags); + mutex_unlock(&ipath_mutex); + + /* Only expose a way to reset the device if we + make it into diag mode. */ + if (ret == 0) + ipath_expose_reset(&dd->pcidev->dev); + + return ret; +} + +static int ipath_diag_release(struct inode *i, struct file *f) +{ + mutex_lock(&ipath_mutex); + ipath_diag_inuse = 0; + mutex_unlock(&ipath_mutex); + return 0; +} + +static ssize_t ipath_diag_read(struct file *fp, char __user *data, + size_t count, loff_t *off) +{ + int unit = 0; /* XXX provide for reads on other units some day */ + struct ipath_devdata *dd; + void __iomem *kreg_base; + ssize_t ret; + + dd = ipath_lookup(unit); + if (!dd) { + ret = -ENODEV; + goto bail; + } + + kreg_base = dd->ipath_kregbase; + + if (count == 0) + ret = 0; + else if ((count % 4) || (*off % 4)) + /* address or length is not 32-bit aligned, hence invalid */ + ret = -EINVAL; + else if ((count % 8) || (*off % 8)) + /* address or length not 64-bit aligned; do 32-bit reads */ + ret = ipath_read_umem32(dd, data, kreg_base + *off, count); + else + ret = ipath_read_umem64(dd, data, kreg_base + *off, count); + + if (ret >= 0) { + *off += count; + ret = count; + } + +bail: + return ret; +} + +static ssize_t ipath_diag_write(struct file *fp, const char __user *data, + size_t count, loff_t *off) +{ + int unit = 0; /* XXX this is bogus */ + struct ipath_devdata *dd; + void __iomem *kreg_base; + ssize_t ret; + + dd = ipath_lookup(unit); + if (!dd) { + ret = -ENODEV; + goto bail; + } + kreg_base = dd->ipath_kregbase; + + if (count == 0) + ret = 0; + else if ((count % 4) || (*off % 4)) + /* address or length is not 32-bit aligned, hence invalid */ + ret = -EINVAL; + else if ((count % 8) || (*off % 8)) + /* address or length not 64-bit aligned; do 32-bit writes */ + ret = ipath_write_umem32(dd, kreg_base + *off, data, count); + else + ret = ipath_write_umem64(dd, kreg_base + *off, data, count); + + if (ret >= 0) { + *off += count; + ret = count; + } + +bail: + return ret; +} + +void ipath_diag_bringup_link(struct ipath_devdata *dd) +{ + if (diag_set_link || (dd->ipath_flags & IPATH_LINKACTIVE)) + return; + + diag_set_link = 1; + ipath_cdbg(VERBOSE, "Trying to set to set link active for " + "diag pkt\n"); + ipath_layer_set_linkstate(dd, IPATH_IB_LINKARM); + ipath_layer_set_linkstate(dd, IPATH_IB_LINKACTIVE); +} diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c new file mode 100644 index 000000000000..58a94efb0070 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -0,0 +1,1983 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "ipath_kernel.h" +#include "ips_common.h" +#include "ipath_layer.h" + +static void ipath_update_pio_bufs(struct ipath_devdata *); + +const char *ipath_get_unit_name(int unit) +{ + static char iname[16]; + snprintf(iname, sizeof iname, "infinipath%u", unit); + return iname; +} + +EXPORT_SYMBOL_GPL(ipath_get_unit_name); + +#define DRIVER_LOAD_MSG "PathScale " IPATH_DRV_NAME " loaded: " +#define PFX IPATH_DRV_NAME ": " + +/* + * The size has to be longer than this string, so we can append + * board/chip information to it in the init code. + */ +const char ipath_core_version[] = IPATH_IDSTR "\n"; + +static struct idr unit_table; +DEFINE_SPINLOCK(ipath_devs_lock); +LIST_HEAD(ipath_dev_list); + +wait_queue_head_t ipath_sma_state_wait; + +unsigned ipath_debug = __IPATH_INFO; + +module_param_named(debug, ipath_debug, uint, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(debug, "mask for debug prints"); +EXPORT_SYMBOL_GPL(ipath_debug); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("PathScale "); +MODULE_DESCRIPTION("Pathscale InfiniPath driver"); + +const char *ipath_ibcstatus_str[] = { + "Disabled", + "LinkUp", + "PollActive", + "PollQuiet", + "SleepDelay", + "SleepQuiet", + "LState6", /* unused */ + "LState7", /* unused */ + "CfgDebounce", + "CfgRcvfCfg", + "CfgWaitRmt", + "CfgIdle", + "RecovRetrain", + "LState0xD", /* unused */ + "RecovWaitRmt", + "RecovIdle", +}; + +/* + * These variables are initialized in the chip-specific files + * but are defined here. + */ +u16 ipath_gpio_sda_num, ipath_gpio_scl_num; +u64 ipath_gpio_sda, ipath_gpio_scl; +u64 infinipath_i_bitsextant; +ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant; +u32 infinipath_i_rcvavail_mask, infinipath_i_rcvurg_mask; + +static void __devexit ipath_remove_one(struct pci_dev *); +static int __devinit ipath_init_one(struct pci_dev *, + const struct pci_device_id *); + +/* Only needed for registration, nothing else needs this info */ +#define PCI_VENDOR_ID_PATHSCALE 0x1fc1 +#define PCI_DEVICE_ID_INFINIPATH_HT 0xd +#define PCI_DEVICE_ID_INFINIPATH_PE800 0x10 + +static const struct pci_device_id ipath_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, + PCI_DEVICE_ID_INFINIPATH_HT)}, + {PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, + PCI_DEVICE_ID_INFINIPATH_PE800)}, +}; + +MODULE_DEVICE_TABLE(pci, ipath_pci_tbl); + +static struct pci_driver ipath_driver = { + .name = IPATH_DRV_NAME, + .probe = ipath_init_one, + .remove = __devexit_p(ipath_remove_one), + .id_table = ipath_pci_tbl, +}; + +/* + * This is where port 0's rcvhdrtail register is written back; we also + * want nothing else sharing the cache line, so make it a cache line + * in size. Used for all units. + */ +volatile __le64 *ipath_port0_rcvhdrtail; +dma_addr_t ipath_port0_rcvhdrtail_dma; +static int port0_rcvhdrtail_refs; + +static inline void read_bars(struct ipath_devdata *dd, struct pci_dev *dev, + u32 *bar0, u32 *bar1) +{ + int ret; + + ret = pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, bar0); + if (ret) + ipath_dev_err(dd, "failed to read bar0 before enable: " + "error %d\n", -ret); + + ret = pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, bar1); + if (ret) + ipath_dev_err(dd, "failed to read bar1 before enable: " + "error %d\n", -ret); + + ipath_dbg("Read bar0 %x bar1 %x\n", *bar0, *bar1); +} + +static void ipath_free_devdata(struct pci_dev *pdev, + struct ipath_devdata *dd) +{ + unsigned long flags; + + pci_set_drvdata(pdev, NULL); + + if (dd->ipath_unit != -1) { + spin_lock_irqsave(&ipath_devs_lock, flags); + idr_remove(&unit_table, dd->ipath_unit); + list_del(&dd->ipath_list); + spin_unlock_irqrestore(&ipath_devs_lock, flags); + } + dma_free_coherent(&pdev->dev, sizeof(*dd), dd, dd->ipath_dma_addr); +} + +static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev) +{ + unsigned long flags; + struct ipath_devdata *dd; + dma_addr_t dma_addr; + int ret; + + if (!idr_pre_get(&unit_table, GFP_KERNEL)) { + dd = ERR_PTR(-ENOMEM); + goto bail; + } + + dd = dma_alloc_coherent(&pdev->dev, sizeof(*dd), &dma_addr, + GFP_KERNEL); + + if (!dd) { + dd = ERR_PTR(-ENOMEM); + goto bail; + } + + dd->ipath_dma_addr = dma_addr; + dd->ipath_unit = -1; + + spin_lock_irqsave(&ipath_devs_lock, flags); + + ret = idr_get_new(&unit_table, dd, &dd->ipath_unit); + if (ret < 0) { + printk(KERN_ERR IPATH_DRV_NAME + ": Could not allocate unit ID: error %d\n", -ret); + ipath_free_devdata(pdev, dd); + dd = ERR_PTR(ret); + goto bail_unlock; + } + + dd->pcidev = pdev; + pci_set_drvdata(pdev, dd); + + list_add(&dd->ipath_list, &ipath_dev_list); + +bail_unlock: + spin_unlock_irqrestore(&ipath_devs_lock, flags); + +bail: + return dd; +} + +static inline struct ipath_devdata *__ipath_lookup(int unit) +{ + return idr_find(&unit_table, unit); +} + +struct ipath_devdata *ipath_lookup(int unit) +{ + struct ipath_devdata *dd; + unsigned long flags; + + spin_lock_irqsave(&ipath_devs_lock, flags); + dd = __ipath_lookup(unit); + spin_unlock_irqrestore(&ipath_devs_lock, flags); + + return dd; +} + +int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp) +{ + int nunits, npresent, nup; + struct ipath_devdata *dd; + unsigned long flags; + u32 maxports; + + nunits = npresent = nup = maxports = 0; + + spin_lock_irqsave(&ipath_devs_lock, flags); + + list_for_each_entry(dd, &ipath_dev_list, ipath_list) { + nunits++; + if ((dd->ipath_flags & IPATH_PRESENT) && dd->ipath_kregbase) + npresent++; + if (dd->ipath_lid && + !(dd->ipath_flags & (IPATH_DISABLED | IPATH_LINKDOWN + | IPATH_LINKUNK))) + nup++; + if (dd->ipath_cfgports > maxports) + maxports = dd->ipath_cfgports; + } + + spin_unlock_irqrestore(&ipath_devs_lock, flags); + + if (npresentp) + *npresentp = npresent; + if (nupp) + *nupp = nup; + if (maxportsp) + *maxportsp = maxports; + + return nunits; +} + +static int init_port0_rcvhdrtail(struct pci_dev *pdev) +{ + int ret; + + mutex_lock(&ipath_mutex); + + if (!ipath_port0_rcvhdrtail) { + ipath_port0_rcvhdrtail = + dma_alloc_coherent(&pdev->dev, + IPATH_PORT0_RCVHDRTAIL_SIZE, + &ipath_port0_rcvhdrtail_dma, + GFP_KERNEL); + + if (!ipath_port0_rcvhdrtail) { + ret = -ENOMEM; + goto bail; + } + } + port0_rcvhdrtail_refs++; + ret = 0; + +bail: + mutex_unlock(&ipath_mutex); + + return ret; +} + +static void cleanup_port0_rcvhdrtail(struct pci_dev *pdev) +{ + mutex_lock(&ipath_mutex); + + if (!--port0_rcvhdrtail_refs) { + dma_free_coherent(&pdev->dev, IPATH_PORT0_RCVHDRTAIL_SIZE, + (void *) ipath_port0_rcvhdrtail, + ipath_port0_rcvhdrtail_dma); + ipath_port0_rcvhdrtail = NULL; + } + + mutex_unlock(&ipath_mutex); +} + +/* + * These next two routines are placeholders in case we don't have per-arch + * code for controlling write combining. If explicit control of write + * combining is not available, performance will probably be awful. + */ + +int __attribute__((weak)) ipath_enable_wc(struct ipath_devdata *dd) +{ + return -EOPNOTSUPP; +} + +void __attribute__((weak)) ipath_disable_wc(struct ipath_devdata *dd) +{ +} + +static int __devinit ipath_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int ret, len, j; + struct ipath_devdata *dd; + unsigned long long addr; + u32 bar0 = 0, bar1 = 0; + u8 rev; + + ret = init_port0_rcvhdrtail(pdev); + if (ret < 0) { + printk(KERN_ERR IPATH_DRV_NAME + ": Could not allocate port0_rcvhdrtail: error %d\n", + -ret); + goto bail; + } + + dd = ipath_alloc_devdata(pdev); + if (IS_ERR(dd)) { + ret = PTR_ERR(dd); + printk(KERN_ERR IPATH_DRV_NAME + ": Could not allocate devdata: error %d\n", -ret); + goto bail_rcvhdrtail; + } + + ipath_cdbg(VERBOSE, "initializing unit #%u\n", dd->ipath_unit); + + read_bars(dd, pdev, &bar0, &bar1); + + ret = pci_enable_device(pdev); + if (ret) { + /* This can happen iff: + * + * We did a chip reset, and then failed to reprogram the + * BAR, or the chip reset due to an internal error. We then + * unloaded the driver and reloaded it. + * + * Both reset cases set the BAR back to initial state. For + * the latter case, the AER sticky error bit at offset 0x718 + * should be set, but the Linux kernel doesn't yet know + * about that, it appears. If the original BAR was retained + * in the kernel data structures, this may be OK. + */ + ipath_dev_err(dd, "enable unit %d failed: error %d\n", + dd->ipath_unit, -ret); + goto bail_devdata; + } + addr = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + ipath_cdbg(VERBOSE, "regbase (0) %llx len %d irq %x, vend %x/%x " + "driver_data %lx\n", addr, len, pdev->irq, ent->vendor, + ent->device, ent->driver_data); + + read_bars(dd, pdev, &bar0, &bar1); + + if (!bar1 && !(bar0 & ~0xf)) { + if (addr) { + dev_info(&pdev->dev, "BAR is 0 (probable RESET), " + "rewriting as %llx\n", addr); + ret = pci_write_config_dword( + pdev, PCI_BASE_ADDRESS_0, addr); + if (ret) { + ipath_dev_err(dd, "rewrite of BAR0 " + "failed: err %d\n", -ret); + goto bail_disable; + } + ret = pci_write_config_dword( + pdev, PCI_BASE_ADDRESS_1, addr >> 32); + if (ret) { + ipath_dev_err(dd, "rewrite of BAR1 " + "failed: err %d\n", -ret); + goto bail_disable; + } + } else { + ipath_dev_err(dd, "BAR is 0 (probable RESET), " + "not usable until reboot\n"); + ret = -ENODEV; + goto bail_disable; + } + } + + ret = pci_request_regions(pdev, IPATH_DRV_NAME); + if (ret) { + dev_info(&pdev->dev, "pci_request_regions unit %u fails: " + "err %d\n", dd->ipath_unit, -ret); + goto bail_disable; + } + + ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (ret) { + dev_info(&pdev->dev, "pci_set_dma_mask unit %u " + "fails: %d\n", dd->ipath_unit, ret); + goto bail_regions; + } + + pci_set_master(pdev); + + /* + * Save BARs to rewrite after device reset. Save all 64 bits of + * BAR, just in case. + */ + dd->ipath_pcibar0 = addr; + dd->ipath_pcibar1 = addr >> 32; + dd->ipath_deviceid = ent->device; /* save for later use */ + dd->ipath_vendorid = ent->vendor; + + /* setup the chip-specific functions, as early as possible. */ + switch (ent->device) { + case PCI_DEVICE_ID_INFINIPATH_HT: + ipath_init_ht400_funcs(dd); + break; + case PCI_DEVICE_ID_INFINIPATH_PE800: + ipath_init_pe800_funcs(dd); + break; + default: + ipath_dev_err(dd, "Found unknown PathScale deviceid 0x%x, " + "failing\n", ent->device); + return -ENODEV; + } + + for (j = 0; j < 6; j++) { + if (!pdev->resource[j].start) + continue; + ipath_cdbg(VERBOSE, "BAR %d start %lx, end %lx, len %lx\n", + j, pdev->resource[j].start, + pdev->resource[j].end, + pci_resource_len(pdev, j)); + } + + if (!addr) { + ipath_dev_err(dd, "No valid address in BAR 0!\n"); + ret = -ENODEV; + goto bail_regions; + } + + dd->ipath_deviceid = ent->device; /* save for later use */ + dd->ipath_vendorid = ent->vendor; + + ret = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + if (ret) { + ipath_dev_err(dd, "Failed to read PCI revision ID unit " + "%u: err %d\n", dd->ipath_unit, -ret); + goto bail_regions; /* shouldn't ever happen */ + } + dd->ipath_pcirev = rev; + + dd->ipath_kregbase = ioremap_nocache(addr, len); + + if (!dd->ipath_kregbase) { + ipath_dbg("Unable to map io addr %llx to kvirt, failing\n", + addr); + ret = -ENOMEM; + goto bail_iounmap; + } + dd->ipath_kregend = (u64 __iomem *) + ((void __iomem *)dd->ipath_kregbase + len); + dd->ipath_physaddr = addr; /* used for io_remap, etc. */ + /* for user mmap */ + dd->ipath_kregvirt = (u64 __iomem *) phys_to_virt(addr); + ipath_cdbg(VERBOSE, "mapped io addr %llx to kregbase %p " + "kregvirt %p\n", addr, dd->ipath_kregbase, + dd->ipath_kregvirt); + + /* + * clear ipath_flags here instead of in ipath_init_chip as it is set + * by ipath_setup_htconfig. + */ + dd->ipath_flags = 0; + + if (dd->ipath_f_bus(dd, pdev)) + ipath_dev_err(dd, "Failed to setup config space; " + "continuing anyway\n"); + + /* + * set up our interrupt handler; SA_SHIRQ probably not needed, + * since MSI interrupts shouldn't be shared but won't hurt for now. + * check 0 irq after we return from chip-specific bus setup, since + * that can affect this due to setup + */ + if (!pdev->irq) + ipath_dev_err(dd, "irq is 0, BIOS error? Interrupts won't " + "work\n"); + else { + ret = request_irq(pdev->irq, ipath_intr, SA_SHIRQ, + IPATH_DRV_NAME, dd); + if (ret) { + ipath_dev_err(dd, "Couldn't setup irq handler, " + "irq=%u: %d\n", pdev->irq, ret); + goto bail_iounmap; + } + } + + ret = ipath_init_chip(dd, 0); /* do the chip-specific init */ + if (ret) + goto bail_iounmap; + + ret = ipath_enable_wc(dd); + + if (ret) { + ipath_dev_err(dd, "Write combining not enabled " + "(err %d): performance may be poor\n", + -ret); + ret = 0; + } + + ipath_device_create_group(&pdev->dev, dd); + ipathfs_add_device(dd); + ipath_user_add(dd); + ipath_layer_add(dd); + + goto bail; + +bail_iounmap: + iounmap((volatile void __iomem *) dd->ipath_kregbase); + +bail_regions: + pci_release_regions(pdev); + +bail_disable: + pci_disable_device(pdev); + +bail_devdata: + ipath_free_devdata(pdev, dd); + +bail_rcvhdrtail: + cleanup_port0_rcvhdrtail(pdev); + +bail: + return ret; +} + +static void __devexit ipath_remove_one(struct pci_dev *pdev) +{ + struct ipath_devdata *dd; + + ipath_cdbg(VERBOSE, "removing, pdev=%p\n", pdev); + if (!pdev) + return; + + dd = pci_get_drvdata(pdev); + ipath_layer_del(dd); + ipath_user_del(dd); + ipathfs_remove_device(dd); + ipath_device_remove_group(&pdev->dev, dd); + ipath_cdbg(VERBOSE, "Releasing pci memory regions, dd %p, " + "unit %u\n", dd, (u32) dd->ipath_unit); + if (dd->ipath_kregbase) { + ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n", + dd->ipath_kregbase); + iounmap((volatile void __iomem *) dd->ipath_kregbase); + dd->ipath_kregbase = NULL; + } + pci_release_regions(pdev); + ipath_cdbg(VERBOSE, "calling pci_disable_device\n"); + pci_disable_device(pdev); + + ipath_free_devdata(pdev, dd); + cleanup_port0_rcvhdrtail(pdev); +} + +/* general driver use */ +DEFINE_MUTEX(ipath_mutex); + +static DEFINE_SPINLOCK(ipath_pioavail_lock); + +/** + * ipath_disarm_piobufs - cancel a range of PIO buffers + * @dd: the infinipath device + * @first: the first PIO buffer to cancel + * @cnt: the number of PIO buffers to cancel + * + * cancel a range of PIO buffers, used when they might be armed, but + * not triggered. Used at init to ensure buffer state, and also user + * process close, in case it died while writing to a PIO buffer + * Also after errors. + */ +void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first, + unsigned cnt) +{ + unsigned i, last = first + cnt; + u64 sendctrl, sendorig; + + ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first); + sendorig = dd->ipath_sendctrl | INFINIPATH_S_DISARM; + for (i = first; i < last; i++) { + sendctrl = sendorig | + (i << INFINIPATH_S_DISARMPIOBUF_SHIFT); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + sendctrl); + } + + /* + * Write it again with current value, in case ipath_sendctrl changed + * while we were looping; no critical bits that would require + * locking. + * + * Write a 0, and then the original value, reading scratch in + * between. This seems to avoid a chip timing race that causes + * pioavail updates to memory to stop. + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + 0); + sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + dd->ipath_sendctrl); +} + +/** + * ipath_wait_linkstate - wait for an IB link state change to occur + * @dd: the infinipath device + * @state: the state to wait for + * @msecs: the number of milliseconds to wait + * + * wait up to msecs milliseconds for IB link state change to occur for + * now, take the easy polling route. Currently used only by + * ipath_layer_set_linkstate. Returns 0 if state reached, otherwise + * -ETIMEDOUT state can have multiple states set, for any of several + * transitions. + */ +int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs) +{ + dd->ipath_sma_state_wanted = state; + wait_event_interruptible_timeout(ipath_sma_state_wait, + (dd->ipath_flags & state), + msecs_to_jiffies(msecs)); + dd->ipath_sma_state_wanted = 0; + + if (!(dd->ipath_flags & state)) { + u64 val; + ipath_cdbg(SMA, "Didn't reach linkstate %s within %u ms\n", + /* test INIT ahead of DOWN, both can be set */ + (state & IPATH_LINKINIT) ? "INIT" : + ((state & IPATH_LINKDOWN) ? "DOWN" : + ((state & IPATH_LINKARMED) ? "ARM" : "ACTIVE")), + msecs); + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus); + ipath_cdbg(VERBOSE, "ibcc=%llx ibcstatus=%llx (%s)\n", + (unsigned long long) ipath_read_kreg64( + dd, dd->ipath_kregs->kr_ibcctrl), + (unsigned long long) val, + ipath_ibcstatus_str[val & 0xf]); + } + return (dd->ipath_flags & state) ? 0 : -ETIMEDOUT; +} + +void ipath_decode_err(char *buf, size_t blen, ipath_err_t err) +{ + *buf = '\0'; + if (err & INFINIPATH_E_RHDRLEN) + strlcat(buf, "rhdrlen ", blen); + if (err & INFINIPATH_E_RBADTID) + strlcat(buf, "rbadtid ", blen); + if (err & INFINIPATH_E_RBADVERSION) + strlcat(buf, "rbadversion ", blen); + if (err & INFINIPATH_E_RHDR) + strlcat(buf, "rhdr ", blen); + if (err & INFINIPATH_E_RLONGPKTLEN) + strlcat(buf, "rlongpktlen ", blen); + if (err & INFINIPATH_E_RSHORTPKTLEN) + strlcat(buf, "rshortpktlen ", blen); + if (err & INFINIPATH_E_RMAXPKTLEN) + strlcat(buf, "rmaxpktlen ", blen); + if (err & INFINIPATH_E_RMINPKTLEN) + strlcat(buf, "rminpktlen ", blen); + if (err & INFINIPATH_E_RFORMATERR) + strlcat(buf, "rformaterr ", blen); + if (err & INFINIPATH_E_RUNSUPVL) + strlcat(buf, "runsupvl ", blen); + if (err & INFINIPATH_E_RUNEXPCHAR) + strlcat(buf, "runexpchar ", blen); + if (err & INFINIPATH_E_RIBFLOW) + strlcat(buf, "ribflow ", blen); + if (err & INFINIPATH_E_REBP) + strlcat(buf, "EBP ", blen); + if (err & INFINIPATH_E_SUNDERRUN) + strlcat(buf, "sunderrun ", blen); + if (err & INFINIPATH_E_SPIOARMLAUNCH) + strlcat(buf, "spioarmlaunch ", blen); + if (err & INFINIPATH_E_SUNEXPERRPKTNUM) + strlcat(buf, "sunexperrpktnum ", blen); + if (err & INFINIPATH_E_SDROPPEDDATAPKT) + strlcat(buf, "sdroppeddatapkt ", blen); + if (err & INFINIPATH_E_SDROPPEDSMPPKT) + strlcat(buf, "sdroppedsmppkt ", blen); + if (err & INFINIPATH_E_SMAXPKTLEN) + strlcat(buf, "smaxpktlen ", blen); + if (err & INFINIPATH_E_SMINPKTLEN) + strlcat(buf, "sminpktlen ", blen); + if (err & INFINIPATH_E_SUNSUPVL) + strlcat(buf, "sunsupVL ", blen); + if (err & INFINIPATH_E_SPKTLEN) + strlcat(buf, "spktlen ", blen); + if (err & INFINIPATH_E_INVALIDADDR) + strlcat(buf, "invalidaddr ", blen); + if (err & INFINIPATH_E_RICRC) + strlcat(buf, "CRC ", blen); + if (err & INFINIPATH_E_RVCRC) + strlcat(buf, "VCRC ", blen); + if (err & INFINIPATH_E_RRCVEGRFULL) + strlcat(buf, "rcvegrfull ", blen); + if (err & INFINIPATH_E_RRCVHDRFULL) + strlcat(buf, "rcvhdrfull ", blen); + if (err & INFINIPATH_E_IBSTATUSCHANGED) + strlcat(buf, "ibcstatuschg ", blen); + if (err & INFINIPATH_E_RIBLOSTLINK) + strlcat(buf, "riblostlink ", blen); + if (err & INFINIPATH_E_HARDWARE) + strlcat(buf, "hardware ", blen); + if (err & INFINIPATH_E_RESET) + strlcat(buf, "reset ", blen); +} + +/** + * get_rhf_errstring - decode RHF errors + * @err: the err number + * @msg: the output buffer + * @len: the length of the output buffer + * + * only used one place now, may want more later + */ +static void get_rhf_errstring(u32 err, char *msg, size_t len) +{ + /* if no errors, and so don't need to check what's first */ + *msg = '\0'; + + if (err & INFINIPATH_RHF_H_ICRCERR) + strlcat(msg, "icrcerr ", len); + if (err & INFINIPATH_RHF_H_VCRCERR) + strlcat(msg, "vcrcerr ", len); + if (err & INFINIPATH_RHF_H_PARITYERR) + strlcat(msg, "parityerr ", len); + if (err & INFINIPATH_RHF_H_LENERR) + strlcat(msg, "lenerr ", len); + if (err & INFINIPATH_RHF_H_MTUERR) + strlcat(msg, "mtuerr ", len); + if (err & INFINIPATH_RHF_H_IHDRERR) + /* infinipath hdr checksum error */ + strlcat(msg, "ipathhdrerr ", len); + if (err & INFINIPATH_RHF_H_TIDERR) + strlcat(msg, "tiderr ", len); + if (err & INFINIPATH_RHF_H_MKERR) + /* bad port, offset, etc. */ + strlcat(msg, "invalid ipathhdr ", len); + if (err & INFINIPATH_RHF_H_IBERR) + strlcat(msg, "iberr ", len); + if (err & INFINIPATH_RHF_L_SWA) + strlcat(msg, "swA ", len); + if (err & INFINIPATH_RHF_L_SWB) + strlcat(msg, "swB ", len); +} + +/** + * ipath_get_egrbuf - get an eager buffer + * @dd: the infinipath device + * @bufnum: the eager buffer to get + * @err: unused + * + * must only be called if ipath_pd[port] is known to be allocated + */ +static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum, + int err) +{ + return dd->ipath_port0_skbs ? + (void *)dd->ipath_port0_skbs[bufnum]->data : NULL; +} + +/** + * ipath_alloc_skb - allocate an skb and buffer with possible constraints + * @dd: the infinipath device + * @gfp_mask: the sk_buff SFP mask + */ +struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd, + gfp_t gfp_mask) +{ + struct sk_buff *skb; + u32 len; + + /* + * Only fully supported way to handle this is to allocate lots + * extra, align as needed, and then do skb_reserve(). That wastes + * a lot of memory... I'll have to hack this into infinipath_copy + * also. + */ + + /* + * We need 4 extra bytes for unaligned transfer copying + */ + if (dd->ipath_flags & IPATH_4BYTE_TID) { + /* we need a 4KB multiple alignment, and there is no way + * to do it except to allocate extra and then skb_reserve + * enough to bring it up to the right alignment. + */ + len = dd->ipath_ibmaxlen + 4 + (1 << 11) - 1; + } + else + len = dd->ipath_ibmaxlen + 4; + skb = __dev_alloc_skb(len, gfp_mask); + if (!skb) { + ipath_dev_err(dd, "Failed to allocate skbuff, length %u\n", + len); + goto bail; + } + if (dd->ipath_flags & IPATH_4BYTE_TID) { + u32 una = ((1 << 11) - 1) & (unsigned long)(skb->data + 4); + if (una) + skb_reserve(skb, 4 + (1 << 11) - una); + else + skb_reserve(skb, 4); + } else + skb_reserve(skb, 4); + +bail: + return skb; +} + +/** + * ipath_rcv_layer - receive a packet for the layered (ethernet) driver + * @dd: the infinipath device + * @etail: the sk_buff number + * @tlen: the total packet length + * @hdr: the ethernet header + * + * Separate routine for better overall optimization + */ +static void ipath_rcv_layer(struct ipath_devdata *dd, u32 etail, + u32 tlen, struct ether_header *hdr) +{ + u32 elen; + u8 pad, *bthbytes; + struct sk_buff *skb, *nskb; + + if (dd->ipath_port0_skbs && hdr->sub_opcode == OPCODE_ENCAP) { + /* + * Allocate a new sk_buff to replace the one we give + * to the network stack. + */ + nskb = ipath_alloc_skb(dd, GFP_ATOMIC); + if (!nskb) { + /* count OK packets that we drop */ + ipath_stats.sps_krdrops++; + return; + } + + bthbytes = (u8 *) hdr->bth; + pad = (bthbytes[1] >> 4) & 3; + /* +CRC32 */ + elen = tlen - (sizeof(*hdr) + pad + sizeof(u32)); + + skb = dd->ipath_port0_skbs[etail]; + dd->ipath_port0_skbs[etail] = nskb; + skb_put(skb, elen); + + dd->ipath_f_put_tid(dd, etail + (u64 __iomem *) + ((char __iomem *) dd->ipath_kregbase + + dd->ipath_rcvegrbase), 0, + virt_to_phys(nskb->data)); + + __ipath_layer_rcv(dd, hdr, skb); + + /* another ether packet received */ + ipath_stats.sps_ether_rpkts++; + } + else if (hdr->sub_opcode == OPCODE_LID_ARP) + __ipath_layer_rcv_lid(dd, hdr); +} + +/* + * ipath_kreceive - receive a packet + * @dd: the infinipath device + * + * called from interrupt handler for errors or receive interrupt + */ +void ipath_kreceive(struct ipath_devdata *dd) +{ + u64 *rc; + void *ebuf; + const u32 rsize = dd->ipath_rcvhdrentsize; /* words */ + const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */ + u32 etail = -1, l, hdrqtail; + struct ips_message_header *hdr; + u32 eflags, i, etype, tlen, pkttot = 0; + static u64 totcalls; /* stats, may eventually remove */ + char emsg[128]; + + if (!dd->ipath_hdrqtailptr) { + ipath_dev_err(dd, + "hdrqtailptr not set, can't do receives\n"); + goto bail; + } + + /* There is already a thread processing this queue. */ + if (test_and_set_bit(0, &dd->ipath_rcv_pending)) + goto bail; + + if (dd->ipath_port0head == + (u32)le64_to_cpu(*dd->ipath_hdrqtailptr)) + goto done; + +gotmore: + /* + * read only once at start. If in flood situation, this helps + * performance slightly. If more arrive while we are processing, + * we'll come back here and do them + */ + hdrqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr); + + for (i = 0, l = dd->ipath_port0head; l != hdrqtail; i++) { + u32 qp; + u8 *bthbytes; + + rc = (u64 *) (dd->ipath_pd[0]->port_rcvhdrq + (l << 2)); + hdr = (struct ips_message_header *)&rc[1]; + /* + * could make a network order version of IPATH_KD_QP, and + * do the obvious shift before masking to speed this up. + */ + qp = ntohl(hdr->bth[1]) & 0xffffff; + bthbytes = (u8 *) hdr->bth; + + eflags = ips_get_hdr_err_flags((__le32 *) rc); + etype = ips_get_rcv_type((__le32 *) rc); + /* total length */ + tlen = ips_get_length_in_bytes((__le32 *) rc); + ebuf = NULL; + if (etype != RCVHQ_RCV_TYPE_EXPECTED) { + /* + * it turns out that the chips uses an eager buffer + * for all non-expected packets, whether it "needs" + * one or not. So always get the index, but don't + * set ebuf (so we try to copy data) unless the + * length requires it. + */ + etail = ips_get_index((__le32 *) rc); + if (tlen > sizeof(*hdr) || + etype == RCVHQ_RCV_TYPE_NON_KD) + ebuf = ipath_get_egrbuf(dd, etail, 0); + } + + /* + * both tiderr and ipathhdrerr are set for all plain IB + * packets; only ipathhdrerr should be set. + */ + + if (etype != RCVHQ_RCV_TYPE_NON_KD && etype != + RCVHQ_RCV_TYPE_ERROR && ips_get_ipath_ver( + hdr->iph.ver_port_tid_offset) != + IPS_PROTO_VERSION) { + ipath_cdbg(PKT, "Bad InfiniPath protocol version " + "%x\n", etype); + } + + if (eflags & ~(INFINIPATH_RHF_H_TIDERR | + INFINIPATH_RHF_H_IHDRERR)) { + get_rhf_errstring(eflags, emsg, sizeof emsg); + ipath_cdbg(PKT, "RHFerrs %x hdrqtail=%x typ=%u " + "tlen=%x opcode=%x egridx=%x: %s\n", + eflags, l, etype, tlen, bthbytes[0], + ips_get_index((__le32 *) rc), emsg); + } else if (etype == RCVHQ_RCV_TYPE_NON_KD) { + int ret = __ipath_verbs_rcv(dd, rc + 1, + ebuf, tlen); + if (ret == -ENODEV) + ipath_cdbg(VERBOSE, + "received IB packet, " + "not SMA (QP=%x)\n", qp); + } else if (etype == RCVHQ_RCV_TYPE_EAGER) { + if (qp == IPATH_KD_QP && + bthbytes[0] == ipath_layer_rcv_opcode && + ebuf) + ipath_rcv_layer(dd, etail, tlen, + (struct ether_header *)hdr); + else + ipath_cdbg(PKT, "typ %x, opcode %x (eager, " + "qp=%x), len %x; ignored\n", + etype, bthbytes[0], qp, tlen); + } + else if (etype == RCVHQ_RCV_TYPE_EXPECTED) + ipath_dbg("Bug: Expected TID, opcode %x; ignored\n", + be32_to_cpu(hdr->bth[0]) & 0xff); + else if (eflags & (INFINIPATH_RHF_H_TIDERR | + INFINIPATH_RHF_H_IHDRERR)) { + /* + * This is a type 3 packet, only the LRH is in the + * rcvhdrq, the rest of the header is in the eager + * buffer. + */ + u8 opcode; + if (ebuf) { + bthbytes = (u8 *) ebuf; + opcode = *bthbytes; + } + else + opcode = 0; + get_rhf_errstring(eflags, emsg, sizeof emsg); + ipath_dbg("Err %x (%s), opcode %x, egrbuf %x, " + "len %x\n", eflags, emsg, opcode, etail, + tlen); + } else { + /* + * error packet, type of error unknown. + * Probably type 3, but we don't know, so don't + * even try to print the opcode, etc. + */ + ipath_dbg("Error Pkt, but no eflags! egrbuf %x, " + "len %x\nhdrq@%lx;hdrq+%x rhf: %llx; " + "hdr %llx %llx %llx %llx %llx\n", + etail, tlen, (unsigned long) rc, l, + (unsigned long long) rc[0], + (unsigned long long) rc[1], + (unsigned long long) rc[2], + (unsigned long long) rc[3], + (unsigned long long) rc[4], + (unsigned long long) rc[5]); + } + l += rsize; + if (l >= maxcnt) + l = 0; + /* + * update for each packet, to help prevent overflows if we + * have lots of packets. + */ + (void)ipath_write_ureg(dd, ur_rcvhdrhead, + dd->ipath_rhdrhead_intr_off | l, 0); + if (etype != RCVHQ_RCV_TYPE_EXPECTED) + (void)ipath_write_ureg(dd, ur_rcvegrindexhead, + etail, 0); + } + + pkttot += i; + + dd->ipath_port0head = l; + + if (hdrqtail != (u32)le64_to_cpu(*dd->ipath_hdrqtailptr)) + /* more arrived while we handled first batch */ + goto gotmore; + + if (pkttot > ipath_stats.sps_maxpkts_call) + ipath_stats.sps_maxpkts_call = pkttot; + ipath_stats.sps_port0pkts += pkttot; + ipath_stats.sps_avgpkts_call = + ipath_stats.sps_port0pkts / ++totcalls; + +done: + clear_bit(0, &dd->ipath_rcv_pending); + smp_mb__after_clear_bit(); + +bail:; +} + +/** + * ipath_update_pio_bufs - update shadow copy of the PIO availability map + * @dd: the infinipath device + * + * called whenever our local copy indicates we have run out of send buffers + * NOTE: This can be called from interrupt context by some code + * and from non-interrupt context by ipath_getpiobuf(). + */ + +static void ipath_update_pio_bufs(struct ipath_devdata *dd) +{ + unsigned long flags; + int i; + const unsigned piobregs = (unsigned)dd->ipath_pioavregs; + + /* If the generation (check) bits have changed, then we update the + * busy bit for the corresponding PIO buffer. This algorithm will + * modify positions to the value they already have in some cases + * (i.e., no change), but it's faster than changing only the bits + * that have changed. + * + * We would like to do this atomicly, to avoid spinlocks in the + * critical send path, but that's not really possible, given the + * type of changes, and that this routine could be called on + * multiple cpu's simultaneously, so we lock in this routine only, + * to avoid conflicting updates; all we change is the shadow, and + * it's a single 64 bit memory location, so by definition the update + * is atomic in terms of what other cpu's can see in testing the + * bits. The spin_lock overhead isn't too bad, since it only + * happens when all buffers are in use, so only cpu overhead, not + * latency or bandwidth is affected. + */ +#define _IPATH_ALL_CHECKBITS 0x5555555555555555ULL + if (!dd->ipath_pioavailregs_dma) { + ipath_dbg("Update shadow pioavail, but regs_dma NULL!\n"); + return; + } + if (ipath_debug & __IPATH_VERBDBG) { + /* only if packet debug and verbose */ + volatile __le64 *dma = dd->ipath_pioavailregs_dma; + unsigned long *shadow = dd->ipath_pioavailshadow; + + ipath_cdbg(PKT, "Refill avail, dma0=%llx shad0=%lx, " + "d1=%llx s1=%lx, d2=%llx s2=%lx, d3=%llx " + "s3=%lx\n", + (unsigned long long) le64_to_cpu(dma[0]), + shadow[0], + (unsigned long long) le64_to_cpu(dma[1]), + shadow[1], + (unsigned long long) le64_to_cpu(dma[2]), + shadow[2], + (unsigned long long) le64_to_cpu(dma[3]), + shadow[3]); + if (piobregs > 4) + ipath_cdbg( + PKT, "2nd group, dma4=%llx shad4=%lx, " + "d5=%llx s5=%lx, d6=%llx s6=%lx, " + "d7=%llx s7=%lx\n", + (unsigned long long) le64_to_cpu(dma[4]), + shadow[4], + (unsigned long long) le64_to_cpu(dma[5]), + shadow[5], + (unsigned long long) le64_to_cpu(dma[6]), + shadow[6], + (unsigned long long) le64_to_cpu(dma[7]), + shadow[7]); + } + spin_lock_irqsave(&ipath_pioavail_lock, flags); + for (i = 0; i < piobregs; i++) { + u64 pchbusy, pchg, piov, pnew; + /* + * Chip Errata: bug 6641; even and odd qwords>3 are swapped + */ + if (i > 3) { + if (i & 1) + piov = le64_to_cpu( + dd->ipath_pioavailregs_dma[i - 1]); + else + piov = le64_to_cpu( + dd->ipath_pioavailregs_dma[i + 1]); + } else + piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]); + pchg = _IPATH_ALL_CHECKBITS & + ~(dd->ipath_pioavailshadow[i] ^ piov); + pchbusy = pchg << INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT; + if (pchg && (pchbusy & dd->ipath_pioavailshadow[i])) { + pnew = dd->ipath_pioavailshadow[i] & ~pchbusy; + pnew |= piov & pchbusy; + dd->ipath_pioavailshadow[i] = pnew; + } + } + spin_unlock_irqrestore(&ipath_pioavail_lock, flags); +} + +/** + * ipath_setrcvhdrsize - set the receive header size + * @dd: the infinipath device + * @rhdrsize: the receive header size + * + * called from user init code, and also layered driver init + */ +int ipath_setrcvhdrsize(struct ipath_devdata *dd, unsigned rhdrsize) +{ + int ret = 0; + + if (dd->ipath_flags & IPATH_RCVHDRSZ_SET) { + if (dd->ipath_rcvhdrsize != rhdrsize) { + dev_info(&dd->pcidev->dev, + "Error: can't set protocol header " + "size %u, already %u\n", + rhdrsize, dd->ipath_rcvhdrsize); + ret = -EAGAIN; + } else + ipath_cdbg(VERBOSE, "Reuse same protocol header " + "size %u\n", dd->ipath_rcvhdrsize); + } else if (rhdrsize > (dd->ipath_rcvhdrentsize - + (sizeof(u64) / sizeof(u32)))) { + ipath_dbg("Error: can't set protocol header size %u " + "(> max %u)\n", rhdrsize, + dd->ipath_rcvhdrentsize - + (u32) (sizeof(u64) / sizeof(u32))); + ret = -EOVERFLOW; + } else { + dd->ipath_flags |= IPATH_RCVHDRSZ_SET; + dd->ipath_rcvhdrsize = rhdrsize; + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvhdrsize, + dd->ipath_rcvhdrsize); + ipath_cdbg(VERBOSE, "Set protocol header size to %u\n", + dd->ipath_rcvhdrsize); + } + return ret; +} + +/** + * ipath_getpiobuf - find an available pio buffer + * @dd: the infinipath device + * @pbufnum: the buffer number is placed here + * + * do appropriate marking as busy, etc. + * returns buffer number if one found (>=0), negative number is error. + * Used by ipath_sma_send_pkt and ipath_layer_send + */ +u32 __iomem *ipath_getpiobuf(struct ipath_devdata *dd, u32 * pbufnum) +{ + int i, j, starti, updated = 0; + unsigned piobcnt, iter; + unsigned long flags; + unsigned long *shadow = dd->ipath_pioavailshadow; + u32 __iomem *buf; + + piobcnt = (unsigned)(dd->ipath_piobcnt2k + + dd->ipath_piobcnt4k); + starti = dd->ipath_lastport_piobuf; + iter = piobcnt - starti; + if (dd->ipath_upd_pio_shadow) { + /* + * Minor optimization. If we had no buffers on last call, + * start out by doing the update; continue and do scan even + * if no buffers were updated, to be paranoid + */ + ipath_update_pio_bufs(dd); + /* we scanned here, don't do it at end of scan */ + updated = 1; + i = starti; + } else + i = dd->ipath_lastpioindex; + +rescan: + /* + * while test_and_set_bit() is atomic, we do that and then the + * change_bit(), and the pair is not. See if this is the cause + * of the remaining armlaunch errors. + */ + spin_lock_irqsave(&ipath_pioavail_lock, flags); + for (j = 0; j < iter; j++, i++) { + if (i >= piobcnt) + i = starti; + /* + * To avoid bus lock overhead, we first find a candidate + * buffer, then do the test and set, and continue if that + * fails. + */ + if (test_bit((2 * i) + 1, shadow) || + test_and_set_bit((2 * i) + 1, shadow)) + continue; + /* flip generation bit */ + change_bit(2 * i, shadow); + break; + } + spin_unlock_irqrestore(&ipath_pioavail_lock, flags); + + if (j == iter) { + volatile __le64 *dma = dd->ipath_pioavailregs_dma; + + /* + * first time through; shadow exhausted, but may be real + * buffers available, so go see; if any updated, rescan + * (once) + */ + if (!updated) { + ipath_update_pio_bufs(dd); + updated = 1; + i = starti; + goto rescan; + } + dd->ipath_upd_pio_shadow = 1; + /* + * not atomic, but if we lose one once in a while, that's OK + */ + ipath_stats.sps_nopiobufs++; + if (!(++dd->ipath_consec_nopiobuf % 100000)) { + ipath_dbg( + "%u pio sends with no bufavail; dmacopy: " + "%llx %llx %llx %llx; shadow: " + "%lx %lx %lx %lx\n", + dd->ipath_consec_nopiobuf, + (unsigned long long) le64_to_cpu(dma[0]), + (unsigned long long) le64_to_cpu(dma[1]), + (unsigned long long) le64_to_cpu(dma[2]), + (unsigned long long) le64_to_cpu(dma[3]), + shadow[0], shadow[1], shadow[2], + shadow[3]); + /* + * 4 buffers per byte, 4 registers above, cover rest + * below + */ + if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > + (sizeof(shadow[0]) * 4 * 4)) + ipath_dbg("2nd group: dmacopy: %llx %llx " + "%llx %llx; shadow: %lx %lx " + "%lx %lx\n", + (unsigned long long) + le64_to_cpu(dma[4]), + (unsigned long long) + le64_to_cpu(dma[5]), + (unsigned long long) + le64_to_cpu(dma[6]), + (unsigned long long) + le64_to_cpu(dma[7]), + shadow[4], shadow[5], + shadow[6], shadow[7]); + } + buf = NULL; + goto bail; + } + + if (updated) + /* + * ran out of bufs, now some (at least this one we just + * got) are now available, so tell the layered driver. + */ + __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE); + + /* + * set next starting place. Since it's just an optimization, + * it doesn't matter who wins on this, so no locking + */ + dd->ipath_lastpioindex = i + 1; + if (dd->ipath_upd_pio_shadow) + dd->ipath_upd_pio_shadow = 0; + if (dd->ipath_consec_nopiobuf) + dd->ipath_consec_nopiobuf = 0; + if (i < dd->ipath_piobcnt2k) + buf = (u32 __iomem *) (dd->ipath_pio2kbase + + i * dd->ipath_palign); + else + buf = (u32 __iomem *) + (dd->ipath_pio4kbase + + (i - dd->ipath_piobcnt2k) * dd->ipath_4kalign); + ipath_cdbg(VERBOSE, "Return piobuf%u %uk @ %p\n", + i, (i < dd->ipath_piobcnt2k) ? 2 : 4, buf); + if (pbufnum) + *pbufnum = i; + +bail: + return buf; +} + +/** + * ipath_create_rcvhdrq - create a receive header queue + * @dd: the infinipath device + * @pd: the port data + * + * this *must* be physically contiguous memory, and for now, + * that limits it to what kmalloc can do. + */ +int ipath_create_rcvhdrq(struct ipath_devdata *dd, + struct ipath_portdata *pd) +{ + int ret = 0, amt; + + amt = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize * + sizeof(u32), PAGE_SIZE); + if (!pd->port_rcvhdrq) { + /* + * not using REPEAT isn't viable; at 128KB, we can easily + * fail this. The problem with REPEAT is we can block here + * "forever". There isn't an inbetween, unfortunately. We + * could reduce the risk by never freeing the rcvhdrq except + * at unload, but even then, the first time a port is used, + * we could delay for some time... + */ + gfp_t gfp_flags = GFP_USER | __GFP_COMP; + + pd->port_rcvhdrq = dma_alloc_coherent( + &dd->pcidev->dev, amt, &pd->port_rcvhdrq_phys, + gfp_flags); + + if (!pd->port_rcvhdrq) { + ipath_dev_err(dd, "attempt to allocate %d bytes " + "for port %u rcvhdrq failed\n", + amt, pd->port_port); + ret = -ENOMEM; + goto bail; + } + + pd->port_rcvhdrq_size = amt; + + ipath_cdbg(VERBOSE, "%d pages at %p (phys %lx) size=%lu " + "for port %u rcvhdr Q\n", + amt >> PAGE_SHIFT, pd->port_rcvhdrq, + (unsigned long) pd->port_rcvhdrq_phys, + (unsigned long) pd->port_rcvhdrq_size, + pd->port_port); + } else { + /* + * clear for security, sanity, and/or debugging, each + * time we reuse + */ + memset(pd->port_rcvhdrq, 0, amt); + } + + /* + * tell chip each time we init it, even if we are re-using previous + * memory (we zero it at process close) + */ + ipath_cdbg(VERBOSE, "writing port %d rcvhdraddr as %lx\n", + pd->port_port, (unsigned long) pd->port_rcvhdrq_phys); + ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr, + pd->port_port, pd->port_rcvhdrq_phys); + + ret = 0; +bail: + return ret; +} + +int ipath_waitfor_complete(struct ipath_devdata *dd, ipath_kreg reg_id, + u64 bits_to_wait_for, u64 * valp) +{ + unsigned long timeout; + u64 lastval, val; + int ret; + + lastval = ipath_read_kreg64(dd, reg_id); + /* wait a ridiculously long time */ + timeout = jiffies + msecs_to_jiffies(5); + do { + val = ipath_read_kreg64(dd, reg_id); + /* set so they have something, even on failures. */ + *valp = val; + if ((val & bits_to_wait_for) == bits_to_wait_for) { + ret = 0; + break; + } + if (val != lastval) + ipath_cdbg(VERBOSE, "Changed from %llx to %llx, " + "waiting for %llx bits\n", + (unsigned long long) lastval, + (unsigned long long) val, + (unsigned long long) bits_to_wait_for); + cond_resched(); + if (time_after(jiffies, timeout)) { + ipath_dbg("Didn't get bits %llx in register 0x%x, " + "got %llx\n", + (unsigned long long) bits_to_wait_for, + reg_id, (unsigned long long) *valp); + ret = -ENODEV; + break; + } + } while (1); + + return ret; +} + +/** + * ipath_waitfor_mdio_cmdready - wait for last command to complete + * @dd: the infinipath device + * + * Like ipath_waitfor_complete(), but we wait for the CMDVALID bit to go + * away indicating the last command has completed. It doesn't return data + */ +int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd) +{ + unsigned long timeout; + u64 val; + int ret; + + /* wait a ridiculously long time */ + timeout = jiffies + msecs_to_jiffies(5); + do { + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_mdio); + if (!(val & IPATH_MDIO_CMDVALID)) { + ret = 0; + break; + } + cond_resched(); + if (time_after(jiffies, timeout)) { + ipath_dbg("CMDVALID stuck in mdio reg? (%llx)\n", + (unsigned long long) val); + ret = -ENODEV; + break; + } + } while (1); + + return ret; +} + +void ipath_set_ib_lstate(struct ipath_devdata *dd, int which) +{ + static const char *what[4] = { + [0] = "DOWN", + [INFINIPATH_IBCC_LINKCMD_INIT] = "INIT", + [INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED", + [INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE" + }; + ipath_cdbg(SMA, "Trying to move unit %u to %s, current ltstate " + "is %s\n", dd->ipath_unit, + what[(which >> INFINIPATH_IBCC_LINKCMD_SHIFT) & + INFINIPATH_IBCC_LINKCMD_MASK], + ipath_ibcstatus_str[ + (ipath_read_kreg64 + (dd, dd->ipath_kregs->kr_ibcstatus) >> + INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & + INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]); + + ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, + dd->ipath_ibcctrl | which); +} + +/** + * ipath_read_kreg64_port - read a device's per-port 64-bit kernel register + * @dd: the infinipath device + * @regno: the register number to read + * @port: the port containing the register + * + * Registers that vary with the chip implementation constants (port) + * use this routine. + */ +u64 ipath_read_kreg64_port(const struct ipath_devdata *dd, ipath_kreg regno, + unsigned port) +{ + u16 where; + + if (port < dd->ipath_portcnt && + (regno == dd->ipath_kregs->kr_rcvhdraddr || + regno == dd->ipath_kregs->kr_rcvhdrtailaddr)) + where = regno + port; + else + where = -1; + + return ipath_read_kreg64(dd, where); +} + +/** + * ipath_write_kreg_port - write a device's per-port 64-bit kernel register + * @dd: the infinipath device + * @regno: the register number to write + * @port: the port containing the register + * @value: the value to write + * + * Registers that vary with the chip implementation constants (port) + * use this routine. + */ +void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno, + unsigned port, u64 value) +{ + u16 where; + + if (port < dd->ipath_portcnt && + (regno == dd->ipath_kregs->kr_rcvhdraddr || + regno == dd->ipath_kregs->kr_rcvhdrtailaddr)) + where = regno + port; + else + where = -1; + + ipath_write_kreg(dd, where, value); +} + +/** + * ipath_shutdown_device - shut down a device + * @dd: the infinipath device + * + * This is called to make the device quiet when we are about to + * unload the driver, and also when the device is administratively + * disabled. It does not free any data structures. + * Everything it does has to be setup again by ipath_init_chip(dd,1) + */ +void ipath_shutdown_device(struct ipath_devdata *dd) +{ + u64 val; + + ipath_dbg("Shutting down the device\n"); + + dd->ipath_flags |= IPATH_LINKUNK; + dd->ipath_flags &= ~(IPATH_INITTED | IPATH_LINKDOWN | + IPATH_LINKINIT | IPATH_LINKARMED | + IPATH_LINKACTIVE); + *dd->ipath_statusp &= ~(IPATH_STATUS_IB_CONF | + IPATH_STATUS_IB_READY); + + /* mask interrupts, but not errors */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL); + + dd->ipath_rcvctrl = 0; + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl); + + /* + * gracefully stop all sends allowing any in progress to trickle out + * first. + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL); + /* flush it */ + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + /* + * enough for anything that's going to trickle out to have actually + * done so. + */ + udelay(5); + + /* + * abort any armed or launched PIO buffers that didn't go. (self + * clearing). Will cause any packet currently being transmitted to + * go out with an EBP, and may also cause a short packet error on + * the receiver. + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + INFINIPATH_S_ABORT); + + ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE << + INFINIPATH_IBCC_LINKINITCMD_SHIFT); + + /* + * we are shutting down, so tell the layered driver. We don't do + * this on just a link state change, much like ethernet, a cable + * unplug, etc. doesn't change driver state + */ + ipath_layer_intr(dd, IPATH_LAYER_INT_IF_DOWN); + + /* disable IBC */ + dd->ipath_control &= ~INFINIPATH_C_LINKENABLE; + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, + dd->ipath_control); + + /* + * clear SerdesEnable and turn the leds off; do this here because + * we are unloading, so don't count on interrupts to move along + * Turn the LEDs off explictly for the same reason. + */ + dd->ipath_f_quiet_serdes(dd); + dd->ipath_f_setextled(dd, 0, 0); + + if (dd->ipath_stats_timer_active) { + del_timer_sync(&dd->ipath_stats_timer); + dd->ipath_stats_timer_active = 0; + } + + /* + * clear all interrupts and errors, so that the next time the driver + * is loaded or device is enabled, we know that whatever is set + * happened while we were unloaded + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, + ~0ULL & ~INFINIPATH_HWE_MEMBISTFAILED); + ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, -1LL); + ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, -1LL); +} + +/** + * ipath_free_pddata - free a port's allocated data + * @dd: the infinipath device + * @port: the port + * @freehdrq: free the port data structure if true + * + * when closing, free up any allocated data for a port, if the + * reference count goes to zero + * Note: this also optionally frees the portdata itself! + * Any changes here have to be matched up with the reinit case + * of ipath_init_chip(), which calls this routine on reinit after reset. + */ +void ipath_free_pddata(struct ipath_devdata *dd, u32 port, int freehdrq) +{ + struct ipath_portdata *pd = dd->ipath_pd[port]; + + if (!pd) + return; + if (freehdrq) + /* + * only clear and free portdata if we are going to also + * release the hdrq, otherwise we leak the hdrq on each + * open/close cycle + */ + dd->ipath_pd[port] = NULL; + if (freehdrq && pd->port_rcvhdrq) { + ipath_cdbg(VERBOSE, "free closed port %d rcvhdrq @ %p " + "(size=%lu)\n", pd->port_port, pd->port_rcvhdrq, + (unsigned long) pd->port_rcvhdrq_size); + dma_free_coherent(&dd->pcidev->dev, pd->port_rcvhdrq_size, + pd->port_rcvhdrq, pd->port_rcvhdrq_phys); + pd->port_rcvhdrq = NULL; + } + if (port && pd->port_rcvegrbuf) { + /* always free this */ + if (pd->port_rcvegrbuf) { + unsigned e; + + for (e = 0; e < pd->port_rcvegrbuf_chunks; e++) { + void *base = pd->port_rcvegrbuf[e]; + size_t size = pd->port_rcvegrbuf_size; + + ipath_cdbg(VERBOSE, "egrbuf free(%p, %lu), " + "chunk %u/%u\n", base, + (unsigned long) size, + e, pd->port_rcvegrbuf_chunks); + dma_free_coherent( + &dd->pcidev->dev, size, base, + pd->port_rcvegrbuf_phys[e]); + } + vfree(pd->port_rcvegrbuf); + pd->port_rcvegrbuf = NULL; + vfree(pd->port_rcvegrbuf_phys); + pd->port_rcvegrbuf_phys = NULL; + } + pd->port_rcvegrbuf_chunks = 0; + } else if (port == 0 && dd->ipath_port0_skbs) { + unsigned e; + struct sk_buff **skbs = dd->ipath_port0_skbs; + + dd->ipath_port0_skbs = NULL; + ipath_cdbg(VERBOSE, "free closed port %d ipath_port0_skbs " + "@ %p\n", pd->port_port, skbs); + for (e = 0; e < dd->ipath_rcvegrcnt; e++) + if (skbs[e]) + dev_kfree_skb(skbs[e]); + vfree(skbs); + } + if (freehdrq) { + kfree(pd->port_tid_pg_list); + kfree(pd); + } +} + +int __init infinipath_init(void) +{ + int ret; + + ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ipath_core_version); + + /* + * These must be called before the driver is registered with + * the PCI subsystem. + */ + idr_init(&unit_table); + if (!idr_pre_get(&unit_table, GFP_KERNEL)) { + ret = -ENOMEM; + goto bail; + } + + ret = pci_register_driver(&ipath_driver); + if (ret < 0) { + printk(KERN_ERR IPATH_DRV_NAME + ": Unable to register driver: error %d\n", -ret); + goto bail_unit; + } + + ret = ipath_driver_create_group(&ipath_driver.driver); + if (ret < 0) { + printk(KERN_ERR IPATH_DRV_NAME ": Unable to create driver " + "sysfs entries: error %d\n", -ret); + goto bail_pci; + } + + ret = ipath_init_ipathfs(); + if (ret < 0) { + printk(KERN_ERR IPATH_DRV_NAME ": Unable to create " + "ipathfs: error %d\n", -ret); + goto bail_group; + } + + goto bail; + +bail_group: + ipath_driver_remove_group(&ipath_driver.driver); + +bail_pci: + pci_unregister_driver(&ipath_driver); + +bail_unit: + idr_destroy(&unit_table); + +bail: + return ret; +} + +static void cleanup_device(struct ipath_devdata *dd) +{ + int port; + + ipath_shutdown_device(dd); + + if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) { + /* can't do anything more with chip; needs re-init */ + *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT; + if (dd->ipath_kregbase) { + /* + * if we haven't already cleaned up before these are + * to ensure any register reads/writes "fail" until + * re-init + */ + dd->ipath_kregbase = NULL; + dd->ipath_kregvirt = NULL; + dd->ipath_uregbase = 0; + dd->ipath_sregbase = 0; + dd->ipath_cregbase = 0; + dd->ipath_kregsize = 0; + } + ipath_disable_wc(dd); + } + + if (dd->ipath_pioavailregs_dma) { + dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE, + (void *) dd->ipath_pioavailregs_dma, + dd->ipath_pioavailregs_phys); + dd->ipath_pioavailregs_dma = NULL; + } + + if (dd->ipath_pageshadow) { + struct page **tmpp = dd->ipath_pageshadow; + int i, cnt = 0; + + ipath_cdbg(VERBOSE, "Unlocking any expTID pages still " + "locked\n"); + for (port = 0; port < dd->ipath_cfgports; port++) { + int port_tidbase = port * dd->ipath_rcvtidcnt; + int maxtid = port_tidbase + dd->ipath_rcvtidcnt; + for (i = port_tidbase; i < maxtid; i++) { + if (!tmpp[i]) + continue; + ipath_release_user_pages(&tmpp[i], 1); + tmpp[i] = NULL; + cnt++; + } + } + if (cnt) { + ipath_stats.sps_pageunlocks += cnt; + ipath_cdbg(VERBOSE, "There were still %u expTID " + "entries locked\n", cnt); + } + if (ipath_stats.sps_pagelocks || + ipath_stats.sps_pageunlocks) + ipath_cdbg(VERBOSE, "%llu pages locked, %llu " + "unlocked via ipath_m{un}lock\n", + (unsigned long long) + ipath_stats.sps_pagelocks, + (unsigned long long) + ipath_stats.sps_pageunlocks); + + ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n", + dd->ipath_pageshadow); + vfree(dd->ipath_pageshadow); + dd->ipath_pageshadow = NULL; + } + + /* + * free any resources still in use (usually just kernel ports) + * at unload + */ + for (port = 0; port < dd->ipath_cfgports; port++) + ipath_free_pddata(dd, port, 1); + kfree(dd->ipath_pd); + /* + * debuggability, in case some cleanup path tries to use it + * after this + */ + dd->ipath_pd = NULL; +} + +static void __exit infinipath_cleanup(void) +{ + struct ipath_devdata *dd, *tmp; + unsigned long flags; + + ipath_exit_ipathfs(); + + ipath_driver_remove_group(&ipath_driver.driver); + + spin_lock_irqsave(&ipath_devs_lock, flags); + + /* + * turn off rcv, send, and interrupts for all ports, all drivers + * should also hard reset the chip here? + * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs + * for all versions of the driver, if they were allocated + */ + list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) { + spin_unlock_irqrestore(&ipath_devs_lock, flags); + + if (dd->ipath_kregbase) + cleanup_device(dd); + + if (dd->pcidev) { + if (dd->pcidev->irq) { + ipath_cdbg(VERBOSE, + "unit %u free_irq of irq %x\n", + dd->ipath_unit, dd->pcidev->irq); + free_irq(dd->pcidev->irq, dd); + } else + ipath_dbg("irq is 0, not doing free_irq " + "for unit %u\n", dd->ipath_unit); + dd->pcidev = NULL; + } + + /* + * we check for NULL here, because it's outside the kregbase + * check, and we need to call it after the free_irq. Thus + * it's possible that the function pointers were never + * initialized. + */ + if (dd->ipath_f_cleanup) + /* clean up chip-specific stuff */ + dd->ipath_f_cleanup(dd); + + spin_lock_irqsave(&ipath_devs_lock, flags); + } + + spin_unlock_irqrestore(&ipath_devs_lock, flags); + + ipath_cdbg(VERBOSE, "Unregistering pci driver\n"); + pci_unregister_driver(&ipath_driver); + + idr_destroy(&unit_table); +} + +/** + * ipath_reset_device - reset the chip if possible + * @unit: the device to reset + * + * Whether or not reset is successful, we attempt to re-initialize the chip + * (that is, much like a driver unload/reload). We clear the INITTED flag + * so that the various entry points will fail until we reinitialize. For + * now, we only allow this if no user ports are open that use chip resources + */ +int ipath_reset_device(int unit) +{ + int ret, i; + struct ipath_devdata *dd = ipath_lookup(unit); + + if (!dd) { + ret = -ENODEV; + goto bail; + } + + dev_info(&dd->pcidev->dev, "Reset on unit %u requested\n", unit); + + if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) { + dev_info(&dd->pcidev->dev, "Invalid unit number %u or " + "not initialized or not present\n", unit); + ret = -ENXIO; + goto bail; + } + + if (dd->ipath_pd) + for (i = 1; i < dd->ipath_portcnt; i++) { + if (dd->ipath_pd[i] && dd->ipath_pd[i]->port_cnt) { + ipath_dbg("unit %u port %d is in use " + "(PID %u cmd %s), can't reset\n", + unit, i, + dd->ipath_pd[i]->port_pid, + dd->ipath_pd[i]->port_comm); + ret = -EBUSY; + goto bail; + } + } + + dd->ipath_flags &= ~IPATH_INITTED; + ret = dd->ipath_f_reset(dd); + if (ret != 1) + ipath_dbg("reset was not successful\n"); + ipath_dbg("Trying to reinitialize unit %u after reset attempt\n", + unit); + ret = ipath_init_chip(dd, 1); + if (ret) + ipath_dev_err(dd, "Reinitialize unit %u after " + "reset failed with %d\n", unit, ret); + else + dev_info(&dd->pcidev->dev, "Reinitialized unit %u after " + "resetting\n", unit); + +bail: + return ret; +} + +module_init(infinipath_init); +module_exit(infinipath_cleanup); diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c new file mode 100644 index 000000000000..f11a900e8cd7 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "ipath_kernel.h" + +/* + * InfiniPath I2C driver for a serial eeprom. This is not a generic + * I2C interface. For a start, the device we're using (Atmel AT24C11) + * doesn't work like a regular I2C device. It looks like one + * electrically, but not logically. Normal I2C devices have a single + * 7-bit or 10-bit I2C address that they respond to. Valid 7-bit + * addresses range from 0x03 to 0x77. Addresses 0x00 to 0x02 and 0x78 + * to 0x7F are special reserved addresses (e.g. 0x00 is the "general + * call" address.) The Atmel device, on the other hand, responds to ALL + * 7-bit addresses. It's designed to be the only device on a given I2C + * bus. A 7-bit address corresponds to the memory address within the + * Atmel device itself. + * + * Also, the timing requirements mean more than simple software + * bitbanging, with readbacks from chip to ensure timing (simple udelay + * is not enough). + * + * This all means that accessing the device is specialized enough + * that using the standard kernel I2C bitbanging interface would be + * impossible. For example, the core I2C eeprom driver expects to find + * a device at one or more of a limited set of addresses only. It doesn't + * allow writing to an eeprom. It also doesn't provide any means of + * accessing eeprom contents from within the kernel, only via sysfs. + */ + +enum i2c_type { + i2c_line_scl = 0, + i2c_line_sda +}; + +enum i2c_state { + i2c_line_low = 0, + i2c_line_high +}; + +#define READ_CMD 1 +#define WRITE_CMD 0 + +static int eeprom_init; + +/* + * The gpioval manipulation really should be protected by spinlocks + * or be converted to use atomic operations. + */ + +/** + * i2c_gpio_set - set a GPIO line + * @dd: the infinipath device + * @line: the line to set + * @new_line_state: the state to set + * + * Returns 0 if the line was set to the new state successfully, non-zero + * on error. + */ +static int i2c_gpio_set(struct ipath_devdata *dd, + enum i2c_type line, + enum i2c_state new_line_state) +{ + u64 read_val, write_val, mask, *gpioval; + + gpioval = &dd->ipath_gpio_out; + read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl); + if (line == i2c_line_scl) + mask = ipath_gpio_scl; + else + mask = ipath_gpio_sda; + + if (new_line_state == i2c_line_high) + /* tri-state the output rather than force high */ + write_val = read_val & ~mask; + else + /* config line to be an output */ + write_val = read_val | mask; + ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, write_val); + + /* set high and verify */ + if (new_line_state == i2c_line_high) + write_val = 0x1UL; + else + write_val = 0x0UL; + + if (line == i2c_line_scl) { + write_val <<= ipath_gpio_scl_num; + *gpioval = *gpioval & ~(1UL << ipath_gpio_scl_num); + *gpioval |= write_val; + } else { + write_val <<= ipath_gpio_sda_num; + *gpioval = *gpioval & ~(1UL << ipath_gpio_sda_num); + *gpioval |= write_val; + } + ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval); + + return 0; +} + +/** + * i2c_gpio_get - get a GPIO line state + * @dd: the infinipath device + * @line: the line to get + * @curr_statep: where to put the line state + * + * Returns 0 if the line was set to the new state successfully, non-zero + * on error. curr_state is not set on error. + */ +static int i2c_gpio_get(struct ipath_devdata *dd, + enum i2c_type line, + enum i2c_state *curr_statep) +{ + u64 read_val, write_val, mask; + int ret; + + /* check args */ + if (curr_statep == NULL) { + ret = 1; + goto bail; + } + + read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl); + /* config line to be an input */ + if (line == i2c_line_scl) + mask = ipath_gpio_scl; + else + mask = ipath_gpio_sda; + write_val = read_val & ~mask; + ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, write_val); + read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus); + + if (read_val & mask) + *curr_statep = i2c_line_high; + else + *curr_statep = i2c_line_low; + + ret = 0; + +bail: + return ret; +} + +/** + * i2c_wait_for_writes - wait for a write + * @dd: the infinipath device + * + * We use this instead of udelay directly, so we can make sure + * that previous register writes have been flushed all the way + * to the chip. Since we are delaying anyway, the cost doesn't + * hurt, and makes the bit twiddling more regular + */ +static void i2c_wait_for_writes(struct ipath_devdata *dd) +{ + (void)ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch); +} + +static void scl_out(struct ipath_devdata *dd, u8 bit) +{ + i2c_gpio_set(dd, i2c_line_scl, bit ? i2c_line_high : i2c_line_low); + + i2c_wait_for_writes(dd); +} + +static void sda_out(struct ipath_devdata *dd, u8 bit) +{ + i2c_gpio_set(dd, i2c_line_sda, bit ? i2c_line_high : i2c_line_low); + + i2c_wait_for_writes(dd); +} + +static u8 sda_in(struct ipath_devdata *dd, int wait) +{ + enum i2c_state bit; + + if (i2c_gpio_get(dd, i2c_line_sda, &bit)) + ipath_dbg("get bit failed!\n"); + + if (wait) + i2c_wait_for_writes(dd); + + return bit == i2c_line_high ? 1U : 0; +} + +/** + * i2c_ackrcv - see if ack following write is true + * @dd: the infinipath device + */ +static int i2c_ackrcv(struct ipath_devdata *dd) +{ + u8 ack_received; + + /* AT ENTRY SCL = LOW */ + /* change direction, ignore data */ + ack_received = sda_in(dd, 1); + scl_out(dd, i2c_line_high); + ack_received = sda_in(dd, 1) == 0; + scl_out(dd, i2c_line_low); + return ack_received; +} + +/** + * wr_byte - write a byte, one bit at a time + * @dd: the infinipath device + * @data: the byte to write + * + * Returns 0 if we got the following ack, otherwise 1 + */ +static int wr_byte(struct ipath_devdata *dd, u8 data) +{ + int bit_cntr; + u8 bit; + + for (bit_cntr = 7; bit_cntr >= 0; bit_cntr--) { + bit = (data >> bit_cntr) & 1; + sda_out(dd, bit); + scl_out(dd, i2c_line_high); + scl_out(dd, i2c_line_low); + } + return (!i2c_ackrcv(dd)) ? 1 : 0; +} + +static void send_ack(struct ipath_devdata *dd) +{ + sda_out(dd, i2c_line_low); + scl_out(dd, i2c_line_high); + scl_out(dd, i2c_line_low); + sda_out(dd, i2c_line_high); +} + +/** + * i2c_startcmd - transmit the start condition, followed by address/cmd + * @dd: the infinipath device + * @offset_dir: direction byte + * + * (both clock/data high, clock high, data low while clock is high) + */ +static int i2c_startcmd(struct ipath_devdata *dd, u8 offset_dir) +{ + int res; + + /* issue start sequence */ + sda_out(dd, i2c_line_high); + scl_out(dd, i2c_line_high); + sda_out(dd, i2c_line_low); + scl_out(dd, i2c_line_low); + + /* issue length and direction byte */ + res = wr_byte(dd, offset_dir); + + if (res) + ipath_cdbg(VERBOSE, "No ack to complete start\n"); + + return res; +} + +/** + * stop_cmd - transmit the stop condition + * @dd: the infinipath device + * + * (both clock/data low, clock high, data high while clock is high) + */ +static void stop_cmd(struct ipath_devdata *dd) +{ + scl_out(dd, i2c_line_low); + sda_out(dd, i2c_line_low); + scl_out(dd, i2c_line_high); + sda_out(dd, i2c_line_high); + udelay(2); +} + +/** + * eeprom_reset - reset I2C communication + * @dd: the infinipath device + */ + +static int eeprom_reset(struct ipath_devdata *dd) +{ + int clock_cycles_left = 9; + u64 *gpioval = &dd->ipath_gpio_out; + int ret; + + eeprom_init = 1; + *gpioval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_out); + ipath_cdbg(VERBOSE, "Resetting i2c eeprom; initial gpioout reg " + "is %llx\n", (unsigned long long) *gpioval); + + /* + * This is to get the i2c into a known state, by first going low, + * then tristate sda (and then tristate scl as first thing + * in loop) + */ + scl_out(dd, i2c_line_low); + sda_out(dd, i2c_line_high); + + while (clock_cycles_left--) { + scl_out(dd, i2c_line_high); + + if (sda_in(dd, 0)) { + sda_out(dd, i2c_line_low); + scl_out(dd, i2c_line_low); + ret = 0; + goto bail; + } + + scl_out(dd, i2c_line_low); + } + + ret = 1; + +bail: + return ret; +} + +/** + * ipath_eeprom_read - receives bytes from the eeprom via I2C + * @dd: the infinipath device + * @eeprom_offset: address to read from + * @buffer: where to store result + * @len: number of bytes to receive + */ + +int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset, + void *buffer, int len) +{ + /* compiler complains unless initialized */ + u8 single_byte = 0; + int bit_cntr; + int ret; + + if (!eeprom_init) + eeprom_reset(dd); + + eeprom_offset = (eeprom_offset << 1) | READ_CMD; + + if (i2c_startcmd(dd, eeprom_offset)) { + ipath_dbg("Failed startcmd\n"); + stop_cmd(dd); + ret = 1; + goto bail; + } + + /* + * eeprom keeps clocking data out as long as we ack, automatically + * incrementing the address. + */ + while (len-- > 0) { + /* get data */ + single_byte = 0; + for (bit_cntr = 8; bit_cntr; bit_cntr--) { + u8 bit; + scl_out(dd, i2c_line_high); + bit = sda_in(dd, 0); + single_byte |= bit << (bit_cntr - 1); + scl_out(dd, i2c_line_low); + } + + /* send ack if not the last byte */ + if (len) + send_ack(dd); + + *((u8 *) buffer) = single_byte; + buffer++; + } + + stop_cmd(dd); + + ret = 0; + +bail: + return ret; +} + +/** + * ipath_eeprom_write - writes data to the eeprom via I2C + * @dd: the infinipath device + * @eeprom_offset: where to place data + * @buffer: data to write + * @len: number of bytes to write + */ +int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset, + const void *buffer, int len) +{ + u8 single_byte; + int sub_len; + const u8 *bp = buffer; + int max_wait_time, i; + int ret; + + if (!eeprom_init) + eeprom_reset(dd); + + while (len > 0) { + if (i2c_startcmd(dd, (eeprom_offset << 1) | WRITE_CMD)) { + ipath_dbg("Failed to start cmd offset %u\n", + eeprom_offset); + goto failed_write; + } + + sub_len = min(len, 4); + eeprom_offset += sub_len; + len -= sub_len; + + for (i = 0; i < sub_len; i++) { + if (wr_byte(dd, *bp++)) { + ipath_dbg("no ack after byte %u/%u (%u " + "total remain)\n", i, sub_len, + len + sub_len - i); + goto failed_write; + } + } + + stop_cmd(dd); + + /* + * wait for write complete by waiting for a successful + * read (the chip replies with a zero after the write + * cmd completes, and before it writes to the eeprom. + * The startcmd for the read will fail the ack until + * the writes have completed. We do this inline to avoid + * the debug prints that are in the real read routine + * if the startcmd fails. + */ + max_wait_time = 100; + while (i2c_startcmd(dd, READ_CMD)) { + stop_cmd(dd); + if (!--max_wait_time) { + ipath_dbg("Did not get successful read to " + "complete write\n"); + goto failed_write; + } + } + /* now read the zero byte */ + for (i = single_byte = 0; i < 8; i++) { + u8 bit; + scl_out(dd, i2c_line_high); + bit = sda_in(dd, 0); + scl_out(dd, i2c_line_low); + single_byte <<= 1; + single_byte |= bit; + } + stop_cmd(dd); + } + + ret = 0; + goto bail; + +failed_write: + stop_cmd(dd); + ret = 1; + +bail: + return ret; +} + +static u8 flash_csum(struct ipath_flash *ifp, int adjust) +{ + u8 *ip = (u8 *) ifp; + u8 csum = 0, len; + + for (len = 0; len < ifp->if_length; len++) + csum += *ip++; + csum -= ifp->if_csum; + csum = ~csum; + if (adjust) + ifp->if_csum = csum; + + return csum; +} + +/** + * ipath_get_guid - get the GUID from the i2c device + * @dd: the infinipath device + * + * When we add the multi-chip support, we will probably have to add + * the ability to use the number of guids field, and get the guid from + * the first chip's flash, to use for all of them. + */ +void ipath_get_guid(struct ipath_devdata *dd) +{ + void *buf; + struct ipath_flash *ifp; + __be64 guid; + int len; + u8 csum, *bguid; + int t = dd->ipath_unit; + struct ipath_devdata *dd0 = ipath_lookup(0); + + if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) { + u8 *bguid, oguid; + dd->ipath_guid = dd0->ipath_guid; + bguid = (u8 *) & dd->ipath_guid; + + oguid = bguid[7]; + bguid[7] += t; + if (oguid > bguid[7]) { + if (bguid[6] == 0xff) { + if (bguid[5] == 0xff) { + ipath_dev_err( + dd, + "Can't set %s GUID from " + "base, wraps to OUI!\n", + ipath_get_unit_name(t)); + dd->ipath_guid = 0; + goto bail; + } + bguid[5]++; + } + bguid[6]++; + } + dd->ipath_nguid = 1; + + ipath_dbg("nguid %u, so adding %u to device 0 guid, " + "for %llx\n", + dd0->ipath_nguid, t, + (unsigned long long) be64_to_cpu(dd->ipath_guid)); + goto bail; + } + + len = offsetof(struct ipath_flash, if_future); + buf = vmalloc(len); + if (!buf) { + ipath_dev_err(dd, "Couldn't allocate memory to read %u " + "bytes from eeprom for GUID\n", len); + goto bail; + } + + if (ipath_eeprom_read(dd, 0, buf, len)) { + ipath_dev_err(dd, "Failed reading GUID from eeprom\n"); + goto done; + } + ifp = (struct ipath_flash *)buf; + + csum = flash_csum(ifp, 0); + if (csum != ifp->if_csum) { + dev_info(&dd->pcidev->dev, "Bad I2C flash checksum: " + "0x%x, not 0x%x\n", csum, ifp->if_csum); + goto done; + } + if (*(__be64 *) ifp->if_guid == 0ULL || + *(__be64 *) ifp->if_guid == __constant_cpu_to_be64(-1LL)) { + ipath_dev_err(dd, "Invalid GUID %llx from flash; " + "ignoring\n", + *(unsigned long long *) ifp->if_guid); + /* don't allow GUID if all 0 or all 1's */ + goto done; + } + + /* complain, but allow it */ + if (*(u64 *) ifp->if_guid == 0x100007511000000ULL) + dev_info(&dd->pcidev->dev, "Warning, GUID %llx is " + "default, probably not correct!\n", + *(unsigned long long *) ifp->if_guid); + + bguid = ifp->if_guid; + if (!bguid[0] && !bguid[1] && !bguid[2]) { + /* original incorrect GUID format in flash; fix in + * core copy, by shifting up 2 octets; don't need to + * change top octet, since both it and shifted are + * 0.. */ + bguid[1] = bguid[3]; + bguid[2] = bguid[4]; + bguid[3] = bguid[4] = 0; + guid = *(__be64 *) ifp->if_guid; + ipath_cdbg(VERBOSE, "Old GUID format in flash, top 3 zero, " + "shifting 2 octets\n"); + } else + guid = *(__be64 *) ifp->if_guid; + dd->ipath_guid = guid; + dd->ipath_nguid = ifp->if_numguid; + memcpy(dd->ipath_serial, ifp->if_serial, + sizeof(ifp->if_serial)); + ipath_cdbg(VERBOSE, "Initted GUID to %llx from eeprom\n", + (unsigned long long) be64_to_cpu(dd->ipath_guid)); + +done: + vfree(buf); + +bail:; +} diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c new file mode 100644 index 000000000000..c347191f02bf --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -0,0 +1,1910 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "ipath_kernel.h" +#include "ips_common.h" +#include "ipath_layer.h" + +static int ipath_open(struct inode *, struct file *); +static int ipath_close(struct inode *, struct file *); +static ssize_t ipath_write(struct file *, const char __user *, size_t, + loff_t *); +static unsigned int ipath_poll(struct file *, struct poll_table_struct *); +static int ipath_mmap(struct file *, struct vm_area_struct *); + +static struct file_operations ipath_file_ops = { + .owner = THIS_MODULE, + .write = ipath_write, + .open = ipath_open, + .release = ipath_close, + .poll = ipath_poll, + .mmap = ipath_mmap +}; + +static int ipath_get_base_info(struct ipath_portdata *pd, + void __user *ubase, size_t ubase_size) +{ + int ret = 0; + struct ipath_base_info *kinfo = NULL; + struct ipath_devdata *dd = pd->port_dd; + + if (ubase_size < sizeof(*kinfo)) { + ipath_cdbg(PROC, + "Base size %lu, need %lu (version mismatch?)\n", + (unsigned long) ubase_size, + (unsigned long) sizeof(*kinfo)); + ret = -EINVAL; + goto bail; + } + + kinfo = kzalloc(sizeof(*kinfo), GFP_KERNEL); + if (kinfo == NULL) { + ret = -ENOMEM; + goto bail; + } + + ret = dd->ipath_f_get_base_info(pd, kinfo); + if (ret < 0) + goto bail; + + kinfo->spi_rcvhdr_cnt = dd->ipath_rcvhdrcnt; + kinfo->spi_rcvhdrent_size = dd->ipath_rcvhdrentsize; + kinfo->spi_tidegrcnt = dd->ipath_rcvegrcnt; + kinfo->spi_rcv_egrbufsize = dd->ipath_rcvegrbufsize; + /* + * have to mmap whole thing + */ + kinfo->spi_rcv_egrbuftotlen = + pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size; + kinfo->spi_rcv_egrperchunk = pd->port_rcvegrbufs_perchunk; + kinfo->spi_rcv_egrchunksize = kinfo->spi_rcv_egrbuftotlen / + pd->port_rcvegrbuf_chunks; + kinfo->spi_tidcnt = dd->ipath_rcvtidcnt; + /* + * for this use, may be ipath_cfgports summed over all chips that + * are are configured and present + */ + kinfo->spi_nports = dd->ipath_cfgports; + /* unit (chip/board) our port is on */ + kinfo->spi_unit = dd->ipath_unit; + /* for now, only a single page */ + kinfo->spi_tid_maxsize = PAGE_SIZE; + + /* + * Doing this per port, and based on the skip value, etc. This has + * to be the actual buffer size, since the protocol code treats it + * as an array. + * + * These have to be set to user addresses in the user code via mmap. + * These values are used on return to user code for the mmap target + * addresses only. For 32 bit, same 44 bit address problem, so use + * the physical address, not virtual. Before 2.6.11, using the + * page_address() macro worked, but in 2.6.11, even that returns the + * full 64 bit address (upper bits all 1's). So far, using the + * physical addresses (or chip offsets, for chip mapping) works, but + * no doubt some future kernel release will chang that, and we'll be + * on to yet another method of dealing with this + */ + kinfo->spi_rcvhdr_base = (u64) pd->port_rcvhdrq_phys; + kinfo->spi_rcv_egrbufs = (u64) pd->port_rcvegr_phys; + kinfo->spi_pioavailaddr = (u64) dd->ipath_pioavailregs_phys; + kinfo->spi_status = (u64) kinfo->spi_pioavailaddr + + (void *) dd->ipath_statusp - + (void *) dd->ipath_pioavailregs_dma; + kinfo->spi_piobufbase = (u64) pd->port_piobufs; + kinfo->__spi_uregbase = + dd->ipath_uregbase + dd->ipath_palign * pd->port_port; + + kinfo->spi_pioindex = dd->ipath_pbufsport * (pd->port_port - 1); + kinfo->spi_piocnt = dd->ipath_pbufsport; + kinfo->spi_pioalign = dd->ipath_palign; + + kinfo->spi_qpair = IPATH_KD_QP; + kinfo->spi_piosize = dd->ipath_ibmaxlen; + kinfo->spi_mtu = dd->ipath_ibmaxlen; /* maxlen, not ibmtu */ + kinfo->spi_port = pd->port_port; + kinfo->spi_sw_version = IPATH_USER_SWVERSION; + kinfo->spi_hw_version = dd->ipath_revision; + + if (copy_to_user(ubase, kinfo, sizeof(*kinfo))) + ret = -EFAULT; + +bail: + kfree(kinfo); + return ret; +} + +/** + * ipath_tid_update - update a port TID + * @pd: the port + * @ti: the TID information + * + * The new implementation as of Oct 2004 is that the driver assigns + * the tid and returns it to the caller. To make it easier to + * catch bugs, and to reduce search time, we keep a cursor for + * each port, walking the shadow tid array to find one that's not + * in use. + * + * For now, if we can't allocate the full list, we fail, although + * in the long run, we'll allocate as many as we can, and the + * caller will deal with that by trying the remaining pages later. + * That means that when we fail, we have to mark the tids as not in + * use again, in our shadow copy. + * + * It's up to the caller to free the tids when they are done. + * We'll unlock the pages as they free them. + * + * Also, right now we are locking one page at a time, but since + * the intended use of this routine is for a single group of + * virtually contiguous pages, that should change to improve + * performance. + */ +static int ipath_tid_update(struct ipath_portdata *pd, + const struct ipath_tid_info *ti) +{ + int ret = 0, ntids; + u32 tid, porttid, cnt, i, tidcnt; + u16 *tidlist; + struct ipath_devdata *dd = pd->port_dd; + u64 physaddr; + unsigned long vaddr; + u64 __iomem *tidbase; + unsigned long tidmap[8]; + struct page **pagep = NULL; + + if (!dd->ipath_pageshadow) { + ret = -ENOMEM; + goto done; + } + + cnt = ti->tidcnt; + if (!cnt) { + ipath_dbg("After copyin, tidcnt 0, tidlist %llx\n", + (unsigned long long) ti->tidlist); + /* + * Should we treat as success? likely a bug + */ + ret = -EFAULT; + goto done; + } + tidcnt = dd->ipath_rcvtidcnt; + if (cnt >= tidcnt) { + /* make sure it all fits in port_tid_pg_list */ + dev_info(&dd->pcidev->dev, "Process tried to allocate %u " + "TIDs, only trying max (%u)\n", cnt, tidcnt); + cnt = tidcnt; + } + pagep = (struct page **)pd->port_tid_pg_list; + tidlist = (u16 *) (&pagep[cnt]); + + memset(tidmap, 0, sizeof(tidmap)); + tid = pd->port_tidcursor; + /* before decrement; chip actual # */ + porttid = pd->port_port * tidcnt; + ntids = tidcnt; + tidbase = (u64 __iomem *) (((char __iomem *) dd->ipath_kregbase) + + dd->ipath_rcvtidbase + + porttid * sizeof(*tidbase)); + + ipath_cdbg(VERBOSE, "Port%u %u tids, cursor %u, tidbase %p\n", + pd->port_port, cnt, tid, tidbase); + + /* virtual address of first page in transfer */ + vaddr = ti->tidvaddr; + if (!access_ok(VERIFY_WRITE, (void __user *) vaddr, + cnt * PAGE_SIZE)) { + ipath_dbg("Fail vaddr %p, %u pages, !access_ok\n", + (void *)vaddr, cnt); + ret = -EFAULT; + goto done; + } + ret = ipath_get_user_pages(vaddr, cnt, pagep); + if (ret) { + if (ret == -EBUSY) { + ipath_dbg("Failed to lock addr %p, %u pages " + "(already locked)\n", + (void *) vaddr, cnt); + /* + * for now, continue, and see what happens but with + * the new implementation, this should never happen, + * unless perhaps the user has mpin'ed the pages + * themselves (something we need to test) + */ + ret = 0; + } else { + dev_info(&dd->pcidev->dev, + "Failed to lock addr %p, %u pages: " + "errno %d\n", (void *) vaddr, cnt, -ret); + goto done; + } + } + for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) { + for (; ntids--; tid++) { + if (tid == tidcnt) + tid = 0; + if (!dd->ipath_pageshadow[porttid + tid]) + break; + } + if (ntids < 0) { + /* + * oops, wrapped all the way through their TIDs, + * and didn't have enough free; see comments at + * start of routine + */ + ipath_dbg("Not enough free TIDs for %u pages " + "(index %d), failing\n", cnt, i); + i--; /* last tidlist[i] not filled in */ + ret = -ENOMEM; + break; + } + tidlist[i] = tid; + ipath_cdbg(VERBOSE, "Updating idx %u to TID %u, " + "vaddr %lx\n", i, tid, vaddr); + /* we "know" system pages and TID pages are same size */ + dd->ipath_pageshadow[porttid + tid] = pagep[i]; + /* + * don't need atomic or it's overhead + */ + __set_bit(tid, tidmap); + physaddr = page_to_phys(pagep[i]); + ipath_stats.sps_pagelocks++; + ipath_cdbg(VERBOSE, + "TID %u, vaddr %lx, physaddr %llx pgp %p\n", + tid, vaddr, (unsigned long long) physaddr, + pagep[i]); + dd->ipath_f_put_tid(dd, &tidbase[tid], 1, physaddr); + /* + * don't check this tid in ipath_portshadow, since we + * just filled it in; start with the next one. + */ + tid++; + } + + if (ret) { + u32 limit; + cleanup: + /* jump here if copy out of updated info failed... */ + ipath_dbg("After failure (ret=%d), undo %d of %d entries\n", + -ret, i, cnt); + /* same code that's in ipath_free_tid() */ + limit = sizeof(tidmap) * BITS_PER_BYTE; + if (limit > tidcnt) + /* just in case size changes in future */ + limit = tidcnt; + tid = find_first_bit((const unsigned long *)tidmap, limit); + for (; tid < limit; tid++) { + if (!test_bit(tid, tidmap)) + continue; + if (dd->ipath_pageshadow[porttid + tid]) { + ipath_cdbg(VERBOSE, "Freeing TID %u\n", + tid); + dd->ipath_f_put_tid(dd, &tidbase[tid], 1, + dd->ipath_tidinvalid); + dd->ipath_pageshadow[porttid + tid] = NULL; + ipath_stats.sps_pageunlocks++; + } + } + ipath_release_user_pages(pagep, cnt); + } else { + /* + * Copy the updated array, with ipath_tid's filled in, back + * to user. Since we did the copy in already, this "should + * never fail" If it does, we have to clean up... + */ + if (copy_to_user((void __user *) + (unsigned long) ti->tidlist, + tidlist, cnt * sizeof(*tidlist))) { + ret = -EFAULT; + goto cleanup; + } + if (copy_to_user((void __user *) (unsigned long) ti->tidmap, + tidmap, sizeof tidmap)) { + ret = -EFAULT; + goto cleanup; + } + if (tid == tidcnt) + tid = 0; + pd->port_tidcursor = tid; + } + +done: + if (ret) + ipath_dbg("Failed to map %u TID pages, failing with %d\n", + ti->tidcnt, -ret); + return ret; +} + +/** + * ipath_tid_free - free a port TID + * @pd: the port + * @ti: the TID info + * + * right now we are unlocking one page at a time, but since + * the intended use of this routine is for a single group of + * virtually contiguous pages, that should change to improve + * performance. We check that the TID is in range for this port + * but otherwise don't check validity; if user has an error and + * frees the wrong tid, it's only their own data that can thereby + * be corrupted. We do check that the TID was in use, for sanity + * We always use our idea of the saved address, not the address that + * they pass in to us. + */ + +static int ipath_tid_free(struct ipath_portdata *pd, + const struct ipath_tid_info *ti) +{ + int ret = 0; + u32 tid, porttid, cnt, limit, tidcnt; + struct ipath_devdata *dd = pd->port_dd; + u64 __iomem *tidbase; + unsigned long tidmap[8]; + + if (!dd->ipath_pageshadow) { + ret = -ENOMEM; + goto done; + } + + if (copy_from_user(tidmap, (void __user *)(unsigned long)ti->tidmap, + sizeof tidmap)) { + ret = -EFAULT; + goto done; + } + + porttid = pd->port_port * dd->ipath_rcvtidcnt; + tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) + + dd->ipath_rcvtidbase + + porttid * sizeof(*tidbase)); + + tidcnt = dd->ipath_rcvtidcnt; + limit = sizeof(tidmap) * BITS_PER_BYTE; + if (limit > tidcnt) + /* just in case size changes in future */ + limit = tidcnt; + tid = find_first_bit(tidmap, limit); + ipath_cdbg(VERBOSE, "Port%u free %u tids; first bit (max=%d) " + "set is %d, porttid %u\n", pd->port_port, ti->tidcnt, + limit, tid, porttid); + for (cnt = 0; tid < limit; tid++) { + /* + * small optimization; if we detect a run of 3 or so without + * any set, use find_first_bit again. That's mainly to + * accelerate the case where we wrapped, so we have some at + * the beginning, and some at the end, and a big gap + * in the middle. + */ + if (!test_bit(tid, tidmap)) + continue; + cnt++; + if (dd->ipath_pageshadow[porttid + tid]) { + ipath_cdbg(VERBOSE, "PID %u freeing TID %u\n", + pd->port_pid, tid); + dd->ipath_f_put_tid(dd, &tidbase[tid], 1, + dd->ipath_tidinvalid); + ipath_release_user_pages( + &dd->ipath_pageshadow[porttid + tid], 1); + dd->ipath_pageshadow[porttid + tid] = NULL; + ipath_stats.sps_pageunlocks++; + } else + ipath_dbg("Unused tid %u, ignoring\n", tid); + } + if (cnt != ti->tidcnt) + ipath_dbg("passed in tidcnt %d, only %d bits set in map\n", + ti->tidcnt, cnt); +done: + if (ret) + ipath_dbg("Failed to unmap %u TID pages, failing with %d\n", + ti->tidcnt, -ret); + return ret; +} + +/** + * ipath_set_part_key - set a partition key + * @pd: the port + * @key: the key + * + * We can have up to 4 active at a time (other than the default, which is + * always allowed). This is somewhat tricky, since multiple ports may set + * the same key, so we reference count them, and clean up at exit. All 4 + * partition keys are packed into a single infinipath register. It's an + * error for a process to set the same pkey multiple times. We provide no + * mechanism to de-allocate a pkey at this time, we may eventually need to + * do that. I've used the atomic operations, and no locking, and only make + * a single pass through what's available. This should be more than + * adequate for some time. I'll think about spinlocks or the like if and as + * it's necessary. + */ +static int ipath_set_part_key(struct ipath_portdata *pd, u16 key) +{ + struct ipath_devdata *dd = pd->port_dd; + int i, any = 0, pidx = -1; + u16 lkey = key & 0x7FFF; + int ret; + + if (lkey == (IPS_DEFAULT_P_KEY & 0x7FFF)) { + /* nothing to do; this key always valid */ + ret = 0; + goto bail; + } + + ipath_cdbg(VERBOSE, "p%u try to set pkey %hx, current keys " + "%hx:%x %hx:%x %hx:%x %hx:%x\n", + pd->port_port, key, dd->ipath_pkeys[0], + atomic_read(&dd->ipath_pkeyrefs[0]), dd->ipath_pkeys[1], + atomic_read(&dd->ipath_pkeyrefs[1]), dd->ipath_pkeys[2], + atomic_read(&dd->ipath_pkeyrefs[2]), dd->ipath_pkeys[3], + atomic_read(&dd->ipath_pkeyrefs[3])); + + if (!lkey) { + ipath_cdbg(PROC, "p%u tries to set key 0, not allowed\n", + pd->port_port); + ret = -EINVAL; + goto bail; + } + + /* + * Set the full membership bit, because it has to be + * set in the register or the packet, and it seems + * cleaner to set in the register than to force all + * callers to set it. (see bug 4331) + */ + key |= 0x8000; + + for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) { + if (!pd->port_pkeys[i] && pidx == -1) + pidx = i; + if (pd->port_pkeys[i] == key) { + ipath_cdbg(VERBOSE, "p%u tries to set same pkey " + "(%x) more than once\n", + pd->port_port, key); + ret = -EEXIST; + goto bail; + } + } + if (pidx == -1) { + ipath_dbg("All pkeys for port %u already in use, " + "can't set %x\n", pd->port_port, key); + ret = -EBUSY; + goto bail; + } + for (any = i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { + if (!dd->ipath_pkeys[i]) { + any++; + continue; + } + if (dd->ipath_pkeys[i] == key) { + atomic_t *pkrefs = &dd->ipath_pkeyrefs[i]; + + if (atomic_inc_return(pkrefs) > 1) { + pd->port_pkeys[pidx] = key; + ipath_cdbg(VERBOSE, "p%u set key %x " + "matches #%d, count now %d\n", + pd->port_port, key, i, + atomic_read(pkrefs)); + ret = 0; + goto bail; + } else { + /* + * lost race, decrement count, catch below + */ + atomic_dec(pkrefs); + ipath_cdbg(VERBOSE, "Lost race, count was " + "0, after dec, it's %d\n", + atomic_read(pkrefs)); + any++; + } + } + if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) { + /* + * It makes no sense to have both the limited and + * full membership PKEY set at the same time since + * the unlimited one will disable the limited one. + */ + ret = -EEXIST; + goto bail; + } + } + if (!any) { + ipath_dbg("port %u, all pkeys already in use, " + "can't set %x\n", pd->port_port, key); + ret = -EBUSY; + goto bail; + } + for (any = i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { + if (!dd->ipath_pkeys[i] && + atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) { + u64 pkey; + + /* for ipathstats, etc. */ + ipath_stats.sps_pkeys[i] = lkey; + pd->port_pkeys[pidx] = dd->ipath_pkeys[i] = key; + pkey = + (u64) dd->ipath_pkeys[0] | + ((u64) dd->ipath_pkeys[1] << 16) | + ((u64) dd->ipath_pkeys[2] << 32) | + ((u64) dd->ipath_pkeys[3] << 48); + ipath_cdbg(PROC, "p%u set key %x in #%d, " + "portidx %d, new pkey reg %llx\n", + pd->port_port, key, i, pidx, + (unsigned long long) pkey); + ipath_write_kreg( + dd, dd->ipath_kregs->kr_partitionkey, pkey); + + ret = 0; + goto bail; + } + } + ipath_dbg("port %u, all pkeys already in use 2nd pass, " + "can't set %x\n", pd->port_port, key); + ret = -EBUSY; + +bail: + return ret; +} + +/** + * ipath_manage_rcvq - manage a port's receive queue + * @pd: the port + * @start_stop: action to carry out + * + * start_stop == 0 disables receive on the port, for use in queue + * overflow conditions. start_stop==1 re-enables, to be used to + * re-init the software copy of the head register + */ +static int ipath_manage_rcvq(struct ipath_portdata *pd, int start_stop) +{ + struct ipath_devdata *dd = pd->port_dd; + u64 tval; + + ipath_cdbg(PROC, "%sabling rcv for unit %u port %u\n", + start_stop ? "en" : "dis", dd->ipath_unit, + pd->port_port); + /* atomically clear receive enable port. */ + if (start_stop) { + /* + * On enable, force in-memory copy of the tail register to + * 0, so that protocol code doesn't have to worry about + * whether or not the chip has yet updated the in-memory + * copy or not on return from the system call. The chip + * always resets it's tail register back to 0 on a + * transition from disabled to enabled. This could cause a + * problem if software was broken, and did the enable w/o + * the disable, but eventually the in-memory copy will be + * updated and correct itself, even in the face of software + * bugs. + */ + *pd->port_rcvhdrtail_kvaddr = 0; + set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port, + &dd->ipath_rcvctrl); + } else + clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port, + &dd->ipath_rcvctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl); + /* now be sure chip saw it before we return */ + tval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + if (start_stop) { + /* + * And try to be sure that tail reg update has happened too. + * This should in theory interlock with the RXE changes to + * the tail register. Don't assign it to the tail register + * in memory copy, since we could overwrite an update by the + * chip if we did. + */ + tval = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port); + } + /* always; new head should be equal to new tail; see above */ + return 0; +} + +static void ipath_clean_part_key(struct ipath_portdata *pd, + struct ipath_devdata *dd) +{ + int i, j, pchanged = 0; + u64 oldpkey; + + /* for debugging only */ + oldpkey = (u64) dd->ipath_pkeys[0] | + ((u64) dd->ipath_pkeys[1] << 16) | + ((u64) dd->ipath_pkeys[2] << 32) | + ((u64) dd->ipath_pkeys[3] << 48); + + for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) { + if (!pd->port_pkeys[i]) + continue; + ipath_cdbg(VERBOSE, "look for key[%d] %hx in pkeys\n", i, + pd->port_pkeys[i]); + for (j = 0; j < ARRAY_SIZE(dd->ipath_pkeys); j++) { + /* check for match independent of the global bit */ + if ((dd->ipath_pkeys[j] & 0x7fff) != + (pd->port_pkeys[i] & 0x7fff)) + continue; + if (atomic_dec_and_test(&dd->ipath_pkeyrefs[j])) { + ipath_cdbg(VERBOSE, "p%u clear key " + "%x matches #%d\n", + pd->port_port, + pd->port_pkeys[i], j); + ipath_stats.sps_pkeys[j] = + dd->ipath_pkeys[j] = 0; + pchanged++; + } + else ipath_cdbg( + VERBOSE, "p%u key %x matches #%d, " + "but ref still %d\n", pd->port_port, + pd->port_pkeys[i], j, + atomic_read(&dd->ipath_pkeyrefs[j])); + break; + } + pd->port_pkeys[i] = 0; + } + if (pchanged) { + u64 pkey = (u64) dd->ipath_pkeys[0] | + ((u64) dd->ipath_pkeys[1] << 16) | + ((u64) dd->ipath_pkeys[2] << 32) | + ((u64) dd->ipath_pkeys[3] << 48); + ipath_cdbg(VERBOSE, "p%u old pkey reg %llx, " + "new pkey reg %llx\n", pd->port_port, + (unsigned long long) oldpkey, + (unsigned long long) pkey); + ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey, + pkey); + } +} + +/** + * ipath_create_user_egr - allocate eager TID buffers + * @pd: the port to allocate TID buffers for + * + * This routine is now quite different for user and kernel, because + * the kernel uses skb's, for the accelerated network performance + * This is the user port version + * + * Allocate the eager TID buffers and program them into infinipath + * They are no longer completely contiguous, we do multiple allocation + * calls. + */ +static int ipath_create_user_egr(struct ipath_portdata *pd) +{ + struct ipath_devdata *dd = pd->port_dd; + unsigned e, egrcnt, alloced, egrperchunk, chunk, egrsize, egroff; + size_t size; + int ret; + + egrcnt = dd->ipath_rcvegrcnt; + /* TID number offset for this port */ + egroff = pd->port_port * egrcnt; + egrsize = dd->ipath_rcvegrbufsize; + ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid " + "offset %x, egrsize %u\n", egrcnt, egroff, egrsize); + + /* + * to avoid wasting a lot of memory, we allocate 32KB chunks of + * physically contiguous memory, advance through it until used up + * and then allocate more. Of course, we need memory to store those + * extra pointers, now. Started out with 256KB, but under heavy + * memory pressure (creating large files and then copying them over + * NFS while doing lots of MPI jobs), we hit some allocation + * failures, even though we can sleep... (2.6.10) Still get + * failures at 64K. 32K is the lowest we can go without waiting + * more memory again. It seems likely that the coalescing in + * free_pages, etc. still has issues (as it has had previously + * during 2.6.x development). + */ + size = 0x8000; + alloced = ALIGN(egrsize * egrcnt, size); + egrperchunk = size / egrsize; + chunk = (egrcnt + egrperchunk - 1) / egrperchunk; + pd->port_rcvegrbuf_chunks = chunk; + pd->port_rcvegrbufs_perchunk = egrperchunk; + pd->port_rcvegrbuf_size = size; + pd->port_rcvegrbuf = vmalloc(chunk * sizeof(pd->port_rcvegrbuf[0])); + if (!pd->port_rcvegrbuf) { + ret = -ENOMEM; + goto bail; + } + pd->port_rcvegrbuf_phys = + vmalloc(chunk * sizeof(pd->port_rcvegrbuf_phys[0])); + if (!pd->port_rcvegrbuf_phys) { + ret = -ENOMEM; + goto bail_rcvegrbuf; + } + for (e = 0; e < pd->port_rcvegrbuf_chunks; e++) { + /* + * GFP_USER, but without GFP_FS, so buffer cache can be + * coalesced (we hope); otherwise, even at order 4, + * heavy filesystem activity makes these fail + */ + gfp_t gfp_flags = __GFP_WAIT | __GFP_IO | __GFP_COMP; + + pd->port_rcvegrbuf[e] = dma_alloc_coherent( + &dd->pcidev->dev, size, &pd->port_rcvegrbuf_phys[e], + gfp_flags); + + if (!pd->port_rcvegrbuf[e]) { + ret = -ENOMEM; + goto bail_rcvegrbuf_phys; + } + } + + pd->port_rcvegr_phys = pd->port_rcvegrbuf_phys[0]; + + for (e = chunk = 0; chunk < pd->port_rcvegrbuf_chunks; chunk++) { + dma_addr_t pa = pd->port_rcvegrbuf_phys[chunk]; + unsigned i; + + for (i = 0; e < egrcnt && i < egrperchunk; e++, i++) { + dd->ipath_f_put_tid(dd, e + egroff + + (u64 __iomem *) + ((char __iomem *) + dd->ipath_kregbase + + dd->ipath_rcvegrbase), 0, pa); + pa += egrsize; + } + cond_resched(); /* don't hog the cpu */ + } + + ret = 0; + goto bail; + +bail_rcvegrbuf_phys: + for (e = 0; e < pd->port_rcvegrbuf_chunks && + pd->port_rcvegrbuf[e]; e++) + dma_free_coherent(&dd->pcidev->dev, size, + pd->port_rcvegrbuf[e], + pd->port_rcvegrbuf_phys[e]); + + vfree(pd->port_rcvegrbuf_phys); + pd->port_rcvegrbuf_phys = NULL; +bail_rcvegrbuf: + vfree(pd->port_rcvegrbuf); + pd->port_rcvegrbuf = NULL; +bail: + return ret; +} + +static int ipath_do_user_init(struct ipath_portdata *pd, + const struct ipath_user_info *uinfo) +{ + int ret = 0; + struct ipath_devdata *dd = pd->port_dd; + u64 physaddr, uaddr, off, atmp; + struct page *pagep; + u32 head32; + u64 head; + + /* for now, if major version is different, bail */ + if ((uinfo->spu_userversion >> 16) != IPATH_USER_SWMAJOR) { + dev_info(&dd->pcidev->dev, + "User major version %d not same as driver " + "major %d\n", uinfo->spu_userversion >> 16, + IPATH_USER_SWMAJOR); + ret = -ENODEV; + goto done; + } + + if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR) + ipath_dbg("User minor version %d not same as driver " + "minor %d\n", uinfo->spu_userversion & 0xffff, + IPATH_USER_SWMINOR); + + if (uinfo->spu_rcvhdrsize) { + ret = ipath_setrcvhdrsize(dd, uinfo->spu_rcvhdrsize); + if (ret) + goto done; + } + + /* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */ + + /* set up for the rcvhdr Q tail register writeback to user memory */ + if (!uinfo->spu_rcvhdraddr || + !access_ok(VERIFY_WRITE, (u64 __user *) (unsigned long) + uinfo->spu_rcvhdraddr, sizeof(u64))) { + ipath_dbg("Port %d rcvhdrtail addr %llx not valid\n", + pd->port_port, + (unsigned long long) uinfo->spu_rcvhdraddr); + ret = -EINVAL; + goto done; + } + + off = offset_in_page(uinfo->spu_rcvhdraddr); + uaddr = PAGE_MASK & (unsigned long) uinfo->spu_rcvhdraddr; + ret = ipath_get_user_pages_nocopy(uaddr, &pagep); + if (ret) { + dev_info(&dd->pcidev->dev, "Failed to lookup and lock " + "address %llx for rcvhdrtail: errno %d\n", + (unsigned long long) uinfo->spu_rcvhdraddr, -ret); + goto done; + } + ipath_stats.sps_pagelocks++; + pd->port_rcvhdrtail_uaddr = uaddr; + pd->port_rcvhdrtail_pagep = pagep; + pd->port_rcvhdrtail_kvaddr = + page_address(pagep); + pd->port_rcvhdrtail_kvaddr += off; + physaddr = page_to_phys(pagep) + off; + ipath_cdbg(VERBOSE, "port %d user addr %llx hdrtailaddr, %llx " + "physical (off=%llx)\n", + pd->port_port, + (unsigned long long) uinfo->spu_rcvhdraddr, + (unsigned long long) physaddr, (unsigned long long) off); + ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdrtailaddr, + pd->port_port, physaddr); + atmp = ipath_read_kreg64_port(dd, + dd->ipath_kregs->kr_rcvhdrtailaddr, + pd->port_port); + if (physaddr != atmp) { + ipath_dev_err(dd, + "Catastrophic software error, " + "RcvHdrTailAddr%u written as %llx, " + "read back as %llx\n", pd->port_port, + (unsigned long long) physaddr, + (unsigned long long) atmp); + ret = -EINVAL; + goto done; + } + + /* for right now, kernel piobufs are at end, so port 1 is at 0 */ + pd->port_piobufs = dd->ipath_piobufbase + + dd->ipath_pbufsport * (pd->port_port - + 1) * dd->ipath_palign; + ipath_cdbg(VERBOSE, "Set base of piobufs for port %u to 0x%x\n", + pd->port_port, pd->port_piobufs); + + /* + * Now allocate the rcvhdr Q and eager TIDs; skip the TID + * array for time being. If pd->port_port > chip-supported, + * we need to do extra stuff here to handle by handling overflow + * through port 0, someday + */ + ret = ipath_create_rcvhdrq(dd, pd); + if (!ret) + ret = ipath_create_user_egr(pd); + if (ret) + goto done; + /* enable receives now */ + /* atomically set enable bit for this port */ + set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port, + &dd->ipath_rcvctrl); + + /* + * set the head registers for this port to the current values + * of the tail pointers, since we don't know if they were + * updated on last use of the port. + */ + head32 = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port); + head = (u64) head32; + ipath_write_ureg(dd, ur_rcvhdrhead, head, pd->port_port); + head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port); + ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port); + dd->ipath_lastegrheads[pd->port_port] = -1; + dd->ipath_lastrcvhdrqtails[pd->port_port] = -1; + ipath_cdbg(VERBOSE, "Wrote port%d head %llx, egrhead %x from " + "tail regs\n", pd->port_port, + (unsigned long long) head, head32); + pd->port_tidcursor = 0; /* start at beginning after open */ + /* + * now enable the port; the tail registers will be written to memory + * by the chip as soon as it sees the write to + * dd->ipath_kregs->kr_rcvctrl. The update only happens on + * transition from 0 to 1, so clear it first, then set it as part of + * enabling the port. This will (very briefly) affect any other + * open ports, but it shouldn't be long enough to be an issue. + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD); + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl); + +done: + return ret; +} + +static int mmap_ureg(struct vm_area_struct *vma, struct ipath_devdata *dd, + u64 ureg) +{ + unsigned long phys; + int ret; + + /* it's the real hardware, so io_remap works */ + + if ((vma->vm_end - vma->vm_start) > PAGE_SIZE) { + dev_info(&dd->pcidev->dev, "FAIL mmap userreg: reqlen " + "%lx > PAGE\n", vma->vm_end - vma->vm_start); + ret = -EFAULT; + } else { + phys = dd->ipath_physaddr + ureg; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND; + ret = io_remap_pfn_range(vma, vma->vm_start, + phys >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); + } + return ret; +} + +static int mmap_piobufs(struct vm_area_struct *vma, + struct ipath_devdata *dd, + struct ipath_portdata *pd) +{ + unsigned long phys; + int ret; + + /* + * When we map the PIO buffers, we want to map them as writeonly, no + * read possible. + */ + + if ((vma->vm_end - vma->vm_start) > + (dd->ipath_pbufsport * dd->ipath_palign)) { + dev_info(&dd->pcidev->dev, "FAIL mmap piobufs: " + "reqlen %lx > PAGE\n", + vma->vm_end - vma->vm_start); + ret = -EFAULT; + goto bail; + } + + phys = dd->ipath_physaddr + pd->port_piobufs; + /* + * Do *NOT* mark this as non-cached (PWT bit), or we don't get the + * write combining behavior we want on the PIO buffers! + * vma->vm_page_prot = + * pgprot_noncached(vma->vm_page_prot); + */ + + if (vma->vm_flags & VM_READ) { + dev_info(&dd->pcidev->dev, + "Can't map piobufs as readable (flags=%lx)\n", + vma->vm_flags); + ret = -EPERM; + goto bail; + } + + /* don't allow them to later change to readable with mprotect */ + + vma->vm_flags &= ~VM_MAYWRITE; + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND; + + ret = io_remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +bail: + return ret; +} + +static int mmap_rcvegrbufs(struct vm_area_struct *vma, + struct ipath_portdata *pd) +{ + struct ipath_devdata *dd = pd->port_dd; + unsigned long start, size; + size_t total_size, i; + dma_addr_t *phys; + int ret; + + if (!pd->port_rcvegrbuf) { + ret = -EFAULT; + goto bail; + } + + size = pd->port_rcvegrbuf_size; + total_size = pd->port_rcvegrbuf_chunks * size; + if ((vma->vm_end - vma->vm_start) > total_size) { + dev_info(&dd->pcidev->dev, "FAIL on egr bufs: " + "reqlen %lx > actual %lx\n", + vma->vm_end - vma->vm_start, + (unsigned long) total_size); + ret = -EFAULT; + goto bail; + } + + if (vma->vm_flags & VM_WRITE) { + dev_info(&dd->pcidev->dev, "Can't map eager buffers as " + "writable (flags=%lx)\n", vma->vm_flags); + ret = -EPERM; + goto bail; + } + + start = vma->vm_start; + phys = pd->port_rcvegrbuf_phys; + + /* don't allow them to later change to writeable with mprotect */ + vma->vm_flags &= ~VM_MAYWRITE; + + for (i = 0; i < pd->port_rcvegrbuf_chunks; i++, start += size) { + ret = remap_pfn_range(vma, start, phys[i] >> PAGE_SHIFT, + size, vma->vm_page_prot); + if (ret < 0) + goto bail; + } + ret = 0; + +bail: + return ret; +} + +static int mmap_rcvhdrq(struct vm_area_struct *vma, + struct ipath_portdata *pd) +{ + struct ipath_devdata *dd = pd->port_dd; + size_t total_size; + int ret; + + /* + * kmalloc'ed memory, physically contiguous; this is from + * spi_rcvhdr_base; we allow user to map read-write so they can + * write hdrq entries to allow protocol code to directly poll + * whether a hdrq entry has been written. + */ + total_size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize * + sizeof(u32), PAGE_SIZE); + if ((vma->vm_end - vma->vm_start) > total_size) { + dev_info(&dd->pcidev->dev, + "FAIL on rcvhdrq: reqlen %lx > actual %lx\n", + vma->vm_end - vma->vm_start, + (unsigned long) total_size); + ret = -EFAULT; + goto bail; + } + + ret = remap_pfn_range(vma, vma->vm_start, + pd->port_rcvhdrq_phys >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +bail: + return ret; +} + +static int mmap_pioavailregs(struct vm_area_struct *vma, + struct ipath_portdata *pd) +{ + struct ipath_devdata *dd = pd->port_dd; + int ret; + + /* + * when we map the PIO bufferavail registers, we want to map them as + * readonly, no write possible. + * + * kmalloc'ed memory, physically contiguous, one page only, readonly + */ + + if ((vma->vm_end - vma->vm_start) > PAGE_SIZE) { + dev_info(&dd->pcidev->dev, "FAIL on pioavailregs_dma: " + "reqlen %lx > actual %lx\n", + vma->vm_end - vma->vm_start, + (unsigned long) PAGE_SIZE); + ret = -EFAULT; + goto bail; + } + + if (vma->vm_flags & VM_WRITE) { + dev_info(&dd->pcidev->dev, + "Can't map pioavailregs as writable (flags=%lx)\n", + vma->vm_flags); + ret = -EPERM; + goto bail; + } + + /* don't allow them to later change with mprotect */ + vma->vm_flags &= ~VM_MAYWRITE; + + ret = remap_pfn_range(vma, vma->vm_start, + dd->ipath_pioavailregs_phys >> PAGE_SHIFT, + PAGE_SIZE, vma->vm_page_prot); +bail: + return ret; +} + +/** + * ipath_mmap - mmap various structures into user space + * @fp: the file pointer + * @vma: the VM area + * + * We use this to have a shared buffer between the kernel and the user code + * for the rcvhdr queue, egr buffers, and the per-port user regs and pio + * buffers in the chip. We have the open and close entries so we can bump + * the ref count and keep the driver from being unloaded while still mapped. + */ +static int ipath_mmap(struct file *fp, struct vm_area_struct *vma) +{ + struct ipath_portdata *pd; + struct ipath_devdata *dd; + u64 pgaddr, ureg; + int ret; + + pd = port_fp(fp); + dd = pd->port_dd; + /* + * This is the ipath_do_user_init() code, mapping the shared buffers + * into the user process. The address referred to by vm_pgoff is the + * virtual, not physical, address; we only do one mmap for each + * space mapped. + */ + pgaddr = vma->vm_pgoff << PAGE_SHIFT; + + /* + * note that ureg does *NOT* have the kregvirt as part of it, to be + * sure that for 32 bit programs, we don't end up trying to map a > + * 44 address. Has to match ipath_get_base_info() code that sets + * __spi_uregbase + */ + + ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port; + + ipath_cdbg(MM, "ushare: pgaddr %llx vm_start=%lx, vmlen %lx\n", + (unsigned long long) pgaddr, vma->vm_start, + vma->vm_end - vma->vm_start); + + if (pgaddr == ureg) + ret = mmap_ureg(vma, dd, ureg); + else if (pgaddr == pd->port_piobufs) + ret = mmap_piobufs(vma, dd, pd); + else if (pgaddr == (u64) pd->port_rcvegr_phys) + ret = mmap_rcvegrbufs(vma, pd); + else if (pgaddr == (u64) pd->port_rcvhdrq_phys) + ret = mmap_rcvhdrq(vma, pd); + else if (pgaddr == dd->ipath_pioavailregs_phys) + ret = mmap_pioavailregs(vma, pd); + else + ret = -EINVAL; + + vma->vm_private_data = NULL; + + if (ret < 0) + dev_info(&dd->pcidev->dev, + "Failure %d on addr %lx, off %lx\n", + -ret, vma->vm_start, vma->vm_pgoff); + + return ret; +} + +static unsigned int ipath_poll(struct file *fp, + struct poll_table_struct *pt) +{ + struct ipath_portdata *pd; + u32 head, tail; + int bit; + struct ipath_devdata *dd; + + pd = port_fp(fp); + dd = pd->port_dd; + + bit = pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT; + set_bit(bit, &dd->ipath_rcvctrl); + + /* + * Before blocking, make sure that head is still == tail, + * reading from the chip, so we can be sure the interrupt + * enable has made it to the chip. If not equal, disable + * interrupt again and return immediately. This avoids races, + * and the overhead of the chip read doesn't matter much at + * this point, since we are waiting for something anyway. + */ + + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl); + + head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port); + tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port); + + if (tail == head) { + set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); + poll_wait(fp, &pd->port_wait, pt); + + if (test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) { + /* timed out, no packets received */ + clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); + pd->port_rcvwait_to++; + } + } + else { + /* it's already happened; don't do wait_event overhead */ + pd->port_rcvnowait++; + } + + clear_bit(bit, &dd->ipath_rcvctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl); + + return 0; +} + +static int try_alloc_port(struct ipath_devdata *dd, int port, + struct file *fp) +{ + int ret; + + if (!dd->ipath_pd[port]) { + void *p, *ptmp; + + p = kzalloc(sizeof(struct ipath_portdata), GFP_KERNEL); + + /* + * Allocate memory for use in ipath_tid_update() just once + * at open, not per call. Reduces cost of expected send + * setup. + */ + ptmp = kmalloc(dd->ipath_rcvtidcnt * sizeof(u16) + + dd->ipath_rcvtidcnt * sizeof(struct page **), + GFP_KERNEL); + if (!p || !ptmp) { + ipath_dev_err(dd, "Unable to allocate portdata " + "memory, failing open\n"); + ret = -ENOMEM; + kfree(p); + kfree(ptmp); + goto bail; + } + dd->ipath_pd[port] = p; + dd->ipath_pd[port]->port_port = port; + dd->ipath_pd[port]->port_dd = dd; + dd->ipath_pd[port]->port_tid_pg_list = ptmp; + init_waitqueue_head(&dd->ipath_pd[port]->port_wait); + } + if (!dd->ipath_pd[port]->port_cnt) { + dd->ipath_pd[port]->port_cnt = 1; + fp->private_data = (void *) dd->ipath_pd[port]; + ipath_cdbg(PROC, "%s[%u] opened unit:port %u:%u\n", + current->comm, current->pid, dd->ipath_unit, + port); + dd->ipath_pd[port]->port_pid = current->pid; + strncpy(dd->ipath_pd[port]->port_comm, current->comm, + sizeof(dd->ipath_pd[port]->port_comm)); + ipath_stats.sps_ports++; + ret = 0; + goto bail; + } + ret = -EBUSY; + +bail: + return ret; +} + +static inline int usable(struct ipath_devdata *dd) +{ + return dd && + (dd->ipath_flags & IPATH_PRESENT) && + dd->ipath_kregbase && + dd->ipath_lid && + !(dd->ipath_flags & (IPATH_LINKDOWN | IPATH_DISABLED + | IPATH_LINKUNK)); +} + +static int find_free_port(int unit, struct file *fp) +{ + struct ipath_devdata *dd = ipath_lookup(unit); + int ret, i; + + if (!dd) { + ret = -ENODEV; + goto bail; + } + + if (!usable(dd)) { + ret = -ENETDOWN; + goto bail; + } + + for (i = 0; i < dd->ipath_cfgports; i++) { + ret = try_alloc_port(dd, i, fp); + if (ret != -EBUSY) + goto bail; + } + ret = -EBUSY; + +bail: + return ret; +} + +static int find_best_unit(struct file *fp) +{ + int ret = 0, i, prefunit = -1, devmax; + int maxofallports, npresent, nup; + int ndev; + + (void) ipath_count_units(&npresent, &nup, &maxofallports); + + /* + * This code is present to allow a knowledgeable person to + * specify the layout of processes to processors before opening + * this driver, and then we'll assign the process to the "closest" + * HT-400 to that processor (we assume reasonable connectivity, + * for now). This code assumes that if affinity has been set + * before this point, that at most one cpu is set; for now this + * is reasonable. I check for both cpus_empty() and cpus_full(), + * in case some kernel variant sets none of the bits when no + * affinity is set. 2.6.11 and 12 kernels have all present + * cpus set. Some day we'll have to fix it up further to handle + * a cpu subset. This algorithm fails for two HT-400's connected + * in tunnel fashion. Eventually this needs real topology + * information. There may be some issues with dual core numbering + * as well. This needs more work prior to release. + */ + if (!cpus_empty(current->cpus_allowed) && + !cpus_full(current->cpus_allowed)) { + int ncpus = num_online_cpus(), curcpu = -1; + for (i = 0; i < ncpus; i++) + if (cpu_isset(i, current->cpus_allowed)) { + ipath_cdbg(PROC, "%s[%u] affinity set for " + "cpu %d\n", current->comm, + current->pid, i); + curcpu = i; + } + if (curcpu != -1) { + if (npresent) { + prefunit = curcpu / (ncpus / npresent); + ipath_dbg("%s[%u] %d chips, %d cpus, " + "%d cpus/chip, select unit %d\n", + current->comm, current->pid, + npresent, ncpus, ncpus / npresent, + prefunit); + } + } + } + + /* + * user ports start at 1, kernel port is 0 + * For now, we do round-robin access across all chips + */ + + if (prefunit != -1) + devmax = prefunit + 1; + else + devmax = ipath_count_units(NULL, NULL, NULL); +recheck: + for (i = 1; i < maxofallports; i++) { + for (ndev = prefunit != -1 ? prefunit : 0; ndev < devmax; + ndev++) { + struct ipath_devdata *dd = ipath_lookup(ndev); + + if (!usable(dd)) + continue; /* can't use this unit */ + if (i >= dd->ipath_cfgports) + /* + * Maxed out on users of this unit. Try + * next. + */ + continue; + ret = try_alloc_port(dd, i, fp); + if (!ret) + goto done; + } + } + + if (npresent) { + if (nup == 0) { + ret = -ENETDOWN; + ipath_dbg("No ports available (none initialized " + "and ready)\n"); + } else { + if (prefunit > 0) { + /* if started above 0, retry from 0 */ + ipath_cdbg(PROC, + "%s[%u] no ports on prefunit " + "%d, clear and re-check\n", + current->comm, current->pid, + prefunit); + devmax = ipath_count_units(NULL, NULL, + NULL); + prefunit = -1; + goto recheck; + } + ret = -EBUSY; + ipath_dbg("No ports available\n"); + } + } else { + ret = -ENXIO; + ipath_dbg("No boards found\n"); + } + +done: + return ret; +} + +static int ipath_open(struct inode *in, struct file *fp) +{ + int ret, minor; + + mutex_lock(&ipath_mutex); + + minor = iminor(in); + ipath_cdbg(VERBOSE, "open on dev %lx (minor %d)\n", + (long)in->i_rdev, minor); + + if (minor) + ret = find_free_port(minor - 1, fp); + else + ret = find_best_unit(fp); + + mutex_unlock(&ipath_mutex); + return ret; +} + +/** + * unlock_exptid - unlock any expected TID entries port still had in use + * @pd: port + * + * We don't actually update the chip here, because we do a bulk update + * below, using ipath_f_clear_tids. + */ +static void unlock_expected_tids(struct ipath_portdata *pd) +{ + struct ipath_devdata *dd = pd->port_dd; + int port_tidbase = pd->port_port * dd->ipath_rcvtidcnt; + int i, cnt = 0, maxtid = port_tidbase + dd->ipath_rcvtidcnt; + + ipath_cdbg(VERBOSE, "Port %u unlocking any locked expTID pages\n", + pd->port_port); + for (i = port_tidbase; i < maxtid; i++) { + if (!dd->ipath_pageshadow[i]) + continue; + + ipath_release_user_pages_on_close(&dd->ipath_pageshadow[i], + 1); + dd->ipath_pageshadow[i] = NULL; + cnt++; + ipath_stats.sps_pageunlocks++; + } + if (cnt) + ipath_cdbg(VERBOSE, "Port %u locked %u expTID entries\n", + pd->port_port, cnt); + + if (ipath_stats.sps_pagelocks || ipath_stats.sps_pageunlocks) + ipath_cdbg(VERBOSE, "%llu pages locked, %llu unlocked\n", + (unsigned long long) ipath_stats.sps_pagelocks, + (unsigned long long) + ipath_stats.sps_pageunlocks); +} + +static int ipath_close(struct inode *in, struct file *fp) +{ + int ret = 0; + struct ipath_portdata *pd; + struct ipath_devdata *dd; + unsigned port; + + ipath_cdbg(VERBOSE, "close on dev %lx, private data %p\n", + (long)in->i_rdev, fp->private_data); + + mutex_lock(&ipath_mutex); + + pd = port_fp(fp); + port = pd->port_port; + fp->private_data = NULL; + dd = pd->port_dd; + + if (pd->port_hdrqfull) { + ipath_cdbg(PROC, "%s[%u] had %u rcvhdrqfull errors " + "during run\n", pd->port_comm, pd->port_pid, + pd->port_hdrqfull); + pd->port_hdrqfull = 0; + } + + if (pd->port_rcvwait_to || pd->port_piowait_to + || pd->port_rcvnowait || pd->port_pionowait) { + ipath_cdbg(VERBOSE, "port%u, %u rcv, %u pio wait timeo; " + "%u rcv %u, pio already\n", + pd->port_port, pd->port_rcvwait_to, + pd->port_piowait_to, pd->port_rcvnowait, + pd->port_pionowait); + pd->port_rcvwait_to = pd->port_piowait_to = + pd->port_rcvnowait = pd->port_pionowait = 0; + } + if (pd->port_flag) { + ipath_dbg("port %u port_flag still set to 0x%lx\n", + pd->port_port, pd->port_flag); + pd->port_flag = 0; + } + + if (dd->ipath_kregbase) { + if (pd->port_rcvhdrtail_uaddr) { + pd->port_rcvhdrtail_uaddr = 0; + pd->port_rcvhdrtail_kvaddr = NULL; + ipath_release_user_pages_on_close( + &pd->port_rcvhdrtail_pagep, 1); + pd->port_rcvhdrtail_pagep = NULL; + ipath_stats.sps_pageunlocks++; + } + ipath_write_kreg_port( + dd, dd->ipath_kregs->kr_rcvhdrtailaddr, + port, 0ULL); + ipath_write_kreg_port( + dd, dd->ipath_kregs->kr_rcvhdraddr, + pd->port_port, 0); + + /* clean up the pkeys for this port user */ + ipath_clean_part_key(pd, dd); + + if (port < dd->ipath_cfgports) { + int i = dd->ipath_pbufsport * (port - 1); + ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport); + + /* atomically clear receive enable port. */ + clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port, + &dd->ipath_rcvctrl); + ipath_write_kreg( + dd, + dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl); + + if (dd->ipath_pageshadow) + unlock_expected_tids(pd); + ipath_stats.sps_ports--; + ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n", + pd->port_comm, pd->port_pid, + dd->ipath_unit, port); + } + } + + pd->port_cnt = 0; + pd->port_pid = 0; + + dd->ipath_f_clear_tids(dd, pd->port_port); + + ipath_free_pddata(dd, pd->port_port, 0); + + mutex_unlock(&ipath_mutex); + + return ret; +} + +static int ipath_port_info(struct ipath_portdata *pd, + struct ipath_port_info __user *uinfo) +{ + struct ipath_port_info info; + int nup; + int ret; + + (void) ipath_count_units(NULL, &nup, NULL); + info.num_active = nup; + info.unit = pd->port_dd->ipath_unit; + info.port = pd->port_port; + + if (copy_to_user(uinfo, &info, sizeof(info))) { + ret = -EFAULT; + goto bail; + } + ret = 0; + +bail: + return ret; +} + +static ssize_t ipath_write(struct file *fp, const char __user *data, + size_t count, loff_t *off) +{ + const struct ipath_cmd __user *ucmd; + struct ipath_portdata *pd; + const void __user *src; + size_t consumed, copy; + struct ipath_cmd cmd; + ssize_t ret = 0; + void *dest; + + if (count < sizeof(cmd.type)) { + ret = -EINVAL; + goto bail; + } + + ucmd = (const struct ipath_cmd __user *) data; + + if (copy_from_user(&cmd.type, &ucmd->type, sizeof(cmd.type))) { + ret = -EFAULT; + goto bail; + } + + consumed = sizeof(cmd.type); + + switch (cmd.type) { + case IPATH_CMD_USER_INIT: + copy = sizeof(cmd.cmd.user_info); + dest = &cmd.cmd.user_info; + src = &ucmd->cmd.user_info; + break; + case IPATH_CMD_RECV_CTRL: + copy = sizeof(cmd.cmd.recv_ctrl); + dest = &cmd.cmd.recv_ctrl; + src = &ucmd->cmd.recv_ctrl; + break; + case IPATH_CMD_PORT_INFO: + copy = sizeof(cmd.cmd.port_info); + dest = &cmd.cmd.port_info; + src = &ucmd->cmd.port_info; + break; + case IPATH_CMD_TID_UPDATE: + case IPATH_CMD_TID_FREE: + copy = sizeof(cmd.cmd.tid_info); + dest = &cmd.cmd.tid_info; + src = &ucmd->cmd.tid_info; + break; + case IPATH_CMD_SET_PART_KEY: + copy = sizeof(cmd.cmd.part_key); + dest = &cmd.cmd.part_key; + src = &ucmd->cmd.part_key; + break; + default: + ret = -EINVAL; + goto bail; + } + + if ((count - consumed) < copy) { + ret = -EINVAL; + goto bail; + } + + if (copy_from_user(dest, src, copy)) { + ret = -EFAULT; + goto bail; + } + + consumed += copy; + pd = port_fp(fp); + + switch (cmd.type) { + case IPATH_CMD_USER_INIT: + ret = ipath_do_user_init(pd, &cmd.cmd.user_info); + if (ret < 0) + goto bail; + ret = ipath_get_base_info( + pd, (void __user *) (unsigned long) + cmd.cmd.user_info.spu_base_info, + cmd.cmd.user_info.spu_base_info_size); + break; + case IPATH_CMD_RECV_CTRL: + ret = ipath_manage_rcvq(pd, cmd.cmd.recv_ctrl); + break; + case IPATH_CMD_PORT_INFO: + ret = ipath_port_info(pd, + (struct ipath_port_info __user *) + (unsigned long) cmd.cmd.port_info); + break; + case IPATH_CMD_TID_UPDATE: + ret = ipath_tid_update(pd, &cmd.cmd.tid_info); + break; + case IPATH_CMD_TID_FREE: + ret = ipath_tid_free(pd, &cmd.cmd.tid_info); + break; + case IPATH_CMD_SET_PART_KEY: + ret = ipath_set_part_key(pd, cmd.cmd.part_key); + break; + } + + if (ret >= 0) + ret = consumed; + +bail: + return ret; +} + +static struct class *ipath_class; + +static int init_cdev(int minor, char *name, struct file_operations *fops, + struct cdev **cdevp, struct class_device **class_devp) +{ + const dev_t dev = MKDEV(IPATH_MAJOR, minor); + struct cdev *cdev = NULL; + struct class_device *class_dev = NULL; + int ret; + + cdev = cdev_alloc(); + if (!cdev) { + printk(KERN_ERR IPATH_DRV_NAME + ": Could not allocate cdev for minor %d, %s\n", + minor, name); + ret = -ENOMEM; + goto done; + } + + cdev->owner = THIS_MODULE; + cdev->ops = fops; + kobject_set_name(&cdev->kobj, name); + + ret = cdev_add(cdev, dev, 1); + if (ret < 0) { + printk(KERN_ERR IPATH_DRV_NAME + ": Could not add cdev for minor %d, %s (err %d)\n", + minor, name, -ret); + goto err_cdev; + } + + class_dev = class_device_create(ipath_class, NULL, dev, NULL, name); + + if (IS_ERR(class_dev)) { + ret = PTR_ERR(class_dev); + printk(KERN_ERR IPATH_DRV_NAME ": Could not create " + "class_dev for minor %d, %s (err %d)\n", + minor, name, -ret); + goto err_cdev; + } + + goto done; + +err_cdev: + cdev_del(cdev); + cdev = NULL; + +done: + if (ret >= 0) { + *cdevp = cdev; + *class_devp = class_dev; + } else { + *cdevp = NULL; + *class_devp = NULL; + } + + return ret; +} + +int ipath_cdev_init(int minor, char *name, struct file_operations *fops, + struct cdev **cdevp, struct class_device **class_devp) +{ + return init_cdev(minor, name, fops, cdevp, class_devp); +} + +static void cleanup_cdev(struct cdev **cdevp, + struct class_device **class_devp) +{ + struct class_device *class_dev = *class_devp; + + if (class_dev) { + class_device_unregister(class_dev); + *class_devp = NULL; + } + + if (*cdevp) { + cdev_del(*cdevp); + *cdevp = NULL; + } +} + +void ipath_cdev_cleanup(struct cdev **cdevp, + struct class_device **class_devp) +{ + cleanup_cdev(cdevp, class_devp); +} + +static struct cdev *wildcard_cdev; +static struct class_device *wildcard_class_dev; + +static const dev_t dev = MKDEV(IPATH_MAJOR, 0); + +static int user_init(void) +{ + int ret; + + ret = register_chrdev_region(dev, IPATH_NMINORS, IPATH_DRV_NAME); + if (ret < 0) { + printk(KERN_ERR IPATH_DRV_NAME ": Could not register " + "chrdev region (err %d)\n", -ret); + goto done; + } + + ipath_class = class_create(THIS_MODULE, IPATH_DRV_NAME); + + if (IS_ERR(ipath_class)) { + ret = PTR_ERR(ipath_class); + printk(KERN_ERR IPATH_DRV_NAME ": Could not create " + "device class (err %d)\n", -ret); + goto bail; + } + + goto done; +bail: + unregister_chrdev_region(dev, IPATH_NMINORS); +done: + return ret; +} + +static void user_cleanup(void) +{ + if (ipath_class) { + class_destroy(ipath_class); + ipath_class = NULL; + } + + unregister_chrdev_region(dev, IPATH_NMINORS); +} + +static atomic_t user_count = ATOMIC_INIT(0); +static atomic_t user_setup = ATOMIC_INIT(0); + +int ipath_user_add(struct ipath_devdata *dd) +{ + char name[10]; + int ret; + + if (atomic_inc_return(&user_count) == 1) { + ret = user_init(); + if (ret < 0) { + ipath_dev_err(dd, "Unable to set up user support: " + "error %d\n", -ret); + goto bail; + } + ret = ipath_diag_init(); + if (ret < 0) { + ipath_dev_err(dd, "Unable to set up diag support: " + "error %d\n", -ret); + goto bail_sma; + } + + ret = init_cdev(0, "ipath", &ipath_file_ops, &wildcard_cdev, + &wildcard_class_dev); + if (ret < 0) { + ipath_dev_err(dd, "Could not create wildcard " + "minor: error %d\n", -ret); + goto bail_diag; + } + + atomic_set(&user_setup, 1); + } + + snprintf(name, sizeof(name), "ipath%d", dd->ipath_unit); + + ret = init_cdev(dd->ipath_unit + 1, name, &ipath_file_ops, + &dd->cdev, &dd->class_dev); + if (ret < 0) + ipath_dev_err(dd, "Could not create user minor %d, %s\n", + dd->ipath_unit + 1, name); + + goto bail; + +bail_diag: + ipath_diag_cleanup(); +bail_sma: + user_cleanup(); +bail: + return ret; +} + +void ipath_user_del(struct ipath_devdata *dd) +{ + cleanup_cdev(&dd->cdev, &dd->class_dev); + + if (atomic_dec_return(&user_count) == 0) { + if (atomic_read(&user_setup) == 0) + goto bail; + + cleanup_cdev(&wildcard_cdev, &wildcard_class_dev); + ipath_diag_cleanup(); + user_cleanup(); + + atomic_set(&user_setup, 0); + } +bail: + return; +} diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c new file mode 100644 index 000000000000..e274120567e1 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ipath_kernel.h" + +#define IPATHFS_MAGIC 0x726a77 + +static struct super_block *ipath_super; + +static int ipathfs_mknod(struct inode *dir, struct dentry *dentry, + int mode, struct file_operations *fops, + void *data) +{ + int error; + struct inode *inode = new_inode(dir->i_sb); + + if (!inode) { + error = -EPERM; + goto bail; + } + + inode->i_mode = mode; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->u.generic_ip = data; + if ((mode & S_IFMT) == S_IFDIR) { + inode->i_op = &simple_dir_inode_operations; + inode->i_nlink++; + dir->i_nlink++; + } + + inode->i_fop = fops; + + d_instantiate(dentry, inode); + error = 0; + +bail: + return error; +} + +static int create_file(const char *name, mode_t mode, + struct dentry *parent, struct dentry **dentry, + struct file_operations *fops, void *data) +{ + int error; + + *dentry = NULL; + mutex_lock(&parent->d_inode->i_mutex); + *dentry = lookup_one_len(name, parent, strlen(name)); + if (!IS_ERR(dentry)) + error = ipathfs_mknod(parent->d_inode, *dentry, + mode, fops, data); + else + error = PTR_ERR(dentry); + mutex_unlock(&parent->d_inode->i_mutex); + + return error; +} + +static ssize_t atomic_stats_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return simple_read_from_buffer(buf, count, ppos, &ipath_stats, + sizeof ipath_stats); +} + +static struct file_operations atomic_stats_ops = { + .read = atomic_stats_read, +}; + +#define NUM_COUNTERS sizeof(struct infinipath_counters) / sizeof(u64) + +static ssize_t atomic_counters_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + u64 counters[NUM_COUNTERS]; + u16 i; + struct ipath_devdata *dd; + + dd = file->f_dentry->d_inode->u.generic_ip; + + for (i = 0; i < NUM_COUNTERS; i++) + counters[i] = ipath_snap_cntr(dd, i); + + return simple_read_from_buffer(buf, count, ppos, counters, + sizeof counters); +} + +static struct file_operations atomic_counters_ops = { + .read = atomic_counters_read, +}; + +static ssize_t atomic_node_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + u32 nodeinfo[10]; + struct ipath_devdata *dd; + u64 guid; + + dd = file->f_dentry->d_inode->u.generic_ip; + + guid = be64_to_cpu(dd->ipath_guid); + + nodeinfo[0] = /* BaseVersion is SMA */ + /* ClassVersion is SMA */ + (1 << 8) /* NodeType */ + | (1 << 0); /* NumPorts */ + nodeinfo[1] = (u32) (guid >> 32); + nodeinfo[2] = (u32) (guid & 0xffffffff); + /* PortGUID == SystemImageGUID for us */ + nodeinfo[3] = nodeinfo[1]; + /* PortGUID == SystemImageGUID for us */ + nodeinfo[4] = nodeinfo[2]; + /* PortGUID == NodeGUID for us */ + nodeinfo[5] = nodeinfo[3]; + /* PortGUID == NodeGUID for us */ + nodeinfo[6] = nodeinfo[4]; + nodeinfo[7] = (4 << 16) /* we support 4 pkeys */ + | (dd->ipath_deviceid << 0); + /* our chip version as 16 bits major, 16 bits minor */ + nodeinfo[8] = dd->ipath_minrev | (dd->ipath_majrev << 16); + nodeinfo[9] = (dd->ipath_unit << 24) | (dd->ipath_vendorid << 0); + + return simple_read_from_buffer(buf, count, ppos, nodeinfo, + sizeof nodeinfo); +} + +static struct file_operations atomic_node_info_ops = { + .read = atomic_node_info_read, +}; + +static ssize_t atomic_port_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + u32 portinfo[13]; + u32 tmp, tmp2; + struct ipath_devdata *dd; + + dd = file->f_dentry->d_inode->u.generic_ip; + + /* so we only initialize non-zero fields. */ + memset(portinfo, 0, sizeof portinfo); + + /* + * Notimpl yet M_Key (64) + * Notimpl yet GID (64) + */ + + portinfo[4] = (dd->ipath_lid << 16); + + /* + * Notimpl yet SMLID (should we store this in the driver, in case + * SMA dies?) CapabilityMask is 0, we don't support any of these + * DiagCode is 0; we don't store any diag info for now Notimpl yet + * M_KeyLeasePeriod (we don't support M_Key) + */ + + /* LocalPortNum is whichever port number they ask for */ + portinfo[7] = (dd->ipath_unit << 24) + /* LinkWidthEnabled */ + | (2 << 16) + /* LinkWidthSupported (really 2, but not IB valid) */ + | (3 << 8) + /* LinkWidthActive */ + | (2 << 0); + tmp = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK; + tmp2 = 5; + if (tmp == IPATH_IBSTATE_INIT) + tmp = 2; + else if (tmp == IPATH_IBSTATE_ARM) + tmp = 3; + else if (tmp == IPATH_IBSTATE_ACTIVE) + tmp = 4; + else { + tmp = 0; /* down */ + tmp2 = tmp & 0xf; + } + + portinfo[8] = (1 << 28) /* LinkSpeedSupported */ + | (tmp << 24) /* PortState */ + | (tmp2 << 20) /* PortPhysicalState */ + | (2 << 16) + + /* LinkDownDefaultState */ + /* M_KeyProtectBits == 0 */ + /* NotImpl yet LMC == 0 (we can support all values) */ + | (1 << 4) /* LinkSpeedActive */ + | (1 << 0); /* LinkSpeedEnabled */ + switch (dd->ipath_ibmtu) { + case 4096: + tmp = 5; + break; + case 2048: + tmp = 4; + break; + case 1024: + tmp = 3; + break; + case 512: + tmp = 2; + break; + case 256: + tmp = 1; + break; + default: /* oops, something is wrong */ + ipath_dbg("Problem, ipath_ibmtu 0x%x not a valid IB MTU, " + "treat as 2048\n", dd->ipath_ibmtu); + tmp = 4; + break; + } + portinfo[9] = (tmp << 28) + /* NeighborMTU */ + /* Notimpl MasterSMSL */ + | (1 << 20) + + /* VLCap */ + /* Notimpl InitType (actually, an SMA decision) */ + /* VLHighLimit is 0 (only one VL) */ + ; /* VLArbitrationHighCap is 0 (only one VL) */ + portinfo[10] = /* VLArbitrationLowCap is 0 (only one VL) */ + /* InitTypeReply is SMA decision */ + (5 << 16) /* MTUCap 4096 */ + | (7 << 13) /* VLStallCount */ + | (0x1f << 8) /* HOQLife */ + | (1 << 4) + + /* OperationalVLs 0 */ + /* PartitionEnforcementInbound */ + /* PartitionEnforcementOutbound not enforced */ + /* FilterRawinbound not enforced */ + ; /* FilterRawOutbound not enforced */ + /* M_KeyViolations are not counted by hardware, SMA can count */ + tmp = ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey); + /* P_KeyViolations are counted by hardware. */ + portinfo[11] = ((tmp & 0xffff) << 0); + portinfo[12] = + /* Q_KeyViolations are not counted by hardware */ + (1 << 8) + + /* GUIDCap */ + /* SubnetTimeOut handled by SMA */ + /* RespTimeValue handled by SMA */ + ; + /* LocalPhyErrors are programmed to max */ + portinfo[12] |= (0xf << 20) + | (0xf << 16) /* OverRunErrors are programmed to max */ + ; + + return simple_read_from_buffer(buf, count, ppos, portinfo, + sizeof portinfo); +} + +static struct file_operations atomic_port_info_ops = { + .read = atomic_port_info_read, +}; + +static ssize_t flash_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct ipath_devdata *dd; + ssize_t ret; + loff_t pos; + char *tmp; + + pos = *ppos; + + if ( pos < 0) { + ret = -EINVAL; + goto bail; + } + + if (pos >= sizeof(struct ipath_flash)) { + ret = 0; + goto bail; + } + + if (count > sizeof(struct ipath_flash) - pos) + count = sizeof(struct ipath_flash) - pos; + + tmp = kmalloc(count, GFP_KERNEL); + if (!tmp) { + ret = -ENOMEM; + goto bail; + } + + dd = file->f_dentry->d_inode->u.generic_ip; + if (ipath_eeprom_read(dd, pos, tmp, count)) { + ipath_dev_err(dd, "failed to read from flash\n"); + ret = -ENXIO; + goto bail_tmp; + } + + if (copy_to_user(buf, tmp, count)) { + ret = -EFAULT; + goto bail_tmp; + } + + *ppos = pos + count; + ret = count; + +bail_tmp: + kfree(tmp); + +bail: + return ret; +} + +static ssize_t flash_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct ipath_devdata *dd; + ssize_t ret; + loff_t pos; + char *tmp; + + pos = *ppos; + + if ( pos < 0) { + ret = -EINVAL; + goto bail; + } + + if (pos >= sizeof(struct ipath_flash)) { + ret = 0; + goto bail; + } + + if (count > sizeof(struct ipath_flash) - pos) + count = sizeof(struct ipath_flash) - pos; + + tmp = kmalloc(count, GFP_KERNEL); + if (!tmp) { + ret = -ENOMEM; + goto bail; + } + + if (copy_from_user(tmp, buf, count)) { + ret = -EFAULT; + goto bail_tmp; + } + + dd = file->f_dentry->d_inode->u.generic_ip; + if (ipath_eeprom_write(dd, pos, tmp, count)) { + ret = -ENXIO; + ipath_dev_err(dd, "failed to write to flash\n"); + goto bail_tmp; + } + + *ppos = pos + count; + ret = count; + +bail_tmp: + kfree(tmp); + +bail: + return ret; +} + +static struct file_operations flash_ops = { + .read = flash_read, + .write = flash_write, +}; + +static int create_device_files(struct super_block *sb, + struct ipath_devdata *dd) +{ + struct dentry *dir, *tmp; + char unit[10]; + int ret; + + snprintf(unit, sizeof unit, "%02d", dd->ipath_unit); + ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir, + (struct file_operations *) &simple_dir_operations, + dd); + if (ret) { + printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret); + goto bail; + } + + ret = create_file("atomic_counters", S_IFREG|S_IRUGO, dir, &tmp, + &atomic_counters_ops, dd); + if (ret) { + printk(KERN_ERR "create_file(%s/atomic_counters) " + "failed: %d\n", unit, ret); + goto bail; + } + + ret = create_file("node_info", S_IFREG|S_IRUGO, dir, &tmp, + &atomic_node_info_ops, dd); + if (ret) { + printk(KERN_ERR "create_file(%s/node_info) " + "failed: %d\n", unit, ret); + goto bail; + } + + ret = create_file("port_info", S_IFREG|S_IRUGO, dir, &tmp, + &atomic_port_info_ops, dd); + if (ret) { + printk(KERN_ERR "create_file(%s/port_info) " + "failed: %d\n", unit, ret); + goto bail; + } + + ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp, + &flash_ops, dd); + if (ret) { + printk(KERN_ERR "create_file(%s/flash) " + "failed: %d\n", unit, ret); + goto bail; + } + +bail: + return ret; +} + +static void remove_file(struct dentry *parent, char *name) +{ + struct dentry *tmp; + + tmp = lookup_one_len(name, parent, strlen(name)); + + spin_lock(&dcache_lock); + spin_lock(&tmp->d_lock); + if (!(d_unhashed(tmp) && tmp->d_inode)) { + dget_locked(tmp); + __d_drop(tmp); + spin_unlock(&tmp->d_lock); + spin_unlock(&dcache_lock); + simple_unlink(parent->d_inode, tmp); + } else { + spin_unlock(&tmp->d_lock); + spin_unlock(&dcache_lock); + } +} + +static int remove_device_files(struct super_block *sb, + struct ipath_devdata *dd) +{ + struct dentry *dir, *root; + char unit[10]; + int ret; + + root = dget(sb->s_root); + mutex_lock(&root->d_inode->i_mutex); + snprintf(unit, sizeof unit, "%02d", dd->ipath_unit); + dir = lookup_one_len(unit, root, strlen(unit)); + + if (IS_ERR(dir)) { + ret = PTR_ERR(dir); + printk(KERN_ERR "Lookup of %s failed\n", unit); + goto bail; + } + + remove_file(dir, "flash"); + remove_file(dir, "port_info"); + remove_file(dir, "node_info"); + remove_file(dir, "atomic_counters"); + d_delete(dir); + ret = simple_rmdir(root->d_inode, dir); + +bail: + mutex_unlock(&root->d_inode->i_mutex); + dput(root); + return ret; +} + +static int ipathfs_fill_super(struct super_block *sb, void *data, + int silent) +{ + struct ipath_devdata *dd, *tmp; + unsigned long flags; + int ret; + + static struct tree_descr files[] = { + [1] = {"atomic_stats", &atomic_stats_ops, S_IRUGO}, + {""}, + }; + + ret = simple_fill_super(sb, IPATHFS_MAGIC, files); + if (ret) { + printk(KERN_ERR "simple_fill_super failed: %d\n", ret); + goto bail; + } + + spin_lock_irqsave(&ipath_devs_lock, flags); + + list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) { + spin_unlock_irqrestore(&ipath_devs_lock, flags); + ret = create_device_files(sb, dd); + if (ret) { + deactivate_super(sb); + goto bail; + } + spin_lock_irqsave(&ipath_devs_lock, flags); + } + + spin_unlock_irqrestore(&ipath_devs_lock, flags); + +bail: + return ret; +} + +static struct super_block *ipathfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) +{ + ipath_super = get_sb_single(fs_type, flags, data, + ipathfs_fill_super); + return ipath_super; +} + +static void ipathfs_kill_super(struct super_block *s) +{ + kill_litter_super(s); + ipath_super = NULL; +} + +int ipathfs_add_device(struct ipath_devdata *dd) +{ + int ret; + + if (ipath_super == NULL) { + ret = 0; + goto bail; + } + + ret = create_device_files(ipath_super, dd); + +bail: + return ret; +} + +int ipathfs_remove_device(struct ipath_devdata *dd) +{ + int ret; + + if (ipath_super == NULL) { + ret = 0; + goto bail; + } + + ret = remove_device_files(ipath_super, dd); + +bail: + return ret; +} + +static struct file_system_type ipathfs_fs_type = { + .owner = THIS_MODULE, + .name = "ipathfs", + .get_sb = ipathfs_get_sb, + .kill_sb = ipathfs_kill_super, +}; + +int __init ipath_init_ipathfs(void) +{ + return register_filesystem(&ipathfs_fs_type); +} + +void __exit ipath_exit_ipathfs(void) +{ + unregister_filesystem(&ipathfs_fs_type); +} diff --git a/drivers/infiniband/hw/ipath/ipath_ht400.c b/drivers/infiniband/hw/ipath/ipath_ht400.c new file mode 100644 index 000000000000..4652435998f3 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_ht400.c @@ -0,0 +1,1586 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This file contains all of the code that is specific to the InfiniPath + * HT-400 chip. + */ + +#include +#include + +#include "ipath_kernel.h" +#include "ipath_registers.h" + +/* + * This lists the InfiniPath HT400 registers, in the actual chip layout. + * This structure should never be directly accessed. + * + * The names are in InterCap form because they're taken straight from + * the chip specification. Since they're only used in this file, they + * don't pollute the rest of the source. +*/ + +struct _infinipath_do_not_use_kernel_regs { + unsigned long long Revision; + unsigned long long Control; + unsigned long long PageAlign; + unsigned long long PortCnt; + unsigned long long DebugPortSelect; + unsigned long long DebugPort; + unsigned long long SendRegBase; + unsigned long long UserRegBase; + unsigned long long CounterRegBase; + unsigned long long Scratch; + unsigned long long ReservedMisc1; + unsigned long long InterruptConfig; + unsigned long long IntBlocked; + unsigned long long IntMask; + unsigned long long IntStatus; + unsigned long long IntClear; + unsigned long long ErrorMask; + unsigned long long ErrorStatus; + unsigned long long ErrorClear; + unsigned long long HwErrMask; + unsigned long long HwErrStatus; + unsigned long long HwErrClear; + unsigned long long HwDiagCtrl; + unsigned long long MDIO; + unsigned long long IBCStatus; + unsigned long long IBCCtrl; + unsigned long long ExtStatus; + unsigned long long ExtCtrl; + unsigned long long GPIOOut; + unsigned long long GPIOMask; + unsigned long long GPIOStatus; + unsigned long long GPIOClear; + unsigned long long RcvCtrl; + unsigned long long RcvBTHQP; + unsigned long long RcvHdrSize; + unsigned long long RcvHdrCnt; + unsigned long long RcvHdrEntSize; + unsigned long long RcvTIDBase; + unsigned long long RcvTIDCnt; + unsigned long long RcvEgrBase; + unsigned long long RcvEgrCnt; + unsigned long long RcvBufBase; + unsigned long long RcvBufSize; + unsigned long long RxIntMemBase; + unsigned long long RxIntMemSize; + unsigned long long RcvPartitionKey; + unsigned long long ReservedRcv[10]; + unsigned long long SendCtrl; + unsigned long long SendPIOBufBase; + unsigned long long SendPIOSize; + unsigned long long SendPIOBufCnt; + unsigned long long SendPIOAvailAddr; + unsigned long long TxIntMemBase; + unsigned long long TxIntMemSize; + unsigned long long ReservedSend[9]; + unsigned long long SendBufferError; + unsigned long long SendBufferErrorCONT1; + unsigned long long SendBufferErrorCONT2; + unsigned long long SendBufferErrorCONT3; + unsigned long long ReservedSBE[4]; + unsigned long long RcvHdrAddr0; + unsigned long long RcvHdrAddr1; + unsigned long long RcvHdrAddr2; + unsigned long long RcvHdrAddr3; + unsigned long long RcvHdrAddr4; + unsigned long long RcvHdrAddr5; + unsigned long long RcvHdrAddr6; + unsigned long long RcvHdrAddr7; + unsigned long long RcvHdrAddr8; + unsigned long long ReservedRHA[7]; + unsigned long long RcvHdrTailAddr0; + unsigned long long RcvHdrTailAddr1; + unsigned long long RcvHdrTailAddr2; + unsigned long long RcvHdrTailAddr3; + unsigned long long RcvHdrTailAddr4; + unsigned long long RcvHdrTailAddr5; + unsigned long long RcvHdrTailAddr6; + unsigned long long RcvHdrTailAddr7; + unsigned long long RcvHdrTailAddr8; + unsigned long long ReservedRHTA[7]; + unsigned long long Sync; /* Software only */ + unsigned long long Dump; /* Software only */ + unsigned long long SimVer; /* Software only */ + unsigned long long ReservedSW[5]; + unsigned long long SerdesConfig0; + unsigned long long SerdesConfig1; + unsigned long long SerdesStatus; + unsigned long long XGXSConfig; + unsigned long long ReservedSW2[4]; +}; + +#define IPATH_KREG_OFFSET(field) (offsetof(struct \ + _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) +#define IPATH_CREG_OFFSET(field) (offsetof( \ + struct infinipath_counters, field) / sizeof(u64)) + +static const struct ipath_kregs ipath_ht_kregs = { + .kr_control = IPATH_KREG_OFFSET(Control), + .kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase), + .kr_debugport = IPATH_KREG_OFFSET(DebugPort), + .kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect), + .kr_errorclear = IPATH_KREG_OFFSET(ErrorClear), + .kr_errormask = IPATH_KREG_OFFSET(ErrorMask), + .kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus), + .kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl), + .kr_extstatus = IPATH_KREG_OFFSET(ExtStatus), + .kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear), + .kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask), + .kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut), + .kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus), + .kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl), + .kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear), + .kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask), + .kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus), + .kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl), + .kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus), + .kr_intblocked = IPATH_KREG_OFFSET(IntBlocked), + .kr_intclear = IPATH_KREG_OFFSET(IntClear), + .kr_interruptconfig = IPATH_KREG_OFFSET(InterruptConfig), + .kr_intmask = IPATH_KREG_OFFSET(IntMask), + .kr_intstatus = IPATH_KREG_OFFSET(IntStatus), + .kr_mdio = IPATH_KREG_OFFSET(MDIO), + .kr_pagealign = IPATH_KREG_OFFSET(PageAlign), + .kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey), + .kr_portcnt = IPATH_KREG_OFFSET(PortCnt), + .kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP), + .kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase), + .kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize), + .kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl), + .kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase), + .kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt), + .kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt), + .kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize), + .kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize), + .kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase), + .kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize), + .kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase), + .kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt), + .kr_revision = IPATH_KREG_OFFSET(Revision), + .kr_scratch = IPATH_KREG_OFFSET(Scratch), + .kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError), + .kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl), + .kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendPIOAvailAddr), + .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendPIOBufBase), + .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendPIOBufCnt), + .kr_sendpiosize = IPATH_KREG_OFFSET(SendPIOSize), + .kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase), + .kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase), + .kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize), + .kr_userregbase = IPATH_KREG_OFFSET(UserRegBase), + .kr_serdesconfig0 = IPATH_KREG_OFFSET(SerdesConfig0), + .kr_serdesconfig1 = IPATH_KREG_OFFSET(SerdesConfig1), + .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus), + .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig), + /* + * These should not be used directly via ipath_read_kreg64(), + * use them with ipath_read_kreg64_port(), + */ + .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0), + .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0) +}; + +static const struct ipath_cregs ipath_ht_cregs = { + .cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt), + .cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt), + .cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt), + .cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt), + .cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt), + .cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt), + .cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt), + .cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt), + .cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt), + .cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt), + .cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt), + .cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt), + /* calc from Reg_CounterRegBase + offset */ + .cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt), + .cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt), + .cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt), + .cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt), + .cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt), + .cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt), + .cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt), + .cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt), + .cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt), + .cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt), + .cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt), + .cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt), + .cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt), + .cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt), + .cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt), + .cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt), + .cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt), + .cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt), + .cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt), + .cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt), + .cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt) +}; + +/* kr_intstatus, kr_intclear, kr_intmask bits */ +#define INFINIPATH_I_RCVURG_MASK 0x1FF +#define INFINIPATH_I_RCVAVAIL_MASK 0x1FF + +/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */ +#define INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT 0 +#define INFINIPATH_HWE_HTCMEMPARITYERR_MASK 0x3FFFFFULL +#define INFINIPATH_HWE_HTCLNKABYTE0CRCERR 0x0000000000800000ULL +#define INFINIPATH_HWE_HTCLNKABYTE1CRCERR 0x0000000001000000ULL +#define INFINIPATH_HWE_HTCLNKBBYTE0CRCERR 0x0000000002000000ULL +#define INFINIPATH_HWE_HTCLNKBBYTE1CRCERR 0x0000000004000000ULL +#define INFINIPATH_HWE_HTCMISCERR4 0x0000000008000000ULL +#define INFINIPATH_HWE_HTCMISCERR5 0x0000000010000000ULL +#define INFINIPATH_HWE_HTCMISCERR6 0x0000000020000000ULL +#define INFINIPATH_HWE_HTCMISCERR7 0x0000000040000000ULL +#define INFINIPATH_HWE_HTCBUSTREQPARITYERR 0x0000000080000000ULL +#define INFINIPATH_HWE_HTCBUSTRESPPARITYERR 0x0000000100000000ULL +#define INFINIPATH_HWE_HTCBUSIREQPARITYERR 0x0000000200000000ULL +#define INFINIPATH_HWE_COREPLL_FBSLIP 0x0080000000000000ULL +#define INFINIPATH_HWE_COREPLL_RFSLIP 0x0100000000000000ULL +#define INFINIPATH_HWE_HTBPLL_FBSLIP 0x0200000000000000ULL +#define INFINIPATH_HWE_HTBPLL_RFSLIP 0x0400000000000000ULL +#define INFINIPATH_HWE_HTAPLL_FBSLIP 0x0800000000000000ULL +#define INFINIPATH_HWE_HTAPLL_RFSLIP 0x1000000000000000ULL +#define INFINIPATH_HWE_SERDESPLLFAILED 0x2000000000000000ULL + +/* kr_extstatus bits */ +#define INFINIPATH_EXTS_FREQSEL 0x2 +#define INFINIPATH_EXTS_SERDESSEL 0x4 +#define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000 +#define INFINIPATH_EXTS_MEMBIST_CORRECT 0x0000000000008000 + +/* + * masks and bits that are different in different chips, or present only + * in one + */ +static const ipath_err_t infinipath_hwe_htcmemparityerr_mask = + INFINIPATH_HWE_HTCMEMPARITYERR_MASK; +static const ipath_err_t infinipath_hwe_htcmemparityerr_shift = + INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT; + +static const ipath_err_t infinipath_hwe_htclnkabyte0crcerr = + INFINIPATH_HWE_HTCLNKABYTE0CRCERR; +static const ipath_err_t infinipath_hwe_htclnkabyte1crcerr = + INFINIPATH_HWE_HTCLNKABYTE1CRCERR; +static const ipath_err_t infinipath_hwe_htclnkbbyte0crcerr = + INFINIPATH_HWE_HTCLNKBBYTE0CRCERR; +static const ipath_err_t infinipath_hwe_htclnkbbyte1crcerr = + INFINIPATH_HWE_HTCLNKBBYTE1CRCERR; + +#define _IPATH_GPIO_SDA_NUM 1 +#define _IPATH_GPIO_SCL_NUM 0 + +#define IPATH_GPIO_SDA \ + (1ULL << (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT)) +#define IPATH_GPIO_SCL \ + (1ULL << (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT)) + +/* keep the code below somewhat more readonable; not used elsewhere */ +#define _IPATH_HTLINK0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr | \ + infinipath_hwe_htclnkabyte1crcerr) +#define _IPATH_HTLINK1_CRCBITS (infinipath_hwe_htclnkbbyte0crcerr | \ + infinipath_hwe_htclnkbbyte1crcerr) +#define _IPATH_HTLANE0_CRCBITS (infinipath_hwe_htclnkabyte0crcerr | \ + infinipath_hwe_htclnkbbyte0crcerr) +#define _IPATH_HTLANE1_CRCBITS (infinipath_hwe_htclnkabyte1crcerr | \ + infinipath_hwe_htclnkbbyte1crcerr) + +static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs, + char *msg, size_t msgl) +{ + char bitsmsg[64]; + ipath_err_t crcbits = hwerrs & + (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS); + /* don't check if 8bit HT */ + if (dd->ipath_flags & IPATH_8BIT_IN_HT0) + crcbits &= ~infinipath_hwe_htclnkabyte1crcerr; + /* don't check if 8bit HT */ + if (dd->ipath_flags & IPATH_8BIT_IN_HT1) + crcbits &= ~infinipath_hwe_htclnkbbyte1crcerr; + /* + * we'll want to ignore link errors on link that is + * not in use, if any. For now, complain about both + */ + if (crcbits) { + u16 ctrl0, ctrl1; + snprintf(bitsmsg, sizeof bitsmsg, + "[HT%s lane %s CRC (%llx); ignore till reload]", + !(crcbits & _IPATH_HTLINK1_CRCBITS) ? + "0 (A)" : (!(crcbits & _IPATH_HTLINK0_CRCBITS) + ? "1 (B)" : "0+1 (A+B)"), + !(crcbits & _IPATH_HTLANE1_CRCBITS) ? "0" + : (!(crcbits & _IPATH_HTLANE0_CRCBITS) ? "1" : + "0+1"), (unsigned long long) crcbits); + strlcat(msg, bitsmsg, msgl); + + /* + * print extra info for debugging. slave/primary + * config word 4, 8 (link control 0, 1) + */ + + if (pci_read_config_word(dd->pcidev, + dd->ipath_ht_slave_off + 0x4, + &ctrl0)) + dev_info(&dd->pcidev->dev, "Couldn't read " + "linkctrl0 of slave/primary " + "config block\n"); + else if (!(ctrl0 & 1 << 6)) + /* not if EOC bit set */ + ipath_dbg("HT linkctrl0 0x%x%s%s\n", ctrl0, + ((ctrl0 >> 8) & 7) ? " CRC" : "", + ((ctrl0 >> 4) & 1) ? "linkfail" : + ""); + if (pci_read_config_word(dd->pcidev, + dd->ipath_ht_slave_off + 0x8, + &ctrl1)) + dev_info(&dd->pcidev->dev, "Couldn't read " + "linkctrl1 of slave/primary " + "config block\n"); + else if (!(ctrl1 & 1 << 6)) + /* not if EOC bit set */ + ipath_dbg("HT linkctrl1 0x%x%s%s\n", ctrl1, + ((ctrl1 >> 8) & 7) ? " CRC" : "", + ((ctrl1 >> 4) & 1) ? "linkfail" : + ""); + + /* disable until driver reloaded */ + dd->ipath_hwerrmask &= ~crcbits; + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, + dd->ipath_hwerrmask); + ipath_dbg("HT crc errs: %s\n", msg); + } else + ipath_dbg("ignoring HT crc errors 0x%llx, " + "not in use\n", (unsigned long long) + (hwerrs & (_IPATH_HTLINK0_CRCBITS | + _IPATH_HTLINK1_CRCBITS))); +} + +/** + * ipath_ht_handle_hwerrors - display hardware errors + * @dd: the infinipath device + * @msg: the output buffer + * @msgl: the size of the output buffer + * + * Use same msg buffer as regular errors to avoid + * excessive stack use. Most hardware errors are catastrophic, but for + * right now, we'll print them and continue. + * We reuse the same message buffer as ipath_handle_errors() to avoid + * excessive stack usage. + */ +static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg, + size_t msgl) +{ + ipath_err_t hwerrs; + u32 bits, ctrl; + int isfatal = 0; + char bitsmsg[64]; + + hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus); + + if (!hwerrs) { + ipath_cdbg(VERBOSE, "Called but no hardware errors set\n"); + /* + * better than printing cofusing messages + * This seems to be related to clearing the crc error, or + * the pll error during init. + */ + goto bail; + } else if (hwerrs == -1LL) { + ipath_dev_err(dd, "Read of hardware error status failed " + "(all bits set); ignoring\n"); + goto bail; + } + ipath_stats.sps_hwerrs++; + + /* Always clear the error status register, except MEMBISTFAIL, + * regardless of whether we continue or stop using the chip. + * We want that set so we know it failed, even across driver reload. + * We'll still ignore it in the hwerrmask. We do this partly for + * diagnostics, but also for support */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, + hwerrs&~INFINIPATH_HWE_MEMBISTFAILED); + + hwerrs &= dd->ipath_hwerrmask; + + /* + * make sure we get this much out, unless told to be quiet, + * or it's occurred within the last 5 seconds + */ + if ((hwerrs & ~dd->ipath_lasthwerror) || + (ipath_debug & __IPATH_VERBDBG)) + dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx " + "(cleared)\n", (unsigned long long) hwerrs); + dd->ipath_lasthwerror |= hwerrs; + + if (hwerrs & ~infinipath_hwe_bitsextant) + ipath_dev_err(dd, "hwerror interrupt with unknown errors " + "%llx set\n", (unsigned long long) + (hwerrs & ~infinipath_hwe_bitsextant)); + + ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control); + if (ctrl & INFINIPATH_C_FREEZEMODE) { + if (hwerrs) { + /* + * if any set that we aren't ignoring; only + * make the complaint once, in case it's stuck + * or recurring, and we get here multiple + * times. + */ + if (dd->ipath_flags & IPATH_INITTED) { + ipath_dev_err(dd, "Fatal Error (freeze " + "mode), no longer usable\n"); + isfatal = 1; + } + *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; + /* mark as having had error */ + *dd->ipath_statusp |= IPATH_STATUS_HWERROR; + /* + * mark as not usable, at a minimum until driver + * is reloaded, probably until reboot, since no + * other reset is possible. + */ + dd->ipath_flags &= ~IPATH_INITTED; + } else { + ipath_dbg("Clearing freezemode on ignored hardware " + "error\n"); + ctrl &= ~INFINIPATH_C_FREEZEMODE; + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, + ctrl); + } + } + + *msg = '\0'; + + /* + * may someday want to decode into which bits are which + * functional area for parity errors, etc. + */ + if (hwerrs & (infinipath_hwe_htcmemparityerr_mask + << INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT)) { + bits = (u32) ((hwerrs >> + INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) & + INFINIPATH_HWE_HTCMEMPARITYERR_MASK); + snprintf(bitsmsg, sizeof bitsmsg, "[HTC Parity Errs %x] ", + bits); + strlcat(msg, bitsmsg, msgl); + } + if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK + << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) { + bits = (u32) ((hwerrs >> + INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) & + INFINIPATH_HWE_RXEMEMPARITYERR_MASK); + snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ", + bits); + strlcat(msg, bitsmsg, msgl); + } + if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) { + bits = (u32) ((hwerrs >> + INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) & + INFINIPATH_HWE_TXEMEMPARITYERR_MASK); + snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ", + bits); + strlcat(msg, bitsmsg, msgl); + } + if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR) + strlcat(msg, "[IB2IPATH Parity]", msgl); + if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR) + strlcat(msg, "[IPATH2IB Parity]", msgl); + if (hwerrs & INFINIPATH_HWE_HTCBUSIREQPARITYERR) + strlcat(msg, "[HTC Ireq Parity]", msgl); + if (hwerrs & INFINIPATH_HWE_HTCBUSTREQPARITYERR) + strlcat(msg, "[HTC Treq Parity]", msgl); + if (hwerrs & INFINIPATH_HWE_HTCBUSTRESPPARITYERR) + strlcat(msg, "[HTC Tresp Parity]", msgl); + + if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS)) + hwerr_crcbits(dd, hwerrs, msg, msgl); + + if (hwerrs & INFINIPATH_HWE_HTCMISCERR5) + strlcat(msg, "[HT core Misc5]", msgl); + if (hwerrs & INFINIPATH_HWE_HTCMISCERR6) + strlcat(msg, "[HT core Misc6]", msgl); + if (hwerrs & INFINIPATH_HWE_HTCMISCERR7) + strlcat(msg, "[HT core Misc7]", msgl); + if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) { + strlcat(msg, "[Memory BIST test failed, HT-400 unusable]", + msgl); + /* ignore from now on, so disable until driver reloaded */ + dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED; + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, + dd->ipath_hwerrmask); + } +#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \ + INFINIPATH_HWE_COREPLL_RFSLIP | \ + INFINIPATH_HWE_HTBPLL_FBSLIP | \ + INFINIPATH_HWE_HTBPLL_RFSLIP | \ + INFINIPATH_HWE_HTAPLL_FBSLIP | \ + INFINIPATH_HWE_HTAPLL_RFSLIP) + + if (hwerrs & _IPATH_PLL_FAIL) { + snprintf(bitsmsg, sizeof bitsmsg, + "[PLL failed (%llx), HT-400 unusable]", + (unsigned long long) (hwerrs & _IPATH_PLL_FAIL)); + strlcat(msg, bitsmsg, msgl); + /* ignore from now on, so disable until driver reloaded */ + dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL); + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, + dd->ipath_hwerrmask); + } + + if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) { + /* + * If it occurs, it is left masked since the eternal + * interface is unused + */ + dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED; + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, + dd->ipath_hwerrmask); + } + + if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR) + strlcat(msg, "[Rx Dsync]", msgl); + if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) + strlcat(msg, "[SerDes PLL]", msgl); + + ipath_dev_err(dd, "%s hardware error\n", msg); + if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) + /* + * for status file; if no trailing brace is copied, + * we'll know it was truncated. + */ + snprintf(dd->ipath_freezemsg, + dd->ipath_freezelen, "{%s}", msg); + +bail:; +} + +/** + * ipath_ht_boardname - fill in the board name + * @dd: the infinipath device + * @name: the output buffer + * @namelen: the size of the output buffer + * + * fill in the board name, based on the board revision register + */ +static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, + size_t namelen) +{ + char *n = NULL; + u8 boardrev = dd->ipath_boardrev; + int ret; + + switch (boardrev) { + case 4: /* Ponderosa is one of the bringup boards */ + n = "Ponderosa"; + break; + case 5: /* HT-460 original production board */ + n = "InfiniPath_HT-460"; + break; + case 6: + n = "OEM_Board_3"; + break; + case 7: + /* HT-460 small form factor production board */ + n = "InfiniPath_HT-465"; + break; + case 8: + n = "LS/X-1"; + break; + case 9: /* Comstock bringup test board */ + n = "Comstock"; + break; + case 10: + n = "OEM_Board_2"; + break; + case 11: + n = "InfiniPath_HT-470"; + break; + case 12: + n = "OEM_Board_4"; + break; + default: /* don't know, just print the number */ + ipath_dev_err(dd, "Don't yet know about board " + "with ID %u\n", boardrev); + snprintf(name, namelen, "Unknown_InfiniPath_HT-4xx_%u", + boardrev); + break; + } + if (n) + snprintf(name, namelen, "%s", n); + + if (dd->ipath_majrev != 3 || dd->ipath_minrev != 2) { + /* + * This version of the driver only supports the HT-400 + * Rev 3.2 + */ + ipath_dev_err(dd, + "Unsupported HT-400 revision %u.%u!\n", + dd->ipath_majrev, dd->ipath_minrev); + ret = 1; + goto bail; + } + /* + * pkt/word counters are 32 bit, and therefore wrap fast enough + * that we snapshot them from a timer, and maintain 64 bit shadow + * copies + */ + dd->ipath_flags |= IPATH_32BITCOUNTERS; + if (dd->ipath_htspeed != 800) + ipath_dev_err(dd, + "Incorrectly configured for HT @ %uMHz\n", + dd->ipath_htspeed); + if (dd->ipath_boardrev == 7 || dd->ipath_boardrev == 11 || + dd->ipath_boardrev == 6) + dd->ipath_flags |= IPATH_GPIO_INTR; + else + dd->ipath_flags |= IPATH_POLL_RX_INTR; + if (dd->ipath_boardrev == 8) { /* LS/X-1 */ + u64 val; + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus); + if (val & INFINIPATH_EXTS_SERDESSEL) { + /* + * hardware disabled + * + * This means that the chip is hardware disabled, + * and will not be able to bring up the link, + * in any case. We special case this and abort + * early, to avoid later messages. We also set + * the DISABLED status bit + */ + ipath_dbg("Unit %u is hardware-disabled\n", + dd->ipath_unit); + *dd->ipath_statusp |= IPATH_STATUS_DISABLED; + /* this value is handled differently */ + ret = 2; + goto bail; + } + } + ret = 0; + +bail: + return ret; +} + +static void ipath_check_htlink(struct ipath_devdata *dd) +{ + u8 linkerr, link_off, i; + + for (i = 0; i < 2; i++) { + link_off = dd->ipath_ht_slave_off + i * 4 + 0xd; + if (pci_read_config_byte(dd->pcidev, link_off, &linkerr)) + dev_info(&dd->pcidev->dev, "Couldn't read " + "linkerror%d of HT slave/primary block\n", + i); + else if (linkerr & 0xf0) { + ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, " + "clearing\n", linkerr >> 4, i); + /* + * writing the linkerr bits that are set should + * clear them + */ + if (pci_write_config_byte(dd->pcidev, link_off, + linkerr)) + ipath_dbg("Failed write to clear HT " + "linkerror%d\n", i); + if (pci_read_config_byte(dd->pcidev, link_off, + &linkerr)) + dev_info(&dd->pcidev->dev, + "Couldn't reread linkerror%d of " + "HT slave/primary block\n", i); + else if (linkerr & 0xf0) + dev_info(&dd->pcidev->dev, + "HT linkerror%d bits 0x%x " + "couldn't be cleared\n", + i, linkerr >> 4); + } + } +} + +static int ipath_setup_ht_reset(struct ipath_devdata *dd) +{ + ipath_dbg("No reset possible for HT-400\n"); + return 0; +} + +#define HT_CAPABILITY_ID 0x08 /* HT capabilities not defined in kernel */ +#define HT_INTR_DISC_CONFIG 0x80 /* HT interrupt and discovery cap */ +#define HT_INTR_REG_INDEX 2 /* intconfig requires indirect accesses */ + +/* + * Bits 13-15 of command==0 is slave/primary block. Clear any HT CRC + * errors. We only bother to do this at load time, because it's OK if + * it happened before we were loaded (first time after boot/reset), + * but any time after that, it's fatal anyway. Also need to not check + * for for upper byte errors if we are in 8 bit mode, so figure out + * our width. For now, at least, also complain if it's 8 bit. + */ +static void slave_or_pri_blk(struct ipath_devdata *dd, struct pci_dev *pdev, + int pos, u8 cap_type) +{ + u8 linkwidth = 0, linkerr, link_a_b_off, link_off; + u16 linkctrl = 0; + int i; + + dd->ipath_ht_slave_off = pos; + /* command word, master_host bit */ + /* master host || slave */ + if ((cap_type >> 2) & 1) + link_a_b_off = 4; + else + link_a_b_off = 0; + ipath_cdbg(VERBOSE, "HT%u (Link %c) connected to processor\n", + link_a_b_off ? 1 : 0, + link_a_b_off ? 'B' : 'A'); + + link_a_b_off += pos; + + /* + * check both link control registers; clear both HT CRC sets if + * necessary. + */ + for (i = 0; i < 2; i++) { + link_off = pos + i * 4 + 0x4; + if (pci_read_config_word(pdev, link_off, &linkctrl)) + ipath_dev_err(dd, "Couldn't read HT link control%d " + "register\n", i); + else if (linkctrl & (0xf << 8)) { + ipath_cdbg(VERBOSE, "Clear linkctrl%d CRC Error " + "bits %x\n", i, linkctrl & (0xf << 8)); + /* + * now write them back to clear the error. + */ + pci_write_config_byte(pdev, link_off, + linkctrl & (0xf << 8)); + } + } + + /* + * As with HT CRC bits, same for protocol errors that might occur + * during boot. + */ + for (i = 0; i < 2; i++) { + link_off = pos + i * 4 + 0xd; + if (pci_read_config_byte(pdev, link_off, &linkerr)) + dev_info(&pdev->dev, "Couldn't read linkerror%d " + "of HT slave/primary block\n", i); + else if (linkerr & 0xf0) { + ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, " + "clearing\n", linkerr >> 4, i); + /* + * writing the linkerr bits that are set will clear + * them + */ + if (pci_write_config_byte + (pdev, link_off, linkerr)) + ipath_dbg("Failed write to clear HT " + "linkerror%d\n", i); + if (pci_read_config_byte(pdev, link_off, &linkerr)) + dev_info(&pdev->dev, "Couldn't reread " + "linkerror%d of HT slave/primary " + "block\n", i); + else if (linkerr & 0xf0) + dev_info(&pdev->dev, "HT linkerror%d bits " + "0x%x couldn't be cleared\n", + i, linkerr >> 4); + } + } + + /* + * this is just for our link to the host, not devices connected + * through tunnel. + */ + + if (pci_read_config_byte(pdev, link_a_b_off + 7, &linkwidth)) + ipath_dev_err(dd, "Couldn't read HT link width " + "config register\n"); + else { + u32 width; + switch (linkwidth & 7) { + case 5: + width = 4; + break; + case 4: + width = 2; + break; + case 3: + width = 32; + break; + case 1: + width = 16; + break; + case 0: + default: /* if wrong, assume 8 bit */ + width = 8; + break; + } + + dd->ipath_htwidth = width; + + if (linkwidth != 0x11) { + ipath_dev_err(dd, "Not configured for 16 bit HT " + "(%x)\n", linkwidth); + if (!(linkwidth & 0xf)) { + ipath_dbg("Will ignore HT lane1 errors\n"); + dd->ipath_flags |= IPATH_8BIT_IN_HT0; + } + } + } + + /* + * this is just for our link to the host, not devices connected + * through tunnel. + */ + if (pci_read_config_byte(pdev, link_a_b_off + 0xd, &linkwidth)) + ipath_dev_err(dd, "Couldn't read HT link frequency " + "config register\n"); + else { + u32 speed; + switch (linkwidth & 0xf) { + case 6: + speed = 1000; + break; + case 5: + speed = 800; + break; + case 4: + speed = 600; + break; + case 3: + speed = 500; + break; + case 2: + speed = 400; + break; + case 1: + speed = 300; + break; + default: + /* + * assume reserved and vendor-specific are 200... + */ + case 0: + speed = 200; + break; + } + dd->ipath_htspeed = speed; + } +} + +static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev, + int pos) +{ + u32 int_handler_addr_lower; + u32 int_handler_addr_upper; + u64 ihandler; + u32 intvec; + + /* use indirection register to get the intr handler */ + pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x10); + pci_read_config_dword(pdev, pos + 4, &int_handler_addr_lower); + pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x11); + pci_read_config_dword(pdev, pos + 4, &int_handler_addr_upper); + + ihandler = (u64) int_handler_addr_lower | + ((u64) int_handler_addr_upper << 32); + + /* + * kernels with CONFIG_PCI_MSI set the vector in the irq field of + * struct pci_device, so we use that to program the HT-400 internal + * interrupt register (not config space) with that value. The BIOS + * must still have done the basic MSI setup. + */ + intvec = pdev->irq; + /* + * clear any vector bits there; normally not set but we'll overload + * this for some debug purposes (setting the HTC debug register + * value from software, rather than GPIOs), so it might be set on a + * driver reload. + */ + ihandler &= ~0xff0000; + /* x86 vector goes in intrinfo[23:16] */ + ihandler |= intvec << 16; + ipath_cdbg(VERBOSE, "ihandler lower %x, upper %x, intvec %x, " + "interruptconfig %llx\n", int_handler_addr_lower, + int_handler_addr_upper, intvec, + (unsigned long long) ihandler); + + /* can't program yet, so save for interrupt setup */ + dd->ipath_intconfig = ihandler; + /* keep going, so we find link control stuff also */ + + return ihandler != 0; +} + +/** + * ipath_setup_ht_config - setup the interruptconfig register + * @dd: the infinipath device + * @pdev: the PCI device + * + * setup the interruptconfig register from the HT config info. + * Also clear CRC errors in HT linkcontrol, if necessary. + * This is done only for the real hardware. It is done before + * chip address space is initted, so can't touch infinipath registers + */ +static int ipath_setup_ht_config(struct ipath_devdata *dd, + struct pci_dev *pdev) +{ + int pos, ret = 0; + int ihandler = 0; + + /* + * Read the capability info to find the interrupt info, and also + * handle clearing CRC errors in linkctrl register if necessary. We + * do this early, before we ever enable errors or hardware errors, + * mostly to avoid causing the chip to enter freeze mode. + */ + pos = pci_find_capability(pdev, HT_CAPABILITY_ID); + if (!pos) { + ipath_dev_err(dd, "Couldn't find HyperTransport " + "capability; no interrupts\n"); + ret = -ENODEV; + goto bail; + } + do { + u8 cap_type; + + /* the HT capability type byte is 3 bytes after the + * capability byte. + */ + if (pci_read_config_byte(pdev, pos + 3, &cap_type)) { + dev_info(&pdev->dev, "Couldn't read config " + "command @ %d\n", pos); + continue; + } + if (!(cap_type & 0xE0)) + slave_or_pri_blk(dd, pdev, pos, cap_type); + else if (cap_type == HT_INTR_DISC_CONFIG) + ihandler = set_int_handler(dd, pdev, pos); + } while ((pos = pci_find_next_capability(pdev, pos, + HT_CAPABILITY_ID))); + + if (!ihandler) { + ipath_dev_err(dd, "Couldn't find interrupt handler in " + "config space\n"); + ret = -ENODEV; + } + +bail: + return ret; +} + +/** + * ipath_setup_ht_cleanup - clean up any per-chip chip-specific stuff + * @dd: the infinipath device + * + * Called during driver unload. + * This is currently a nop for the HT-400, not for all chips + */ +static void ipath_setup_ht_cleanup(struct ipath_devdata *dd) +{ +} + +/** + * ipath_setup_ht_setextled - set the state of the two external LEDs + * @dd: the infinipath device + * @lst: the L state + * @ltst: the LT state + * + * Set the state of the two external LEDs, to indicate physical and + * logical state of IB link. For this chip (at least with recommended + * board pinouts), LED1 is Green (physical state), and LED2 is Yellow + * (logical state) + * + * Note: We try to match the Mellanox HCA LED behavior as best + * we can. Green indicates physical link state is OK (something is + * plugged in, and we can train). + * Amber indicates the link is logically up (ACTIVE). + * Mellanox further blinks the amber LED to indicate data packet + * activity, but we have no hardware support for that, so it would + * require waking up every 10-20 msecs and checking the counters + * on the chip, and then turning the LED off if appropriate. That's + * visible overhead, so not something we will do. + * + */ +static void ipath_setup_ht_setextled(struct ipath_devdata *dd, + u64 lst, u64 ltst) +{ + u64 extctl; + + /* the diags use the LED to indicate diag info, so we leave + * the external LED alone when the diags are running */ + if (ipath_diag_inuse) + return; + + /* + * start by setting both LED control bits to off, then turn + * on the appropriate bit(s). + */ + if (dd->ipath_boardrev == 8) { /* LS/X-1 uses different pins */ + /* + * major difference is that INFINIPATH_EXTC_LEDGBLERR_OFF + * is inverted, because it is normally used to indicate + * a hardware fault at reset, if there were errors + */ + extctl = (dd->ipath_extctrl & ~INFINIPATH_EXTC_LEDGBLOK_ON) + | INFINIPATH_EXTC_LEDGBLERR_OFF; + if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP) + extctl &= ~INFINIPATH_EXTC_LEDGBLERR_OFF; + if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE) + extctl |= INFINIPATH_EXTC_LEDGBLOK_ON; + } + else { + extctl = dd->ipath_extctrl & + ~(INFINIPATH_EXTC_LED1PRIPORT_ON | + INFINIPATH_EXTC_LED2PRIPORT_ON); + if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP) + extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON; + if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE) + extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON; + } + dd->ipath_extctrl = extctl; + ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl); +} + +static void ipath_init_ht_variables(void) +{ + ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM; + ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM; + ipath_gpio_sda = IPATH_GPIO_SDA; + ipath_gpio_scl = IPATH_GPIO_SCL; + + infinipath_i_bitsextant = + (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) | + (INFINIPATH_I_RCVAVAIL_MASK << + INFINIPATH_I_RCVAVAIL_SHIFT) | + INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT | + INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO; + + infinipath_e_bitsextant = + INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC | + INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN | + INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN | + INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR | + INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP | + INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION | + INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL | + INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN | + INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK | + INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN | + INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN | + INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT | + INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | + INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED | + INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET | + INFINIPATH_E_HARDWARE; + + infinipath_hwe_bitsextant = + (INFINIPATH_HWE_HTCMEMPARITYERR_MASK << + INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) | + (INFINIPATH_HWE_TXEMEMPARITYERR_MASK << + INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) | + (INFINIPATH_HWE_RXEMEMPARITYERR_MASK << + INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) | + INFINIPATH_HWE_HTCLNKABYTE0CRCERR | + INFINIPATH_HWE_HTCLNKABYTE1CRCERR | + INFINIPATH_HWE_HTCLNKBBYTE0CRCERR | + INFINIPATH_HWE_HTCLNKBBYTE1CRCERR | + INFINIPATH_HWE_HTCMISCERR4 | + INFINIPATH_HWE_HTCMISCERR5 | INFINIPATH_HWE_HTCMISCERR6 | + INFINIPATH_HWE_HTCMISCERR7 | + INFINIPATH_HWE_HTCBUSTREQPARITYERR | + INFINIPATH_HWE_HTCBUSTRESPPARITYERR | + INFINIPATH_HWE_HTCBUSIREQPARITYERR | + INFINIPATH_HWE_RXDSYNCMEMPARITYERR | + INFINIPATH_HWE_MEMBISTFAILED | + INFINIPATH_HWE_COREPLL_FBSLIP | + INFINIPATH_HWE_COREPLL_RFSLIP | + INFINIPATH_HWE_HTBPLL_FBSLIP | + INFINIPATH_HWE_HTBPLL_RFSLIP | + INFINIPATH_HWE_HTAPLL_FBSLIP | + INFINIPATH_HWE_HTAPLL_RFSLIP | + INFINIPATH_HWE_SERDESPLLFAILED | + INFINIPATH_HWE_IBCBUSTOSPCPARITYERR | + INFINIPATH_HWE_IBCBUSFRSPCPARITYERR; + + infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK; + infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK; +} + +/** + * ipath_ht_init_hwerrors - enable hardware errors + * @dd: the infinipath device + * + * now that we have finished initializing everything that might reasonably + * cause a hardware error, and cleared those errors bits as they occur, + * we can enable hardware errors in the mask (potentially enabling + * freeze mode), and enable hardware errors as errors (along with + * everything else) in errormask + */ +static void ipath_ht_init_hwerrors(struct ipath_devdata *dd) +{ + ipath_err_t val; + u64 extsval; + + extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus); + + if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST)) + ipath_dev_err(dd, "MemBIST did not complete!\n"); + + ipath_check_htlink(dd); + + /* barring bugs, all hwerrors become interrupts, which can */ + val = -1LL; + /* don't look at crc lane1 if 8 bit */ + if (dd->ipath_flags & IPATH_8BIT_IN_HT0) + val &= ~infinipath_hwe_htclnkabyte1crcerr; + /* don't look at crc lane1 if 8 bit */ + if (dd->ipath_flags & IPATH_8BIT_IN_HT1) + val &= ~infinipath_hwe_htclnkbbyte1crcerr; + + /* + * disable RXDSYNCMEMPARITY because external serdes is unused, + * and therefore the logic will never be used or initialized, + * and uninitialized state will normally result in this error + * being asserted. Similarly for the external serdess pll + * lock signal. + */ + val &= ~(INFINIPATH_HWE_SERDESPLLFAILED | + INFINIPATH_HWE_RXDSYNCMEMPARITYERR); + + /* + * Disable MISCERR4 because of an inversion in the HT core + * logic checking for errors that cause this bit to be set. + * The errata can also cause the protocol error bit to be set + * in the HT config space linkerror register(s). + */ + val &= ~INFINIPATH_HWE_HTCMISCERR4; + + /* + * PLL ignored because MDIO interface has a logic problem + * for reads, on Comstock and Ponderosa. BRINGUP + */ + if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9) + val &= ~INFINIPATH_HWE_SERDESPLLFAILED; + dd->ipath_hwerrmask = val; +} + +/** + * ipath_ht_bringup_serdes - bring up the serdes + * @dd: the infinipath device + */ +static int ipath_ht_bringup_serdes(struct ipath_devdata *dd) +{ + u64 val, config1; + int ret = 0, change = 0; + + ipath_dbg("Trying to bringup serdes\n"); + + if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) & + INFINIPATH_HWE_SERDESPLLFAILED) + { + ipath_dbg("At start, serdes PLL failed bit set in " + "hwerrstatus, clearing and continuing\n"); + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, + INFINIPATH_HWE_SERDESPLLFAILED); + } + + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); + config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1); + + ipath_cdbg(VERBOSE, "Initial serdes status is config0=%llx " + "config1=%llx, sstatus=%llx xgxs %llx\n", + (unsigned long long) val, (unsigned long long) config1, + (unsigned long long) + ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus), + (unsigned long long) + ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); + + /* force reset on */ + val |= INFINIPATH_SERDC0_RESET_PLL + /* | INFINIPATH_SERDC0_RESET_MASK */ + ; + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); + udelay(15); /* need pll reset set at least for a bit */ + + if (val & INFINIPATH_SERDC0_RESET_PLL) { + u64 val2 = val &= ~INFINIPATH_SERDC0_RESET_PLL; + /* set lane resets, and tx idle, during pll reset */ + val2 |= INFINIPATH_SERDC0_RESET_MASK | + INFINIPATH_SERDC0_TXIDLE; + ipath_cdbg(VERBOSE, "Clearing serdes PLL reset (writing " + "%llx)\n", (unsigned long long) val2); + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, + val2); + /* + * be sure chip saw it + */ + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + /* + * need pll reset clear at least 11 usec before lane + * resets cleared; give it a few more + */ + udelay(15); + val = val2; /* for check below */ + } + + if (val & (INFINIPATH_SERDC0_RESET_PLL | + INFINIPATH_SERDC0_RESET_MASK | + INFINIPATH_SERDC0_TXIDLE)) { + val &= ~(INFINIPATH_SERDC0_RESET_PLL | + INFINIPATH_SERDC0_RESET_MASK | + INFINIPATH_SERDC0_TXIDLE); + /* clear them */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, + val); + } + + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); + if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & + INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { + val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK << + INFINIPATH_XGXS_MDIOADDR_SHIFT); + /* + * we use address 3 + */ + val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; + change = 1; + } + if (val & INFINIPATH_XGXS_RESET) { + /* normally true after boot */ + val &= ~INFINIPATH_XGXS_RESET; + change = 1; + } + if (change) + ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); + + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); + + /* clear current and de-emphasis bits */ + config1 &= ~0x0ffffffff00ULL; + /* set current to 20ma */ + config1 |= 0x00000000000ULL; + /* set de-emphasis to -5.68dB */ + config1 |= 0x0cccc000000ULL; + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1); + + ipath_cdbg(VERBOSE, "After setup: serdes status is config0=%llx " + "config1=%llx, sstatus=%llx xgxs %llx\n", + (unsigned long long) val, (unsigned long long) config1, + (unsigned long long) + ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus), + (unsigned long long) + ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); + + if (!ipath_waitfor_mdio_cmdready(dd)) { + ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio, + ipath_mdio_req(IPATH_MDIO_CMD_READ, 31, + IPATH_MDIO_CTRL_XGXS_REG_8, + 0)); + if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio, + IPATH_MDIO_DATAVALID, &val)) + ipath_dbg("Never got MDIO data for XGXS status " + "read\n"); + else + ipath_cdbg(VERBOSE, "MDIO Read reg8, " + "'bank' 31 %x\n", (u32) val); + } else + ipath_dbg("Never got MDIO cmdready for XGXS status read\n"); + + return ret; /* for now, say we always succeeded */ +} + +/** + * ipath_ht_quiet_serdes - set serdes to txidle + * @dd: the infinipath device + * driver is being unloaded + */ +static void ipath_ht_quiet_serdes(struct ipath_devdata *dd) +{ + u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); + + val |= INFINIPATH_SERDC0_TXIDLE; + ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n", + (unsigned long long) val); + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); +} + +static int ipath_ht_intconfig(struct ipath_devdata *dd) +{ + int ret; + + if (!dd->ipath_intconfig) { + ipath_dev_err(dd, "No interrupts enabled, couldn't setup " + "interrupt address\n"); + ret = 1; + goto bail; + } + + ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig, + dd->ipath_intconfig); /* interrupt address */ + ret = 0; + +bail: + return ret; +} + +/** + * ipath_pe_put_tid - write a TID in chip + * @dd: the infinipath device + * @tidptr: pointer to the expected TID (in chip) to udpate + * @tidtype: 0 for eager, 1 for expected + * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing + * + * This exists as a separate routine to allow for special locking etc. + * It's used for both the full cleanup on exit, as well as the normal + * setup and teardown. + */ +static void ipath_ht_put_tid(struct ipath_devdata *dd, + u64 __iomem *tidptr, u32 type, + unsigned long pa) +{ + if (pa != dd->ipath_tidinvalid) { + if (unlikely((pa & ~INFINIPATH_RT_ADDR_MASK))) { + dev_info(&dd->pcidev->dev, + "physaddr %lx has more than " + "40 bits, using only 40!!!\n", pa); + pa &= INFINIPATH_RT_ADDR_MASK; + } + if (type == 0) + pa |= dd->ipath_tidtemplate; + else { + /* in words (fixed, full page). */ + u64 lenvalid = PAGE_SIZE >> 2; + lenvalid <<= INFINIPATH_RT_BUFSIZE_SHIFT; + pa |= lenvalid | INFINIPATH_RT_VALID; + } + } + if (dd->ipath_kregbase) + writeq(pa, tidptr); +} + +/** + * ipath_ht_clear_tid - clear all TID entries for a port, expected and eager + * @dd: the infinipath device + * @port: the port + * + * Used from ipath_close(), and at chip initialization. + */ +static void ipath_ht_clear_tids(struct ipath_devdata *dd, unsigned port) +{ + u64 __iomem *tidbase; + int i; + + if (!dd->ipath_kregbase) + return; + + ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port); + + /* + * need to invalidate all of the expected TID entries for this + * port, so we don't have valid entries that might somehow get + * used (early in next use of this port, or through some bug) + */ + tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) + + dd->ipath_rcvtidbase + + port * dd->ipath_rcvtidcnt * + sizeof(*tidbase)); + for (i = 0; i < dd->ipath_rcvtidcnt; i++) + ipath_ht_put_tid(dd, &tidbase[i], 1, dd->ipath_tidinvalid); + + tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) + + dd->ipath_rcvegrbase + + port * dd->ipath_rcvegrcnt * + sizeof(*tidbase)); + + for (i = 0; i < dd->ipath_rcvegrcnt; i++) + ipath_ht_put_tid(dd, &tidbase[i], 0, dd->ipath_tidinvalid); +} + +/** + * ipath_ht_tidtemplate - setup constants for TID updates + * @dd: the infinipath device + * + * We setup stuff that we use a lot, to avoid calculating each time + */ +static void ipath_ht_tidtemplate(struct ipath_devdata *dd) +{ + dd->ipath_tidtemplate = dd->ipath_ibmaxlen >> 2; + dd->ipath_tidtemplate <<= INFINIPATH_RT_BUFSIZE_SHIFT; + dd->ipath_tidtemplate |= INFINIPATH_RT_VALID; + + /* + * work around chip errata bug 7358, by marking invalid tids + * as having max length + */ + dd->ipath_tidinvalid = (-1LL & INFINIPATH_RT_BUFSIZE_MASK) << + INFINIPATH_RT_BUFSIZE_SHIFT; +} + +static int ipath_ht_early_init(struct ipath_devdata *dd) +{ + u32 __iomem *piobuf; + u32 pioincr, val32, egrsize; + int i; + + /* + * one cache line; long IB headers will spill over into received + * buffer + */ + dd->ipath_rcvhdrentsize = 16; + dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; + + /* + * For HT-400, we allocate a somewhat overly large eager buffer, + * such that we can guarantee that we can receive the largest + * packet that we can send out. To truly support a 4KB MTU, + * we need to bump this to a large value. To date, other than + * testing, we have never encountered an HCA that can really + * send 4KB MTU packets, so we do not handle that (we'll get + * errors interrupts if we ever see one). + */ + dd->ipath_rcvegrbufsize = dd->ipath_piosize2k; + egrsize = dd->ipath_rcvegrbufsize; + + /* + * the min() check here is currently a nop, but it may not + * always be, depending on just how we do ipath_rcvegrbufsize + */ + dd->ipath_ibmaxlen = min(dd->ipath_piosize2k, + dd->ipath_rcvegrbufsize); + dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen; + ipath_ht_tidtemplate(dd); + + /* + * zero all the TID entries at startup. We do this for sanity, + * in case of a previous driver crash of some kind, and also + * because the chip powers up with these memories in an unknown + * state. Use portcnt, not cfgports, since this is for the + * full chip, not for current (possibly different) configuration + * value. + * Chip Errata bug 6447 + */ + for (val32 = 0; val32 < dd->ipath_portcnt; val32++) + ipath_ht_clear_tids(dd, val32); + + /* + * write the pbc of each buffer, to be sure it's initialized, then + * cancel all the buffers, and also abort any packets that might + * have been in flight for some reason (the latter is for driver + * unload/reload, but isn't a bad idea at first init). PIO send + * isn't enabled at this point, so there is no danger of sending + * these out on the wire. + * Chip Errata bug 6610 + */ + piobuf = (u32 __iomem *) (((char __iomem *)(dd->ipath_kregbase)) + + dd->ipath_piobufbase); + pioincr = dd->ipath_palign / sizeof(*piobuf); + for (i = 0; i < dd->ipath_piobcnt2k; i++) { + /* + * reasonable word count, just to init pbc + */ + writel(16, piobuf); + piobuf += pioincr; + } + /* + * self-clearing + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + INFINIPATH_S_ABORT); + return 0; +} + +/** + * ipath_init_ht_get_base_info - set chip-specific flags for user code + * @dd: the infinipath device + * @kbase: ipath_base_info pointer + * + * We set the PCIE flag because the lower bandwidth on PCIe vs + * HyperTransport can affect some user packet algorithims. + */ +static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase) +{ + struct ipath_base_info *kinfo = kbase; + + kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT | + IPATH_RUNTIME_RCVHDR_COPY; + + return 0; +} + +/** + * ipath_init_ht400_funcs - set up the chip-specific function pointers + * @dd: the infinipath device + * + * This is global, and is called directly at init to set up the + * chip-specific function pointers for later use. + */ +void ipath_init_ht400_funcs(struct ipath_devdata *dd) +{ + dd->ipath_f_intrsetup = ipath_ht_intconfig; + dd->ipath_f_bus = ipath_setup_ht_config; + dd->ipath_f_reset = ipath_setup_ht_reset; + dd->ipath_f_get_boardname = ipath_ht_boardname; + dd->ipath_f_init_hwerrors = ipath_ht_init_hwerrors; + dd->ipath_f_init_hwerrors = ipath_ht_init_hwerrors; + dd->ipath_f_early_init = ipath_ht_early_init; + dd->ipath_f_handle_hwerrors = ipath_ht_handle_hwerrors; + dd->ipath_f_quiet_serdes = ipath_ht_quiet_serdes; + dd->ipath_f_bringup_serdes = ipath_ht_bringup_serdes; + dd->ipath_f_clear_tids = ipath_ht_clear_tids; + dd->ipath_f_put_tid = ipath_ht_put_tid; + dd->ipath_f_cleanup = ipath_setup_ht_cleanup; + dd->ipath_f_setextled = ipath_setup_ht_setextled; + dd->ipath_f_get_base_info = ipath_ht_get_base_info; + + /* + * initialize chip-specific variables + */ + dd->ipath_f_tidtemplate = ipath_ht_tidtemplate; + + /* + * setup the register offsets, since they are different for each + * chip + */ + dd->ipath_kregs = &ipath_ht_kregs; + dd->ipath_cregs = &ipath_ht_cregs; + + /* + * do very early init that is needed before ipath_f_bus is + * called + */ + ipath_init_ht_variables(); +} diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c new file mode 100644 index 000000000000..2823ff9c0c62 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -0,0 +1,951 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "ipath_kernel.h" +#include "ips_common.h" + +/* + * min buffers we want to have per port, after driver + */ +#define IPATH_MIN_USER_PORT_BUFCNT 8 + +/* + * Number of ports we are configured to use (to allow for more pio + * buffers per port, etc.) Zero means use chip value. + */ +static ushort ipath_cfgports; + +module_param_named(cfgports, ipath_cfgports, ushort, S_IRUGO); +MODULE_PARM_DESC(cfgports, "Set max number of ports to use"); + +/* + * Number of buffers reserved for driver (layered drivers and SMA + * send). Reserved at end of buffer list. + */ +static ushort ipath_kpiobufs = 32; + +static int ipath_set_kpiobufs(const char *val, struct kernel_param *kp); + +module_param_call(kpiobufs, ipath_set_kpiobufs, param_get_uint, + &ipath_kpiobufs, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver"); + +/** + * create_port0_egr - allocate the eager TID buffers + * @dd: the infinipath device + * + * This code is now quite different for user and kernel, because + * the kernel uses skb's, for the accelerated network performance. + * This is the kernel (port0) version. + * + * Allocate the eager TID buffers and program them into infinipath. + * We use the network layer alloc_skb() allocator to allocate the + * memory, and either use the buffers as is for things like SMA + * packets, or pass the buffers up to the ipath layered driver and + * thence the network layer, replacing them as we do so (see + * ipath_rcv_layer()). + */ +static int create_port0_egr(struct ipath_devdata *dd) +{ + unsigned e, egrcnt; + struct sk_buff **skbs; + int ret; + + egrcnt = dd->ipath_rcvegrcnt; + + skbs = vmalloc(sizeof(*dd->ipath_port0_skbs) * egrcnt); + if (skbs == NULL) { + ipath_dev_err(dd, "allocation error for eager TID " + "skb array\n"); + ret = -ENOMEM; + goto bail; + } + for (e = 0; e < egrcnt; e++) { + /* + * This is a bit tricky in that we allocate extra + * space for 2 bytes of the 14 byte ethernet header. + * These two bytes are passed in the ipath header so + * the rest of the data is word aligned. We allocate + * 4 bytes so that the data buffer stays word aligned. + * See ipath_kreceive() for more details. + */ + skbs[e] = ipath_alloc_skb(dd, GFP_KERNEL); + if (!skbs[e]) { + ipath_dev_err(dd, "SKB allocation error for " + "eager TID %u\n", e); + while (e != 0) + dev_kfree_skb(skbs[--e]); + ret = -ENOMEM; + goto bail; + } + } + /* + * After loop above, so we can test non-NULL to see if ready + * to use at receive, etc. + */ + dd->ipath_port0_skbs = skbs; + + for (e = 0; e < egrcnt; e++) { + unsigned long phys = + virt_to_phys(dd->ipath_port0_skbs[e]->data); + dd->ipath_f_put_tid(dd, e + (u64 __iomem *) + ((char __iomem *) dd->ipath_kregbase + + dd->ipath_rcvegrbase), 0, phys); + } + + ret = 0; + +bail: + return ret; +} + +static int bringup_link(struct ipath_devdata *dd) +{ + u64 val, ibc; + int ret = 0; + + /* hold IBC in reset */ + dd->ipath_control &= ~INFINIPATH_C_LINKENABLE; + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, + dd->ipath_control); + + /* + * Note that prior to try 14 or 15 of IB, the credit scaling + * wasn't working, because it was swapped for writes with the + * 1 bit default linkstate field + */ + + /* ignore pbc and align word */ + val = dd->ipath_piosize2k - 2 * sizeof(u32); + /* + * for ICRC, which we only send in diag test pkt mode, and we + * don't need to worry about that for mtu + */ + val += 1; + /* + * Set the IBC maxpktlength to the size of our pio buffers the + * maxpktlength is in words. This is *not* the IB data MTU. + */ + ibc = (val / sizeof(u32)) << INFINIPATH_IBCC_MAXPKTLEN_SHIFT; + /* in KB */ + ibc |= 0x5ULL << INFINIPATH_IBCC_FLOWCTRLWATERMARK_SHIFT; + /* + * How often flowctrl sent. More or less in usecs; balance against + * watermark value, so that in theory senders always get a flow + * control update in time to not let the IB link go idle. + */ + ibc |= 0x3ULL << INFINIPATH_IBCC_FLOWCTRLPERIOD_SHIFT; + /* max error tolerance */ + ibc |= 0xfULL << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT; + /* use "real" buffer space for */ + ibc |= 4ULL << INFINIPATH_IBCC_CREDITSCALE_SHIFT; + /* IB credit flow control. */ + ibc |= 0xfULL << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT; + /* initially come up waiting for TS1, without sending anything. */ + dd->ipath_ibcctrl = ibc; + /* + * Want to start out with both LINKCMD and LINKINITCMD in NOP + * (0 and 0). Don't put linkinitcmd in ipath_ibcctrl, want that + * to stay a NOP + */ + ibc |= INFINIPATH_IBCC_LINKINITCMD_DISABLE << + INFINIPATH_IBCC_LINKINITCMD_SHIFT; + ipath_cdbg(VERBOSE, "Writing 0x%llx to ibcctrl\n", + (unsigned long long) ibc); + ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, ibc); + + // be sure chip saw it + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + + ret = dd->ipath_f_bringup_serdes(dd); + + if (ret) + dev_info(&dd->pcidev->dev, "Could not initialize SerDes, " + "not usable\n"); + else { + /* enable IBC */ + dd->ipath_control |= INFINIPATH_C_LINKENABLE; + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, + dd->ipath_control); + } + + return ret; +} + +static int init_chip_first(struct ipath_devdata *dd, + struct ipath_portdata **pdp) +{ + struct ipath_portdata *pd = NULL; + int ret = 0; + u64 val; + + /* + * skip cfgports stuff because we are not allocating memory, + * and we don't want problems if the portcnt changed due to + * cfgports. We do still check and report a difference, if + * not same (should be impossible). + */ + dd->ipath_portcnt = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); + if (!ipath_cfgports) + dd->ipath_cfgports = dd->ipath_portcnt; + else if (ipath_cfgports <= dd->ipath_portcnt) { + dd->ipath_cfgports = ipath_cfgports; + ipath_dbg("Configured to use %u ports out of %u in chip\n", + dd->ipath_cfgports, dd->ipath_portcnt); + } else { + dd->ipath_cfgports = dd->ipath_portcnt; + ipath_dbg("Tried to configured to use %u ports; chip " + "only supports %u\n", ipath_cfgports, + dd->ipath_portcnt); + } + dd->ipath_pd = kzalloc(sizeof(*dd->ipath_pd) * dd->ipath_cfgports, + GFP_KERNEL); + + if (!dd->ipath_pd) { + ipath_dev_err(dd, "Unable to allocate portdata array, " + "failing\n"); + ret = -ENOMEM; + goto done; + } + + dd->ipath_lastegrheads = kzalloc(sizeof(*dd->ipath_lastegrheads) + * dd->ipath_cfgports, + GFP_KERNEL); + dd->ipath_lastrcvhdrqtails = + kzalloc(sizeof(*dd->ipath_lastrcvhdrqtails) + * dd->ipath_cfgports, GFP_KERNEL); + + if (!dd->ipath_lastegrheads || !dd->ipath_lastrcvhdrqtails) { + ipath_dev_err(dd, "Unable to allocate head arrays, " + "failing\n"); + ret = -ENOMEM; + goto done; + } + + dd->ipath_pd[0] = kzalloc(sizeof(*pd), GFP_KERNEL); + + if (!dd->ipath_pd[0]) { + ipath_dev_err(dd, "Unable to allocate portdata for port " + "0, failing\n"); + ret = -ENOMEM; + goto done; + } + pd = dd->ipath_pd[0]; + pd->port_dd = dd; + pd->port_port = 0; + pd->port_cnt = 1; + /* The port 0 pkey table is used by the layer interface. */ + pd->port_pkeys[0] = IPS_DEFAULT_P_KEY; + dd->ipath_rcvtidcnt = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt); + dd->ipath_rcvtidbase = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidbase); + dd->ipath_rcvegrcnt = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt); + dd->ipath_rcvegrbase = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrbase); + dd->ipath_palign = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign); + dd->ipath_piobufbase = + ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpiobufbase); + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpiosize); + dd->ipath_piosize2k = val & ~0U; + dd->ipath_piosize4k = val >> 32; + dd->ipath_ibmtu = 4096; /* default to largest legal MTU */ + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpiobufcnt); + dd->ipath_piobcnt2k = val & ~0U; + dd->ipath_piobcnt4k = val >> 32; + dd->ipath_pio2kbase = + (u32 __iomem *) (((char __iomem *) dd->ipath_kregbase) + + (dd->ipath_piobufbase & 0xffffffff)); + if (dd->ipath_piobcnt4k) { + dd->ipath_pio4kbase = (u32 __iomem *) + (((char __iomem *) dd->ipath_kregbase) + + (dd->ipath_piobufbase >> 32)); + /* + * 4K buffers take 2 pages; we use roundup just to be + * paranoid; we calculate it once here, rather than on + * ever buf allocate + */ + dd->ipath_4kalign = ALIGN(dd->ipath_piosize4k, + dd->ipath_palign); + ipath_dbg("%u 2k(%x) piobufs @ %p, %u 4k(%x) @ %p " + "(%x aligned)\n", + dd->ipath_piobcnt2k, dd->ipath_piosize2k, + dd->ipath_pio2kbase, dd->ipath_piobcnt4k, + dd->ipath_piosize4k, dd->ipath_pio4kbase, + dd->ipath_4kalign); + } + else ipath_dbg("%u 2k piobufs @ %p\n", + dd->ipath_piobcnt2k, dd->ipath_pio2kbase); + + spin_lock_init(&dd->ipath_tid_lock); + +done: + *pdp = pd; + return ret; +} + +/** + * init_chip_reset - re-initialize after a reset, or enable + * @dd: the infinipath device + * @pdp: output for port data + * + * sanity check at least some of the values after reset, and + * ensure no receive or transmit (explictly, in case reset + * failed + */ +static int init_chip_reset(struct ipath_devdata *dd, + struct ipath_portdata **pdp) +{ + struct ipath_portdata *pd; + u32 rtmp; + + *pdp = pd = dd->ipath_pd[0]; + /* ensure chip does no sends or receives while we re-initialize */ + dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U; + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0); + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0); + + rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); + if (dd->ipath_portcnt != rtmp) + dev_info(&dd->pcidev->dev, "portcnt was %u before " + "reset, now %u, using original\n", + dd->ipath_portcnt, rtmp); + rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt); + if (rtmp != dd->ipath_rcvtidcnt) + dev_info(&dd->pcidev->dev, "tidcnt was %u before " + "reset, now %u, using original\n", + dd->ipath_rcvtidcnt, rtmp); + rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidbase); + if (rtmp != dd->ipath_rcvtidbase) + dev_info(&dd->pcidev->dev, "tidbase was %u before " + "reset, now %u, using original\n", + dd->ipath_rcvtidbase, rtmp); + rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt); + if (rtmp != dd->ipath_rcvegrcnt) + dev_info(&dd->pcidev->dev, "egrcnt was %u before " + "reset, now %u, using original\n", + dd->ipath_rcvegrcnt, rtmp); + rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrbase); + if (rtmp != dd->ipath_rcvegrbase) + dev_info(&dd->pcidev->dev, "egrbase was %u before " + "reset, now %u, using original\n", + dd->ipath_rcvegrbase, rtmp); + + return 0; +} + +static int init_pioavailregs(struct ipath_devdata *dd) +{ + int ret; + + dd->ipath_pioavailregs_dma = dma_alloc_coherent( + &dd->pcidev->dev, PAGE_SIZE, &dd->ipath_pioavailregs_phys, + GFP_KERNEL); + if (!dd->ipath_pioavailregs_dma) { + ipath_dev_err(dd, "failed to allocate PIOavail reg area " + "in memory\n"); + ret = -ENOMEM; + goto done; + } + + /* + * we really want L2 cache aligned, but for current CPUs of + * interest, they are the same. + */ + dd->ipath_statusp = (u64 *) + ((char *)dd->ipath_pioavailregs_dma + + ((2 * L1_CACHE_BYTES + + dd->ipath_pioavregs * sizeof(u64)) & ~L1_CACHE_BYTES)); + /* copy the current value now that it's really allocated */ + *dd->ipath_statusp = dd->_ipath_status; + /* + * setup buffer to hold freeze msg, accessible to apps, + * following statusp + */ + dd->ipath_freezemsg = (char *)&dd->ipath_statusp[1]; + /* and its length */ + dd->ipath_freezelen = L1_CACHE_BYTES - sizeof(dd->ipath_statusp[0]); + + if (dd->ipath_unit * 64 > (IPATH_PORT0_RCVHDRTAIL_SIZE - 64)) { + ipath_dev_err(dd, "unit %u too large for port 0 " + "rcvhdrtail buffer size\n", dd->ipath_unit); + ret = -ENODEV; + } + else + ret = 0; + + /* so we can get current tail in ipath_kreceive(), per chip */ + dd->ipath_hdrqtailptr = &ipath_port0_rcvhdrtail[ + dd->ipath_unit * (64 / sizeof(*ipath_port0_rcvhdrtail))]; +done: + return ret; +} + +/** + * init_shadow_tids - allocate the shadow TID array + * @dd: the infinipath device + * + * allocate the shadow TID array, so we can ipath_munlock previous + * entries. It may make more sense to move the pageshadow to the + * port data structure, so we only allocate memory for ports actually + * in use, since we at 8k per port, now. + */ +static void init_shadow_tids(struct ipath_devdata *dd) +{ + dd->ipath_pageshadow = (struct page **) + vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt * + sizeof(struct page *)); + if (!dd->ipath_pageshadow) + ipath_dev_err(dd, "failed to allocate shadow page * " + "array, no expected sends!\n"); + else + memset(dd->ipath_pageshadow, 0, + dd->ipath_cfgports * dd->ipath_rcvtidcnt * + sizeof(struct page *)); +} + +static void enable_chip(struct ipath_devdata *dd, + struct ipath_portdata *pd, int reinit) +{ + u32 val; + int i; + + if (!reinit) { + init_waitqueue_head(&ipath_sma_state_wait); + } + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl); + + /* Enable PIO send, and update of PIOavail regs to memory. */ + dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE | + INFINIPATH_S_PIOBUFAVAILUPD; + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + dd->ipath_sendctrl); + + /* + * enable port 0 receive, and receive interrupt. other ports + * done as user opens and inits them. + */ + dd->ipath_rcvctrl = INFINIPATH_R_TAILUPD | + (1ULL << INFINIPATH_R_PORTENABLE_SHIFT) | + (1ULL << INFINIPATH_R_INTRAVAIL_SHIFT); + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl); + + /* + * now ready for use. this should be cleared whenever we + * detect a reset, or initiate one. + */ + dd->ipath_flags |= IPATH_INITTED; + + /* + * init our shadow copies of head from tail values, and write + * head values to match. + */ + val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0); + (void)ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0); + dd->ipath_port0head = ipath_read_ureg32(dd, ur_rcvhdrtail, 0); + + /* Initialize so we interrupt on next packet received */ + (void)ipath_write_ureg(dd, ur_rcvhdrhead, + dd->ipath_rhdrhead_intr_off | + dd->ipath_port0head, 0); + + /* + * by now pioavail updates to memory should have occurred, so + * copy them into our working/shadow registers; this is in + * case something went wrong with abort, but mostly to get the + * initial values of the generation bit correct. + */ + for (i = 0; i < dd->ipath_pioavregs; i++) { + __le64 val; + + /* + * Chip Errata bug 6641; even and odd qwords>3 are swapped. + */ + if (i > 3) { + if (i & 1) + val = dd->ipath_pioavailregs_dma[i - 1]; + else + val = dd->ipath_pioavailregs_dma[i + 1]; + } + else + val = dd->ipath_pioavailregs_dma[i]; + dd->ipath_pioavailshadow[i] = le64_to_cpu(val); + } + /* can get counters, stats, etc. */ + dd->ipath_flags |= IPATH_PRESENT; +} + +static int init_housekeeping(struct ipath_devdata *dd, + struct ipath_portdata **pdp, int reinit) +{ + char boardn[32]; + int ret = 0; + + /* + * have to clear shadow copies of registers at init that are + * not otherwise set here, or all kinds of bizarre things + * happen with driver on chip reset + */ + dd->ipath_rcvhdrsize = 0; + + /* + * Don't clear ipath_flags as 8bit mode was set before + * entering this func. However, we do set the linkstate to + * unknown, so we can watch for a transition. + */ + dd->ipath_flags |= IPATH_LINKUNK; + dd->ipath_flags &= ~(IPATH_LINKACTIVE | IPATH_LINKARMED | + IPATH_LINKDOWN | IPATH_LINKINIT); + + ipath_cdbg(VERBOSE, "Try to read spc chip revision\n"); + dd->ipath_revision = + ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision); + + /* + * set up fundamental info we need to use the chip; we assume + * if the revision reg and these regs are OK, we don't need to + * special case the rest + */ + dd->ipath_sregbase = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_sendregbase); + dd->ipath_cregbase = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_counterregbase); + dd->ipath_uregbase = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_userregbase); + ipath_cdbg(VERBOSE, "ipath_kregbase %p, sendbase %x usrbase %x, " + "cntrbase %x\n", dd->ipath_kregbase, dd->ipath_sregbase, + dd->ipath_uregbase, dd->ipath_cregbase); + if ((dd->ipath_revision & 0xffffffff) == 0xffffffff + || (dd->ipath_sregbase & 0xffffffff) == 0xffffffff + || (dd->ipath_cregbase & 0xffffffff) == 0xffffffff + || (dd->ipath_uregbase & 0xffffffff) == 0xffffffff) { + ipath_dev_err(dd, "Register read failures from chip, " + "giving up initialization\n"); + ret = -ENODEV; + goto done; + } + + /* clear the initial reset flag, in case first driver load */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, + INFINIPATH_E_RESET); + + if (reinit) + ret = init_chip_reset(dd, pdp); + else + ret = init_chip_first(dd, pdp); + + if (ret) + goto done; + + ipath_cdbg(VERBOSE, "Revision %llx (PCI %x), %u ports, %u tids, " + "%u egrtids\n", (unsigned long long) dd->ipath_revision, + dd->ipath_pcirev, dd->ipath_portcnt, dd->ipath_rcvtidcnt, + dd->ipath_rcvegrcnt); + + if (((dd->ipath_revision >> INFINIPATH_R_SOFTWARE_SHIFT) & + INFINIPATH_R_SOFTWARE_MASK) != IPATH_CHIP_SWVERSION) { + ipath_dev_err(dd, "Driver only handles version %d, " + "chip swversion is %d (%llx), failng\n", + IPATH_CHIP_SWVERSION, + (int)(dd->ipath_revision >> + INFINIPATH_R_SOFTWARE_SHIFT) & + INFINIPATH_R_SOFTWARE_MASK, + (unsigned long long) dd->ipath_revision); + ret = -ENOSYS; + goto done; + } + dd->ipath_majrev = (u8) ((dd->ipath_revision >> + INFINIPATH_R_CHIPREVMAJOR_SHIFT) & + INFINIPATH_R_CHIPREVMAJOR_MASK); + dd->ipath_minrev = (u8) ((dd->ipath_revision >> + INFINIPATH_R_CHIPREVMINOR_SHIFT) & + INFINIPATH_R_CHIPREVMINOR_MASK); + dd->ipath_boardrev = (u8) ((dd->ipath_revision >> + INFINIPATH_R_BOARDID_SHIFT) & + INFINIPATH_R_BOARDID_MASK); + + ret = dd->ipath_f_get_boardname(dd, boardn, sizeof boardn); + + snprintf(dd->ipath_boardversion, sizeof(dd->ipath_boardversion), + "Driver %u.%u, %s, InfiniPath%u %u.%u, PCI %u, " + "SW Compat %u\n", + IPATH_CHIP_VERS_MAJ, IPATH_CHIP_VERS_MIN, boardn, + (unsigned)(dd->ipath_revision >> INFINIPATH_R_ARCH_SHIFT) & + INFINIPATH_R_ARCH_MASK, + dd->ipath_majrev, dd->ipath_minrev, dd->ipath_pcirev, + (unsigned)(dd->ipath_revision >> + INFINIPATH_R_SOFTWARE_SHIFT) & + INFINIPATH_R_SOFTWARE_MASK); + + ipath_dbg("%s", dd->ipath_boardversion); + +done: + return ret; +} + + +/** + * ipath_init_chip - do the actual initialization sequence on the chip + * @dd: the infinipath device + * @reinit: reinitializing, so don't allocate new memory + * + * Do the actual initialization sequence on the chip. This is done + * both from the init routine called from the PCI infrastructure, and + * when we reset the chip, or detect that it was reset internally, + * or it's administratively re-enabled. + * + * Memory allocation here and in called routines is only done in + * the first case (reinit == 0). We have to be careful, because even + * without memory allocation, we need to re-write all the chip registers + * TIDs, etc. after the reset or enable has completed. + */ +int ipath_init_chip(struct ipath_devdata *dd, int reinit) +{ + int ret = 0, i; + u32 val32, kpiobufs; + u64 val, atmp; + struct ipath_portdata *pd = NULL; /* keep gcc4 happy */ + + ret = init_housekeeping(dd, &pd, reinit); + if (ret) + goto done; + + /* + * we ignore most issues after reporting them, but have to specially + * handle hardware-disabled chips. + */ + if (ret == 2) { + /* unique error, known to ipath_init_one */ + ret = -EPERM; + goto done; + } + + /* + * We could bump this to allow for full rcvegrcnt + rcvtidcnt, + * but then it no longer nicely fits power of two, and since + * we now use routines that backend onto __get_free_pages, the + * rest would be wasted. + */ + dd->ipath_rcvhdrcnt = dd->ipath_rcvegrcnt; + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvhdrcnt, + dd->ipath_rcvhdrcnt); + + /* + * Set up the shadow copies of the piobufavail registers, + * which we compare against the chip registers for now, and + * the in memory DMA'ed copies of the registers. This has to + * be done early, before we calculate lastport, etc. + */ + val = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k; + /* + * calc number of pioavail registers, and save it; we have 2 + * bits per buffer. + */ + dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2) + / (sizeof(u64) * BITS_PER_BYTE / 2); + if (!ipath_kpiobufs) /* have to have at least 1, for SMA */ + kpiobufs = ipath_kpiobufs = 1; + else if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) < + (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT)) { + dev_info(&dd->pcidev->dev, "Too few PIO buffers (%u) " + "for %u ports to have %u each!\n", + dd->ipath_piobcnt2k + dd->ipath_piobcnt4k, + dd->ipath_cfgports, IPATH_MIN_USER_PORT_BUFCNT); + kpiobufs = 1; /* reserve just the minimum for SMA/ether */ + } else + kpiobufs = ipath_kpiobufs; + + if (kpiobufs > + (dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - + (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT))) { + i = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - + (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT); + if (i < 0) + i = 0; + dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs for " + "kernel leaves too few for %d user ports " + "(%d each); using %u\n", kpiobufs, + dd->ipath_cfgports - 1, + IPATH_MIN_USER_PORT_BUFCNT, i); + /* + * shouldn't change ipath_kpiobufs, because could be + * different for different devices... + */ + kpiobufs = i; + } + dd->ipath_lastport_piobuf = + dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - kpiobufs; + dd->ipath_pbufsport = dd->ipath_cfgports > 1 + ? dd->ipath_lastport_piobuf / (dd->ipath_cfgports - 1) + : 0; + val32 = dd->ipath_lastport_piobuf - + (dd->ipath_pbufsport * (dd->ipath_cfgports - 1)); + if (val32 > 0) { + ipath_dbg("allocating %u pbufs/port leaves %u unused, " + "add to kernel\n", dd->ipath_pbufsport, val32); + dd->ipath_lastport_piobuf -= val32; + ipath_dbg("%u pbufs/port leaves %u unused, add to kernel\n", + dd->ipath_pbufsport, val32); + } + dd->ipath_lastpioindex = dd->ipath_lastport_piobuf; + ipath_cdbg(VERBOSE, "%d PIO bufs for kernel out of %d total %u " + "each for %u user ports\n", kpiobufs, + dd->ipath_piobcnt2k + dd->ipath_piobcnt4k, + dd->ipath_pbufsport, dd->ipath_cfgports - 1); + + dd->ipath_f_early_init(dd); + + /* early_init sets rcvhdrentsize and rcvhdrsize, so this must be + * done after early_init */ + dd->ipath_hdrqlast = + dd->ipath_rcvhdrentsize * (dd->ipath_rcvhdrcnt - 1); + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvhdrentsize, + dd->ipath_rcvhdrentsize); + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvhdrsize, + dd->ipath_rcvhdrsize); + + if (!reinit) { + ret = init_pioavailregs(dd); + init_shadow_tids(dd); + if (ret) + goto done; + } + + (void)ipath_write_kreg(dd, dd->ipath_kregs->kr_sendpioavailaddr, + dd->ipath_pioavailregs_phys); + /* + * this is to detect s/w errors, which the h/w works around by + * ignoring the low 6 bits of address, if it wasn't aligned. + */ + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpioavailaddr); + if (val != dd->ipath_pioavailregs_phys) { + ipath_dev_err(dd, "Catastrophic software error, " + "SendPIOAvailAddr written as %lx, " + "read back as %llx\n", + (unsigned long) dd->ipath_pioavailregs_phys, + (unsigned long long) val); + ret = -EINVAL; + goto done; + } + + val = ipath_port0_rcvhdrtail_dma + dd->ipath_unit * 64; + + /* verify that the alignment requirement was met */ + ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdrtailaddr, + 0, val); + atmp = ipath_read_kreg64_port( + dd, dd->ipath_kregs->kr_rcvhdrtailaddr, 0); + if (val != atmp) { + ipath_dev_err(dd, "Catastrophic software error, " + "RcvHdrTailAddr0 written as %llx, " + "read back as %llx from %x\n", + (unsigned long long) val, + (unsigned long long) atmp, + dd->ipath_kregs->kr_rcvhdrtailaddr); + ret = -EINVAL; + goto done; + } + + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvbthqp, IPATH_KD_QP); + + /* + * make sure we are not in freeze, and PIO send enabled, so + * writes to pbc happen + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, 0ULL); + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, + ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED); + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + INFINIPATH_S_PIOENABLE); + + /* + * before error clears, since we expect serdes pll errors during + * this, the first time after reset + */ + if (bringup_link(dd)) { + dev_info(&dd->pcidev->dev, "Failed to bringup IB link\n"); + ret = -ENETDOWN; + goto done; + } + + /* + * clear any "expected" hwerrs from reset and/or initialization + * clear any that aren't enabled (at least this once), and then + * set the enable mask + */ + dd->ipath_f_init_hwerrors(dd); + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, + ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED); + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, + dd->ipath_hwerrmask); + + dd->ipath_maskederrs = dd->ipath_ignorederrs; + /* clear all */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, -1LL); + /* enable errors that are masked, at least this first time. */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, + ~dd->ipath_maskederrs); + /* clear any interrups up to this point (ints still not enabled) */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, -1LL); + + ipath_stats.sps_lid[dd->ipath_unit] = dd->ipath_lid; + + /* + * Set up the port 0 (kernel) rcvhdr q and egr TIDs. If doing + * re-init, the simplest way to handle this is to free + * existing, and re-allocate. + */ + if (reinit) + ipath_free_pddata(dd, 0, 0); + dd->ipath_f_tidtemplate(dd); + ret = ipath_create_rcvhdrq(dd, pd); + if (!ret) + ret = create_port0_egr(dd); + if (ret) + ipath_dev_err(dd, "failed to allocate port 0 (kernel) " + "rcvhdrq and/or egr bufs\n"); + else + enable_chip(dd, pd, reinit); + + /* + * cause retrigger of pending interrupts ignored during init, + * even if we had errors + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL); + + if(!dd->ipath_stats_timer_active) { + /* + * first init, or after an admin disable/enable + * set up stats retrieval timer, even if we had errors + * in last portion of setup + */ + init_timer(&dd->ipath_stats_timer); + dd->ipath_stats_timer.function = ipath_get_faststats; + dd->ipath_stats_timer.data = (unsigned long) dd; + /* every 5 seconds; */ + dd->ipath_stats_timer.expires = jiffies + 5 * HZ; + /* takes ~16 seconds to overflow at full IB 4x bandwdith */ + add_timer(&dd->ipath_stats_timer); + dd->ipath_stats_timer_active = 1; + } + +done: + if (!ret) { + ipath_get_guid(dd); + *dd->ipath_statusp |= IPATH_STATUS_CHIP_PRESENT; + if (!dd->ipath_f_intrsetup(dd)) { + /* now we can enable all interrupts from the chip */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, + -1LL); + /* force re-interrupt of any pending interrupts. */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, + 0ULL); + /* chip is usable; mark it as initialized */ + *dd->ipath_statusp |= IPATH_STATUS_INITTED; + } else + ipath_dev_err(dd, "No interrupts enabled, couldn't " + "setup interrupt address\n"); + + if (dd->ipath_cfgports > ipath_stats.sps_nports) + /* + * sps_nports is a global, so, we set it to + * the highest number of ports of any of the + * chips we find; we never decrement it, at + * least for now. Since this might have changed + * over disable/enable or prior to reset, always + * do the check and potentially adjust. + */ + ipath_stats.sps_nports = dd->ipath_cfgports; + } else + ipath_dbg("Failed (%d) to initialize chip\n", ret); + + /* if ret is non-zero, we probably should do some cleanup + here... */ + return ret; +} + +static int ipath_set_kpiobufs(const char *str, struct kernel_param *kp) +{ + struct ipath_devdata *dd; + unsigned long flags; + unsigned short val; + int ret; + + ret = ipath_parse_ushort(str, &val); + + spin_lock_irqsave(&ipath_devs_lock, flags); + + if (ret < 0) + goto bail; + + if (val == 0) { + ret = -EINVAL; + goto bail; + } + + list_for_each_entry(dd, &ipath_dev_list, ipath_list) { + if (dd->ipath_kregbase) + continue; + if (val > (dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - + (dd->ipath_cfgports * + IPATH_MIN_USER_PORT_BUFCNT))) + { + ipath_dev_err( + dd, + "Allocating %d PIO bufs for kernel leaves " + "too few for %d user ports (%d each)\n", + val, dd->ipath_cfgports - 1, + IPATH_MIN_USER_PORT_BUFCNT); + ret = -EINVAL; + goto bail; + } + dd->ipath_lastport_piobuf = + dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - val; + } + + ret = 0; +bail: + spin_unlock_irqrestore(&ipath_devs_lock, flags); + + return ret; +} diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c new file mode 100644 index 000000000000..60f5f4108069 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -0,0 +1,841 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "ipath_kernel.h" +#include "ips_common.h" +#include "ipath_layer.h" + +#define E_SUM_PKTERRS \ + (INFINIPATH_E_RHDRLEN | INFINIPATH_E_RBADTID | \ + INFINIPATH_E_RBADVERSION | INFINIPATH_E_RHDR | \ + INFINIPATH_E_RLONGPKTLEN | INFINIPATH_E_RSHORTPKTLEN | \ + INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RMINPKTLEN | \ + INFINIPATH_E_RFORMATERR | INFINIPATH_E_RUNSUPVL | \ + INFINIPATH_E_RUNEXPCHAR | INFINIPATH_E_REBP) + +#define E_SUM_ERRS \ + (INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | \ + INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \ + INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SUNSUPVL | \ + INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \ + INFINIPATH_E_INVALIDADDR) + +static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs) +{ + unsigned long sbuf[4]; + u64 ignore_this_time = 0; + u32 piobcnt; + + /* if possible that sendbuffererror could be valid */ + piobcnt = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k; + /* read these before writing errorclear */ + sbuf[0] = ipath_read_kreg64( + dd, dd->ipath_kregs->kr_sendbuffererror); + sbuf[1] = ipath_read_kreg64( + dd, dd->ipath_kregs->kr_sendbuffererror + 1); + if (piobcnt > 128) { + sbuf[2] = ipath_read_kreg64( + dd, dd->ipath_kregs->kr_sendbuffererror + 2); + sbuf[3] = ipath_read_kreg64( + dd, dd->ipath_kregs->kr_sendbuffererror + 3); + } + + if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) { + int i; + + ipath_cdbg(PKT, "SendbufErrs %lx %lx ", sbuf[0], sbuf[1]); + if (ipath_debug & __IPATH_PKTDBG && piobcnt > 128) + printk("%lx %lx ", sbuf[2], sbuf[3]); + for (i = 0; i < piobcnt; i++) { + if (test_bit(i, sbuf)) { + u32 __iomem *piobuf; + if (i < dd->ipath_piobcnt2k) + piobuf = (u32 __iomem *) + (dd->ipath_pio2kbase + + i * dd->ipath_palign); + else + piobuf = (u32 __iomem *) + (dd->ipath_pio4kbase + + (i - dd->ipath_piobcnt2k) * + dd->ipath_4kalign); + + ipath_cdbg(PKT, + "PIObuf[%u] @%p pbc is %x; ", + i, piobuf, readl(piobuf)); + + ipath_disarm_piobufs(dd, i, 1); + } + } + if (ipath_debug & __IPATH_PKTDBG) + printk("\n"); + } + if ((errs & (INFINIPATH_E_SDROPPEDDATAPKT | + INFINIPATH_E_SDROPPEDSMPPKT | + INFINIPATH_E_SMINPKTLEN)) && + !(dd->ipath_flags & IPATH_LINKACTIVE)) { + /* + * This can happen when SMA is trying to bring the link + * up, but the IB link changes state at the "wrong" time. + * The IB logic then complains that the packet isn't + * valid. We don't want to confuse people, so we just + * don't print them, except at debug + */ + ipath_dbg("Ignoring pktsend errors %llx, because not " + "yet active\n", (unsigned long long) errs); + ignore_this_time = INFINIPATH_E_SDROPPEDDATAPKT | + INFINIPATH_E_SDROPPEDSMPPKT | + INFINIPATH_E_SMINPKTLEN; + } + + return ignore_this_time; +} + +/* return the strings for the most common link states */ +static char *ib_linkstate(u32 linkstate) +{ + char *ret; + + switch (linkstate) { + case IPATH_IBSTATE_INIT: + ret = "Init"; + break; + case IPATH_IBSTATE_ARM: + ret = "Arm"; + break; + case IPATH_IBSTATE_ACTIVE: + ret = "Active"; + break; + default: + ret = "Down"; + } + + return ret; +} + +static void handle_e_ibstatuschanged(struct ipath_devdata *dd, + ipath_err_t errs, int noprint) +{ + u64 val; + u32 ltstate, lstate; + + /* + * even if diags are enabled, we want to notice LINKINIT, etc. + * We just don't want to change the LED state, or + * dd->ipath_kregs->kr_ibcctrl + */ + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus); + lstate = val & IPATH_IBSTATE_MASK; + if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM || + lstate == IPATH_IBSTATE_ACTIVE) { + /* + * only print at SMA if there is a change, debug if not + * (sometimes we want to know that, usually not). + */ + if (lstate == ((unsigned) dd->ipath_lastibcstat + & IPATH_IBSTATE_MASK)) { + ipath_dbg("Status change intr but no change (%s)\n", + ib_linkstate(lstate)); + } + else + ipath_cdbg(SMA, "Unit %u link state %s, last " + "was %s\n", dd->ipath_unit, + ib_linkstate(lstate), + ib_linkstate((unsigned) + dd->ipath_lastibcstat + & IPATH_IBSTATE_MASK)); + } + else { + lstate = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK; + if (lstate == IPATH_IBSTATE_INIT || + lstate == IPATH_IBSTATE_ARM || + lstate == IPATH_IBSTATE_ACTIVE) + ipath_cdbg(SMA, "Unit %u link state down" + " (state 0x%x), from %s\n", + dd->ipath_unit, + (u32)val & IPATH_IBSTATE_MASK, + ib_linkstate(lstate)); + else + ipath_cdbg(VERBOSE, "Unit %u link state changed " + "to 0x%x from down (%x)\n", + dd->ipath_unit, (u32) val, lstate); + } + ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & + INFINIPATH_IBCS_LINKTRAININGSTATE_MASK; + lstate = (val >> INFINIPATH_IBCS_LINKSTATE_SHIFT) & + INFINIPATH_IBCS_LINKSTATE_MASK; + + if (ltstate == INFINIPATH_IBCS_LT_STATE_POLLACTIVE || + ltstate == INFINIPATH_IBCS_LT_STATE_POLLQUIET) { + u32 last_ltstate; + + /* + * Ignore cycling back and forth from Polling.Active + * to Polling.Quiet while waiting for the other end of + * the link to come up. We will cycle back and forth + * between them if no cable is plugged in, + * the other device is powered off or disabled, etc. + */ + last_ltstate = (dd->ipath_lastibcstat >> + INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) + & INFINIPATH_IBCS_LINKTRAININGSTATE_MASK; + if (last_ltstate == INFINIPATH_IBCS_LT_STATE_POLLACTIVE + || last_ltstate == + INFINIPATH_IBCS_LT_STATE_POLLQUIET) { + if (dd->ipath_ibpollcnt > 40) { + dd->ipath_flags |= IPATH_NOCABLE; + *dd->ipath_statusp |= + IPATH_STATUS_IB_NOCABLE; + } else + dd->ipath_ibpollcnt++; + goto skip_ibchange; + } + } + dd->ipath_ibpollcnt = 0; /* some state other than 2 or 3 */ + ipath_stats.sps_iblink++; + if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) { + dd->ipath_flags |= IPATH_LINKDOWN; + dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT + | IPATH_LINKACTIVE | + IPATH_LINKARMED); + *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; + if (!noprint) { + if (((dd->ipath_lastibcstat >> + INFINIPATH_IBCS_LINKSTATE_SHIFT) & + INFINIPATH_IBCS_LINKSTATE_MASK) + == INFINIPATH_IBCS_L_STATE_ACTIVE) + /* if from up to down be more vocal */ + ipath_cdbg(SMA, + "Unit %u link now down (%s)\n", + dd->ipath_unit, + ipath_ibcstatus_str[ltstate]); + else + ipath_cdbg(VERBOSE, "Unit %u link is " + "down (%s)\n", dd->ipath_unit, + ipath_ibcstatus_str[ltstate]); + } + + dd->ipath_f_setextled(dd, lstate, ltstate); + } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ACTIVE) { + dd->ipath_flags |= IPATH_LINKACTIVE; + dd->ipath_flags &= + ~(IPATH_LINKUNK | IPATH_LINKINIT | IPATH_LINKDOWN | + IPATH_LINKARMED | IPATH_NOCABLE); + *dd->ipath_statusp &= ~IPATH_STATUS_IB_NOCABLE; + *dd->ipath_statusp |= + IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF; + dd->ipath_f_setextled(dd, lstate, ltstate); + + __ipath_layer_intr(dd, IPATH_LAYER_INT_IF_UP); + } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) { + /* + * set INIT and DOWN. Down is checked by most of the other + * code, but INIT is useful to know in a few places. + */ + dd->ipath_flags |= IPATH_LINKINIT | IPATH_LINKDOWN; + dd->ipath_flags &= + ~(IPATH_LINKUNK | IPATH_LINKACTIVE | IPATH_LINKARMED + | IPATH_NOCABLE); + *dd->ipath_statusp &= ~(IPATH_STATUS_IB_NOCABLE + | IPATH_STATUS_IB_READY); + dd->ipath_f_setextled(dd, lstate, ltstate); + } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) { + dd->ipath_flags |= IPATH_LINKARMED; + dd->ipath_flags &= + ~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT | + IPATH_LINKACTIVE | IPATH_NOCABLE); + *dd->ipath_statusp &= ~(IPATH_STATUS_IB_NOCABLE + | IPATH_STATUS_IB_READY); + dd->ipath_f_setextled(dd, lstate, ltstate); + } else { + if (!noprint) + ipath_dbg("IBstatuschange unit %u: %s (%x)\n", + dd->ipath_unit, + ipath_ibcstatus_str[ltstate], ltstate); + } +skip_ibchange: + dd->ipath_lastibcstat = val; +} + +static void handle_supp_msgs(struct ipath_devdata *dd, + unsigned supp_msgs, char msg[512]) +{ + /* + * Print the message unless it's ibc status change only, which + * happens so often we never want to count it. + */ + if (dd->ipath_lasterror & ~INFINIPATH_E_IBSTATUSCHANGED) { + ipath_decode_err(msg, sizeof msg, dd->ipath_lasterror & + ~INFINIPATH_E_IBSTATUSCHANGED); + if (dd->ipath_lasterror & + ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL)) + ipath_dev_err(dd, "Suppressed %u messages for " + "fast-repeating errors (%s) (%llx)\n", + supp_msgs, msg, + (unsigned long long) + dd->ipath_lasterror); + else { + /* + * rcvegrfull and rcvhdrqfull are "normal", for some + * types of processes (mostly benchmarks) that send + * huge numbers of messages, while not processing + * them. So only complain about these at debug + * level. + */ + ipath_dbg("Suppressed %u messages for %s\n", + supp_msgs, msg); + } + } +} + +static unsigned handle_frequent_errors(struct ipath_devdata *dd, + ipath_err_t errs, char msg[512], + int *noprint) +{ + unsigned long nc; + static unsigned long nextmsg_time; + static unsigned nmsgs, supp_msgs; + + /* + * Throttle back "fast" messages to no more than 10 per 5 seconds. + * This isn't perfect, but it's a reasonable heuristic. If we get + * more than 10, give a 6x longer delay. + */ + nc = jiffies; + if (nmsgs > 10) { + if (time_before(nc, nextmsg_time)) { + *noprint = 1; + if (!supp_msgs++) + nextmsg_time = nc + HZ * 3; + } + else if (supp_msgs) { + handle_supp_msgs(dd, supp_msgs, msg); + supp_msgs = 0; + nmsgs = 0; + } + } + else if (!nmsgs++ || time_after(nc, nextmsg_time)) + nextmsg_time = nc + HZ / 2; + + return supp_msgs; +} + +static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs) +{ + char msg[512]; + u64 ignore_this_time = 0; + int i; + int chkerrpkts = 0, noprint = 0; + unsigned supp_msgs; + + supp_msgs = handle_frequent_errors(dd, errs, msg, &noprint); + + /* + * don't report errors that are masked (includes those always + * ignored) + */ + errs &= ~dd->ipath_maskederrs; + + /* do these first, they are most important */ + if (errs & INFINIPATH_E_HARDWARE) { + /* reuse same msg buf */ + dd->ipath_f_handle_hwerrors(dd, msg, sizeof msg); + } + + if (!noprint && (errs & ~infinipath_e_bitsextant)) + ipath_dev_err(dd, "error interrupt with unknown errors " + "%llx set\n", (unsigned long long) + (errs & ~infinipath_e_bitsextant)); + + if (errs & E_SUM_ERRS) + ignore_this_time = handle_e_sum_errs(dd, errs); + + if (supp_msgs == 250000) { + /* + * It's not entirely reasonable assuming that the errors set + * in the last clear period are all responsible for the + * problem, but the alternative is to assume it's the only + * ones on this particular interrupt, which also isn't great + */ + dd->ipath_maskederrs |= dd->ipath_lasterror | errs; + ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, + ~dd->ipath_maskederrs); + ipath_decode_err(msg, sizeof msg, + (dd->ipath_maskederrs & ~dd-> + ipath_ignorederrs)); + + if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) & + ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL)) + ipath_dev_err(dd, "Disabling error(s) %llx because " + "occuring too frequently (%s)\n", + (unsigned long long) + (dd->ipath_maskederrs & + ~dd->ipath_ignorederrs), msg); + else { + /* + * rcvegrfull and rcvhdrqfull are "normal", + * for some types of processes (mostly benchmarks) + * that send huge numbers of messages, while not + * processing them. So only complain about + * these at debug level. + */ + ipath_dbg("Disabling frequent queue full errors " + "(%s)\n", msg); + } + + /* + * Re-enable the masked errors after around 3 minutes. in + * ipath_get_faststats(). If we have a series of fast + * repeating but different errors, the interval will keep + * stretching out, but that's OK, as that's pretty + * catastrophic. + */ + dd->ipath_unmasktime = jiffies + HZ * 180; + } + + ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, errs); + if (ignore_this_time) + errs &= ~ignore_this_time; + if (errs & ~dd->ipath_lasterror) { + errs &= ~dd->ipath_lasterror; + /* never suppress duplicate hwerrors or ibstatuschange */ + dd->ipath_lasterror |= errs & + ~(INFINIPATH_E_HARDWARE | + INFINIPATH_E_IBSTATUSCHANGED); + } + if (!errs) + return; + + if (!noprint) + /* + * the ones we mask off are handled specially below or above + */ + ipath_decode_err(msg, sizeof msg, + errs & ~(INFINIPATH_E_IBSTATUSCHANGED | + INFINIPATH_E_RRCVEGRFULL | + INFINIPATH_E_RRCVHDRFULL | + INFINIPATH_E_HARDWARE)); + else + /* so we don't need if (!noprint) at strlcat's below */ + *msg = 0; + + if (errs & E_SUM_PKTERRS) { + ipath_stats.sps_pkterrs++; + chkerrpkts = 1; + } + if (errs & E_SUM_ERRS) + ipath_stats.sps_errs++; + + if (errs & (INFINIPATH_E_RICRC | INFINIPATH_E_RVCRC)) { + ipath_stats.sps_crcerrs++; + chkerrpkts = 1; + } + + /* + * We don't want to print these two as they happen, or we can make + * the situation even worse, because it takes so long to print + * messages to serial consoles. Kernel ports get printed from + * fast_stats, no more than every 5 seconds, user ports get printed + * on close + */ + if (errs & INFINIPATH_E_RRCVHDRFULL) { + int any; + u32 hd, tl; + ipath_stats.sps_hdrqfull++; + for (any = i = 0; i < dd->ipath_cfgports; i++) { + struct ipath_portdata *pd = dd->ipath_pd[i]; + if (i == 0) { + hd = dd->ipath_port0head; + tl = (u32) le64_to_cpu( + *dd->ipath_hdrqtailptr); + } else if (pd && pd->port_cnt && + pd->port_rcvhdrtail_kvaddr) { + /* + * don't report same point multiple times, + * except kernel + */ + tl = (u32) * pd->port_rcvhdrtail_kvaddr; + if (tl == dd->ipath_lastrcvhdrqtails[i]) + continue; + hd = ipath_read_ureg32(dd, ur_rcvhdrhead, + i); + } else + continue; + if (hd == (tl + 1) || + (!hd && tl == dd->ipath_hdrqlast)) { + dd->ipath_lastrcvhdrqtails[i] = tl; + pd->port_hdrqfull++; + if (i == 0) + chkerrpkts = 1; + } + } + } + if (errs & INFINIPATH_E_RRCVEGRFULL) { + /* + * since this is of less importance and not likely to + * happen without also getting hdrfull, only count + * occurrences; don't check each port (or even the kernel + * vs user) + */ + ipath_stats.sps_etidfull++; + if (dd->ipath_port0head != + (u32) le64_to_cpu(*dd->ipath_hdrqtailptr)) + chkerrpkts = 1; + } + + /* + * do this before IBSTATUSCHANGED, in case both bits set in a single + * interrupt; we want the STATUSCHANGE to "win", so we do our + * internal copy of state machine correctly + */ + if (errs & INFINIPATH_E_RIBLOSTLINK) { + /* + * force through block below + */ + errs |= INFINIPATH_E_IBSTATUSCHANGED; + ipath_stats.sps_iblink++; + dd->ipath_flags |= IPATH_LINKDOWN; + dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT + | IPATH_LINKARMED | IPATH_LINKACTIVE); + *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; + if (!noprint) { + u64 st = ipath_read_kreg64( + dd, dd->ipath_kregs->kr_ibcstatus); + + ipath_dbg("Lost link, link now down (%s)\n", + ipath_ibcstatus_str[st & 0xf]); + } + } + if (errs & INFINIPATH_E_IBSTATUSCHANGED) + handle_e_ibstatuschanged(dd, errs, noprint); + + if (errs & INFINIPATH_E_RESET) { + if (!noprint) + ipath_dev_err(dd, "Got reset, requires re-init " + "(unload and reload driver)\n"); + dd->ipath_flags &= ~IPATH_INITTED; /* needs re-init */ + /* mark as having had error */ + *dd->ipath_statusp |= IPATH_STATUS_HWERROR; + *dd->ipath_statusp &= ~IPATH_STATUS_IB_CONF; + } + + if (!noprint && *msg) + ipath_dev_err(dd, "%s error\n", msg); + if (dd->ipath_sma_state_wanted & dd->ipath_flags) { + ipath_cdbg(VERBOSE, "sma wanted state %x, iflags now %x, " + "waking\n", dd->ipath_sma_state_wanted, + dd->ipath_flags); + wake_up_interruptible(&ipath_sma_state_wait); + } + + if (chkerrpkts) + /* process possible error packets in hdrq */ + ipath_kreceive(dd); +} + +/* this is separate to allow for better optimization of ipath_intr() */ + +static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp) +{ + /* + * sometimes happen during driver init and unload, don't want + * to process any interrupts at that point + */ + + /* this is just a bandaid, not a fix, if something goes badly + * wrong */ + if (++*unexpectp > 100) { + if (++*unexpectp > 105) { + /* + * ok, we must be taking somebody else's interrupts, + * due to a messed up mptable and/or PIRQ table, so + * unregister the interrupt. We've seen this during + * linuxbios development work, and it may happen in + * the future again. + */ + if (dd->pcidev && dd->pcidev->irq) { + ipath_dev_err(dd, "Now %u unexpected " + "interrupts, unregistering " + "interrupt handler\n", + *unexpectp); + ipath_dbg("free_irq of irq %x\n", + dd->pcidev->irq); + free_irq(dd->pcidev->irq, dd); + } + } + if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) { + ipath_dev_err(dd, "%u unexpected interrupts, " + "disabling interrupts completely\n", + *unexpectp); + /* + * disable all interrupts, something is very wrong + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, + 0ULL); + } + } else if (*unexpectp > 1) + ipath_dbg("Interrupt when not ready, should not happen, " + "ignoring\n"); +} + +static void ipath_bad_regread(struct ipath_devdata *dd) +{ + static int allbits; + + /* separate routine, for better optimization of ipath_intr() */ + + /* + * We print the message and disable interrupts, in hope of + * having a better chance of debugging the problem. + */ + ipath_dev_err(dd, + "Read of interrupt status failed (all bits set)\n"); + if (allbits++) { + /* disable all interrupts, something is very wrong */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL); + if (allbits == 2) { + ipath_dev_err(dd, "Still bad interrupt status, " + "unregistering interrupt\n"); + free_irq(dd->pcidev->irq, dd); + } else if (allbits > 2) { + if ((allbits % 10000) == 0) + printk("."); + } else + ipath_dev_err(dd, "Disabling interrupts, " + "multiple errors\n"); + } +} + +static void handle_port_pioavail(struct ipath_devdata *dd) +{ + u32 i; + /* + * start from port 1, since for now port 0 is never using + * wait_event for PIO + */ + for (i = 1; dd->ipath_portpiowait && i < dd->ipath_cfgports; i++) { + struct ipath_portdata *pd = dd->ipath_pd[i]; + + if (pd && pd->port_cnt && + dd->ipath_portpiowait & (1U << i)) { + clear_bit(i, &dd->ipath_portpiowait); + if (test_bit(IPATH_PORT_WAITING_PIO, + &pd->port_flag)) { + clear_bit(IPATH_PORT_WAITING_PIO, + &pd->port_flag); + wake_up_interruptible(&pd->port_wait); + } + } + } +} + +static void handle_layer_pioavail(struct ipath_devdata *dd) +{ + int ret; + + ret = __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE); + if (ret > 0) + goto clear; + + ret = __ipath_verbs_piobufavail(dd); + if (ret > 0) + goto clear; + + return; +clear: + set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + dd->ipath_sendctrl); +} + +static void handle_rcv(struct ipath_devdata *dd, u32 istat) +{ + u64 portr; + int i; + int rcvdint = 0; + + portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) & + infinipath_i_rcvavail_mask) + | ((istat >> INFINIPATH_I_RCVURG_SHIFT) & + infinipath_i_rcvurg_mask); + for (i = 0; i < dd->ipath_cfgports; i++) { + struct ipath_portdata *pd = dd->ipath_pd[i]; + if (portr & (1 << i) && pd && + pd->port_cnt) { + if (i == 0) + ipath_kreceive(dd); + else if (test_bit(IPATH_PORT_WAITING_RCV, + &pd->port_flag)) { + int rcbit; + clear_bit(IPATH_PORT_WAITING_RCV, + &pd->port_flag); + rcbit = i + INFINIPATH_R_INTRAVAIL_SHIFT; + clear_bit(1UL << rcbit, &dd->ipath_rcvctrl); + wake_up_interruptible(&pd->port_wait); + rcvdint = 1; + } + } + } + if (rcvdint) { + /* only want to take one interrupt, so turn off the rcv + * interrupt for all the ports that we did the wakeup on + * (but never for kernel port) + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, + dd->ipath_rcvctrl); + } +} + +irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs) +{ + struct ipath_devdata *dd = data; + u32 istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus); + ipath_err_t estat = 0; + static unsigned unexpected = 0; + irqreturn_t ret; + + if (unlikely(!istat)) { + ipath_stats.sps_nullintr++; + ret = IRQ_NONE; /* not our interrupt, or already handled */ + goto bail; + } + if (unlikely(istat == -1)) { + ipath_bad_regread(dd); + /* don't know if it was our interrupt or not */ + ret = IRQ_NONE; + goto bail; + } + + ipath_stats.sps_ints++; + + /* + * this needs to be flags&initted, not statusp, so we keep + * taking interrupts even after link goes down, etc. + * Also, we *must* clear the interrupt at some point, or we won't + * take it again, which can be real bad for errors, etc... + */ + + if (!(dd->ipath_flags & IPATH_INITTED)) { + ipath_bad_intr(dd, &unexpected); + ret = IRQ_NONE; + goto bail; + } + if (unexpected) + unexpected = 0; + + ipath_cdbg(VERBOSE, "intr stat=0x%x\n", istat); + + if (istat & ~infinipath_i_bitsextant) + ipath_dev_err(dd, + "interrupt with unknown interrupts %x set\n", + istat & (u32) ~ infinipath_i_bitsextant); + + if (istat & INFINIPATH_I_ERROR) { + ipath_stats.sps_errints++; + estat = ipath_read_kreg64(dd, + dd->ipath_kregs->kr_errorstatus); + if (!estat) + dev_info(&dd->pcidev->dev, "error interrupt (%x), " + "but no error bits set!\n", istat); + else if (estat == -1LL) + /* + * should we try clearing all, or hope next read + * works? + */ + ipath_dev_err(dd, "Read of error status failed " + "(all bits set); ignoring\n"); + else + handle_errors(dd, estat); + } + + if (istat & INFINIPATH_I_GPIO) { + if (unlikely(!(dd->ipath_flags & IPATH_GPIO_INTR))) { + u32 gpiostatus; + gpiostatus = ipath_read_kreg32( + dd, dd->ipath_kregs->kr_gpio_status); + ipath_dbg("Unexpected GPIO interrupt bits %x\n", + gpiostatus); + ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear, + gpiostatus); + } + else { + /* Clear GPIO status bit 2 */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear, + (u64) (1 << 2)); + + /* + * Packets are available in the port 0 rcv queue. + * Eventually this needs to be generalized to check + * IPATH_GPIO_INTR, and the specific GPIO bit, if + * GPIO interrupts are used for anything else. + */ + ipath_kreceive(dd); + } + } + + /* + * clear the ones we will deal with on this round + * We clear it early, mostly for receive interrupts, so we + * know the chip will have seen this by the time we process + * the queue, and will re-interrupt if necessary. The processor + * itself won't take the interrupt again until we return. + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat); + + if (istat & INFINIPATH_I_SPIOBUFAVAIL) { + clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + dd->ipath_sendctrl); + + if (dd->ipath_portpiowait) + handle_port_pioavail(dd); + + handle_layer_pioavail(dd); + } + + /* + * we check for both transition from empty to non-empty, and urgent + * packets (those with the interrupt bit set in the header) + */ + + if (istat & ((infinipath_i_rcvavail_mask << + INFINIPATH_I_RCVAVAIL_SHIFT) + | (infinipath_i_rcvurg_mask << + INFINIPATH_I_RCVURG_SHIFT))) + handle_rcv(dd, istat); + + ret = IRQ_HANDLED; + +bail: + return ret; +} diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h new file mode 100644 index 000000000000..159d0aed31a5 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -0,0 +1,884 @@ +#ifndef _IPATH_KERNEL_H +#define _IPATH_KERNEL_H +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This header file is the base header file for infinipath kernel code + * ipath_user.h serves a similar purpose for user code. + */ + +#include +#include + +#include "ipath_common.h" +#include "ipath_debug.h" +#include "ipath_registers.h" + +/* only s/w major version of InfiniPath we can handle */ +#define IPATH_CHIP_VERS_MAJ 2U + +/* don't care about this except printing */ +#define IPATH_CHIP_VERS_MIN 0U + +/* temporary, maybe always */ +extern struct infinipath_stats ipath_stats; + +#define IPATH_CHIP_SWVERSION IPATH_CHIP_VERS_MAJ + +struct ipath_portdata { + void **port_rcvegrbuf; + dma_addr_t *port_rcvegrbuf_phys; + /* rcvhdrq base, needs mmap before useful */ + void *port_rcvhdrq; + /* kernel virtual address where hdrqtail is updated */ + u64 *port_rcvhdrtail_kvaddr; + /* page * used for uaddr */ + struct page *port_rcvhdrtail_pagep; + /* + * temp buffer for expected send setup, allocated at open, instead + * of each setup call + */ + void *port_tid_pg_list; + /* when waiting for rcv or pioavail */ + wait_queue_head_t port_wait; + /* + * rcvegr bufs base, physical, must fit + * in 44 bits so 32 bit programs mmap64 44 bit works) + */ + dma_addr_t port_rcvegr_phys; + /* mmap of hdrq, must fit in 44 bits */ + dma_addr_t port_rcvhdrq_phys; + /* + * the actual user address that we ipath_mlock'ed, so we can + * ipath_munlock it at close + */ + unsigned long port_rcvhdrtail_uaddr; + /* + * number of opens on this instance (0 or 1; ignoring forks, dup, + * etc. for now) + */ + int port_cnt; + /* + * how much space to leave at start of eager TID entries for + * protocol use, on each TID + */ + /* instead of calculating it */ + unsigned port_port; + /* chip offset of PIO buffers for this port */ + u32 port_piobufs; + /* how many alloc_pages() chunks in port_rcvegrbuf_pages */ + u32 port_rcvegrbuf_chunks; + /* how many egrbufs per chunk */ + u32 port_rcvegrbufs_perchunk; + /* order for port_rcvegrbuf_pages */ + size_t port_rcvegrbuf_size; + /* rcvhdrq size (for freeing) */ + size_t port_rcvhdrq_size; + /* next expected TID to check when looking for free */ + u32 port_tidcursor; + /* next expected TID to check */ + unsigned long port_flag; + /* WAIT_RCV that timed out, no interrupt */ + u32 port_rcvwait_to; + /* WAIT_PIO that timed out, no interrupt */ + u32 port_piowait_to; + /* WAIT_RCV already happened, no wait */ + u32 port_rcvnowait; + /* WAIT_PIO already happened, no wait */ + u32 port_pionowait; + /* total number of rcvhdrqfull errors */ + u32 port_hdrqfull; + /* pid of process using this port */ + pid_t port_pid; + /* same size as task_struct .comm[] */ + char port_comm[16]; + /* pkeys set by this use of this port */ + u16 port_pkeys[4]; + /* so file ops can get at unit */ + struct ipath_devdata *port_dd; +}; + +struct sk_buff; + +/* + * control information for layered drivers + */ +struct _ipath_layer { + void *l_arg; +}; + +/* Verbs layer interface */ +struct _verbs_layer { + void *l_arg; + struct timer_list l_timer; +}; + +struct ipath_devdata { + struct list_head ipath_list; + + struct ipath_kregs const *ipath_kregs; + struct ipath_cregs const *ipath_cregs; + + /* mem-mapped pointer to base of chip regs */ + u64 __iomem *ipath_kregbase; + /* end of mem-mapped chip space; range checking */ + u64 __iomem *ipath_kregend; + /* physical address of chip for io_remap, etc. */ + unsigned long ipath_physaddr; + /* base of memory alloced for ipath_kregbase, for free */ + u64 *ipath_kregalloc; + /* + * version of kregbase that doesn't have high bits set (for 32 bit + * programs, so mmap64 44 bit works) + */ + u64 __iomem *ipath_kregvirt; + /* + * virtual address where port0 rcvhdrqtail updated for this unit. + * only written to by the chip, not the driver. + */ + volatile __le64 *ipath_hdrqtailptr; + dma_addr_t ipath_dma_addr; + /* ipath_cfgports pointers */ + struct ipath_portdata **ipath_pd; + /* sk_buffs used by port 0 eager receive queue */ + struct sk_buff **ipath_port0_skbs; + /* kvirt address of 1st 2k pio buffer */ + void __iomem *ipath_pio2kbase; + /* kvirt address of 1st 4k pio buffer */ + void __iomem *ipath_pio4kbase; + /* + * points to area where PIOavail registers will be DMA'ed. + * Has to be on a page of it's own, because the page will be + * mapped into user program space. This copy is *ONLY* ever + * written by DMA, not by the driver! Need a copy per device + * when we get to multiple devices + */ + volatile __le64 *ipath_pioavailregs_dma; + /* physical address where updates occur */ + dma_addr_t ipath_pioavailregs_phys; + struct _ipath_layer ipath_layer; + /* setup intr */ + int (*ipath_f_intrsetup)(struct ipath_devdata *); + /* setup on-chip bus config */ + int (*ipath_f_bus)(struct ipath_devdata *, struct pci_dev *); + /* hard reset chip */ + int (*ipath_f_reset)(struct ipath_devdata *); + int (*ipath_f_get_boardname)(struct ipath_devdata *, char *, + size_t); + void (*ipath_f_init_hwerrors)(struct ipath_devdata *); + void (*ipath_f_handle_hwerrors)(struct ipath_devdata *, char *, + size_t); + void (*ipath_f_quiet_serdes)(struct ipath_devdata *); + int (*ipath_f_bringup_serdes)(struct ipath_devdata *); + int (*ipath_f_early_init)(struct ipath_devdata *); + void (*ipath_f_clear_tids)(struct ipath_devdata *, unsigned); + void (*ipath_f_put_tid)(struct ipath_devdata *, u64 __iomem*, + u32, unsigned long); + void (*ipath_f_tidtemplate)(struct ipath_devdata *); + void (*ipath_f_cleanup)(struct ipath_devdata *); + void (*ipath_f_setextled)(struct ipath_devdata *, u64, u64); + /* fill out chip-specific fields */ + int (*ipath_f_get_base_info)(struct ipath_portdata *, void *); + struct _verbs_layer verbs_layer; + /* total dwords sent (summed from counter) */ + u64 ipath_sword; + /* total dwords rcvd (summed from counter) */ + u64 ipath_rword; + /* total packets sent (summed from counter) */ + u64 ipath_spkts; + /* total packets rcvd (summed from counter) */ + u64 ipath_rpkts; + /* ipath_statusp initially points to this. */ + u64 _ipath_status; + /* GUID for this interface, in network order */ + __be64 ipath_guid; + /* + * aggregrate of error bits reported since last cleared, for + * limiting of error reporting + */ + ipath_err_t ipath_lasterror; + /* + * aggregrate of error bits reported since last cleared, for + * limiting of hwerror reporting + */ + ipath_err_t ipath_lasthwerror; + /* + * errors masked because they occur too fast, also includes errors + * that are always ignored (ipath_ignorederrs) + */ + ipath_err_t ipath_maskederrs; + /* time in jiffies at which to re-enable maskederrs */ + unsigned long ipath_unmasktime; + /* + * errors always ignored (masked), at least for a given + * chip/device, because they are wrong or not useful + */ + ipath_err_t ipath_ignorederrs; + /* count of egrfull errors, combined for all ports */ + u64 ipath_last_tidfull; + /* for ipath_qcheck() */ + u64 ipath_lastport0rcv_cnt; + /* template for writing TIDs */ + u64 ipath_tidtemplate; + /* value to write to free TIDs */ + u64 ipath_tidinvalid; + /* PE-800 rcv interrupt setup */ + u64 ipath_rhdrhead_intr_off; + + /* size of memory at ipath_kregbase */ + u32 ipath_kregsize; + /* number of registers used for pioavail */ + u32 ipath_pioavregs; + /* IPATH_POLL, etc. */ + u32 ipath_flags; + /* ipath_flags sma is waiting for */ + u32 ipath_sma_state_wanted; + /* last buffer for user use, first buf for kernel use is this + * index. */ + u32 ipath_lastport_piobuf; + /* is a stats timer active */ + u32 ipath_stats_timer_active; + /* dwords sent read from counter */ + u32 ipath_lastsword; + /* dwords received read from counter */ + u32 ipath_lastrword; + /* sent packets read from counter */ + u32 ipath_lastspkts; + /* received packets read from counter */ + u32 ipath_lastrpkts; + /* pio bufs allocated per port */ + u32 ipath_pbufsport; + /* + * number of ports configured as max; zero is set to number chip + * supports, less gives more pio bufs/port, etc. + */ + u32 ipath_cfgports; + /* port0 rcvhdrq head offset */ + u32 ipath_port0head; + /* count of port 0 hdrqfull errors */ + u32 ipath_p0_hdrqfull; + + /* + * (*cfgports) used to suppress multiple instances of same + * port staying stuck at same point + */ + u32 *ipath_lastrcvhdrqtails; + /* + * (*cfgports) used to suppress multiple instances of same + * port staying stuck at same point + */ + u32 *ipath_lastegrheads; + /* + * index of last piobuffer we used. Speeds up searching, by + * starting at this point. Doesn't matter if multiple cpu's use and + * update, last updater is only write that matters. Whenever it + * wraps, we update shadow copies. Need a copy per device when we + * get to multiple devices + */ + u32 ipath_lastpioindex; + /* max length of freezemsg */ + u32 ipath_freezelen; + /* + * consecutive times we wanted a PIO buffer but were unable to + * get one + */ + u32 ipath_consec_nopiobuf; + /* + * hint that we should update ipath_pioavailshadow before + * looking for a PIO buffer + */ + u32 ipath_upd_pio_shadow; + /* so we can rewrite it after a chip reset */ + u32 ipath_pcibar0; + /* so we can rewrite it after a chip reset */ + u32 ipath_pcibar1; + /* sequential tries for SMA send and no bufs */ + u32 ipath_nosma_bufs; + /* duration (seconds) ipath_nosma_bufs set */ + u32 ipath_nosma_secs; + + /* HT/PCI Vendor ID (here for NodeInfo) */ + u16 ipath_vendorid; + /* HT/PCI Device ID (here for NodeInfo) */ + u16 ipath_deviceid; + /* offset in HT config space of slave/primary interface block */ + u8 ipath_ht_slave_off; + /* for write combining settings */ + unsigned long ipath_wc_cookie; + /* ref count for each pkey */ + atomic_t ipath_pkeyrefs[4]; + /* shadow copy of all exptids physaddr; used only by funcsim */ + u64 *ipath_tidsimshadow; + /* shadow copy of struct page *'s for exp tid pages */ + struct page **ipath_pageshadow; + /* lock to workaround chip bug 9437 */ + spinlock_t ipath_tid_lock; + + /* + * IPATH_STATUS_*, + * this address is mapped readonly into user processes so they can + * get status cheaply, whenever they want. + */ + u64 *ipath_statusp; + /* freeze msg if hw error put chip in freeze */ + char *ipath_freezemsg; + /* pci access data structure */ + struct pci_dev *pcidev; + struct cdev *cdev; + struct class_device *class_dev; + /* timer used to prevent stats overflow, error throttling, etc. */ + struct timer_list ipath_stats_timer; + /* check for stale messages in rcv queue */ + /* only allow one intr at a time. */ + unsigned long ipath_rcv_pending; + + /* + * Shadow copies of registers; size indicates read access size. + * Most of them are readonly, but some are write-only register, + * where we manipulate the bits in the shadow copy, and then write + * the shadow copy to infinipath. + * + * We deliberately make most of these 32 bits, since they have + * restricted range. For any that we read, we won't to generate 32 + * bit accesses, since Opteron will generate 2 separate 32 bit HT + * transactions for a 64 bit read, and we want to avoid unnecessary + * HT transactions. + */ + + /* This is the 64 bit group */ + + /* + * shadow of pioavail, check to be sure it's large enough at + * init time. + */ + unsigned long ipath_pioavailshadow[8]; + /* shadow of kr_gpio_out, for rmw ops */ + u64 ipath_gpio_out; + /* kr_revision shadow */ + u64 ipath_revision; + /* + * shadow of ibcctrl, for interrupt handling of link changes, + * etc. + */ + u64 ipath_ibcctrl; + /* + * last ibcstatus, to suppress "duplicate" status change messages, + * mostly from 2 to 3 + */ + u64 ipath_lastibcstat; + /* hwerrmask shadow */ + ipath_err_t ipath_hwerrmask; + /* interrupt config reg shadow */ + u64 ipath_intconfig; + /* kr_sendpiobufbase value */ + u64 ipath_piobufbase; + + /* these are the "32 bit" regs */ + + /* + * number of GUIDs in the flash for this interface; may need some + * rethinking for setting on other ifaces + */ + u32 ipath_nguid; + /* + * the following two are 32-bit bitmasks, but {test,clear,set}_bit + * all expect bit fields to be "unsigned long" + */ + /* shadow kr_rcvctrl */ + unsigned long ipath_rcvctrl; + /* shadow kr_sendctrl */ + unsigned long ipath_sendctrl; + + /* value we put in kr_rcvhdrcnt */ + u32 ipath_rcvhdrcnt; + /* value we put in kr_rcvhdrsize */ + u32 ipath_rcvhdrsize; + /* value we put in kr_rcvhdrentsize */ + u32 ipath_rcvhdrentsize; + /* offset of last entry in rcvhdrq */ + u32 ipath_hdrqlast; + /* kr_portcnt value */ + u32 ipath_portcnt; + /* kr_pagealign value */ + u32 ipath_palign; + /* number of "2KB" PIO buffers */ + u32 ipath_piobcnt2k; + /* size in bytes of "2KB" PIO buffers */ + u32 ipath_piosize2k; + /* number of "4KB" PIO buffers */ + u32 ipath_piobcnt4k; + /* size in bytes of "4KB" PIO buffers */ + u32 ipath_piosize4k; + /* kr_rcvegrbase value */ + u32 ipath_rcvegrbase; + /* kr_rcvegrcnt value */ + u32 ipath_rcvegrcnt; + /* kr_rcvtidbase value */ + u32 ipath_rcvtidbase; + /* kr_rcvtidcnt value */ + u32 ipath_rcvtidcnt; + /* kr_sendregbase */ + u32 ipath_sregbase; + /* kr_userregbase */ + u32 ipath_uregbase; + /* kr_counterregbase */ + u32 ipath_cregbase; + /* shadow the control register contents */ + u32 ipath_control; + /* shadow the gpio output contents */ + u32 ipath_extctrl; + /* PCI revision register (HTC rev on FPGA) */ + u32 ipath_pcirev; + + /* chip address space used by 4k pio buffers */ + u32 ipath_4kalign; + /* The MTU programmed for this unit */ + u32 ipath_ibmtu; + /* + * The max size IB packet, included IB headers that we can send. + * Starts same as ipath_piosize, but is affected when ibmtu is + * changed, or by size of eager buffers + */ + u32 ipath_ibmaxlen; + /* + * ibmaxlen at init time, limited by chip and by receive buffer + * size. Not changed after init. + */ + u32 ipath_init_ibmaxlen; + /* size of each rcvegrbuffer */ + u32 ipath_rcvegrbufsize; + /* width (2,4,8,16,32) from HT config reg */ + u32 ipath_htwidth; + /* HT speed (200,400,800,1000) from HT config */ + u32 ipath_htspeed; + /* ports waiting for PIOavail intr */ + unsigned long ipath_portpiowait; + /* + * number of sequential ibcstatus change for polling active/quiet + * (i.e., link not coming up). + */ + u32 ipath_ibpollcnt; + /* low and high portions of MSI capability/vector */ + u32 ipath_msi_lo; + /* saved after PCIe init for restore after reset */ + u32 ipath_msi_hi; + /* MSI data (vector) saved for restore */ + u16 ipath_msi_data; + /* MLID programmed for this instance */ + u16 ipath_mlid; + /* LID programmed for this instance */ + u16 ipath_lid; + /* list of pkeys programmed; 0 if not set */ + u16 ipath_pkeys[4]; + /* ASCII serial number, from flash */ + u8 ipath_serial[12]; + /* human readable board version */ + u8 ipath_boardversion[80]; + /* chip major rev, from ipath_revision */ + u8 ipath_majrev; + /* chip minor rev, from ipath_revision */ + u8 ipath_minrev; + /* board rev, from ipath_revision */ + u8 ipath_boardrev; + /* unit # of this chip, if present */ + int ipath_unit; + /* saved for restore after reset */ + u8 ipath_pci_cacheline; + /* LID mask control */ + u8 ipath_lmc; +}; + +extern volatile __le64 *ipath_port0_rcvhdrtail; +extern dma_addr_t ipath_port0_rcvhdrtail_dma; + +#define IPATH_PORT0_RCVHDRTAIL_SIZE PAGE_SIZE + +extern struct list_head ipath_dev_list; +extern spinlock_t ipath_devs_lock; +extern struct ipath_devdata *ipath_lookup(int unit); + +extern u16 ipath_layer_rcv_opcode; +extern int ipath_verbs_registered; +extern int __ipath_layer_intr(struct ipath_devdata *, u32); +extern int ipath_layer_intr(struct ipath_devdata *, u32); +extern int __ipath_layer_rcv(struct ipath_devdata *, void *, + struct sk_buff *); +extern int __ipath_layer_rcv_lid(struct ipath_devdata *, void *); +extern int __ipath_verbs_piobufavail(struct ipath_devdata *); +extern int __ipath_verbs_rcv(struct ipath_devdata *, void *, void *, u32); + +void ipath_layer_add(struct ipath_devdata *); +void ipath_layer_del(struct ipath_devdata *); + +int ipath_init_chip(struct ipath_devdata *, int); +int ipath_enable_wc(struct ipath_devdata *dd); +void ipath_disable_wc(struct ipath_devdata *dd); +int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp); +void ipath_shutdown_device(struct ipath_devdata *); + +struct file_operations; +int ipath_cdev_init(int minor, char *name, struct file_operations *fops, + struct cdev **cdevp, struct class_device **class_devp); +void ipath_cdev_cleanup(struct cdev **cdevp, + struct class_device **class_devp); + +int ipath_diag_init(void); +void ipath_diag_cleanup(void); +void ipath_diag_bringup_link(struct ipath_devdata *); + +extern wait_queue_head_t ipath_sma_state_wait; + +int ipath_user_add(struct ipath_devdata *dd); +void ipath_user_del(struct ipath_devdata *dd); + +struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd, gfp_t); + +extern int ipath_diag_inuse; + +irqreturn_t ipath_intr(int irq, void *devid, struct pt_regs *regs); +void ipath_decode_err(char *buf, size_t blen, ipath_err_t err); +#if __IPATH_INFO || __IPATH_DBG +extern const char *ipath_ibcstatus_str[]; +#endif + +/* clean up any per-chip chip-specific stuff */ +void ipath_chip_cleanup(struct ipath_devdata *); +/* clean up any chip type-specific stuff */ +void ipath_chip_done(void); + +/* check to see if we have to force ordering for write combining */ +int ipath_unordered_wc(void); + +void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first, + unsigned cnt); + +int ipath_create_rcvhdrq(struct ipath_devdata *, struct ipath_portdata *); +void ipath_free_pddata(struct ipath_devdata *, u32, int); + +int ipath_parse_ushort(const char *str, unsigned short *valp); + +int ipath_wait_linkstate(struct ipath_devdata *, u32, int); +void ipath_set_ib_lstate(struct ipath_devdata *, int); +void ipath_kreceive(struct ipath_devdata *); +int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned); +int ipath_reset_device(int); +void ipath_get_faststats(unsigned long); + +/* for use in system calls, where we want to know device type, etc. */ +#define port_fp(fp) ((struct ipath_portdata *) (fp)->private_data) + +/* + * values for ipath_flags + */ +/* The chip is up and initted */ +#define IPATH_INITTED 0x2 + /* set if any user code has set kr_rcvhdrsize */ +#define IPATH_RCVHDRSZ_SET 0x4 + /* The chip is present and valid for accesses */ +#define IPATH_PRESENT 0x8 + /* HT link0 is only 8 bits wide, ignore upper byte crc + * errors, etc. */ +#define IPATH_8BIT_IN_HT0 0x10 + /* HT link1 is only 8 bits wide, ignore upper byte crc + * errors, etc. */ +#define IPATH_8BIT_IN_HT1 0x20 + /* The link is down */ +#define IPATH_LINKDOWN 0x40 + /* The link level is up (0x11) */ +#define IPATH_LINKINIT 0x80 + /* The link is in the armed (0x21) state */ +#define IPATH_LINKARMED 0x100 + /* The link is in the active (0x31) state */ +#define IPATH_LINKACTIVE 0x200 + /* link current state is unknown */ +#define IPATH_LINKUNK 0x400 + /* no IB cable, or no device on IB cable */ +#define IPATH_NOCABLE 0x4000 + /* Supports port zero per packet receive interrupts via + * GPIO */ +#define IPATH_GPIO_INTR 0x8000 + /* uses the coded 4byte TID, not 8 byte */ +#define IPATH_4BYTE_TID 0x10000 + /* packet/word counters are 32 bit, else those 4 counters + * are 64bit */ +#define IPATH_32BITCOUNTERS 0x20000 + /* can miss port0 rx interrupts */ +#define IPATH_POLL_RX_INTR 0x40000 +#define IPATH_DISABLED 0x80000 /* administratively disabled */ + +/* portdata flag bit offsets */ + /* waiting for a packet to arrive */ +#define IPATH_PORT_WAITING_RCV 2 + /* waiting for a PIO buffer to be available */ +#define IPATH_PORT_WAITING_PIO 3 + +/* free up any allocated data at closes */ +void ipath_free_data(struct ipath_portdata *dd); +int ipath_waitfor_mdio_cmdready(struct ipath_devdata *); +int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *); +u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *); +/* init PE-800-specific func */ +void ipath_init_pe800_funcs(struct ipath_devdata *); +/* init HT-400-specific func */ +void ipath_init_ht400_funcs(struct ipath_devdata *); +void ipath_get_guid(struct ipath_devdata *); +u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); + +/* + * number of words used for protocol header if not set by ipath_userinit(); + */ +#define IPATH_DFLT_RCVHDRSIZE 9 + +#define IPATH_MDIO_CMD_WRITE 1 +#define IPATH_MDIO_CMD_READ 2 +#define IPATH_MDIO_CLD_DIV 25 /* to get 2.5 Mhz mdio clock */ +#define IPATH_MDIO_CMDVALID 0x40000000 /* bit 30 */ +#define IPATH_MDIO_DATAVALID 0x80000000 /* bit 31 */ +#define IPATH_MDIO_CTRL_STD 0x0 + +static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data) +{ + return (((u64) IPATH_MDIO_CLD_DIV) << 32) | + (cmd << 26) | + (dev << 21) | + (reg << 16) | + (data & 0xFFFF); +} + + /* signal and fifo status, in bank 31 */ +#define IPATH_MDIO_CTRL_XGXS_REG_8 0x8 + /* controls loopback, redundancy */ +#define IPATH_MDIO_CTRL_8355_REG_1 0x10 + /* premph, encdec, etc. */ +#define IPATH_MDIO_CTRL_8355_REG_2 0x11 + /* Kchars, etc. */ +#define IPATH_MDIO_CTRL_8355_REG_6 0x15 +#define IPATH_MDIO_CTRL_8355_REG_9 0x18 +#define IPATH_MDIO_CTRL_8355_REG_10 0x1D + +int ipath_get_user_pages(unsigned long, size_t, struct page **); +int ipath_get_user_pages_nocopy(unsigned long, struct page **); +void ipath_release_user_pages(struct page **, size_t); +void ipath_release_user_pages_on_close(struct page **, size_t); +int ipath_eeprom_read(struct ipath_devdata *, u8, void *, int); +int ipath_eeprom_write(struct ipath_devdata *, u8, const void *, int); + +/* these are used for the registers that vary with port */ +void ipath_write_kreg_port(const struct ipath_devdata *, ipath_kreg, + unsigned, u64); +u64 ipath_read_kreg64_port(const struct ipath_devdata *, ipath_kreg, + unsigned); + +/* + * We could have a single register get/put routine, that takes a group type, + * but this is somewhat clearer and cleaner. It also gives us some error + * checking. 64 bit register reads should always work, but are inefficient + * on opteron (the northbridge always generates 2 separate HT 32 bit reads), + * so we use kreg32 wherever possible. User register and counter register + * reads are always 32 bit reads, so only one form of those routines. + */ + +/* + * At the moment, none of the s-registers are writable, so no + * ipath_write_sreg(), and none of the c-registers are writable, so no + * ipath_write_creg(). + */ + +/** + * ipath_read_ureg32 - read 32-bit virtualized per-port register + * @dd: device + * @regno: register number + * @port: port number + * + * Return the contents of a register that is virtualized to be per port. + * Prints a debug message and returns -1 on errors (not distinguishable from + * valid contents at runtime; we may add a separate error variable at some + * point). + * + * This is normally not used by the kernel, but may be for debugging, and + * has a different implementation than user mode, which is why it's not in + * _common.h. + */ +static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd, + ipath_ureg regno, int port) +{ + if (!dd->ipath_kregbase) + return 0; + + return readl(regno + (u64 __iomem *) + (dd->ipath_uregbase + + (char __iomem *)dd->ipath_kregbase + + dd->ipath_palign * port)); +} + +/** + * ipath_write_ureg - write 32-bit virtualized per-port register + * @dd: device + * @regno: register number + * @value: value + * @port: port + * + * Write the contents of a register that is virtualized to be per port. + */ +static inline void ipath_write_ureg(const struct ipath_devdata *dd, + ipath_ureg regno, u64 value, int port) +{ + u64 __iomem *ubase = (u64 __iomem *) + (dd->ipath_uregbase + (char __iomem *) dd->ipath_kregbase + + dd->ipath_palign * port); + if (dd->ipath_kregbase) + writeq(value, &ubase[regno]); +} + +static inline u32 ipath_read_kreg32(const struct ipath_devdata *dd, + ipath_kreg regno) +{ + if (!dd->ipath_kregbase) + return -1; + return readl((u32 __iomem *) & dd->ipath_kregbase[regno]); +} + +static inline u64 ipath_read_kreg64(const struct ipath_devdata *dd, + ipath_kreg regno) +{ + if (!dd->ipath_kregbase) + return -1; + + return readq(&dd->ipath_kregbase[regno]); +} + +static inline void ipath_write_kreg(const struct ipath_devdata *dd, + ipath_kreg regno, u64 value) +{ + if (dd->ipath_kregbase) + writeq(value, &dd->ipath_kregbase[regno]); +} + +static inline u64 ipath_read_creg(const struct ipath_devdata *dd, + ipath_sreg regno) +{ + if (!dd->ipath_kregbase) + return 0; + + return readq(regno + (u64 __iomem *) + (dd->ipath_cregbase + + (char __iomem *)dd->ipath_kregbase)); +} + +static inline u32 ipath_read_creg32(const struct ipath_devdata *dd, + ipath_sreg regno) +{ + if (!dd->ipath_kregbase) + return 0; + return readl(regno + (u64 __iomem *) + (dd->ipath_cregbase + + (char __iomem *)dd->ipath_kregbase)); +} + +/* + * sysfs interface. + */ + +struct device_driver; + +extern const char ipath_core_version[]; + +int ipath_driver_create_group(struct device_driver *); +void ipath_driver_remove_group(struct device_driver *); + +int ipath_device_create_group(struct device *, struct ipath_devdata *); +void ipath_device_remove_group(struct device *, struct ipath_devdata *); +int ipath_expose_reset(struct device *); + +int ipath_init_ipathfs(void); +void ipath_exit_ipathfs(void); +int ipathfs_add_device(struct ipath_devdata *); +int ipathfs_remove_device(struct ipath_devdata *); + +/* + * Flush write combining store buffers (if present) and perform a write + * barrier. + */ +#if defined(CONFIG_X86_64) +#define ipath_flush_wc() asm volatile("sfence" ::: "memory") +#else +#define ipath_flush_wc() wmb() +#endif + +extern unsigned ipath_debug; /* debugging bit mask */ + +const char *ipath_get_unit_name(int unit); + +extern struct mutex ipath_mutex; + +#define IPATH_DRV_NAME "ipath_core" +#define IPATH_MAJOR 233 +#define IPATH_SMA_MINOR 128 +#define IPATH_DIAG_MINOR 129 +#define IPATH_NMINORS 130 + +#define ipath_dev_err(dd,fmt,...) \ + do { \ + const struct ipath_devdata *__dd = (dd); \ + if (__dd->pcidev) \ + dev_err(&__dd->pcidev->dev, "%s: " fmt, \ + ipath_get_unit_name(__dd->ipath_unit), \ + ##__VA_ARGS__); \ + else \ + printk(KERN_ERR IPATH_DRV_NAME ": %s: " fmt, \ + ipath_get_unit_name(__dd->ipath_unit), \ + ##__VA_ARGS__); \ + } while (0) + +#if _IPATH_DEBUGGING + +# define __IPATH_DBG_WHICH(which,fmt,...) \ + do { \ + if(unlikely(ipath_debug&(which))) \ + printk(KERN_DEBUG IPATH_DRV_NAME ": %s: " fmt, \ + __func__,##__VA_ARGS__); \ + } while(0) + +# define ipath_dbg(fmt,...) \ + __IPATH_DBG_WHICH(__IPATH_DBG,fmt,##__VA_ARGS__) +# define ipath_cdbg(which,fmt,...) \ + __IPATH_DBG_WHICH(__IPATH_##which##DBG,fmt,##__VA_ARGS__) + +#else /* ! _IPATH_DEBUGGING */ + +# define ipath_dbg(fmt,...) +# define ipath_cdbg(which,fmt,...) + +#endif /* _IPATH_DEBUGGING */ + +#endif /* _IPATH_KERNEL_H */ diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c new file mode 100644 index 000000000000..aa33b0e9f2f6 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_keys.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "ipath_verbs.h" + +/** + * ipath_alloc_lkey - allocate an lkey + * @rkt: lkey table in which to allocate the lkey + * @mr: memory region that this lkey protects + * + * Returns 1 if successful, otherwise returns 0. + */ + +int ipath_alloc_lkey(struct ipath_lkey_table *rkt, struct ipath_mregion *mr) +{ + unsigned long flags; + u32 r; + u32 n; + int ret; + + spin_lock_irqsave(&rkt->lock, flags); + + /* Find the next available LKEY */ + r = n = rkt->next; + for (;;) { + if (rkt->table[r] == NULL) + break; + r = (r + 1) & (rkt->max - 1); + if (r == n) { + spin_unlock_irqrestore(&rkt->lock, flags); + _VERBS_INFO("LKEY table full\n"); + ret = 0; + goto bail; + } + } + rkt->next = (r + 1) & (rkt->max - 1); + /* + * Make sure lkey is never zero which is reserved to indicate an + * unrestricted LKEY. + */ + rkt->gen++; + mr->lkey = (r << (32 - ib_ipath_lkey_table_size)) | + ((((1 << (24 - ib_ipath_lkey_table_size)) - 1) & rkt->gen) + << 8); + if (mr->lkey == 0) { + mr->lkey |= 1 << 8; + rkt->gen++; + } + rkt->table[r] = mr; + spin_unlock_irqrestore(&rkt->lock, flags); + + ret = 1; + +bail: + return ret; +} + +/** + * ipath_free_lkey - free an lkey + * @rkt: table from which to free the lkey + * @lkey: lkey id to free + */ +void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey) +{ + unsigned long flags; + u32 r; + + if (lkey == 0) + return; + r = lkey >> (32 - ib_ipath_lkey_table_size); + spin_lock_irqsave(&rkt->lock, flags); + rkt->table[r] = NULL; + spin_unlock_irqrestore(&rkt->lock, flags); +} + +/** + * ipath_lkey_ok - check IB SGE for validity and initialize + * @rkt: table containing lkey to check SGE against + * @isge: outgoing internal SGE + * @sge: SGE to check + * @acc: access flags + * + * Return 1 if valid and successful, otherwise returns 0. + * + * Check the IB SGE for validity and initialize our internal version + * of it. + */ +int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge, + struct ib_sge *sge, int acc) +{ + struct ipath_mregion *mr; + size_t off; + int ret; + + /* + * We use LKEY == zero to mean a physical kmalloc() address. + * This is a bit of a hack since we rely on dma_map_single() + * being reversible by calling bus_to_virt(). + */ + if (sge->lkey == 0) { + isge->mr = NULL; + isge->vaddr = bus_to_virt(sge->addr); + isge->length = sge->length; + isge->sge_length = sge->length; + ret = 1; + goto bail; + } + spin_lock(&rkt->lock); + mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))]; + spin_unlock(&rkt->lock); + if (unlikely(mr == NULL || mr->lkey != sge->lkey)) { + ret = 0; + goto bail; + } + + off = sge->addr - mr->user_base; + if (unlikely(sge->addr < mr->user_base || + off + sge->length > mr->length || + (mr->access_flags & acc) != acc)) { + ret = 0; + goto bail; + } + + off += mr->offset; + isge->mr = mr; + isge->m = 0; + isge->n = 0; + while (off >= mr->map[isge->m]->segs[isge->n].length) { + off -= mr->map[isge->m]->segs[isge->n].length; + isge->n++; + if (isge->n >= IPATH_SEGSZ) { + isge->m++; + isge->n = 0; + } + } + isge->vaddr = mr->map[isge->m]->segs[isge->n].vaddr + off; + isge->length = mr->map[isge->m]->segs[isge->n].length - off; + isge->sge_length = sge->length; + + ret = 1; + +bail: + return ret; +} + +/** + * ipath_rkey_ok - check the IB virtual address, length, and RKEY + * @dev: infiniband device + * @ss: SGE state + * @len: length of data + * @vaddr: virtual address to place data + * @rkey: rkey to check + * @acc: access flags + * + * Return 1 if successful, otherwise 0. + * + * The QP r_rq.lock should be held. + */ +int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss, + u32 len, u64 vaddr, u32 rkey, int acc) +{ + struct ipath_lkey_table *rkt = &dev->lk_table; + struct ipath_sge *sge = &ss->sge; + struct ipath_mregion *mr; + size_t off; + int ret; + + spin_lock(&rkt->lock); + mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))]; + spin_unlock(&rkt->lock); + if (unlikely(mr == NULL || mr->lkey != rkey)) { + ret = 0; + goto bail; + } + + off = vaddr - mr->iova; + if (unlikely(vaddr < mr->iova || off + len > mr->length || + (mr->access_flags & acc) == 0)) { + ret = 0; + goto bail; + } + + off += mr->offset; + sge->mr = mr; + sge->m = 0; + sge->n = 0; + while (off >= mr->map[sge->m]->segs[sge->n].length) { + off -= mr->map[sge->m]->segs[sge->n].length; + sge->n++; + if (sge->n >= IPATH_SEGSZ) { + sge->m++; + sge->n = 0; + } + } + sge->vaddr = mr->map[sge->m]->segs[sge->n].vaddr + off; + sge->length = mr->map[sge->m]->segs[sge->n].length - off; + sge->sge_length = len; + ss->sg_list = NULL; + ss->num_sge = 1; + + ret = 1; + +bail: + return ret; +} diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c new file mode 100644 index 000000000000..2cabf6340572 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_layer.c @@ -0,0 +1,1515 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * These are the routines used by layered drivers, currently just the + * layered ethernet driver and verbs layer. + */ + +#include +#include +#include + +#include "ipath_kernel.h" +#include "ips_common.h" +#include "ipath_layer.h" + +/* Acquire before ipath_devs_lock. */ +static DEFINE_MUTEX(ipath_layer_mutex); + +u16 ipath_layer_rcv_opcode; +static int (*layer_intr)(void *, u32); +static int (*layer_rcv)(void *, void *, struct sk_buff *); +static int (*layer_rcv_lid)(void *, void *); +static int (*verbs_piobufavail)(void *); +static void (*verbs_rcv)(void *, void *, void *, u32); +int ipath_verbs_registered; + +static void *(*layer_add_one)(int, struct ipath_devdata *); +static void (*layer_remove_one)(void *); +static void *(*verbs_add_one)(int, struct ipath_devdata *); +static void (*verbs_remove_one)(void *); +static void (*verbs_timer_cb)(void *); + +int __ipath_layer_intr(struct ipath_devdata *dd, u32 arg) +{ + int ret = -ENODEV; + + if (dd->ipath_layer.l_arg && layer_intr) + ret = layer_intr(dd->ipath_layer.l_arg, arg); + + return ret; +} + +int ipath_layer_intr(struct ipath_devdata *dd, u32 arg) +{ + int ret; + + mutex_lock(&ipath_layer_mutex); + + ret = __ipath_layer_intr(dd, arg); + + mutex_unlock(&ipath_layer_mutex); + + return ret; +} + +int __ipath_layer_rcv(struct ipath_devdata *dd, void *hdr, + struct sk_buff *skb) +{ + int ret = -ENODEV; + + if (dd->ipath_layer.l_arg && layer_rcv) + ret = layer_rcv(dd->ipath_layer.l_arg, hdr, skb); + + return ret; +} + +int __ipath_layer_rcv_lid(struct ipath_devdata *dd, void *hdr) +{ + int ret = -ENODEV; + + if (dd->ipath_layer.l_arg && layer_rcv_lid) + ret = layer_rcv_lid(dd->ipath_layer.l_arg, hdr); + + return ret; +} + +int __ipath_verbs_piobufavail(struct ipath_devdata *dd) +{ + int ret = -ENODEV; + + if (dd->verbs_layer.l_arg && verbs_piobufavail) + ret = verbs_piobufavail(dd->verbs_layer.l_arg); + + return ret; +} + +int __ipath_verbs_rcv(struct ipath_devdata *dd, void *rc, void *ebuf, + u32 tlen) +{ + int ret = -ENODEV; + + if (dd->verbs_layer.l_arg && verbs_rcv) { + verbs_rcv(dd->verbs_layer.l_arg, rc, ebuf, tlen); + ret = 0; + } + + return ret; +} + +int ipath_layer_set_linkstate(struct ipath_devdata *dd, u8 newstate) +{ + u32 lstate; + int ret; + + switch (newstate) { + case IPATH_IB_LINKDOWN: + ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL << + INFINIPATH_IBCC_LINKINITCMD_SHIFT); + /* don't wait */ + ret = 0; + goto bail; + + case IPATH_IB_LINKDOWN_SLEEP: + ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_SLEEP << + INFINIPATH_IBCC_LINKINITCMD_SHIFT); + /* don't wait */ + ret = 0; + goto bail; + + case IPATH_IB_LINKDOWN_DISABLE: + ipath_set_ib_lstate(dd, + INFINIPATH_IBCC_LINKINITCMD_DISABLE << + INFINIPATH_IBCC_LINKINITCMD_SHIFT); + /* don't wait */ + ret = 0; + goto bail; + + case IPATH_IB_LINKINIT: + if (dd->ipath_flags & IPATH_LINKINIT) { + ret = 0; + goto bail; + } + ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT << + INFINIPATH_IBCC_LINKCMD_SHIFT); + lstate = IPATH_LINKINIT; + break; + + case IPATH_IB_LINKARM: + if (dd->ipath_flags & IPATH_LINKARMED) { + ret = 0; + goto bail; + } + if (!(dd->ipath_flags & + (IPATH_LINKINIT | IPATH_LINKACTIVE))) { + ret = -EINVAL; + goto bail; + } + ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED << + INFINIPATH_IBCC_LINKCMD_SHIFT); + /* + * Since the port can transition to ACTIVE by receiving + * a non VL 15 packet, wait for either state. + */ + lstate = IPATH_LINKARMED | IPATH_LINKACTIVE; + break; + + case IPATH_IB_LINKACTIVE: + if (dd->ipath_flags & IPATH_LINKACTIVE) { + ret = 0; + goto bail; + } + if (!(dd->ipath_flags & IPATH_LINKARMED)) { + ret = -EINVAL; + goto bail; + } + ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE << + INFINIPATH_IBCC_LINKCMD_SHIFT); + lstate = IPATH_LINKACTIVE; + break; + + default: + ipath_dbg("Invalid linkstate 0x%x requested\n", newstate); + ret = -EINVAL; + goto bail; + } + ret = ipath_wait_linkstate(dd, lstate, 2000); + +bail: + return ret; +} + +EXPORT_SYMBOL_GPL(ipath_layer_set_linkstate); + +/** + * ipath_layer_set_mtu - set the MTU + * @dd: the infinipath device + * @arg: the new MTU + * + * we can handle "any" incoming size, the issue here is whether we + * need to restrict our outgoing size. For now, we don't do any + * sanity checking on this, and we don't deal with what happens to + * programs that are already running when the size changes. + * NOTE: changing the MTU will usually cause the IBC to go back to + * link initialize (IPATH_IBSTATE_INIT) state... + */ +int ipath_layer_set_mtu(struct ipath_devdata *dd, u16 arg) +{ + u32 piosize; + int changed = 0; + int ret; + + /* + * mtu is IB data payload max. It's the largest power of 2 less + * than piosize (or even larger, since it only really controls the + * largest we can receive; we can send the max of the mtu and + * piosize). We check that it's one of the valid IB sizes. + */ + if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 && + arg != 4096) { + ipath_dbg("Trying to set invalid mtu %u, failing\n", arg); + ret = -EINVAL; + goto bail; + } + if (dd->ipath_ibmtu == arg) { + ret = 0; /* same as current */ + goto bail; + } + + piosize = dd->ipath_ibmaxlen; + dd->ipath_ibmtu = arg; + + if (arg >= (piosize - IPATH_PIO_MAXIBHDR)) { + /* Only if it's not the initial value (or reset to it) */ + if (piosize != dd->ipath_init_ibmaxlen) { + dd->ipath_ibmaxlen = piosize; + changed = 1; + } + } else if ((arg + IPATH_PIO_MAXIBHDR) != dd->ipath_ibmaxlen) { + piosize = arg + IPATH_PIO_MAXIBHDR; + ipath_cdbg(VERBOSE, "ibmaxlen was 0x%x, setting to 0x%x " + "(mtu 0x%x)\n", dd->ipath_ibmaxlen, piosize, + arg); + dd->ipath_ibmaxlen = piosize; + changed = 1; + } + + if (changed) { + /* + * set the IBC maxpktlength to the size of our pio + * buffers in words + */ + u64 ibc = dd->ipath_ibcctrl; + ibc &= ~(INFINIPATH_IBCC_MAXPKTLEN_MASK << + INFINIPATH_IBCC_MAXPKTLEN_SHIFT); + + piosize = piosize - 2 * sizeof(u32); /* ignore pbc */ + dd->ipath_ibmaxlen = piosize; + piosize /= sizeof(u32); /* in words */ + /* + * for ICRC, which we only send in diag test pkt mode, and + * we don't need to worry about that for mtu + */ + piosize += 1; + + ibc |= piosize << INFINIPATH_IBCC_MAXPKTLEN_SHIFT; + dd->ipath_ibcctrl = ibc; + ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, + dd->ipath_ibcctrl); + dd->ipath_f_tidtemplate(dd); + } + + ret = 0; + +bail: + return ret; +} + +EXPORT_SYMBOL_GPL(ipath_layer_set_mtu); + +int ipath_set_sps_lid(struct ipath_devdata *dd, u32 arg, u8 lmc) +{ + ipath_stats.sps_lid[dd->ipath_unit] = arg; + dd->ipath_lid = arg; + dd->ipath_lmc = lmc; + + mutex_lock(&ipath_layer_mutex); + + if (dd->ipath_layer.l_arg && layer_intr) + layer_intr(dd->ipath_layer.l_arg, IPATH_LAYER_INT_LID); + + mutex_unlock(&ipath_layer_mutex); + + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_set_sps_lid); + +int ipath_layer_set_guid(struct ipath_devdata *dd, __be64 guid) +{ + /* XXX - need to inform anyone who cares this just happened. */ + dd->ipath_guid = guid; + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_set_guid); + +__be64 ipath_layer_get_guid(struct ipath_devdata *dd) +{ + return dd->ipath_guid; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_guid); + +u32 ipath_layer_get_nguid(struct ipath_devdata *dd) +{ + return dd->ipath_nguid; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_nguid); + +int ipath_layer_query_device(struct ipath_devdata *dd, u32 * vendor, + u32 * boardrev, u32 * majrev, u32 * minrev) +{ + *vendor = dd->ipath_vendorid; + *boardrev = dd->ipath_boardrev; + *majrev = dd->ipath_majrev; + *minrev = dd->ipath_minrev; + + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_query_device); + +u32 ipath_layer_get_flags(struct ipath_devdata *dd) +{ + return dd->ipath_flags; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_flags); + +struct device *ipath_layer_get_device(struct ipath_devdata *dd) +{ + return &dd->pcidev->dev; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_device); + +u16 ipath_layer_get_deviceid(struct ipath_devdata *dd) +{ + return dd->ipath_deviceid; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_deviceid); + +u64 ipath_layer_get_lastibcstat(struct ipath_devdata *dd) +{ + return dd->ipath_lastibcstat; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_lastibcstat); + +u32 ipath_layer_get_ibmtu(struct ipath_devdata *dd) +{ + return dd->ipath_ibmtu; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_ibmtu); + +void ipath_layer_add(struct ipath_devdata *dd) +{ + mutex_lock(&ipath_layer_mutex); + + if (layer_add_one) + dd->ipath_layer.l_arg = + layer_add_one(dd->ipath_unit, dd); + + if (verbs_add_one) + dd->verbs_layer.l_arg = + verbs_add_one(dd->ipath_unit, dd); + + mutex_unlock(&ipath_layer_mutex); +} + +void ipath_layer_del(struct ipath_devdata *dd) +{ + mutex_lock(&ipath_layer_mutex); + + if (dd->ipath_layer.l_arg && layer_remove_one) { + layer_remove_one(dd->ipath_layer.l_arg); + dd->ipath_layer.l_arg = NULL; + } + + if (dd->verbs_layer.l_arg && verbs_remove_one) { + verbs_remove_one(dd->verbs_layer.l_arg); + dd->verbs_layer.l_arg = NULL; + } + + mutex_unlock(&ipath_layer_mutex); +} + +int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *), + void (*l_remove)(void *), + int (*l_intr)(void *, u32), + int (*l_rcv)(void *, void *, struct sk_buff *), + u16 l_rcv_opcode, + int (*l_rcv_lid)(void *, void *)) +{ + struct ipath_devdata *dd, *tmp; + unsigned long flags; + + mutex_lock(&ipath_layer_mutex); + + layer_add_one = l_add; + layer_remove_one = l_remove; + layer_intr = l_intr; + layer_rcv = l_rcv; + layer_rcv_lid = l_rcv_lid; + ipath_layer_rcv_opcode = l_rcv_opcode; + + spin_lock_irqsave(&ipath_devs_lock, flags); + + list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) { + if (!(dd->ipath_flags & IPATH_INITTED)) + continue; + + if (dd->ipath_layer.l_arg) + continue; + + if (!(*dd->ipath_statusp & IPATH_STATUS_SMA)) + *dd->ipath_statusp |= IPATH_STATUS_OIB_SMA; + + spin_unlock_irqrestore(&ipath_devs_lock, flags); + dd->ipath_layer.l_arg = l_add(dd->ipath_unit, dd); + spin_lock_irqsave(&ipath_devs_lock, flags); + } + + spin_unlock_irqrestore(&ipath_devs_lock, flags); + mutex_unlock(&ipath_layer_mutex); + + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_register); + +void ipath_layer_unregister(void) +{ + struct ipath_devdata *dd, *tmp; + unsigned long flags; + + mutex_lock(&ipath_layer_mutex); + spin_lock_irqsave(&ipath_devs_lock, flags); + + list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) { + if (dd->ipath_layer.l_arg && layer_remove_one) { + spin_unlock_irqrestore(&ipath_devs_lock, flags); + layer_remove_one(dd->ipath_layer.l_arg); + spin_lock_irqsave(&ipath_devs_lock, flags); + dd->ipath_layer.l_arg = NULL; + } + } + + spin_unlock_irqrestore(&ipath_devs_lock, flags); + + layer_add_one = NULL; + layer_remove_one = NULL; + layer_intr = NULL; + layer_rcv = NULL; + layer_rcv_lid = NULL; + + mutex_unlock(&ipath_layer_mutex); +} + +EXPORT_SYMBOL_GPL(ipath_layer_unregister); + +static void __ipath_verbs_timer(unsigned long arg) +{ + struct ipath_devdata *dd = (struct ipath_devdata *) arg; + + /* + * If port 0 receive packet interrupts are not available, or + * can be missed, poll the receive queue + */ + if (dd->ipath_flags & IPATH_POLL_RX_INTR) + ipath_kreceive(dd); + + /* Handle verbs layer timeouts. */ + if (dd->verbs_layer.l_arg && verbs_timer_cb) + verbs_timer_cb(dd->verbs_layer.l_arg); + + mod_timer(&dd->verbs_layer.l_timer, jiffies + 1); +} + +/** + * ipath_verbs_register - verbs layer registration + * @l_piobufavail: callback for when PIO buffers become available + * @l_rcv: callback for receiving a packet + * @l_timer_cb: timer callback + * @ipath_devdata: device data structure is put here + */ +int ipath_verbs_register(void *(*l_add)(int, struct ipath_devdata *), + void (*l_remove)(void *arg), + int (*l_piobufavail) (void *arg), + void (*l_rcv) (void *arg, void *rhdr, + void *data, u32 tlen), + void (*l_timer_cb) (void *arg)) +{ + struct ipath_devdata *dd, *tmp; + unsigned long flags; + + mutex_lock(&ipath_layer_mutex); + + verbs_add_one = l_add; + verbs_remove_one = l_remove; + verbs_piobufavail = l_piobufavail; + verbs_rcv = l_rcv; + verbs_timer_cb = l_timer_cb; + + spin_lock_irqsave(&ipath_devs_lock, flags); + + list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) { + if (!(dd->ipath_flags & IPATH_INITTED)) + continue; + + if (dd->verbs_layer.l_arg) + continue; + + spin_unlock_irqrestore(&ipath_devs_lock, flags); + dd->verbs_layer.l_arg = l_add(dd->ipath_unit, dd); + spin_lock_irqsave(&ipath_devs_lock, flags); + } + + spin_unlock_irqrestore(&ipath_devs_lock, flags); + mutex_unlock(&ipath_layer_mutex); + + ipath_verbs_registered = 1; + + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_verbs_register); + +void ipath_verbs_unregister(void) +{ + struct ipath_devdata *dd, *tmp; + unsigned long flags; + + mutex_lock(&ipath_layer_mutex); + spin_lock_irqsave(&ipath_devs_lock, flags); + + list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) { + *dd->ipath_statusp &= ~IPATH_STATUS_OIB_SMA; + + if (dd->verbs_layer.l_arg && verbs_remove_one) { + spin_unlock_irqrestore(&ipath_devs_lock, flags); + verbs_remove_one(dd->verbs_layer.l_arg); + spin_lock_irqsave(&ipath_devs_lock, flags); + dd->verbs_layer.l_arg = NULL; + } + } + + spin_unlock_irqrestore(&ipath_devs_lock, flags); + + verbs_add_one = NULL; + verbs_remove_one = NULL; + verbs_piobufavail = NULL; + verbs_rcv = NULL; + verbs_timer_cb = NULL; + + mutex_unlock(&ipath_layer_mutex); +} + +EXPORT_SYMBOL_GPL(ipath_verbs_unregister); + +int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax) +{ + int ret; + u32 intval = 0; + + mutex_lock(&ipath_layer_mutex); + + if (!dd->ipath_layer.l_arg) { + ret = -EINVAL; + goto bail; + } + + ret = ipath_setrcvhdrsize(dd, NUM_OF_EXTRA_WORDS_IN_HEADER_QUEUE); + + if (ret < 0) + goto bail; + + *pktmax = dd->ipath_ibmaxlen; + + if (*dd->ipath_statusp & IPATH_STATUS_IB_READY) + intval |= IPATH_LAYER_INT_IF_UP; + if (ipath_stats.sps_lid[dd->ipath_unit]) + intval |= IPATH_LAYER_INT_LID; + if (ipath_stats.sps_mlid[dd->ipath_unit]) + intval |= IPATH_LAYER_INT_BCAST; + /* + * do this on open, in case low level is already up and + * just layered driver was reloaded, etc. + */ + if (intval) + layer_intr(dd->ipath_layer.l_arg, intval); + + ret = 0; +bail: + mutex_unlock(&ipath_layer_mutex); + + return ret; +} + +EXPORT_SYMBOL_GPL(ipath_layer_open); + +u16 ipath_layer_get_lid(struct ipath_devdata *dd) +{ + return dd->ipath_lid; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_lid); + +/** + * ipath_layer_get_mac - get the MAC address + * @dd: the infinipath device + * @mac: the MAC is put here + * + * This is the EUID-64 OUI octets (top 3), then + * skip the next 2 (which should both be zero or 0xff). + * The returned MAC is in network order + * mac points to at least 6 bytes of buffer + * We assume that by the time the LID is set, that the GUID is as valid + * as it's ever going to be, rather than adding yet another status bit. + */ + +int ipath_layer_get_mac(struct ipath_devdata *dd, u8 * mac) +{ + u8 *guid; + + guid = (u8 *) &dd->ipath_guid; + + mac[0] = guid[0]; + mac[1] = guid[1]; + mac[2] = guid[2]; + mac[3] = guid[5]; + mac[4] = guid[6]; + mac[5] = guid[7]; + if ((guid[3] || guid[4]) && !(guid[3] == 0xff && guid[4] == 0xff)) + ipath_dbg("Warning, guid bytes 3 and 4 not 0 or 0xffff: " + "%x %x\n", guid[3], guid[4]); + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_mac); + +u16 ipath_layer_get_bcast(struct ipath_devdata *dd) +{ + return dd->ipath_mlid; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_bcast); + +u32 ipath_layer_get_cr_errpkey(struct ipath_devdata *dd) +{ + return ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey); +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_cr_errpkey); + +static void update_sge(struct ipath_sge_state *ss, u32 length) +{ + struct ipath_sge *sge = &ss->sge; + + sge->vaddr += length; + sge->length -= length; + sge->sge_length -= length; + if (sge->sge_length == 0) { + if (--ss->num_sge) + *sge = *ss->sg_list++; + } else if (sge->length == 0 && sge->mr != NULL) { + if (++sge->n >= IPATH_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + return; + sge->n = 0; + } + sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = sge->mr->map[sge->m]->segs[sge->n].length; + } +} + +#ifdef __LITTLE_ENDIAN +static inline u32 get_upper_bits(u32 data, u32 shift) +{ + return data >> shift; +} + +static inline u32 set_upper_bits(u32 data, u32 shift) +{ + return data << shift; +} + +static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off) +{ + data <<= ((sizeof(u32) - n) * BITS_PER_BYTE); + data >>= ((sizeof(u32) - n - off) * BITS_PER_BYTE); + return data; +} +#else +static inline u32 get_upper_bits(u32 data, u32 shift) +{ + return data << shift; +} + +static inline u32 set_upper_bits(u32 data, u32 shift) +{ + return data >> shift; +} + +static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off) +{ + data >>= ((sizeof(u32) - n) * BITS_PER_BYTE); + data <<= ((sizeof(u32) - n - off) * BITS_PER_BYTE); + return data; +} +#endif + +static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss, + u32 length) +{ + u32 extra = 0; + u32 data = 0; + u32 last; + + while (1) { + u32 len = ss->sge.length; + u32 off; + + BUG_ON(len == 0); + if (len > length) + len = length; + if (len > ss->sge.sge_length) + len = ss->sge.sge_length; + /* If the source address is not aligned, try to align it. */ + off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1); + if (off) { + u32 *addr = (u32 *)((unsigned long)ss->sge.vaddr & + ~(sizeof(u32) - 1)); + u32 v = get_upper_bits(*addr, off * BITS_PER_BYTE); + u32 y; + + y = sizeof(u32) - off; + if (len > y) + len = y; + if (len + extra >= sizeof(u32)) { + data |= set_upper_bits(v, extra * + BITS_PER_BYTE); + len = sizeof(u32) - extra; + if (len == length) { + last = data; + break; + } + __raw_writel(data, piobuf); + piobuf++; + extra = 0; + data = 0; + } else { + /* Clear unused upper bytes */ + data |= clear_upper_bytes(v, len, extra); + if (len == length) { + last = data; + break; + } + extra += len; + } + } else if (extra) { + /* Source address is aligned. */ + u32 *addr = (u32 *) ss->sge.vaddr; + int shift = extra * BITS_PER_BYTE; + int ushift = 32 - shift; + u32 l = len; + + while (l >= sizeof(u32)) { + u32 v = *addr; + + data |= set_upper_bits(v, shift); + __raw_writel(data, piobuf); + data = get_upper_bits(v, ushift); + piobuf++; + addr++; + l -= sizeof(u32); + } + /* + * We still have 'extra' number of bytes leftover. + */ + if (l) { + u32 v = *addr; + + if (l + extra >= sizeof(u32)) { + data |= set_upper_bits(v, shift); + len -= l + extra - sizeof(u32); + if (len == length) { + last = data; + break; + } + __raw_writel(data, piobuf); + piobuf++; + extra = 0; + data = 0; + } else { + /* Clear unused upper bytes */ + data |= clear_upper_bytes(v, l, + extra); + if (len == length) { + last = data; + break; + } + extra += l; + } + } else if (len == length) { + last = data; + break; + } + } else if (len == length) { + u32 w; + + /* + * Need to round up for the last dword in the + * packet. + */ + w = (len + 3) >> 2; + __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1); + piobuf += w - 1; + last = ((u32 *) ss->sge.vaddr)[w - 1]; + break; + } else { + u32 w = len >> 2; + + __iowrite32_copy(piobuf, ss->sge.vaddr, w); + piobuf += w; + + extra = len & (sizeof(u32) - 1); + if (extra) { + u32 v = ((u32 *) ss->sge.vaddr)[w]; + + /* Clear unused upper bytes */ + data = clear_upper_bytes(v, extra, 0); + } + } + update_sge(ss, len); + length -= len; + } + /* must flush early everything before trigger word */ + ipath_flush_wc(); + __raw_writel(last, piobuf); + /* be sure trigger word is written */ + ipath_flush_wc(); + update_sge(ss, length); +} + +/** + * ipath_verbs_send - send a packet from the verbs layer + * @dd: the infinipath device + * @hdrwords: the number of works in the header + * @hdr: the packet header + * @len: the length of the packet in bytes + * @ss: the SGE to send + * + * This is like ipath_sma_send_pkt() in that we need to be able to send + * packets after the chip is initialized (MADs) but also like + * ipath_layer_send_hdr() since its used by the verbs layer. + */ +int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, + u32 *hdr, u32 len, struct ipath_sge_state *ss) +{ + u32 __iomem *piobuf; + u32 plen; + int ret; + + /* +1 is for the qword padding of pbc */ + plen = hdrwords + ((len + 3) >> 2) + 1; + if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) { + ipath_dbg("packet len 0x%x too long, failing\n", plen); + ret = -EINVAL; + goto bail; + } + + /* Get a PIO buffer to use. */ + piobuf = ipath_getpiobuf(dd, NULL); + if (unlikely(piobuf == NULL)) { + ret = -EBUSY; + goto bail; + } + + /* + * Write len to control qword, no flags. + * We have to flush after the PBC for correctness on some cpus + * or WC buffer can be written out of order. + */ + writeq(plen, piobuf); + ipath_flush_wc(); + piobuf += 2; + if (len == 0) { + /* + * If there is just the header portion, must flush before + * writing last word of header for correctness, and after + * the last header word (trigger word). + */ + __iowrite32_copy(piobuf, hdr, hdrwords - 1); + ipath_flush_wc(); + __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1); + ipath_flush_wc(); + ret = 0; + goto bail; + } + + __iowrite32_copy(piobuf, hdr, hdrwords); + piobuf += hdrwords; + + /* The common case is aligned and contained in one segment. */ + if (likely(ss->num_sge == 1 && len <= ss->sge.length && + !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) { + u32 w; + + /* Need to round up for the last dword in the packet. */ + w = (len + 3) >> 2; + __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1); + /* must flush early everything before trigger word */ + ipath_flush_wc(); + __raw_writel(((u32 *) ss->sge.vaddr)[w - 1], + piobuf + w - 1); + /* be sure trigger word is written */ + ipath_flush_wc(); + update_sge(ss, len); + ret = 0; + goto bail; + } + copy_io(piobuf, ss, len); + ret = 0; + +bail: + return ret; +} + +EXPORT_SYMBOL_GPL(ipath_verbs_send); + +int ipath_layer_snapshot_counters(struct ipath_devdata *dd, u64 *swords, + u64 *rwords, u64 *spkts, u64 *rpkts, + u64 *xmit_wait) +{ + int ret; + + if (!(dd->ipath_flags & IPATH_INITTED)) { + /* no hardware, freeze, etc. */ + ipath_dbg("unit %u not usable\n", dd->ipath_unit); + ret = -EINVAL; + goto bail; + } + *swords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); + *rwords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); + *spkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); + *rpkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); + *xmit_wait = ipath_snap_cntr(dd, dd->ipath_cregs->cr_sendstallcnt); + + ret = 0; + +bail: + return ret; +} + +EXPORT_SYMBOL_GPL(ipath_layer_snapshot_counters); + +/** + * ipath_layer_get_counters - get various chip counters + * @dd: the infinipath device + * @cntrs: counters are placed here + * + * Return the counters needed by recv_pma_get_portcounters(). + */ +int ipath_layer_get_counters(struct ipath_devdata *dd, + struct ipath_layer_counters *cntrs) +{ + int ret; + + if (!(dd->ipath_flags & IPATH_INITTED)) { + /* no hardware, freeze, etc. */ + ipath_dbg("unit %u not usable\n", dd->ipath_unit); + ret = -EINVAL; + goto bail; + } + cntrs->symbol_error_counter = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt); + cntrs->link_error_recovery_counter = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt); + cntrs->link_downed_counter = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt); + cntrs->port_rcv_errors = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_errrcvflowctrlcnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlinkcnt) + + ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt); + cntrs->port_rcv_remphys_errors = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt); + cntrs->port_xmit_discards = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt); + cntrs->port_xmit_data = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); + cntrs->port_rcv_data = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); + cntrs->port_xmit_packets = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); + cntrs->port_rcv_packets = + ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); + + ret = 0; + +bail: + return ret; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_counters); + +int ipath_layer_want_buffer(struct ipath_devdata *dd) +{ + set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + dd->ipath_sendctrl); + + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_want_buffer); + +int ipath_layer_send_hdr(struct ipath_devdata *dd, struct ether_header *hdr) +{ + int ret = 0; + u32 __iomem *piobuf; + u32 plen, *uhdr; + size_t count; + __be16 vlsllnh; + + if (!(dd->ipath_flags & IPATH_RCVHDRSZ_SET)) { + ipath_dbg("send while not open\n"); + ret = -EINVAL; + } else + if ((dd->ipath_flags & (IPATH_LINKUNK | IPATH_LINKDOWN)) || + dd->ipath_lid == 0) { + /* + * lid check is for when sma hasn't yet configured + */ + ret = -ENETDOWN; + ipath_cdbg(VERBOSE, "send while not ready, " + "mylid=%u, flags=0x%x\n", + dd->ipath_lid, dd->ipath_flags); + } + + vlsllnh = *((__be16 *) hdr); + if (vlsllnh != htons(IPS_LRH_BTH)) { + ipath_dbg("Warning: lrh[0] wrong (%x, not %x); " + "not sending\n", be16_to_cpu(vlsllnh), + IPS_LRH_BTH); + ret = -EINVAL; + } + if (ret) + goto done; + + /* Get a PIO buffer to use. */ + piobuf = ipath_getpiobuf(dd, NULL); + if (piobuf == NULL) { + ret = -EBUSY; + goto done; + } + + plen = (sizeof(*hdr) >> 2); /* actual length */ + ipath_cdbg(EPKT, "0x%x+1w pio %p\n", plen, piobuf); + + writeq(plen+1, piobuf); /* len (+1 for pad) to pbc, no flags */ + ipath_flush_wc(); + piobuf += 2; + uhdr = (u32 *)hdr; + count = plen-1; /* amount we can copy before trigger word */ + __iowrite32_copy(piobuf, uhdr, count); + ipath_flush_wc(); + __raw_writel(uhdr[count], piobuf + count); + ipath_flush_wc(); /* ensure it's sent, now */ + + ipath_stats.sps_ether_spkts++; /* ether packet sent */ + +done: + return ret; +} + +EXPORT_SYMBOL_GPL(ipath_layer_send_hdr); + +int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd) +{ + set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); + + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + dd->ipath_sendctrl); + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_set_piointbufavail_int); + +int ipath_layer_enable_timer(struct ipath_devdata *dd) +{ + /* + * HT-400 has a design flaw where the chip and kernel idea + * of the tail register don't always agree, and therefore we won't + * get an interrupt on the next packet received. + * If the board supports per packet receive interrupts, use it. + * Otherwise, the timer function periodically checks for packets + * to cover this case. + * Either way, the timer is needed for verbs layer related + * processing. + */ + if (dd->ipath_flags & IPATH_GPIO_INTR) { + ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect, + 0x2074076542310ULL); + /* Enable GPIO bit 2 interrupt */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, + (u64) (1 << 2)); + } + + init_timer(&dd->verbs_layer.l_timer); + dd->verbs_layer.l_timer.function = __ipath_verbs_timer; + dd->verbs_layer.l_timer.data = (unsigned long)dd; + dd->verbs_layer.l_timer.expires = jiffies + 1; + add_timer(&dd->verbs_layer.l_timer); + + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_enable_timer); + +int ipath_layer_disable_timer(struct ipath_devdata *dd) +{ + /* Disable GPIO bit 2 interrupt */ + if (dd->ipath_flags & IPATH_GPIO_INTR) + ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, 0); + + del_timer_sync(&dd->verbs_layer.l_timer); + + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_disable_timer); + +/** + * ipath_layer_set_verbs_flags - set the verbs layer flags + * @dd: the infinipath device + * @flags: the flags to set + */ +int ipath_layer_set_verbs_flags(struct ipath_devdata *dd, unsigned flags) +{ + struct ipath_devdata *ss; + unsigned long lflags; + + spin_lock_irqsave(&ipath_devs_lock, lflags); + + list_for_each_entry(ss, &ipath_dev_list, ipath_list) { + if (!(ss->ipath_flags & IPATH_INITTED)) + continue; + if ((flags & IPATH_VERBS_KERNEL_SMA) && + !(*ss->ipath_statusp & IPATH_STATUS_SMA)) + *ss->ipath_statusp |= IPATH_STATUS_OIB_SMA; + else + *ss->ipath_statusp &= ~IPATH_STATUS_OIB_SMA; + } + + spin_unlock_irqrestore(&ipath_devs_lock, lflags); + + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_set_verbs_flags); + +/** + * ipath_layer_get_npkeys - return the size of the PKEY table for port 0 + * @dd: the infinipath device + */ +unsigned ipath_layer_get_npkeys(struct ipath_devdata *dd) +{ + return ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys); +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_npkeys); + +/** + * ipath_layer_get_pkey - return the indexed PKEY from the port 0 PKEY table + * @dd: the infinipath device + * @index: the PKEY index + */ +unsigned ipath_layer_get_pkey(struct ipath_devdata *dd, unsigned index) +{ + unsigned ret; + + if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys)) + ret = 0; + else + ret = dd->ipath_pd[0]->port_pkeys[index]; + + return ret; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_pkey); + +/** + * ipath_layer_get_pkeys - return the PKEY table for port 0 + * @dd: the infinipath device + * @pkeys: the pkey table is placed here + */ +int ipath_layer_get_pkeys(struct ipath_devdata *dd, u16 * pkeys) +{ + struct ipath_portdata *pd = dd->ipath_pd[0]; + + memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys)); + + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_pkeys); + +/** + * rm_pkey - decrecment the reference count for the given PKEY + * @dd: the infinipath device + * @key: the PKEY index + * + * Return true if this was the last reference and the hardware table entry + * needs to be changed. + */ +static int rm_pkey(struct ipath_devdata *dd, u16 key) +{ + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { + if (dd->ipath_pkeys[i] != key) + continue; + if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) { + dd->ipath_pkeys[i] = 0; + ret = 1; + goto bail; + } + break; + } + + ret = 0; + +bail: + return ret; +} + +/** + * add_pkey - add the given PKEY to the hardware table + * @dd: the infinipath device + * @key: the PKEY + * + * Return an error code if unable to add the entry, zero if no change, + * or 1 if the hardware PKEY register needs to be updated. + */ +static int add_pkey(struct ipath_devdata *dd, u16 key) +{ + int i; + u16 lkey = key & 0x7FFF; + int any = 0; + int ret; + + if (lkey == 0x7FFF) { + ret = 0; + goto bail; + } + + /* Look for an empty slot or a matching PKEY. */ + for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { + if (!dd->ipath_pkeys[i]) { + any++; + continue; + } + /* If it matches exactly, try to increment the ref count */ + if (dd->ipath_pkeys[i] == key) { + if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) { + ret = 0; + goto bail; + } + /* Lost the race. Look for an empty slot below. */ + atomic_dec(&dd->ipath_pkeyrefs[i]); + any++; + } + /* + * It makes no sense to have both the limited and unlimited + * PKEY set at the same time since the unlimited one will + * disable the limited one. + */ + if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) { + ret = -EEXIST; + goto bail; + } + } + if (!any) { + ret = -EBUSY; + goto bail; + } + for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) { + if (!dd->ipath_pkeys[i] && + atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) { + /* for ipathstats, etc. */ + ipath_stats.sps_pkeys[i] = lkey; + dd->ipath_pkeys[i] = key; + ret = 1; + goto bail; + } + } + ret = -EBUSY; + +bail: + return ret; +} + +/** + * ipath_layer_set_pkeys - set the PKEY table for port 0 + * @dd: the infinipath device + * @pkeys: the PKEY table + */ +int ipath_layer_set_pkeys(struct ipath_devdata *dd, u16 * pkeys) +{ + struct ipath_portdata *pd; + int i; + int changed = 0; + + pd = dd->ipath_pd[0]; + + for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) { + u16 key = pkeys[i]; + u16 okey = pd->port_pkeys[i]; + + if (key == okey) + continue; + /* + * The value of this PKEY table entry is changing. + * Remove the old entry in the hardware's array of PKEYs. + */ + if (okey & 0x7FFF) + changed |= rm_pkey(dd, okey); + if (key & 0x7FFF) { + int ret = add_pkey(dd, key); + + if (ret < 0) + key = 0; + else + changed |= ret; + } + pd->port_pkeys[i] = key; + } + if (changed) { + u64 pkey; + + pkey = (u64) dd->ipath_pkeys[0] | + ((u64) dd->ipath_pkeys[1] << 16) | + ((u64) dd->ipath_pkeys[2] << 32) | + ((u64) dd->ipath_pkeys[3] << 48); + ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n", + (unsigned long long) pkey); + ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey, + pkey); + } + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_set_pkeys); + +/** + * ipath_layer_get_linkdowndefaultstate - get the default linkdown state + * @dd: the infinipath device + * + * Returns zero if the default is POLL, 1 if the default is SLEEP. + */ +int ipath_layer_get_linkdowndefaultstate(struct ipath_devdata *dd) +{ + return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE); +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_linkdowndefaultstate); + +/** + * ipath_layer_set_linkdowndefaultstate - set the default linkdown state + * @dd: the infinipath device + * @sleep: the new state + * + * Note that this will only take effect when the link state changes. + */ +int ipath_layer_set_linkdowndefaultstate(struct ipath_devdata *dd, + int sleep) +{ + if (sleep) + dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE; + else + dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE; + ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, + dd->ipath_ibcctrl); + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_set_linkdowndefaultstate); + +int ipath_layer_get_phyerrthreshold(struct ipath_devdata *dd) +{ + return (dd->ipath_ibcctrl >> + INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) & + INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_phyerrthreshold); + +/** + * ipath_layer_set_phyerrthreshold - set the physical error threshold + * @dd: the infinipath device + * @n: the new threshold + * + * Note that this will only take effect when the link state changes. + */ +int ipath_layer_set_phyerrthreshold(struct ipath_devdata *dd, unsigned n) +{ + unsigned v; + + v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) & + INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK; + if (v != n) { + dd->ipath_ibcctrl &= + ~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK << + INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT); + dd->ipath_ibcctrl |= + (u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT; + ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, + dd->ipath_ibcctrl); + } + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_set_phyerrthreshold); + +int ipath_layer_get_overrunthreshold(struct ipath_devdata *dd) +{ + return (dd->ipath_ibcctrl >> + INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) & + INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK; +} + +EXPORT_SYMBOL_GPL(ipath_layer_get_overrunthreshold); + +/** + * ipath_layer_set_overrunthreshold - set the overrun threshold + * @dd: the infinipath device + * @n: the new threshold + * + * Note that this will only take effect when the link state changes. + */ +int ipath_layer_set_overrunthreshold(struct ipath_devdata *dd, unsigned n) +{ + unsigned v; + + v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) & + INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK; + if (v != n) { + dd->ipath_ibcctrl &= + ~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK << + INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT); + dd->ipath_ibcctrl |= + (u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT; + ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl, + dd->ipath_ibcctrl); + } + return 0; +} + +EXPORT_SYMBOL_GPL(ipath_layer_set_overrunthreshold); + +int ipath_layer_get_boardname(struct ipath_devdata *dd, char *name, + size_t namelen) +{ + return dd->ipath_f_get_boardname(dd, name, namelen); +} +EXPORT_SYMBOL_GPL(ipath_layer_get_boardname); + +u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd) +{ + return dd->ipath_rcvhdrentsize; +} +EXPORT_SYMBOL_GPL(ipath_layer_get_rcvhdrentsize); diff --git a/drivers/infiniband/hw/ipath/ipath_layer.h b/drivers/infiniband/hw/ipath/ipath_layer.h new file mode 100644 index 000000000000..6fefd15bd2da --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_layer.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _IPATH_LAYER_H +#define _IPATH_LAYER_H + +/* + * This header file is for symbols shared between the infinipath driver + * and drivers layered upon it (such as ipath). + */ + +struct sk_buff; +struct ipath_sge_state; +struct ipath_devdata; +struct ether_header; + +struct ipath_layer_counters { + u64 symbol_error_counter; + u64 link_error_recovery_counter; + u64 link_downed_counter; + u64 port_rcv_errors; + u64 port_rcv_remphys_errors; + u64 port_xmit_discards; + u64 port_xmit_data; + u64 port_rcv_data; + u64 port_xmit_packets; + u64 port_rcv_packets; +}; + +/* + * A segment is a linear region of low physical memory. + * XXX Maybe we should use phys addr here and kmap()/kunmap(). + * Used by the verbs layer. + */ +struct ipath_seg { + void *vaddr; + size_t length; +}; + +/* The number of ipath_segs that fit in a page. */ +#define IPATH_SEGSZ (PAGE_SIZE / sizeof (struct ipath_seg)) + +struct ipath_segarray { + struct ipath_seg segs[IPATH_SEGSZ]; +}; + +struct ipath_mregion { + u64 user_base; /* User's address for this region */ + u64 iova; /* IB start address of this region */ + size_t length; + u32 lkey; + u32 offset; /* offset (bytes) to start of region */ + int access_flags; + u32 max_segs; /* number of ipath_segs in all the arrays */ + u32 mapsz; /* size of the map array */ + struct ipath_segarray *map[0]; /* the segments */ +}; + +/* + * These keep track of the copy progress within a memory region. + * Used by the verbs layer. + */ +struct ipath_sge { + struct ipath_mregion *mr; + void *vaddr; /* current pointer into the segment */ + u32 sge_length; /* length of the SGE */ + u32 length; /* remaining length of the segment */ + u16 m; /* current index: mr->map[m] */ + u16 n; /* current index: mr->map[m]->segs[n] */ +}; + +struct ipath_sge_state { + struct ipath_sge *sg_list; /* next SGE to be used if any */ + struct ipath_sge sge; /* progress state for the current SGE */ + u8 num_sge; +}; + +int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *), + void (*l_remove)(void *), + int (*l_intr)(void *, u32), + int (*l_rcv)(void *, void *, + struct sk_buff *), + u16 rcv_opcode, + int (*l_rcv_lid)(void *, void *)); +int ipath_verbs_register(void *(*l_add)(int, struct ipath_devdata *), + void (*l_remove)(void *arg), + int (*l_piobufavail)(void *arg), + void (*l_rcv)(void *arg, void *rhdr, + void *data, u32 tlen), + void (*l_timer_cb)(void *arg)); +void ipath_layer_unregister(void); +void ipath_verbs_unregister(void); +int ipath_layer_open(struct ipath_devdata *, u32 * pktmax); +u16 ipath_layer_get_lid(struct ipath_devdata *dd); +int ipath_layer_get_mac(struct ipath_devdata *dd, u8 *); +u16 ipath_layer_get_bcast(struct ipath_devdata *dd); +u32 ipath_layer_get_cr_errpkey(struct ipath_devdata *dd); +int ipath_layer_set_linkstate(struct ipath_devdata *dd, u8 state); +int ipath_layer_set_mtu(struct ipath_devdata *, u16); +int ipath_set_sps_lid(struct ipath_devdata *, u32, u8); +int ipath_layer_send_hdr(struct ipath_devdata *dd, + struct ether_header *hdr); +int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords, + u32 * hdr, u32 len, struct ipath_sge_state *ss); +int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd); +int ipath_layer_get_boardname(struct ipath_devdata *dd, char *name, + size_t namelen); +int ipath_layer_snapshot_counters(struct ipath_devdata *dd, u64 *swords, + u64 *rwords, u64 *spkts, u64 *rpkts, + u64 *xmit_wait); +int ipath_layer_get_counters(struct ipath_devdata *dd, + struct ipath_layer_counters *cntrs); +int ipath_layer_want_buffer(struct ipath_devdata *dd); +int ipath_layer_set_guid(struct ipath_devdata *, __be64 guid); +__be64 ipath_layer_get_guid(struct ipath_devdata *); +u32 ipath_layer_get_nguid(struct ipath_devdata *); +int ipath_layer_query_device(struct ipath_devdata *, u32 * vendor, + u32 * boardrev, u32 * majrev, u32 * minrev); +u32 ipath_layer_get_flags(struct ipath_devdata *dd); +struct device *ipath_layer_get_device(struct ipath_devdata *dd); +u16 ipath_layer_get_deviceid(struct ipath_devdata *dd); +u64 ipath_layer_get_lastibcstat(struct ipath_devdata *dd); +u32 ipath_layer_get_ibmtu(struct ipath_devdata *dd); +int ipath_layer_enable_timer(struct ipath_devdata *dd); +int ipath_layer_disable_timer(struct ipath_devdata *dd); +int ipath_layer_set_verbs_flags(struct ipath_devdata *dd, unsigned flags); +unsigned ipath_layer_get_npkeys(struct ipath_devdata *dd); +unsigned ipath_layer_get_pkey(struct ipath_devdata *dd, unsigned index); +int ipath_layer_get_pkeys(struct ipath_devdata *dd, u16 *pkeys); +int ipath_layer_set_pkeys(struct ipath_devdata *dd, u16 *pkeys); +int ipath_layer_get_linkdowndefaultstate(struct ipath_devdata *dd); +int ipath_layer_set_linkdowndefaultstate(struct ipath_devdata *dd, + int sleep); +int ipath_layer_get_phyerrthreshold(struct ipath_devdata *dd); +int ipath_layer_set_phyerrthreshold(struct ipath_devdata *dd, unsigned n); +int ipath_layer_get_overrunthreshold(struct ipath_devdata *dd); +int ipath_layer_set_overrunthreshold(struct ipath_devdata *dd, unsigned n); +u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd); + +/* ipath_ether interrupt values */ +#define IPATH_LAYER_INT_IF_UP 0x2 +#define IPATH_LAYER_INT_IF_DOWN 0x4 +#define IPATH_LAYER_INT_LID 0x8 +#define IPATH_LAYER_INT_SEND_CONTINUE 0x10 +#define IPATH_LAYER_INT_BCAST 0x40 + +/* _verbs_layer.l_flags */ +#define IPATH_VERBS_KERNEL_SMA 0x1 + +extern unsigned ipath_debug; /* debugging bit mask */ + +#endif /* _IPATH_LAYER_H */ diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c new file mode 100644 index 000000000000..f7f8391fe43f --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -0,0 +1,1352 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "ipath_kernel.h" +#include "ipath_verbs.h" +#include "ips_common.h" + +#define IB_SMP_UNSUP_VERSION __constant_htons(0x0004) +#define IB_SMP_UNSUP_METHOD __constant_htons(0x0008) +#define IB_SMP_UNSUP_METH_ATTR __constant_htons(0x000C) +#define IB_SMP_INVALID_FIELD __constant_htons(0x001C) + +static int reply(struct ib_smp *smp) +{ + /* + * The verbs framework will handle the directed/LID route + * packet changes. + */ + smp->method = IB_MGMT_METHOD_GET_RESP; + if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) + smp->status |= IB_SMP_DIRECTION; + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; +} + +static int recv_subn_get_nodedescription(struct ib_smp *smp, + struct ib_device *ibdev) +{ + if (smp->attr_mod) + smp->status |= IB_SMP_INVALID_FIELD; + + strncpy(smp->data, ibdev->node_desc, sizeof(smp->data)); + + return reply(smp); +} + +struct nodeinfo { + u8 base_version; + u8 class_version; + u8 node_type; + u8 num_ports; + __be64 sys_guid; + __be64 node_guid; + __be64 port_guid; + __be16 partition_cap; + __be16 device_id; + __be32 revision; + u8 local_port_num; + u8 vendor_id[3]; +} __attribute__ ((packed)); + +static int recv_subn_get_nodeinfo(struct ib_smp *smp, + struct ib_device *ibdev, u8 port) +{ + struct nodeinfo *nip = (struct nodeinfo *)&smp->data; + struct ipath_devdata *dd = to_idev(ibdev)->dd; + u32 vendor, boardid, majrev, minrev; + + if (smp->attr_mod) + smp->status |= IB_SMP_INVALID_FIELD; + + nip->base_version = 1; + nip->class_version = 1; + nip->node_type = 1; /* channel adapter */ + /* + * XXX The num_ports value will need a layer function to get + * the value if we ever have more than one IB port on a chip. + * We will also need to get the GUID for the port. + */ + nip->num_ports = ibdev->phys_port_cnt; + /* This is already in network order */ + nip->sys_guid = to_idev(ibdev)->sys_image_guid; + nip->node_guid = ipath_layer_get_guid(dd); + nip->port_guid = nip->sys_guid; + nip->partition_cap = cpu_to_be16(ipath_layer_get_npkeys(dd)); + nip->device_id = cpu_to_be16(ipath_layer_get_deviceid(dd)); + ipath_layer_query_device(dd, &vendor, &boardid, &majrev, &minrev); + nip->revision = cpu_to_be32((majrev << 16) | minrev); + nip->local_port_num = port; + nip->vendor_id[0] = 0; + nip->vendor_id[1] = vendor >> 8; + nip->vendor_id[2] = vendor; + + return reply(smp); +} + +static int recv_subn_get_guidinfo(struct ib_smp *smp, + struct ib_device *ibdev) +{ + u32 startgx = 8 * be32_to_cpu(smp->attr_mod); + __be64 *p = (__be64 *) smp->data; + + /* 32 blocks of 8 64-bit GUIDs per block */ + + memset(smp->data, 0, sizeof(smp->data)); + + /* + * We only support one GUID for now. If this changes, the + * portinfo.guid_cap field needs to be updated too. + */ + if (startgx == 0) + /* The first is a copy of the read-only HW GUID. */ + *p = ipath_layer_get_guid(to_idev(ibdev)->dd); + else + smp->status |= IB_SMP_INVALID_FIELD; + + return reply(smp); +} + +struct port_info { + __be64 mkey; + __be64 gid_prefix; + __be16 lid; + __be16 sm_lid; + __be32 cap_mask; + __be16 diag_code; + __be16 mkey_lease_period; + u8 local_port_num; + u8 link_width_enabled; + u8 link_width_supported; + u8 link_width_active; + u8 linkspeed_portstate; /* 4 bits, 4 bits */ + u8 portphysstate_linkdown; /* 4 bits, 4 bits */ + u8 mkeyprot_resv_lmc; /* 2 bits, 3, 3 */ + u8 linkspeedactive_enabled; /* 4 bits, 4 bits */ + u8 neighbormtu_mastersmsl; /* 4 bits, 4 bits */ + u8 vlcap_inittype; /* 4 bits, 4 bits */ + u8 vl_high_limit; + u8 vl_arb_high_cap; + u8 vl_arb_low_cap; + u8 inittypereply_mtucap; /* 4 bits, 4 bits */ + u8 vlstallcnt_hoqlife; /* 3 bits, 5 bits */ + u8 operationalvl_pei_peo_fpi_fpo; /* 4 bits, 1, 1, 1, 1 */ + __be16 mkey_violations; + __be16 pkey_violations; + __be16 qkey_violations; + u8 guid_cap; + u8 clientrereg_resv_subnetto; /* 1 bit, 2 bits, 5 */ + u8 resv_resptimevalue; /* 3 bits, 5 bits */ + u8 localphyerrors_overrunerrors; /* 4 bits, 4 bits */ + __be16 max_credit_hint; + u8 resv; + u8 link_roundtrip_latency[3]; +} __attribute__ ((packed)); + +static int recv_subn_get_portinfo(struct ib_smp *smp, + struct ib_device *ibdev, u8 port) +{ + struct ipath_ibdev *dev; + struct port_info *pip = (struct port_info *)smp->data; + u16 lid; + u8 ibcstat; + u8 mtu; + int ret; + + if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt) { + smp->status |= IB_SMP_INVALID_FIELD; + ret = reply(smp); + goto bail; + } + + dev = to_idev(ibdev); + + /* Clear all fields. Only set the non-zero fields. */ + memset(smp->data, 0, sizeof(smp->data)); + + /* Only return the mkey if the protection field allows it. */ + if (smp->method == IB_MGMT_METHOD_SET || dev->mkey == smp->mkey || + (dev->mkeyprot_resv_lmc >> 6) == 0) + pip->mkey = dev->mkey; + pip->gid_prefix = dev->gid_prefix; + lid = ipath_layer_get_lid(dev->dd); + pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE; + pip->sm_lid = cpu_to_be16(dev->sm_lid); + pip->cap_mask = cpu_to_be32(dev->port_cap_flags); + /* pip->diag_code; */ + pip->mkey_lease_period = cpu_to_be16(dev->mkey_lease_period); + pip->local_port_num = port; + pip->link_width_enabled = dev->link_width_enabled; + pip->link_width_supported = 3; /* 1x or 4x */ + pip->link_width_active = 2; /* 4x */ + pip->linkspeed_portstate = 0x10; /* 2.5Gbps */ + ibcstat = ipath_layer_get_lastibcstat(dev->dd); + pip->linkspeed_portstate |= ((ibcstat >> 4) & 0x3) + 1; + pip->portphysstate_linkdown = + (ipath_cvt_physportstate[ibcstat & 0xf] << 4) | + (ipath_layer_get_linkdowndefaultstate(dev->dd) ? 1 : 2); + pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc; + pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */ + switch (ipath_layer_get_ibmtu(dev->dd)) { + case 4096: + mtu = IB_MTU_4096; + break; + case 2048: + mtu = IB_MTU_2048; + break; + case 1024: + mtu = IB_MTU_1024; + break; + case 512: + mtu = IB_MTU_512; + break; + case 256: + mtu = IB_MTU_256; + break; + default: /* oops, something is wrong */ + mtu = IB_MTU_2048; + break; + } + pip->neighbormtu_mastersmsl = (mtu << 4) | dev->sm_sl; + pip->vlcap_inittype = 0x10; /* VLCap = VL0, InitType = 0 */ + pip->vl_high_limit = dev->vl_high_limit; + /* pip->vl_arb_high_cap; // only one VL */ + /* pip->vl_arb_low_cap; // only one VL */ + /* InitTypeReply = 0 */ + pip->inittypereply_mtucap = IB_MTU_4096; + // HCAs ignore VLStallCount and HOQLife + /* pip->vlstallcnt_hoqlife; */ + pip->operationalvl_pei_peo_fpi_fpo = 0x10; /* OVLs = 1 */ + pip->mkey_violations = cpu_to_be16(dev->mkey_violations); + /* P_KeyViolations are counted by hardware. */ + pip->pkey_violations = + cpu_to_be16((ipath_layer_get_cr_errpkey(dev->dd) - + dev->n_pkey_violations) & 0xFFFF); + pip->qkey_violations = cpu_to_be16(dev->qkey_violations); + /* Only the hardware GUID is supported for now */ + pip->guid_cap = 1; + pip->clientrereg_resv_subnetto = dev->subnet_timeout; + /* 32.768 usec. response time (guessing) */ + pip->resv_resptimevalue = 3; + pip->localphyerrors_overrunerrors = + (ipath_layer_get_phyerrthreshold(dev->dd) << 4) | + ipath_layer_get_overrunthreshold(dev->dd); + /* pip->max_credit_hint; */ + /* pip->link_roundtrip_latency[3]; */ + + ret = reply(smp); + +bail: + return ret; +} + +static int recv_subn_get_pkeytable(struct ib_smp *smp, + struct ib_device *ibdev) +{ + u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff); + u16 *p = (u16 *) smp->data; + __be16 *q = (__be16 *) smp->data; + + /* 64 blocks of 32 16-bit P_Key entries */ + + memset(smp->data, 0, sizeof(smp->data)); + if (startpx == 0) { + struct ipath_ibdev *dev = to_idev(ibdev); + unsigned i, n = ipath_layer_get_npkeys(dev->dd); + + ipath_layer_get_pkeys(dev->dd, p); + + for (i = 0; i < n; i++) + q[i] = cpu_to_be16(p[i]); + } else + smp->status |= IB_SMP_INVALID_FIELD; + + return reply(smp); +} + +static int recv_subn_set_guidinfo(struct ib_smp *smp, + struct ib_device *ibdev) +{ + /* The only GUID we support is the first read-only entry. */ + return recv_subn_get_guidinfo(smp, ibdev); +} + +/** + * recv_subn_set_portinfo - set port information + * @smp: the incoming SM packet + * @ibdev: the infiniband device + * @port: the port on the device + * + * Set Portinfo (see ch. 14.2.5.6). + */ +static int recv_subn_set_portinfo(struct ib_smp *smp, + struct ib_device *ibdev, u8 port) +{ + struct port_info *pip = (struct port_info *)smp->data; + struct ib_event event; + struct ipath_ibdev *dev; + u32 flags; + char clientrereg = 0; + u16 lid, smlid; + u8 lwe; + u8 lse; + u8 state; + u16 lstate; + u32 mtu; + int ret; + + if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt) + goto err; + + dev = to_idev(ibdev); + event.device = ibdev; + event.element.port_num = port; + + dev->mkey = pip->mkey; + dev->gid_prefix = pip->gid_prefix; + dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period); + + lid = be16_to_cpu(pip->lid); + if (lid != ipath_layer_get_lid(dev->dd)) { + /* Must be a valid unicast LID address. */ + if (lid == 0 || lid >= IPS_MULTICAST_LID_BASE) + goto err; + ipath_set_sps_lid(dev->dd, lid, pip->mkeyprot_resv_lmc & 7); + event.event = IB_EVENT_LID_CHANGE; + ib_dispatch_event(&event); + } + + smlid = be16_to_cpu(pip->sm_lid); + if (smlid != dev->sm_lid) { + /* Must be a valid unicast LID address. */ + if (smlid == 0 || smlid >= IPS_MULTICAST_LID_BASE) + goto err; + dev->sm_lid = smlid; + event.event = IB_EVENT_SM_CHANGE; + ib_dispatch_event(&event); + } + + /* Only 4x supported but allow 1x or 4x to be set (see 14.2.6.6). */ + lwe = pip->link_width_enabled; + if ((lwe >= 4 && lwe <= 8) || (lwe >= 0xC && lwe <= 0xFE)) + goto err; + if (lwe == 0xFF) + dev->link_width_enabled = 3; /* 1x or 4x */ + else if (lwe) + dev->link_width_enabled = lwe; + + /* Only 2.5 Gbs supported. */ + lse = pip->linkspeedactive_enabled & 0xF; + if (lse >= 2 && lse <= 0xE) + goto err; + + /* Set link down default state. */ + switch (pip->portphysstate_linkdown & 0xF) { + case 0: /* NOP */ + break; + case 1: /* SLEEP */ + if (ipath_layer_set_linkdowndefaultstate(dev->dd, 1)) + goto err; + break; + case 2: /* POLL */ + if (ipath_layer_set_linkdowndefaultstate(dev->dd, 0)) + goto err; + break; + default: + goto err; + } + + dev->mkeyprot_resv_lmc = pip->mkeyprot_resv_lmc; + dev->vl_high_limit = pip->vl_high_limit; + + switch ((pip->neighbormtu_mastersmsl >> 4) & 0xF) { + case IB_MTU_256: + mtu = 256; + break; + case IB_MTU_512: + mtu = 512; + break; + case IB_MTU_1024: + mtu = 1024; + break; + case IB_MTU_2048: + mtu = 2048; + break; + case IB_MTU_4096: + mtu = 4096; + break; + default: + /* XXX We have already partially updated our state! */ + goto err; + } + ipath_layer_set_mtu(dev->dd, mtu); + + dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF; + + /* We only support VL0 */ + if (((pip->operationalvl_pei_peo_fpi_fpo >> 4) & 0xF) > 1) + goto err; + + if (pip->mkey_violations == 0) + dev->mkey_violations = 0; + + /* + * Hardware counter can't be reset so snapshot and subtract + * later. + */ + if (pip->pkey_violations == 0) + dev->n_pkey_violations = + ipath_layer_get_cr_errpkey(dev->dd); + + if (pip->qkey_violations == 0) + dev->qkey_violations = 0; + + if (ipath_layer_set_phyerrthreshold( + dev->dd, + (pip->localphyerrors_overrunerrors >> 4) & 0xF)) + goto err; + + if (ipath_layer_set_overrunthreshold( + dev->dd, + (pip->localphyerrors_overrunerrors & 0xF))) + goto err; + + dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F; + + if (pip->clientrereg_resv_subnetto & 0x80) { + clientrereg = 1; + event.event = IB_EVENT_LID_CHANGE; + ib_dispatch_event(&event); + } + + /* + * Do the port state change now that the other link parameters + * have been set. + * Changing the port physical state only makes sense if the link + * is down or is being set to down. + */ + state = pip->linkspeed_portstate & 0xF; + flags = ipath_layer_get_flags(dev->dd); + lstate = (pip->portphysstate_linkdown >> 4) & 0xF; + if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP)) + goto err; + + /* + * Only state changes of DOWN, ARM, and ACTIVE are valid + * and must be in the correct state to take effect (see 7.2.6). + */ + switch (state) { + case IB_PORT_NOP: + if (lstate == 0) + break; + /* FALLTHROUGH */ + case IB_PORT_DOWN: + if (lstate == 0) + if (ipath_layer_get_linkdowndefaultstate(dev->dd)) + lstate = IPATH_IB_LINKDOWN_SLEEP; + else + lstate = IPATH_IB_LINKDOWN; + else if (lstate == 1) + lstate = IPATH_IB_LINKDOWN_SLEEP; + else if (lstate == 2) + lstate = IPATH_IB_LINKDOWN; + else if (lstate == 3) + lstate = IPATH_IB_LINKDOWN_DISABLE; + else + goto err; + ipath_layer_set_linkstate(dev->dd, lstate); + if (flags & IPATH_LINKACTIVE) { + event.event = IB_EVENT_PORT_ERR; + ib_dispatch_event(&event); + } + break; + case IB_PORT_ARMED: + if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) + break; + ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKARM); + if (flags & IPATH_LINKACTIVE) { + event.event = IB_EVENT_PORT_ERR; + ib_dispatch_event(&event); + } + break; + case IB_PORT_ACTIVE: + if (!(flags & IPATH_LINKARMED)) + break; + ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE); + event.event = IB_EVENT_PORT_ACTIVE; + ib_dispatch_event(&event); + break; + default: + /* XXX We have already partially updated our state! */ + goto err; + } + + ret = recv_subn_get_portinfo(smp, ibdev, port); + + if (clientrereg) + pip->clientrereg_resv_subnetto |= 0x80; + + goto done; + +err: + smp->status |= IB_SMP_INVALID_FIELD; + ret = recv_subn_get_portinfo(smp, ibdev, port); + +done: + return ret; +} + +static int recv_subn_set_pkeytable(struct ib_smp *smp, + struct ib_device *ibdev) +{ + u32 startpx = 32 * (be32_to_cpu(smp->attr_mod) & 0xffff); + __be16 *p = (__be16 *) smp->data; + u16 *q = (u16 *) smp->data; + struct ipath_ibdev *dev = to_idev(ibdev); + unsigned i, n = ipath_layer_get_npkeys(dev->dd); + + for (i = 0; i < n; i++) + q[i] = be16_to_cpu(p[i]); + + if (startpx != 0 || + ipath_layer_set_pkeys(dev->dd, q) != 0) + smp->status |= IB_SMP_INVALID_FIELD; + + return recv_subn_get_pkeytable(smp, ibdev); +} + +#define IB_PMA_CLASS_PORT_INFO __constant_htons(0x0001) +#define IB_PMA_PORT_SAMPLES_CONTROL __constant_htons(0x0010) +#define IB_PMA_PORT_SAMPLES_RESULT __constant_htons(0x0011) +#define IB_PMA_PORT_COUNTERS __constant_htons(0x0012) +#define IB_PMA_PORT_COUNTERS_EXT __constant_htons(0x001D) +#define IB_PMA_PORT_SAMPLES_RESULT_EXT __constant_htons(0x001E) + +struct ib_perf { + u8 base_version; + u8 mgmt_class; + u8 class_version; + u8 method; + __be16 status; + __be16 unused; + __be64 tid; + __be16 attr_id; + __be16 resv; + __be32 attr_mod; + u8 reserved[40]; + u8 data[192]; +} __attribute__ ((packed)); + +struct ib_pma_classportinfo { + u8 base_version; + u8 class_version; + __be16 cap_mask; + u8 reserved[3]; + u8 resp_time_value; /* only lower 5 bits */ + union ib_gid redirect_gid; + __be32 redirect_tc_sl_fl; /* 8, 4, 20 bits respectively */ + __be16 redirect_lid; + __be16 redirect_pkey; + __be32 redirect_qp; /* only lower 24 bits */ + __be32 redirect_qkey; + union ib_gid trap_gid; + __be32 trap_tc_sl_fl; /* 8, 4, 20 bits respectively */ + __be16 trap_lid; + __be16 trap_pkey; + __be32 trap_hl_qp; /* 8, 24 bits respectively */ + __be32 trap_qkey; +} __attribute__ ((packed)); + +struct ib_pma_portsamplescontrol { + u8 opcode; + u8 port_select; + u8 tick; + u8 counter_width; /* only lower 3 bits */ + __be32 counter_mask0_9; /* 2, 10 * 3, bits */ + __be16 counter_mask10_14; /* 1, 5 * 3, bits */ + u8 sample_mechanisms; + u8 sample_status; /* only lower 2 bits */ + __be64 option_mask; + __be64 vendor_mask; + __be32 sample_start; + __be32 sample_interval; + __be16 tag; + __be16 counter_select[15]; +} __attribute__ ((packed)); + +struct ib_pma_portsamplesresult { + __be16 tag; + __be16 sample_status; /* only lower 2 bits */ + __be32 counter[15]; +} __attribute__ ((packed)); + +struct ib_pma_portsamplesresult_ext { + __be16 tag; + __be16 sample_status; /* only lower 2 bits */ + __be32 extended_width; /* only upper 2 bits */ + __be64 counter[15]; +} __attribute__ ((packed)); + +struct ib_pma_portcounters { + u8 reserved; + u8 port_select; + __be16 counter_select; + __be16 symbol_error_counter; + u8 link_error_recovery_counter; + u8 link_downed_counter; + __be16 port_rcv_errors; + __be16 port_rcv_remphys_errors; + __be16 port_rcv_switch_relay_errors; + __be16 port_xmit_discards; + u8 port_xmit_constraint_errors; + u8 port_rcv_constraint_errors; + u8 reserved1; + u8 lli_ebor_errors; /* 4, 4, bits */ + __be16 reserved2; + __be16 vl15_dropped; + __be32 port_xmit_data; + __be32 port_rcv_data; + __be32 port_xmit_packets; + __be32 port_rcv_packets; +} __attribute__ ((packed)); + +#define IB_PMA_SEL_SYMBOL_ERROR __constant_htons(0x0001) +#define IB_PMA_SEL_LINK_ERROR_RECOVERY __constant_htons(0x0002) +#define IB_PMA_SEL_LINK_DOWNED __constant_htons(0x0004) +#define IB_PMA_SEL_PORT_RCV_ERRORS __constant_htons(0x0008) +#define IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS __constant_htons(0x0010) +#define IB_PMA_SEL_PORT_XMIT_DISCARDS __constant_htons(0x0040) +#define IB_PMA_SEL_PORT_XMIT_DATA __constant_htons(0x1000) +#define IB_PMA_SEL_PORT_RCV_DATA __constant_htons(0x2000) +#define IB_PMA_SEL_PORT_XMIT_PACKETS __constant_htons(0x4000) +#define IB_PMA_SEL_PORT_RCV_PACKETS __constant_htons(0x8000) + +struct ib_pma_portcounters_ext { + u8 reserved; + u8 port_select; + __be16 counter_select; + __be32 reserved1; + __be64 port_xmit_data; + __be64 port_rcv_data; + __be64 port_xmit_packets; + __be64 port_rcv_packets; + __be64 port_unicast_xmit_packets; + __be64 port_unicast_rcv_packets; + __be64 port_multicast_xmit_packets; + __be64 port_multicast_rcv_packets; +} __attribute__ ((packed)); + +#define IB_PMA_SELX_PORT_XMIT_DATA __constant_htons(0x0001) +#define IB_PMA_SELX_PORT_RCV_DATA __constant_htons(0x0002) +#define IB_PMA_SELX_PORT_XMIT_PACKETS __constant_htons(0x0004) +#define IB_PMA_SELX_PORT_RCV_PACKETS __constant_htons(0x0008) +#define IB_PMA_SELX_PORT_UNI_XMIT_PACKETS __constant_htons(0x0010) +#define IB_PMA_SELX_PORT_UNI_RCV_PACKETS __constant_htons(0x0020) +#define IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS __constant_htons(0x0040) +#define IB_PMA_SELX_PORT_MULTI_RCV_PACKETS __constant_htons(0x0080) + +static int recv_pma_get_classportinfo(struct ib_perf *pmp) +{ + struct ib_pma_classportinfo *p = + (struct ib_pma_classportinfo *)pmp->data; + + memset(pmp->data, 0, sizeof(pmp->data)); + + if (pmp->attr_mod != 0) + pmp->status |= IB_SMP_INVALID_FIELD; + + /* Indicate AllPortSelect is valid (only one port anyway) */ + p->cap_mask = __constant_cpu_to_be16(1 << 8); + p->base_version = 1; + p->class_version = 1; + /* + * Expected response time is 4.096 usec. * 2^18 == 1.073741824 + * sec. + */ + p->resp_time_value = 18; + + return reply((struct ib_smp *) pmp); +} + +/* + * The PortSamplesControl.CounterMasks field is an array of 3 bit fields + * which specify the N'th counter's capabilities. See ch. 16.1.3.2. + * We support 5 counters which only count the mandatory quantities. + */ +#define COUNTER_MASK(q, n) (q << ((9 - n) * 3)) +#define COUNTER_MASK0_9 \ + __constant_cpu_to_be32(COUNTER_MASK(1, 0) | \ + COUNTER_MASK(1, 1) | \ + COUNTER_MASK(1, 2) | \ + COUNTER_MASK(1, 3) | \ + COUNTER_MASK(1, 4)) + +static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp, + struct ib_device *ibdev, u8 port) +{ + struct ib_pma_portsamplescontrol *p = + (struct ib_pma_portsamplescontrol *)pmp->data; + struct ipath_ibdev *dev = to_idev(ibdev); + unsigned long flags; + u8 port_select = p->port_select; + + memset(pmp->data, 0, sizeof(pmp->data)); + + p->port_select = port_select; + if (pmp->attr_mod != 0 || + (port_select != port && port_select != 0xFF)) + pmp->status |= IB_SMP_INVALID_FIELD; + /* + * Ticks are 10x the link transfer period which for 2.5Gbs is 4 + * nsec. 0 == 4 nsec., 1 == 8 nsec., ..., 255 == 1020 nsec. Sample + * intervals are counted in ticks. Since we use Linux timers, that + * count in jiffies, we can't sample for less than 1000 ticks if HZ + * == 1000 (4000 ticks if HZ is 250). + */ + /* XXX This is WRONG. */ + p->tick = 250; /* 1 usec. */ + p->counter_width = 4; /* 32 bit counters */ + p->counter_mask0_9 = COUNTER_MASK0_9; + spin_lock_irqsave(&dev->pending_lock, flags); + p->sample_status = dev->pma_sample_status; + p->sample_start = cpu_to_be32(dev->pma_sample_start); + p->sample_interval = cpu_to_be32(dev->pma_sample_interval); + p->tag = cpu_to_be16(dev->pma_tag); + p->counter_select[0] = dev->pma_counter_select[0]; + p->counter_select[1] = dev->pma_counter_select[1]; + p->counter_select[2] = dev->pma_counter_select[2]; + p->counter_select[3] = dev->pma_counter_select[3]; + p->counter_select[4] = dev->pma_counter_select[4]; + spin_unlock_irqrestore(&dev->pending_lock, flags); + + return reply((struct ib_smp *) pmp); +} + +static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp, + struct ib_device *ibdev, u8 port) +{ + struct ib_pma_portsamplescontrol *p = + (struct ib_pma_portsamplescontrol *)pmp->data; + struct ipath_ibdev *dev = to_idev(ibdev); + unsigned long flags; + u32 start; + int ret; + + if (pmp->attr_mod != 0 || + (p->port_select != port && p->port_select != 0xFF)) { + pmp->status |= IB_SMP_INVALID_FIELD; + ret = reply((struct ib_smp *) pmp); + goto bail; + } + + start = be32_to_cpu(p->sample_start); + if (start != 0) { + spin_lock_irqsave(&dev->pending_lock, flags); + if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_DONE) { + dev->pma_sample_status = + IB_PMA_SAMPLE_STATUS_STARTED; + dev->pma_sample_start = start; + dev->pma_sample_interval = + be32_to_cpu(p->sample_interval); + dev->pma_tag = be16_to_cpu(p->tag); + if (p->counter_select[0]) + dev->pma_counter_select[0] = + p->counter_select[0]; + if (p->counter_select[1]) + dev->pma_counter_select[1] = + p->counter_select[1]; + if (p->counter_select[2]) + dev->pma_counter_select[2] = + p->counter_select[2]; + if (p->counter_select[3]) + dev->pma_counter_select[3] = + p->counter_select[3]; + if (p->counter_select[4]) + dev->pma_counter_select[4] = + p->counter_select[4]; + } + spin_unlock_irqrestore(&dev->pending_lock, flags); + } + ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port); + +bail: + return ret; +} + +static u64 get_counter(struct ipath_ibdev *dev, __be16 sel) +{ + u64 ret; + + switch (sel) { + case IB_PMA_PORT_XMIT_DATA: + ret = dev->ipath_sword; + break; + case IB_PMA_PORT_RCV_DATA: + ret = dev->ipath_rword; + break; + case IB_PMA_PORT_XMIT_PKTS: + ret = dev->ipath_spkts; + break; + case IB_PMA_PORT_RCV_PKTS: + ret = dev->ipath_rpkts; + break; + case IB_PMA_PORT_XMIT_WAIT: + ret = dev->ipath_xmit_wait; + break; + default: + ret = 0; + } + + return ret; +} + +static int recv_pma_get_portsamplesresult(struct ib_perf *pmp, + struct ib_device *ibdev) +{ + struct ib_pma_portsamplesresult *p = + (struct ib_pma_portsamplesresult *)pmp->data; + struct ipath_ibdev *dev = to_idev(ibdev); + int i; + + memset(pmp->data, 0, sizeof(pmp->data)); + p->tag = cpu_to_be16(dev->pma_tag); + p->sample_status = cpu_to_be16(dev->pma_sample_status); + for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++) + p->counter[i] = cpu_to_be32( + get_counter(dev, dev->pma_counter_select[i])); + + return reply((struct ib_smp *) pmp); +} + +static int recv_pma_get_portsamplesresult_ext(struct ib_perf *pmp, + struct ib_device *ibdev) +{ + struct ib_pma_portsamplesresult_ext *p = + (struct ib_pma_portsamplesresult_ext *)pmp->data; + struct ipath_ibdev *dev = to_idev(ibdev); + int i; + + memset(pmp->data, 0, sizeof(pmp->data)); + p->tag = cpu_to_be16(dev->pma_tag); + p->sample_status = cpu_to_be16(dev->pma_sample_status); + /* 64 bits */ + p->extended_width = __constant_cpu_to_be32(0x80000000); + for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++) + p->counter[i] = cpu_to_be64( + get_counter(dev, dev->pma_counter_select[i])); + + return reply((struct ib_smp *) pmp); +} + +static int recv_pma_get_portcounters(struct ib_perf *pmp, + struct ib_device *ibdev, u8 port) +{ + struct ib_pma_portcounters *p = (struct ib_pma_portcounters *) + pmp->data; + struct ipath_ibdev *dev = to_idev(ibdev); + struct ipath_layer_counters cntrs; + u8 port_select = p->port_select; + + ipath_layer_get_counters(dev->dd, &cntrs); + + /* Adjust counters for any resets done. */ + cntrs.symbol_error_counter -= dev->n_symbol_error_counter; + cntrs.link_error_recovery_counter -= + dev->n_link_error_recovery_counter; + cntrs.link_downed_counter -= dev->n_link_downed_counter; + cntrs.port_rcv_errors += dev->rcv_errors; + cntrs.port_rcv_errors -= dev->n_port_rcv_errors; + cntrs.port_rcv_remphys_errors -= dev->n_port_rcv_remphys_errors; + cntrs.port_xmit_discards -= dev->n_port_xmit_discards; + cntrs.port_xmit_data -= dev->n_port_xmit_data; + cntrs.port_rcv_data -= dev->n_port_rcv_data; + cntrs.port_xmit_packets -= dev->n_port_xmit_packets; + cntrs.port_rcv_packets -= dev->n_port_rcv_packets; + + memset(pmp->data, 0, sizeof(pmp->data)); + + p->port_select = port_select; + if (pmp->attr_mod != 0 || + (port_select != port && port_select != 0xFF)) + pmp->status |= IB_SMP_INVALID_FIELD; + + if (cntrs.symbol_error_counter > 0xFFFFUL) + p->symbol_error_counter = __constant_cpu_to_be16(0xFFFF); + else + p->symbol_error_counter = + cpu_to_be16((u16)cntrs.symbol_error_counter); + if (cntrs.link_error_recovery_counter > 0xFFUL) + p->link_error_recovery_counter = 0xFF; + else + p->link_error_recovery_counter = + (u8)cntrs.link_error_recovery_counter; + if (cntrs.link_downed_counter > 0xFFUL) + p->link_downed_counter = 0xFF; + else + p->link_downed_counter = (u8)cntrs.link_downed_counter; + if (cntrs.port_rcv_errors > 0xFFFFUL) + p->port_rcv_errors = __constant_cpu_to_be16(0xFFFF); + else + p->port_rcv_errors = + cpu_to_be16((u16) cntrs.port_rcv_errors); + if (cntrs.port_rcv_remphys_errors > 0xFFFFUL) + p->port_rcv_remphys_errors = __constant_cpu_to_be16(0xFFFF); + else + p->port_rcv_remphys_errors = + cpu_to_be16((u16)cntrs.port_rcv_remphys_errors); + if (cntrs.port_xmit_discards > 0xFFFFUL) + p->port_xmit_discards = __constant_cpu_to_be16(0xFFFF); + else + p->port_xmit_discards = + cpu_to_be16((u16)cntrs.port_xmit_discards); + if (cntrs.port_xmit_data > 0xFFFFFFFFUL) + p->port_xmit_data = __constant_cpu_to_be32(0xFFFFFFFF); + else + p->port_xmit_data = cpu_to_be32((u32)cntrs.port_xmit_data); + if (cntrs.port_rcv_data > 0xFFFFFFFFUL) + p->port_rcv_data = __constant_cpu_to_be32(0xFFFFFFFF); + else + p->port_rcv_data = cpu_to_be32((u32)cntrs.port_rcv_data); + if (cntrs.port_xmit_packets > 0xFFFFFFFFUL) + p->port_xmit_packets = __constant_cpu_to_be32(0xFFFFFFFF); + else + p->port_xmit_packets = + cpu_to_be32((u32)cntrs.port_xmit_packets); + if (cntrs.port_rcv_packets > 0xFFFFFFFFUL) + p->port_rcv_packets = __constant_cpu_to_be32(0xFFFFFFFF); + else + p->port_rcv_packets = + cpu_to_be32((u32) cntrs.port_rcv_packets); + + return reply((struct ib_smp *) pmp); +} + +static int recv_pma_get_portcounters_ext(struct ib_perf *pmp, + struct ib_device *ibdev, u8 port) +{ + struct ib_pma_portcounters_ext *p = + (struct ib_pma_portcounters_ext *)pmp->data; + struct ipath_ibdev *dev = to_idev(ibdev); + u64 swords, rwords, spkts, rpkts, xwait; + u8 port_select = p->port_select; + + ipath_layer_snapshot_counters(dev->dd, &swords, &rwords, &spkts, + &rpkts, &xwait); + + /* Adjust counters for any resets done. */ + swords -= dev->n_port_xmit_data; + rwords -= dev->n_port_rcv_data; + spkts -= dev->n_port_xmit_packets; + rpkts -= dev->n_port_rcv_packets; + + memset(pmp->data, 0, sizeof(pmp->data)); + + p->port_select = port_select; + if (pmp->attr_mod != 0 || + (port_select != port && port_select != 0xFF)) + pmp->status |= IB_SMP_INVALID_FIELD; + + p->port_xmit_data = cpu_to_be64(swords); + p->port_rcv_data = cpu_to_be64(rwords); + p->port_xmit_packets = cpu_to_be64(spkts); + p->port_rcv_packets = cpu_to_be64(rpkts); + p->port_unicast_xmit_packets = cpu_to_be64(dev->n_unicast_xmit); + p->port_unicast_rcv_packets = cpu_to_be64(dev->n_unicast_rcv); + p->port_multicast_xmit_packets = cpu_to_be64(dev->n_multicast_xmit); + p->port_multicast_rcv_packets = cpu_to_be64(dev->n_multicast_rcv); + + return reply((struct ib_smp *) pmp); +} + +static int recv_pma_set_portcounters(struct ib_perf *pmp, + struct ib_device *ibdev, u8 port) +{ + struct ib_pma_portcounters *p = (struct ib_pma_portcounters *) + pmp->data; + struct ipath_ibdev *dev = to_idev(ibdev); + struct ipath_layer_counters cntrs; + + /* + * Since the HW doesn't support clearing counters, we save the + * current count and subtract it from future responses. + */ + ipath_layer_get_counters(dev->dd, &cntrs); + + if (p->counter_select & IB_PMA_SEL_SYMBOL_ERROR) + dev->n_symbol_error_counter = cntrs.symbol_error_counter; + + if (p->counter_select & IB_PMA_SEL_LINK_ERROR_RECOVERY) + dev->n_link_error_recovery_counter = + cntrs.link_error_recovery_counter; + + if (p->counter_select & IB_PMA_SEL_LINK_DOWNED) + dev->n_link_downed_counter = cntrs.link_downed_counter; + + if (p->counter_select & IB_PMA_SEL_PORT_RCV_ERRORS) + dev->n_port_rcv_errors = + cntrs.port_rcv_errors + dev->rcv_errors; + + if (p->counter_select & IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS) + dev->n_port_rcv_remphys_errors = + cntrs.port_rcv_remphys_errors; + + if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DISCARDS) + dev->n_port_xmit_discards = cntrs.port_xmit_discards; + + if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA) + dev->n_port_xmit_data = cntrs.port_xmit_data; + + if (p->counter_select & IB_PMA_SEL_PORT_RCV_DATA) + dev->n_port_rcv_data = cntrs.port_rcv_data; + + if (p->counter_select & IB_PMA_SEL_PORT_XMIT_PACKETS) + dev->n_port_xmit_packets = cntrs.port_xmit_packets; + + if (p->counter_select & IB_PMA_SEL_PORT_RCV_PACKETS) + dev->n_port_rcv_packets = cntrs.port_rcv_packets; + + return recv_pma_get_portcounters(pmp, ibdev, port); +} + +static int recv_pma_set_portcounters_ext(struct ib_perf *pmp, + struct ib_device *ibdev, u8 port) +{ + struct ib_pma_portcounters *p = (struct ib_pma_portcounters *) + pmp->data; + struct ipath_ibdev *dev = to_idev(ibdev); + u64 swords, rwords, spkts, rpkts, xwait; + + ipath_layer_snapshot_counters(dev->dd, &swords, &rwords, &spkts, + &rpkts, &xwait); + + if (p->counter_select & IB_PMA_SELX_PORT_XMIT_DATA) + dev->n_port_xmit_data = swords; + + if (p->counter_select & IB_PMA_SELX_PORT_RCV_DATA) + dev->n_port_rcv_data = rwords; + + if (p->counter_select & IB_PMA_SELX_PORT_XMIT_PACKETS) + dev->n_port_xmit_packets = spkts; + + if (p->counter_select & IB_PMA_SELX_PORT_RCV_PACKETS) + dev->n_port_rcv_packets = rpkts; + + if (p->counter_select & IB_PMA_SELX_PORT_UNI_XMIT_PACKETS) + dev->n_unicast_xmit = 0; + + if (p->counter_select & IB_PMA_SELX_PORT_UNI_RCV_PACKETS) + dev->n_unicast_rcv = 0; + + if (p->counter_select & IB_PMA_SELX_PORT_MULTI_XMIT_PACKETS) + dev->n_multicast_xmit = 0; + + if (p->counter_select & IB_PMA_SELX_PORT_MULTI_RCV_PACKETS) + dev->n_multicast_rcv = 0; + + return recv_pma_get_portcounters_ext(pmp, ibdev, port); +} + +static int process_subn(struct ib_device *ibdev, int mad_flags, + u8 port_num, struct ib_mad *in_mad, + struct ib_mad *out_mad) +{ + struct ib_smp *smp = (struct ib_smp *)out_mad; + struct ipath_ibdev *dev = to_idev(ibdev); + int ret; + + *out_mad = *in_mad; + if (smp->class_version != 1) { + smp->status |= IB_SMP_UNSUP_VERSION; + ret = reply(smp); + goto bail; + } + + /* Is the mkey in the process of expiring? */ + if (dev->mkey_lease_timeout && jiffies >= dev->mkey_lease_timeout) { + /* Clear timeout and mkey protection field. */ + dev->mkey_lease_timeout = 0; + dev->mkeyprot_resv_lmc &= 0x3F; + } + + /* + * M_Key checking depends on + * Portinfo:M_Key_protect_bits + */ + if ((mad_flags & IB_MAD_IGNORE_MKEY) == 0 && dev->mkey != 0 && + dev->mkey != smp->mkey && + (smp->method == IB_MGMT_METHOD_SET || + (smp->method == IB_MGMT_METHOD_GET && + (dev->mkeyprot_resv_lmc >> 7) != 0))) { + if (dev->mkey_violations != 0xFFFF) + ++dev->mkey_violations; + if (dev->mkey_lease_timeout || + dev->mkey_lease_period == 0) { + ret = IB_MAD_RESULT_SUCCESS | + IB_MAD_RESULT_CONSUMED; + goto bail; + } + dev->mkey_lease_timeout = jiffies + + dev->mkey_lease_period * HZ; + /* Future: Generate a trap notice. */ + ret = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + goto bail; + } else if (dev->mkey_lease_timeout) + dev->mkey_lease_timeout = 0; + + switch (smp->method) { + case IB_MGMT_METHOD_GET: + switch (smp->attr_id) { + case IB_SMP_ATTR_NODE_DESC: + ret = recv_subn_get_nodedescription(smp, ibdev); + goto bail; + case IB_SMP_ATTR_NODE_INFO: + ret = recv_subn_get_nodeinfo(smp, ibdev, port_num); + goto bail; + case IB_SMP_ATTR_GUID_INFO: + ret = recv_subn_get_guidinfo(smp, ibdev); + goto bail; + case IB_SMP_ATTR_PORT_INFO: + ret = recv_subn_get_portinfo(smp, ibdev, port_num); + goto bail; + case IB_SMP_ATTR_PKEY_TABLE: + ret = recv_subn_get_pkeytable(smp, ibdev); + goto bail; + case IB_SMP_ATTR_SM_INFO: + if (dev->port_cap_flags & IB_PORT_SM_DISABLED) { + ret = IB_MAD_RESULT_SUCCESS | + IB_MAD_RESULT_CONSUMED; + goto bail; + } + if (dev->port_cap_flags & IB_PORT_SM) { + ret = IB_MAD_RESULT_SUCCESS; + goto bail; + } + /* FALLTHROUGH */ + default: + smp->status |= IB_SMP_UNSUP_METH_ATTR; + ret = reply(smp); + goto bail; + } + + case IB_MGMT_METHOD_SET: + switch (smp->attr_id) { + case IB_SMP_ATTR_GUID_INFO: + ret = recv_subn_set_guidinfo(smp, ibdev); + goto bail; + case IB_SMP_ATTR_PORT_INFO: + ret = recv_subn_set_portinfo(smp, ibdev, port_num); + goto bail; + case IB_SMP_ATTR_PKEY_TABLE: + ret = recv_subn_set_pkeytable(smp, ibdev); + goto bail; + case IB_SMP_ATTR_SM_INFO: + if (dev->port_cap_flags & IB_PORT_SM_DISABLED) { + ret = IB_MAD_RESULT_SUCCESS | + IB_MAD_RESULT_CONSUMED; + goto bail; + } + if (dev->port_cap_flags & IB_PORT_SM) { + ret = IB_MAD_RESULT_SUCCESS; + goto bail; + } + /* FALLTHROUGH */ + default: + smp->status |= IB_SMP_UNSUP_METH_ATTR; + ret = reply(smp); + goto bail; + } + + case IB_MGMT_METHOD_GET_RESP: + /* + * The ib_mad module will call us to process responses + * before checking for other consumers. + * Just tell the caller to process it normally. + */ + ret = IB_MAD_RESULT_FAILURE; + goto bail; + default: + smp->status |= IB_SMP_UNSUP_METHOD; + ret = reply(smp); + } + +bail: + return ret; +} + +static int process_perf(struct ib_device *ibdev, u8 port_num, + struct ib_mad *in_mad, + struct ib_mad *out_mad) +{ + struct ib_perf *pmp = (struct ib_perf *)out_mad; + int ret; + + *out_mad = *in_mad; + if (pmp->class_version != 1) { + pmp->status |= IB_SMP_UNSUP_VERSION; + ret = reply((struct ib_smp *) pmp); + goto bail; + } + + switch (pmp->method) { + case IB_MGMT_METHOD_GET: + switch (pmp->attr_id) { + case IB_PMA_CLASS_PORT_INFO: + ret = recv_pma_get_classportinfo(pmp); + goto bail; + case IB_PMA_PORT_SAMPLES_CONTROL: + ret = recv_pma_get_portsamplescontrol(pmp, ibdev, + port_num); + goto bail; + case IB_PMA_PORT_SAMPLES_RESULT: + ret = recv_pma_get_portsamplesresult(pmp, ibdev); + goto bail; + case IB_PMA_PORT_SAMPLES_RESULT_EXT: + ret = recv_pma_get_portsamplesresult_ext(pmp, + ibdev); + goto bail; + case IB_PMA_PORT_COUNTERS: + ret = recv_pma_get_portcounters(pmp, ibdev, + port_num); + goto bail; + case IB_PMA_PORT_COUNTERS_EXT: + ret = recv_pma_get_portcounters_ext(pmp, ibdev, + port_num); + goto bail; + default: + pmp->status |= IB_SMP_UNSUP_METH_ATTR; + ret = reply((struct ib_smp *) pmp); + goto bail; + } + + case IB_MGMT_METHOD_SET: + switch (pmp->attr_id) { + case IB_PMA_PORT_SAMPLES_CONTROL: + ret = recv_pma_set_portsamplescontrol(pmp, ibdev, + port_num); + goto bail; + case IB_PMA_PORT_COUNTERS: + ret = recv_pma_set_portcounters(pmp, ibdev, + port_num); + goto bail; + case IB_PMA_PORT_COUNTERS_EXT: + ret = recv_pma_set_portcounters_ext(pmp, ibdev, + port_num); + goto bail; + default: + pmp->status |= IB_SMP_UNSUP_METH_ATTR; + ret = reply((struct ib_smp *) pmp); + goto bail; + } + + case IB_MGMT_METHOD_GET_RESP: + /* + * The ib_mad module will call us to process responses + * before checking for other consumers. + * Just tell the caller to process it normally. + */ + ret = IB_MAD_RESULT_FAILURE; + goto bail; + default: + pmp->status |= IB_SMP_UNSUP_METHOD; + ret = reply((struct ib_smp *) pmp); + } + +bail: + return ret; +} + +/** + * ipath_process_mad - process an incoming MAD packet + * @ibdev: the infiniband device this packet came in on + * @mad_flags: MAD flags + * @port_num: the port number this packet came in on + * @in_wc: the work completion entry for this packet + * @in_grh: the global route header for this packet + * @in_mad: the incoming MAD + * @out_mad: any outgoing MAD reply + * + * Returns IB_MAD_RESULT_SUCCESS if this is a MAD that we are not + * interested in processing. + * + * Note that the verbs framework has already done the MAD sanity checks, + * and hop count/pointer updating for IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE + * MADs. + * + * This is called by the ib_mad module. + */ +int ipath_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, + struct ib_wc *in_wc, struct ib_grh *in_grh, + struct ib_mad *in_mad, struct ib_mad *out_mad) +{ + struct ipath_ibdev *dev = to_idev(ibdev); + int ret; + + /* + * Snapshot current HW counters to "clear" them. + * This should be done when the driver is loaded except that for + * some reason we get a zillion errors when brining up the link. + */ + if (dev->rcv_errors == 0) { + struct ipath_layer_counters cntrs; + + ipath_layer_get_counters(to_idev(ibdev)->dd, &cntrs); + dev->rcv_errors++; + dev->n_symbol_error_counter = cntrs.symbol_error_counter; + dev->n_link_error_recovery_counter = + cntrs.link_error_recovery_counter; + dev->n_link_downed_counter = cntrs.link_downed_counter; + dev->n_port_rcv_errors = cntrs.port_rcv_errors + 1; + dev->n_port_rcv_remphys_errors = + cntrs.port_rcv_remphys_errors; + dev->n_port_xmit_discards = cntrs.port_xmit_discards; + dev->n_port_xmit_data = cntrs.port_xmit_data; + dev->n_port_rcv_data = cntrs.port_rcv_data; + dev->n_port_xmit_packets = cntrs.port_xmit_packets; + dev->n_port_rcv_packets = cntrs.port_rcv_packets; + } + switch (in_mad->mad_hdr.mgmt_class) { + case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: + case IB_MGMT_CLASS_SUBN_LID_ROUTED: + ret = process_subn(ibdev, mad_flags, port_num, + in_mad, out_mad); + goto bail; + case IB_MGMT_CLASS_PERF_MGMT: + ret = process_perf(ibdev, port_num, in_mad, out_mad); + goto bail; + default: + ret = IB_MAD_RESULT_SUCCESS; + } + +bail: + return ret; +} diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c new file mode 100644 index 000000000000..69ffec66d45d --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_mr.c @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "ipath_verbs.h" + +/** + * ipath_get_dma_mr - get a DMA memory region + * @pd: protection domain for this memory region + * @acc: access flags + * + * Returns the memory region on success, otherwise returns an errno. + */ +struct ib_mr *ipath_get_dma_mr(struct ib_pd *pd, int acc) +{ + struct ipath_mr *mr; + struct ib_mr *ret; + + mr = kzalloc(sizeof *mr, GFP_KERNEL); + if (!mr) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + mr->mr.access_flags = acc; + ret = &mr->ibmr; + +bail: + return ret; +} + +static struct ipath_mr *alloc_mr(int count, + struct ipath_lkey_table *lk_table) +{ + struct ipath_mr *mr; + int m, i = 0; + + /* Allocate struct plus pointers to first level page tables. */ + m = (count + IPATH_SEGSZ - 1) / IPATH_SEGSZ; + mr = kmalloc(sizeof *mr + m * sizeof mr->mr.map[0], GFP_KERNEL); + if (!mr) + goto done; + + /* Allocate first level page tables. */ + for (; i < m; i++) { + mr->mr.map[i] = kmalloc(sizeof *mr->mr.map[0], GFP_KERNEL); + if (!mr->mr.map[i]) + goto bail; + } + mr->mr.mapsz = m; + + /* + * ib_reg_phys_mr() will initialize mr->ibmr except for + * lkey and rkey. + */ + if (!ipath_alloc_lkey(lk_table, &mr->mr)) + goto bail; + mr->ibmr.rkey = mr->ibmr.lkey = mr->mr.lkey; + + goto done; + +bail: + while (i) { + i--; + kfree(mr->mr.map[i]); + } + kfree(mr); + mr = NULL; + +done: + return mr; +} + +/** + * ipath_reg_phys_mr - register a physical memory region + * @pd: protection domain for this memory region + * @buffer_list: pointer to the list of physical buffers to register + * @num_phys_buf: the number of physical buffers to register + * @iova_start: the starting address passed over IB which maps to this MR + * + * Returns the memory region on success, otherwise returns an errno. + */ +struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *buffer_list, + int num_phys_buf, int acc, u64 *iova_start) +{ + struct ipath_mr *mr; + int n, m, i; + struct ib_mr *ret; + + mr = alloc_mr(num_phys_buf, &to_idev(pd->device)->lk_table); + if (mr == NULL) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + mr->mr.user_base = *iova_start; + mr->mr.iova = *iova_start; + mr->mr.length = 0; + mr->mr.offset = 0; + mr->mr.access_flags = acc; + mr->mr.max_segs = num_phys_buf; + + m = 0; + n = 0; + for (i = 0; i < num_phys_buf; i++) { + mr->mr.map[m]->segs[n].vaddr = + phys_to_virt(buffer_list[i].addr); + mr->mr.map[m]->segs[n].length = buffer_list[i].size; + mr->mr.length += buffer_list[i].size; + n++; + if (n == IPATH_SEGSZ) { + m++; + n = 0; + } + } + + ret = &mr->ibmr; + +bail: + return ret; +} + +/** + * ipath_reg_user_mr - register a userspace memory region + * @pd: protection domain for this memory region + * @region: the user memory region + * @mr_access_flags: access flags for this memory region + * @udata: unused by the InfiniPath driver + * + * Returns the memory region on success, otherwise returns an errno. + */ +struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, + int mr_access_flags, struct ib_udata *udata) +{ + struct ipath_mr *mr; + struct ib_umem_chunk *chunk; + int n, m, i; + struct ib_mr *ret; + + n = 0; + list_for_each_entry(chunk, ®ion->chunk_list, list) + n += chunk->nents; + + mr = alloc_mr(n, &to_idev(pd->device)->lk_table); + if (!mr) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + mr->mr.user_base = region->user_base; + mr->mr.iova = region->virt_base; + mr->mr.length = region->length; + mr->mr.offset = region->offset; + mr->mr.access_flags = mr_access_flags; + mr->mr.max_segs = n; + + m = 0; + n = 0; + list_for_each_entry(chunk, ®ion->chunk_list, list) { + for (i = 0; i < chunk->nmap; i++) { + mr->mr.map[m]->segs[n].vaddr = + page_address(chunk->page_list[i].page); + mr->mr.map[m]->segs[n].length = region->page_size; + n++; + if (n == IPATH_SEGSZ) { + m++; + n = 0; + } + } + } + ret = &mr->ibmr; + +bail: + return ret; +} + +/** + * ipath_dereg_mr - unregister and free a memory region + * @ibmr: the memory region to free + * + * Returns 0 on success. + * + * Note that this is called to free MRs created by ipath_get_dma_mr() + * or ipath_reg_user_mr(). + */ +int ipath_dereg_mr(struct ib_mr *ibmr) +{ + struct ipath_mr *mr = to_imr(ibmr); + int i; + + ipath_free_lkey(&to_idev(ibmr->device)->lk_table, ibmr->lkey); + i = mr->mr.mapsz; + while (i) { + i--; + kfree(mr->mr.map[i]); + } + kfree(mr); + return 0; +} + +/** + * ipath_alloc_fmr - allocate a fast memory region + * @pd: the protection domain for this memory region + * @mr_access_flags: access flags for this memory region + * @fmr_attr: fast memory region attributes + * + * Returns the memory region on success, otherwise returns an errno. + */ +struct ib_fmr *ipath_alloc_fmr(struct ib_pd *pd, int mr_access_flags, + struct ib_fmr_attr *fmr_attr) +{ + struct ipath_fmr *fmr; + int m, i = 0; + struct ib_fmr *ret; + + /* Allocate struct plus pointers to first level page tables. */ + m = (fmr_attr->max_pages + IPATH_SEGSZ - 1) / IPATH_SEGSZ; + fmr = kmalloc(sizeof *fmr + m * sizeof fmr->mr.map[0], GFP_KERNEL); + if (!fmr) + goto bail; + + /* Allocate first level page tables. */ + for (; i < m; i++) { + fmr->mr.map[i] = kmalloc(sizeof *fmr->mr.map[0], + GFP_KERNEL); + if (!fmr->mr.map[i]) + goto bail; + } + fmr->mr.mapsz = m; + + /* + * ib_alloc_fmr() will initialize fmr->ibfmr except for lkey & + * rkey. + */ + if (!ipath_alloc_lkey(&to_idev(pd->device)->lk_table, &fmr->mr)) + goto bail; + fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mr.lkey; + /* + * Resources are allocated but no valid mapping (RKEY can't be + * used). + */ + fmr->mr.user_base = 0; + fmr->mr.iova = 0; + fmr->mr.length = 0; + fmr->mr.offset = 0; + fmr->mr.access_flags = mr_access_flags; + fmr->mr.max_segs = fmr_attr->max_pages; + fmr->page_shift = fmr_attr->page_shift; + + ret = &fmr->ibfmr; + goto done; + +bail: + while (i) + kfree(fmr->mr.map[--i]); + kfree(fmr); + ret = ERR_PTR(-ENOMEM); + +done: + return ret; +} + +/** + * ipath_map_phys_fmr - set up a fast memory region + * @ibmfr: the fast memory region to set up + * @page_list: the list of pages to associate with the fast memory region + * @list_len: the number of pages to associate with the fast memory region + * @iova: the virtual address of the start of the fast memory region + * + * This may be called from interrupt context. + */ + +int ipath_map_phys_fmr(struct ib_fmr *ibfmr, u64 * page_list, + int list_len, u64 iova) +{ + struct ipath_fmr *fmr = to_ifmr(ibfmr); + struct ipath_lkey_table *rkt; + unsigned long flags; + int m, n, i; + u32 ps; + int ret; + + if (list_len > fmr->mr.max_segs) { + ret = -EINVAL; + goto bail; + } + rkt = &to_idev(ibfmr->device)->lk_table; + spin_lock_irqsave(&rkt->lock, flags); + fmr->mr.user_base = iova; + fmr->mr.iova = iova; + ps = 1 << fmr->page_shift; + fmr->mr.length = list_len * ps; + m = 0; + n = 0; + ps = 1 << fmr->page_shift; + for (i = 0; i < list_len; i++) { + fmr->mr.map[m]->segs[n].vaddr = phys_to_virt(page_list[i]); + fmr->mr.map[m]->segs[n].length = ps; + if (++n == IPATH_SEGSZ) { + m++; + n = 0; + } + } + spin_unlock_irqrestore(&rkt->lock, flags); + ret = 0; + +bail: + return ret; +} + +/** + * ipath_unmap_fmr - unmap fast memory regions + * @fmr_list: the list of fast memory regions to unmap + * + * Returns 0 on success. + */ +int ipath_unmap_fmr(struct list_head *fmr_list) +{ + struct ipath_fmr *fmr; + struct ipath_lkey_table *rkt; + unsigned long flags; + + list_for_each_entry(fmr, fmr_list, ibfmr.list) { + rkt = &to_idev(fmr->ibfmr.device)->lk_table; + spin_lock_irqsave(&rkt->lock, flags); + fmr->mr.user_base = 0; + fmr->mr.iova = 0; + fmr->mr.length = 0; + spin_unlock_irqrestore(&rkt->lock, flags); + } + return 0; +} + +/** + * ipath_dealloc_fmr - deallocate a fast memory region + * @ibfmr: the fast memory region to deallocate + * + * Returns 0 on success. + */ +int ipath_dealloc_fmr(struct ib_fmr *ibfmr) +{ + struct ipath_fmr *fmr = to_ifmr(ibfmr); + int i; + + ipath_free_lkey(&to_idev(ibfmr->device)->lk_table, ibfmr->lkey); + i = fmr->mr.mapsz; + while (i) + kfree(fmr->mr.map[--i]); + kfree(fmr); + return 0; +} diff --git a/drivers/infiniband/hw/ipath/ipath_pe800.c b/drivers/infiniband/hw/ipath/ipath_pe800.c new file mode 100644 index 000000000000..e693a7a82667 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_pe800.c @@ -0,0 +1,1247 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/* + * This file contains all of the code that is specific to the + * InfiniPath PE-800 chip. + */ + +#include +#include +#include + + +#include "ipath_kernel.h" +#include "ipath_registers.h" + +/* + * This file contains all the chip-specific register information and + * access functions for the PathScale PE800, the PCI-Express chip. + * + * This lists the InfiniPath PE800 registers, in the actual chip layout. + * This structure should never be directly accessed. + */ +struct _infinipath_do_not_use_kernel_regs { + unsigned long long Revision; + unsigned long long Control; + unsigned long long PageAlign; + unsigned long long PortCnt; + unsigned long long DebugPortSelect; + unsigned long long Reserved0; + unsigned long long SendRegBase; + unsigned long long UserRegBase; + unsigned long long CounterRegBase; + unsigned long long Scratch; + unsigned long long Reserved1; + unsigned long long Reserved2; + unsigned long long IntBlocked; + unsigned long long IntMask; + unsigned long long IntStatus; + unsigned long long IntClear; + unsigned long long ErrorMask; + unsigned long long ErrorStatus; + unsigned long long ErrorClear; + unsigned long long HwErrMask; + unsigned long long HwErrStatus; + unsigned long long HwErrClear; + unsigned long long HwDiagCtrl; + unsigned long long MDIO; + unsigned long long IBCStatus; + unsigned long long IBCCtrl; + unsigned long long ExtStatus; + unsigned long long ExtCtrl; + unsigned long long GPIOOut; + unsigned long long GPIOMask; + unsigned long long GPIOStatus; + unsigned long long GPIOClear; + unsigned long long RcvCtrl; + unsigned long long RcvBTHQP; + unsigned long long RcvHdrSize; + unsigned long long RcvHdrCnt; + unsigned long long RcvHdrEntSize; + unsigned long long RcvTIDBase; + unsigned long long RcvTIDCnt; + unsigned long long RcvEgrBase; + unsigned long long RcvEgrCnt; + unsigned long long RcvBufBase; + unsigned long long RcvBufSize; + unsigned long long RxIntMemBase; + unsigned long long RxIntMemSize; + unsigned long long RcvPartitionKey; + unsigned long long Reserved3; + unsigned long long RcvPktLEDCnt; + unsigned long long Reserved4[8]; + unsigned long long SendCtrl; + unsigned long long SendPIOBufBase; + unsigned long long SendPIOSize; + unsigned long long SendPIOBufCnt; + unsigned long long SendPIOAvailAddr; + unsigned long long TxIntMemBase; + unsigned long long TxIntMemSize; + unsigned long long Reserved5; + unsigned long long PCIeRBufTestReg0; + unsigned long long PCIeRBufTestReg1; + unsigned long long Reserved51[6]; + unsigned long long SendBufferError; + unsigned long long SendBufferErrorCONT1; + unsigned long long Reserved6SBE[6]; + unsigned long long RcvHdrAddr0; + unsigned long long RcvHdrAddr1; + unsigned long long RcvHdrAddr2; + unsigned long long RcvHdrAddr3; + unsigned long long RcvHdrAddr4; + unsigned long long Reserved7RHA[11]; + unsigned long long RcvHdrTailAddr0; + unsigned long long RcvHdrTailAddr1; + unsigned long long RcvHdrTailAddr2; + unsigned long long RcvHdrTailAddr3; + unsigned long long RcvHdrTailAddr4; + unsigned long long Reserved8RHTA[11]; + unsigned long long Reserved9SW[8]; + unsigned long long SerdesConfig0; + unsigned long long SerdesConfig1; + unsigned long long SerdesStatus; + unsigned long long XGXSConfig; + unsigned long long IBPLLCfg; + unsigned long long Reserved10SW2[3]; + unsigned long long PCIEQ0SerdesConfig0; + unsigned long long PCIEQ0SerdesConfig1; + unsigned long long PCIEQ0SerdesStatus; + unsigned long long Reserved11; + unsigned long long PCIEQ1SerdesConfig0; + unsigned long long PCIEQ1SerdesConfig1; + unsigned long long PCIEQ1SerdesStatus; + unsigned long long Reserved12; +}; + +#define IPATH_KREG_OFFSET(field) (offsetof(struct \ + _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) +#define IPATH_CREG_OFFSET(field) (offsetof( \ + struct infinipath_counters, field) / sizeof(u64)) + +static const struct ipath_kregs ipath_pe_kregs = { + .kr_control = IPATH_KREG_OFFSET(Control), + .kr_counterregbase = IPATH_KREG_OFFSET(CounterRegBase), + .kr_debugportselect = IPATH_KREG_OFFSET(DebugPortSelect), + .kr_errorclear = IPATH_KREG_OFFSET(ErrorClear), + .kr_errormask = IPATH_KREG_OFFSET(ErrorMask), + .kr_errorstatus = IPATH_KREG_OFFSET(ErrorStatus), + .kr_extctrl = IPATH_KREG_OFFSET(ExtCtrl), + .kr_extstatus = IPATH_KREG_OFFSET(ExtStatus), + .kr_gpio_clear = IPATH_KREG_OFFSET(GPIOClear), + .kr_gpio_mask = IPATH_KREG_OFFSET(GPIOMask), + .kr_gpio_out = IPATH_KREG_OFFSET(GPIOOut), + .kr_gpio_status = IPATH_KREG_OFFSET(GPIOStatus), + .kr_hwdiagctrl = IPATH_KREG_OFFSET(HwDiagCtrl), + .kr_hwerrclear = IPATH_KREG_OFFSET(HwErrClear), + .kr_hwerrmask = IPATH_KREG_OFFSET(HwErrMask), + .kr_hwerrstatus = IPATH_KREG_OFFSET(HwErrStatus), + .kr_ibcctrl = IPATH_KREG_OFFSET(IBCCtrl), + .kr_ibcstatus = IPATH_KREG_OFFSET(IBCStatus), + .kr_intblocked = IPATH_KREG_OFFSET(IntBlocked), + .kr_intclear = IPATH_KREG_OFFSET(IntClear), + .kr_intmask = IPATH_KREG_OFFSET(IntMask), + .kr_intstatus = IPATH_KREG_OFFSET(IntStatus), + .kr_mdio = IPATH_KREG_OFFSET(MDIO), + .kr_pagealign = IPATH_KREG_OFFSET(PageAlign), + .kr_partitionkey = IPATH_KREG_OFFSET(RcvPartitionKey), + .kr_portcnt = IPATH_KREG_OFFSET(PortCnt), + .kr_rcvbthqp = IPATH_KREG_OFFSET(RcvBTHQP), + .kr_rcvbufbase = IPATH_KREG_OFFSET(RcvBufBase), + .kr_rcvbufsize = IPATH_KREG_OFFSET(RcvBufSize), + .kr_rcvctrl = IPATH_KREG_OFFSET(RcvCtrl), + .kr_rcvegrbase = IPATH_KREG_OFFSET(RcvEgrBase), + .kr_rcvegrcnt = IPATH_KREG_OFFSET(RcvEgrCnt), + .kr_rcvhdrcnt = IPATH_KREG_OFFSET(RcvHdrCnt), + .kr_rcvhdrentsize = IPATH_KREG_OFFSET(RcvHdrEntSize), + .kr_rcvhdrsize = IPATH_KREG_OFFSET(RcvHdrSize), + .kr_rcvintmembase = IPATH_KREG_OFFSET(RxIntMemBase), + .kr_rcvintmemsize = IPATH_KREG_OFFSET(RxIntMemSize), + .kr_rcvtidbase = IPATH_KREG_OFFSET(RcvTIDBase), + .kr_rcvtidcnt = IPATH_KREG_OFFSET(RcvTIDCnt), + .kr_revision = IPATH_KREG_OFFSET(Revision), + .kr_scratch = IPATH_KREG_OFFSET(Scratch), + .kr_sendbuffererror = IPATH_KREG_OFFSET(SendBufferError), + .kr_sendctrl = IPATH_KREG_OFFSET(SendCtrl), + .kr_sendpioavailaddr = IPATH_KREG_OFFSET(SendPIOAvailAddr), + .kr_sendpiobufbase = IPATH_KREG_OFFSET(SendPIOBufBase), + .kr_sendpiobufcnt = IPATH_KREG_OFFSET(SendPIOBufCnt), + .kr_sendpiosize = IPATH_KREG_OFFSET(SendPIOSize), + .kr_sendregbase = IPATH_KREG_OFFSET(SendRegBase), + .kr_txintmembase = IPATH_KREG_OFFSET(TxIntMemBase), + .kr_txintmemsize = IPATH_KREG_OFFSET(TxIntMemSize), + .kr_userregbase = IPATH_KREG_OFFSET(UserRegBase), + .kr_serdesconfig0 = IPATH_KREG_OFFSET(SerdesConfig0), + .kr_serdesconfig1 = IPATH_KREG_OFFSET(SerdesConfig1), + .kr_serdesstatus = IPATH_KREG_OFFSET(SerdesStatus), + .kr_xgxsconfig = IPATH_KREG_OFFSET(XGXSConfig), + .kr_ibpllcfg = IPATH_KREG_OFFSET(IBPLLCfg), + + /* + * These should not be used directly via ipath_read_kreg64(), + * use them with ipath_read_kreg64_port() + */ + .kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0), + .kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0), + + /* This group is pe-800-specific; and used only in this file */ + /* The rcvpktled register controls one of the debug port signals, so + * a packet activity LED can be connected to it. */ + .kr_rcvpktledcnt = IPATH_KREG_OFFSET(RcvPktLEDCnt), + .kr_pcierbuftestreg0 = IPATH_KREG_OFFSET(PCIeRBufTestReg0), + .kr_pcierbuftestreg1 = IPATH_KREG_OFFSET(PCIeRBufTestReg1), + .kr_pcieq0serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig0), + .kr_pcieq0serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ0SerdesConfig1), + .kr_pcieq0serdesstatus = IPATH_KREG_OFFSET(PCIEQ0SerdesStatus), + .kr_pcieq1serdesconfig0 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig0), + .kr_pcieq1serdesconfig1 = IPATH_KREG_OFFSET(PCIEQ1SerdesConfig1), + .kr_pcieq1serdesstatus = IPATH_KREG_OFFSET(PCIEQ1SerdesStatus) +}; + +static const struct ipath_cregs ipath_pe_cregs = { + .cr_badformatcnt = IPATH_CREG_OFFSET(RxBadFormatCnt), + .cr_erricrccnt = IPATH_CREG_OFFSET(RxICRCErrCnt), + .cr_errlinkcnt = IPATH_CREG_OFFSET(RxLinkProblemCnt), + .cr_errlpcrccnt = IPATH_CREG_OFFSET(RxLPCRCErrCnt), + .cr_errpkey = IPATH_CREG_OFFSET(RxPKeyMismatchCnt), + .cr_errrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowCtrlErrCnt), + .cr_err_rlencnt = IPATH_CREG_OFFSET(RxLenErrCnt), + .cr_errslencnt = IPATH_CREG_OFFSET(TxLenErrCnt), + .cr_errtidfull = IPATH_CREG_OFFSET(RxTIDFullErrCnt), + .cr_errtidvalid = IPATH_CREG_OFFSET(RxTIDValidErrCnt), + .cr_errvcrccnt = IPATH_CREG_OFFSET(RxVCRCErrCnt), + .cr_ibstatuschange = IPATH_CREG_OFFSET(IBStatusChangeCnt), + .cr_intcnt = IPATH_CREG_OFFSET(LBIntCnt), + .cr_invalidrlencnt = IPATH_CREG_OFFSET(RxMaxMinLenErrCnt), + .cr_invalidslencnt = IPATH_CREG_OFFSET(TxMaxMinLenErrCnt), + .cr_lbflowstallcnt = IPATH_CREG_OFFSET(LBFlowStallCnt), + .cr_pktrcvcnt = IPATH_CREG_OFFSET(RxDataPktCnt), + .cr_pktrcvflowctrlcnt = IPATH_CREG_OFFSET(RxFlowPktCnt), + .cr_pktsendcnt = IPATH_CREG_OFFSET(TxDataPktCnt), + .cr_pktsendflowcnt = IPATH_CREG_OFFSET(TxFlowPktCnt), + .cr_portovflcnt = IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt), + .cr_rcvebpcnt = IPATH_CREG_OFFSET(RxEBPCnt), + .cr_rcvovflcnt = IPATH_CREG_OFFSET(RxBufOvflCnt), + .cr_senddropped = IPATH_CREG_OFFSET(TxDroppedPktCnt), + .cr_sendstallcnt = IPATH_CREG_OFFSET(TxFlowStallCnt), + .cr_sendunderruncnt = IPATH_CREG_OFFSET(TxUnderrunCnt), + .cr_wordrcvcnt = IPATH_CREG_OFFSET(RxDwordCnt), + .cr_wordsendcnt = IPATH_CREG_OFFSET(TxDwordCnt), + .cr_unsupvlcnt = IPATH_CREG_OFFSET(TxUnsupVLErrCnt), + .cr_rxdroppktcnt = IPATH_CREG_OFFSET(RxDroppedPktCnt), + .cr_iblinkerrrecovcnt = IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt), + .cr_iblinkdowncnt = IPATH_CREG_OFFSET(IBLinkDownedCnt), + .cr_ibsymbolerrcnt = IPATH_CREG_OFFSET(IBSymbolErrCnt) +}; + +/* kr_intstatus, kr_intclear, kr_intmask bits */ +#define INFINIPATH_I_RCVURG_MASK 0x1F +#define INFINIPATH_I_RCVAVAIL_MASK 0x1F + +/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */ +#define INFINIPATH_HWE_PCIEMEMPARITYERR_MASK 0x000000000000003fULL +#define INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT 0 +#define INFINIPATH_HWE_PCIEPOISONEDTLP 0x0000000010000000ULL +#define INFINIPATH_HWE_PCIECPLTIMEOUT 0x0000000020000000ULL +#define INFINIPATH_HWE_PCIEBUSPARITYXTLH 0x0000000040000000ULL +#define INFINIPATH_HWE_PCIEBUSPARITYXADM 0x0000000080000000ULL +#define INFINIPATH_HWE_PCIEBUSPARITYRADM 0x0000000100000000ULL +#define INFINIPATH_HWE_COREPLL_FBSLIP 0x0080000000000000ULL +#define INFINIPATH_HWE_COREPLL_RFSLIP 0x0100000000000000ULL +#define INFINIPATH_HWE_PCIE1PLLFAILED 0x0400000000000000ULL +#define INFINIPATH_HWE_PCIE0PLLFAILED 0x0800000000000000ULL +#define INFINIPATH_HWE_SERDESPLLFAILED 0x1000000000000000ULL + +/* kr_extstatus bits */ +#define INFINIPATH_EXTS_FREQSEL 0x2 +#define INFINIPATH_EXTS_SERDESSEL 0x4 +#define INFINIPATH_EXTS_MEMBIST_ENDTEST 0x0000000000004000 +#define INFINIPATH_EXTS_MEMBIST_FOUND 0x0000000000008000 + +#define _IPATH_GPIO_SDA_NUM 1 +#define _IPATH_GPIO_SCL_NUM 0 + +#define IPATH_GPIO_SDA (1ULL << \ + (_IPATH_GPIO_SDA_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT)) +#define IPATH_GPIO_SCL (1ULL << \ + (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT)) + +/** + * ipath_pe_handle_hwerrors - display hardware errors. + * @dd: the infinipath device + * @msg: the output buffer + * @msgl: the size of the output buffer + * + * Use same msg buffer as regular errors to avoid excessive stack + * use. Most hardware errors are catastrophic, but for right now, + * we'll print them and continue. We reuse the same message buffer as + * ipath_handle_errors() to avoid excessive stack usage. + */ +void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, + size_t msgl) +{ + ipath_err_t hwerrs; + u32 bits, ctrl; + int isfatal = 0; + char bitsmsg[64]; + + hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus); + if (!hwerrs) { + /* + * better than printing cofusing messages + * This seems to be related to clearing the crc error, or + * the pll error during init. + */ + ipath_cdbg(VERBOSE, "Called but no hardware errors set\n"); + return; + } else if (hwerrs == ~0ULL) { + ipath_dev_err(dd, "Read of hardware error status failed " + "(all bits set); ignoring\n"); + return; + } + ipath_stats.sps_hwerrs++; + + /* Always clear the error status register, except MEMBISTFAIL, + * regardless of whether we continue or stop using the chip. + * We want that set so we know it failed, even across driver reload. + * We'll still ignore it in the hwerrmask. We do this partly for + * diagnostics, but also for support */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, + hwerrs&~INFINIPATH_HWE_MEMBISTFAILED); + + hwerrs &= dd->ipath_hwerrmask; + + /* + * make sure we get this much out, unless told to be quiet, + * or it's occurred within the last 5 seconds + */ + if ((hwerrs & ~dd->ipath_lasthwerror) || + (ipath_debug & __IPATH_VERBDBG)) + dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx " + "(cleared)\n", (unsigned long long) hwerrs); + dd->ipath_lasthwerror |= hwerrs; + + if (hwerrs & ~infinipath_hwe_bitsextant) + ipath_dev_err(dd, "hwerror interrupt with unknown errors " + "%llx set\n", (unsigned long long) + (hwerrs & ~infinipath_hwe_bitsextant)); + + ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control); + if (ctrl & INFINIPATH_C_FREEZEMODE) { + if (hwerrs) { + /* + * if any set that we aren't ignoring only make the + * complaint once, in case it's stuck or recurring, + * and we get here multiple times + */ + if (dd->ipath_flags & IPATH_INITTED) { + ipath_dev_err(dd, "Fatal Error (freeze " + "mode), no longer usable\n"); + isfatal = 1; + } + /* + * Mark as having had an error for driver, and also + * for /sys and status word mapped to user programs. + * This marks unit as not usable, until reset + */ + *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; + *dd->ipath_statusp |= IPATH_STATUS_HWERROR; + dd->ipath_flags &= ~IPATH_INITTED; + } else { + ipath_dbg("Clearing freezemode on ignored hardware " + "error\n"); + ctrl &= ~INFINIPATH_C_FREEZEMODE; + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, + ctrl); + } + } + + *msg = '\0'; + + if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) { + strlcat(msg, "[Memory BIST test failed, PE-800 unusable]", + msgl); + /* ignore from now on, so disable until driver reloaded */ + *dd->ipath_statusp |= IPATH_STATUS_HWERROR; + dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED; + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, + dd->ipath_hwerrmask); + } + if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK + << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) { + bits = (u32) ((hwerrs >> + INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) & + INFINIPATH_HWE_RXEMEMPARITYERR_MASK); + snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ", + bits); + strlcat(msg, bitsmsg, msgl); + } + if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK + << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) { + bits = (u32) ((hwerrs >> + INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) & + INFINIPATH_HWE_TXEMEMPARITYERR_MASK); + snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ", + bits); + strlcat(msg, bitsmsg, msgl); + } + if (hwerrs & (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK + << INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT)) { + bits = (u32) ((hwerrs >> + INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) & + INFINIPATH_HWE_PCIEMEMPARITYERR_MASK); + snprintf(bitsmsg, sizeof bitsmsg, + "[PCIe Mem Parity Errs %x] ", bits); + strlcat(msg, bitsmsg, msgl); + } + if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR) + strlcat(msg, "[IB2IPATH Parity]", msgl); + if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR) + strlcat(msg, "[IPATH2IB Parity]", msgl); + +#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \ + INFINIPATH_HWE_COREPLL_RFSLIP ) + + if (hwerrs & _IPATH_PLL_FAIL) { + snprintf(bitsmsg, sizeof bitsmsg, + "[PLL failed (%llx), PE-800 unusable]", + (unsigned long long) hwerrs & _IPATH_PLL_FAIL); + strlcat(msg, bitsmsg, msgl); + /* ignore from now on, so disable until driver reloaded */ + dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL); + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, + dd->ipath_hwerrmask); + } + + if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) { + /* + * If it occurs, it is left masked since the eternal + * interface is unused + */ + dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED; + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, + dd->ipath_hwerrmask); + } + + if (hwerrs & INFINIPATH_HWE_PCIEPOISONEDTLP) + strlcat(msg, "[PCIe Poisoned TLP]", msgl); + if (hwerrs & INFINIPATH_HWE_PCIECPLTIMEOUT) + strlcat(msg, "[PCIe completion timeout]", msgl); + + /* + * In practice, it's unlikely wthat we'll see PCIe PLL, or bus + * parity or memory parity error failures, because most likely we + * won't be able to talk to the core of the chip. Nonetheless, we + * might see them, if they are in parts of the PCIe core that aren't + * essential. + */ + if (hwerrs & INFINIPATH_HWE_PCIE1PLLFAILED) + strlcat(msg, "[PCIePLL1]", msgl); + if (hwerrs & INFINIPATH_HWE_PCIE0PLLFAILED) + strlcat(msg, "[PCIePLL0]", msgl); + if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXTLH) + strlcat(msg, "[PCIe XTLH core parity]", msgl); + if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXADM) + strlcat(msg, "[PCIe ADM TX core parity]", msgl); + if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYRADM) + strlcat(msg, "[PCIe ADM RX core parity]", msgl); + + if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR) + strlcat(msg, "[Rx Dsync]", msgl); + if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) + strlcat(msg, "[SerDes PLL]", msgl); + + ipath_dev_err(dd, "%s hardware error\n", msg); + if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) { + /* + * for /sys status file ; if no trailing } is copied, we'll + * know it was truncated. + */ + snprintf(dd->ipath_freezemsg, dd->ipath_freezelen, + "{%s}", msg); + } +} + +/** + * ipath_pe_boardname - fill in the board name + * @dd: the infinipath device + * @name: the output buffer + * @namelen: the size of the output buffer + * + * info is based on the board revision register + */ +static int ipath_pe_boardname(struct ipath_devdata *dd, char *name, + size_t namelen) +{ + char *n = NULL; + u8 boardrev = dd->ipath_boardrev; + int ret; + + switch (boardrev) { + case 0: + n = "InfiniPath_Emulation"; + break; + case 1: + n = "InfiniPath_PE-800-Bringup"; + break; + case 2: + n = "InfiniPath_PE-880"; + break; + case 3: + n = "InfiniPath_PE-850"; + break; + case 4: + n = "InfiniPath_PE-860"; + break; + default: + ipath_dev_err(dd, + "Don't yet know about board with ID %u\n", + boardrev); + snprintf(name, namelen, "Unknown_InfiniPath_PE-8xx_%u", + boardrev); + break; + } + if (n) + snprintf(name, namelen, "%s", n); + + if (dd->ipath_majrev != 4 || dd->ipath_minrev != 1) { + ipath_dev_err(dd, "Unsupported PE-800 revision %u.%u!\n", + dd->ipath_majrev, dd->ipath_minrev); + ret = 1; + } else + ret = 0; + + return ret; +} + +/** + * ipath_pe_init_hwerrors - enable hardware errors + * @dd: the infinipath device + * + * now that we have finished initializing everything that might reasonably + * cause a hardware error, and cleared those errors bits as they occur, + * we can enable hardware errors in the mask (potentially enabling + * freeze mode), and enable hardware errors as errors (along with + * everything else) in errormask + */ +void ipath_pe_init_hwerrors(struct ipath_devdata *dd) +{ + ipath_err_t val; + u64 extsval; + + extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus); + + if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST)) + ipath_dev_err(dd, "MemBIST did not complete!\n"); + + val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */ + + if (!dd->ipath_boardrev) // no PLL for Emulator + val &= ~INFINIPATH_HWE_SERDESPLLFAILED; + + /* workaround bug 9460 in internal interface bus parity checking */ + val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM; + + dd->ipath_hwerrmask = val; +} + +/** + * ipath_pe_bringup_serdes - bring up the serdes + * @dd: the infinipath device + */ +int ipath_pe_bringup_serdes(struct ipath_devdata *dd) +{ + u64 val, tmp, config1; + int ret = 0, change = 0; + + ipath_dbg("Trying to bringup serdes\n"); + + if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) & + INFINIPATH_HWE_SERDESPLLFAILED) { + ipath_dbg("At start, serdes PLL failed bit set " + "in hwerrstatus, clearing and continuing\n"); + ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, + INFINIPATH_HWE_SERDESPLLFAILED); + } + + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); + config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1); + + ipath_cdbg(VERBOSE, "SerDes status config0=%llx config1=%llx, " + "xgxsconfig %llx\n", (unsigned long long) val, + (unsigned long long) config1, (unsigned long long) + ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); + + /* + * Force reset on, also set rxdetect enable. Must do before reading + * serdesstatus at least for simulation, or some of the bits in + * serdes status will come back as undefined and cause simulation + * failures + */ + val |= INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RXDETECT_EN + | INFINIPATH_SERDC0_L1PWR_DN; + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); + /* be sure chip saw it */ + tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + udelay(5); /* need pll reset set at least for a bit */ + /* + * after PLL is reset, set the per-lane Resets and TxIdle and + * clear the PLL reset and rxdetect (to get falling edge). + * Leave L1PWR bits set (permanently) + */ + val &= ~(INFINIPATH_SERDC0_RXDETECT_EN | INFINIPATH_SERDC0_RESET_PLL + | INFINIPATH_SERDC0_L1PWR_DN); + val |= INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE; + ipath_cdbg(VERBOSE, "Clearing pll reset and setting lane resets " + "and txidle (%llx)\n", (unsigned long long) val); + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); + /* be sure chip saw it */ + tmp = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + /* need PLL reset clear for at least 11 usec before lane + * resets cleared; give it a few more to be sure */ + udelay(15); + val &= ~(INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE); + + ipath_cdbg(VERBOSE, "Clearing lane resets and txidle " + "(writing %llx)\n", (unsigned long long) val); + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); + /* be sure chip saw it */ + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); + if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & + INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { + val &= + ~(INFINIPATH_XGXS_MDIOADDR_MASK << + INFINIPATH_XGXS_MDIOADDR_SHIFT); + /* MDIO address 3 */ + val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; + change = 1; + } + if (val & INFINIPATH_XGXS_RESET) { + val &= ~INFINIPATH_XGXS_RESET; + change = 1; + } + if (change) + ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); + + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); + + /* clear current and de-emphasis bits */ + config1 &= ~0x0ffffffff00ULL; + /* set current to 20ma */ + config1 |= 0x00000000000ULL; + /* set de-emphasis to -5.68dB */ + config1 |= 0x0cccc000000ULL; + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1); + + ipath_cdbg(VERBOSE, "done: SerDes status config0=%llx " + "config1=%llx, sstatus=%llx xgxs=%llx\n", + (unsigned long long) val, (unsigned long long) config1, + (unsigned long long) + ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus), + (unsigned long long) + ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); + + if (!ipath_waitfor_mdio_cmdready(dd)) { + ipath_write_kreg( + dd, dd->ipath_kregs->kr_mdio, + ipath_mdio_req(IPATH_MDIO_CMD_READ, 31, + IPATH_MDIO_CTRL_XGXS_REG_8, 0)); + if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio, + IPATH_MDIO_DATAVALID, &val)) + ipath_dbg("Never got MDIO data for XGXS " + "status read\n"); + else + ipath_cdbg(VERBOSE, "MDIO Read reg8, " + "'bank' 31 %x\n", (u32) val); + } else + ipath_dbg("Never got MDIO cmdready for XGXS status read\n"); + + return ret; +} + +/** + * ipath_pe_quiet_serdes - set serdes to txidle + * @dd: the infinipath device + * Called when driver is being unloaded + */ +void ipath_pe_quiet_serdes(struct ipath_devdata *dd) +{ + u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); + + val |= INFINIPATH_SERDC0_TXIDLE; + ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n", + (unsigned long long) val); + ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); +} + +/* this is not yet needed on the PE800, so just return 0. */ +static int ipath_pe_intconfig(struct ipath_devdata *dd) +{ + return 0; +} + +/** + * ipath_setup_pe_setextled - set the state of the two external LEDs + * @dd: the infinipath device + * @lst: the L state + * @ltst: the LT state + + * These LEDs indicate the physical and logical state of IB link. + * For this chip (at least with recommended board pinouts), LED1 + * is Yellow (logical state) and LED2 is Green (physical state), + * + * Note: We try to match the Mellanox HCA LED behavior as best + * we can. Green indicates physical link state is OK (something is + * plugged in, and we can train). + * Amber indicates the link is logically up (ACTIVE). + * Mellanox further blinks the amber LED to indicate data packet + * activity, but we have no hardware support for that, so it would + * require waking up every 10-20 msecs and checking the counters + * on the chip, and then turning the LED off if appropriate. That's + * visible overhead, so not something we will do. + * + */ +static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst, + u64 ltst) +{ + u64 extctl; + + /* the diags use the LED to indicate diag info, so we leave + * the external LED alone when the diags are running */ + if (ipath_diag_inuse) + return; + + extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON | + INFINIPATH_EXTC_LED2PRIPORT_ON); + + if (ltst & INFINIPATH_IBCS_LT_STATE_LINKUP) + extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON; + if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE) + extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON; + dd->ipath_extctrl = extctl; + ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl); +} + +/** + * ipath_setup_pe_cleanup - clean up any per-chip chip-specific stuff + * @dd: the infinipath device + * + * This is called during driver unload. + * We do the pci_disable_msi here, not in generic code, because it + * isn't used for the HT-400. If we do end up needing pci_enable_msi + * at some point in the future for HT-400, we'll move the call back + * into the main init_one code. + */ +static void ipath_setup_pe_cleanup(struct ipath_devdata *dd) +{ + dd->ipath_msi_lo = 0; /* just in case unload fails */ + pci_disable_msi(dd->pcidev); +} + +/** + * ipath_setup_pe_config - setup PCIe config related stuff + * @dd: the infinipath device + * @pdev: the PCI device + * + * The pci_enable_msi() call will fail on systems with MSI quirks + * such as those with AMD8131, even if the device of interest is not + * attached to that device, (in the 2.6.13 - 2.6.15 kernels, at least, fixed + * late in 2.6.16). + * All that can be done is to edit the kernel source to remove the quirk + * check until that is fixed. + * We do not need to call enable_msi() for our HyperTransport chip (HT-400), + * even those it uses MSI, and we want to avoid the quirk warning, so + * So we call enable_msi only for the PE-800. If we do end up needing + * pci_enable_msi at some point in the future for HT-400, we'll move the + * call back into the main init_one code. + * We save the msi lo and hi values, so we can restore them after + * chip reset (the kernel PCI infrastructure doesn't yet handle that + * correctly). + */ +static int ipath_setup_pe_config(struct ipath_devdata *dd, + struct pci_dev *pdev) +{ + int pos, ret; + + dd->ipath_msi_lo = 0; /* used as a flag during reset processing */ + ret = pci_enable_msi(dd->pcidev); + if (ret) + ipath_dev_err(dd, "pci_enable_msi failed: %d, " + "interrupts may not work\n", ret); + /* continue even if it fails, we may still be OK... */ + + if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) { + u16 control; + pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO, + &dd->ipath_msi_lo); + pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI, + &dd->ipath_msi_hi); + pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, + &control); + /* now save the data (vector) info */ + pci_read_config_word(dd->pcidev, + pos + ((control & PCI_MSI_FLAGS_64BIT) + ? 12 : 8), + &dd->ipath_msi_data); + ipath_cdbg(VERBOSE, "Read msi data 0x%x from config offset " + "0x%x, control=0x%x\n", dd->ipath_msi_data, + pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8), + control); + /* we save the cachelinesize also, although it doesn't + * really matter */ + pci_read_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE, + &dd->ipath_pci_cacheline); + } else + ipath_dev_err(dd, "Can't find MSI capability, " + "can't save MSI settings for reset\n"); + if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_EXP))) { + u16 linkstat; + pci_read_config_word(dd->pcidev, pos + PCI_EXP_LNKSTA, + &linkstat); + linkstat >>= 4; + linkstat &= 0x1f; + if (linkstat != 8) + ipath_dev_err(dd, "PCIe width %u, " + "performance reduced\n", linkstat); + } + else + ipath_dev_err(dd, "Can't find PCI Express " + "capability!\n"); + return 0; +} + +static void ipath_init_pe_variables(void) +{ + /* + * bits for selecting i2c direction and values, + * used for I2C serial flash + */ + ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM; + ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM; + ipath_gpio_sda = IPATH_GPIO_SDA; + ipath_gpio_scl = IPATH_GPIO_SCL; + + /* variables for sanity checking interrupt and errors */ + infinipath_hwe_bitsextant = + (INFINIPATH_HWE_RXEMEMPARITYERR_MASK << + INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) | + (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK << + INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) | + INFINIPATH_HWE_PCIE1PLLFAILED | + INFINIPATH_HWE_PCIE0PLLFAILED | + INFINIPATH_HWE_PCIEPOISONEDTLP | + INFINIPATH_HWE_PCIECPLTIMEOUT | + INFINIPATH_HWE_PCIEBUSPARITYXTLH | + INFINIPATH_HWE_PCIEBUSPARITYXADM | + INFINIPATH_HWE_PCIEBUSPARITYRADM | + INFINIPATH_HWE_MEMBISTFAILED | + INFINIPATH_HWE_COREPLL_FBSLIP | + INFINIPATH_HWE_COREPLL_RFSLIP | + INFINIPATH_HWE_SERDESPLLFAILED | + INFINIPATH_HWE_IBCBUSTOSPCPARITYERR | + INFINIPATH_HWE_IBCBUSFRSPCPARITYERR; + infinipath_i_bitsextant = + (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) | + (INFINIPATH_I_RCVAVAIL_MASK << + INFINIPATH_I_RCVAVAIL_SHIFT) | + INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT | + INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO; + infinipath_e_bitsextant = + INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC | + INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN | + INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN | + INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR | + INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP | + INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION | + INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL | + INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN | + INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK | + INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN | + INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN | + INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT | + INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | + INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED | + INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET | + INFINIPATH_E_HARDWARE; + + infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK; + infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK; +} + +/* setup the MSI stuff again after a reset. I'd like to just call + * pci_enable_msi() and request_irq() again, but when I do that, + * the MSI enable bit doesn't get set in the command word, and + * we switch to to a different interrupt vector, which is confusing, + * so I instead just do it all inline. Perhaps somehow can tie this + * into the PCIe hotplug support at some point + * Note, because I'm doing it all here, I don't call pci_disable_msi() + * or free_irq() at the start of ipath_setup_pe_reset(). + */ +static int ipath_reinit_msi(struct ipath_devdata *dd) +{ + int pos; + u16 control; + int ret; + + if (!dd->ipath_msi_lo) { + dev_info(&dd->pcidev->dev, "Can't restore MSI config, " + "initial setup failed?\n"); + ret = 0; + goto bail; + } + + if (!(pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) { + ipath_dev_err(dd, "Can't find MSI capability, " + "can't restore MSI settings\n"); + ret = 0; + goto bail; + } + ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n", + dd->ipath_msi_lo, pos + PCI_MSI_ADDRESS_LO); + pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO, + dd->ipath_msi_lo); + ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n", + dd->ipath_msi_hi, pos + PCI_MSI_ADDRESS_HI); + pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI, + dd->ipath_msi_hi); + pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control); + if (!(control & PCI_MSI_FLAGS_ENABLE)) { + ipath_cdbg(VERBOSE, "MSI control at off %x was %x, " + "setting MSI enable (%x)\n", pos + PCI_MSI_FLAGS, + control, control | PCI_MSI_FLAGS_ENABLE); + control |= PCI_MSI_FLAGS_ENABLE; + pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, + control); + } + /* now rewrite the data (vector) info */ + pci_write_config_word(dd->pcidev, pos + + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8), + dd->ipath_msi_data); + /* we restore the cachelinesize also, although it doesn't really + * matter */ + pci_write_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE, + dd->ipath_pci_cacheline); + /* and now set the pci master bit again */ + pci_set_master(dd->pcidev); + ret = 1; + +bail: + return ret; +} + +/* This routine sleeps, so it can only be called from user context, not + * from interrupt context. If we need interrupt context, we can split + * it into two routines. +*/ +static int ipath_setup_pe_reset(struct ipath_devdata *dd) +{ + u64 val; + int i; + int ret; + + /* Use ERROR so it shows up in logs, etc. */ + ipath_dev_err(dd, "Resetting PE-800 unit %u\n", + dd->ipath_unit); + val = dd->ipath_control | INFINIPATH_C_RESET; + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val); + mb(); + + for (i = 1; i <= 5; i++) { + int r; + /* allow MBIST, etc. to complete; longer on each retry. + * We sometimes get machine checks from bus timeout if no + * response, so for now, make it *really* long. + */ + msleep(1000 + (1 + i) * 2000); + if ((r = + pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0, + dd->ipath_pcibar0))) + ipath_dev_err(dd, "rewrite of BAR0 failed: %d\n", + r); + if ((r = + pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1, + dd->ipath_pcibar1))) + ipath_dev_err(dd, "rewrite of BAR1 failed: %d\n", + r); + /* now re-enable memory access */ + if ((r = pci_enable_device(dd->pcidev))) + ipath_dev_err(dd, "pci_enable_device failed after " + "reset: %d\n", r); + val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision); + if (val == dd->ipath_revision) { + ipath_cdbg(VERBOSE, "Got matching revision " + "register %llx on try %d\n", + (unsigned long long) val, i); + ret = ipath_reinit_msi(dd); + goto bail; + } + /* Probably getting -1 back */ + ipath_dbg("Didn't get expected revision register, " + "got %llx, try %d\n", (unsigned long long) val, + i + 1); + } + ret = 0; /* failed */ + +bail: + return ret; +} + +/** + * ipath_pe_put_tid - write a TID in chip + * @dd: the infinipath device + * @tidptr: pointer to the expected TID (in chip) to udpate + * @tidtype: 0 for eager, 1 for expected + * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing + * + * This exists as a separate routine to allow for special locking etc. + * It's used for both the full cleanup on exit, as well as the normal + * setup and teardown. + */ +static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr, + u32 type, unsigned long pa) +{ + u32 __iomem *tidp32 = (u32 __iomem *)tidptr; + unsigned long flags = 0; /* keep gcc quiet */ + + if (pa != dd->ipath_tidinvalid) { + if (pa & ((1U << 11) - 1)) { + dev_info(&dd->pcidev->dev, "BUG: physaddr %lx " + "not 4KB aligned!\n", pa); + return; + } + pa >>= 11; + /* paranoia check */ + if (pa & (7<<29)) + ipath_dev_err(dd, + "BUG: Physical page address 0x%lx " + "has bits set in 31-29\n", pa); + + if (type == 0) + pa |= dd->ipath_tidtemplate; + else /* for now, always full 4KB page */ + pa |= 2 << 29; + } + + /* workaround chip bug 9437 by writing each TID twice + * and holding a spinlock around the writes, so they don't + * intermix with other TID (eager or expected) writes + * Unfortunately, this call can be done from interrupt level + * for the port 0 eager TIDs, so we have to use irqsave + */ + spin_lock_irqsave(&dd->ipath_tid_lock, flags); + ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf); + if (dd->ipath_kregbase) + writel(pa, tidp32); + ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xdeadbeef); + mmiowb(); + spin_unlock_irqrestore(&dd->ipath_tid_lock, flags); +} + +/** + * ipath_pe_clear_tid - clear all TID entries for a port, expected and eager + * @dd: the infinipath device + * @port: the port + * + * clear all TID entries for a port, expected and eager. + * Used from ipath_close(). On PE800, TIDs are only 32 bits, + * not 64, but they are still on 64 bit boundaries, so tidbase + * is declared as u64 * for the pointer math, even though we write 32 bits + */ +static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port) +{ + u64 __iomem *tidbase; + unsigned long tidinv; + int i; + + if (!dd->ipath_kregbase) + return; + + ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port); + + tidinv = dd->ipath_tidinvalid; + tidbase = (u64 __iomem *) + ((char __iomem *)(dd->ipath_kregbase) + + dd->ipath_rcvtidbase + + port * dd->ipath_rcvtidcnt * sizeof(*tidbase)); + + for (i = 0; i < dd->ipath_rcvtidcnt; i++) + ipath_pe_put_tid(dd, &tidbase[i], 0, tidinv); + + tidbase = (u64 __iomem *) + ((char __iomem *)(dd->ipath_kregbase) + + dd->ipath_rcvegrbase + + port * dd->ipath_rcvegrcnt * sizeof(*tidbase)); + + for (i = 0; i < dd->ipath_rcvegrcnt; i++) + ipath_pe_put_tid(dd, &tidbase[i], 1, tidinv); +} + +/** + * ipath_pe_tidtemplate - setup constants for TID updates + * @dd: the infinipath device + * + * We setup stuff that we use a lot, to avoid calculating each time + */ +static void ipath_pe_tidtemplate(struct ipath_devdata *dd) +{ + u32 egrsize = dd->ipath_rcvegrbufsize; + + /* For now, we always allocate 4KB buffers (at init) so we can + * receive max size packets. We may want a module parameter to + * specify 2KB or 4KB and/or make be per port instead of per device + * for those who want to reduce memory footprint. Note that the + * ipath_rcvhdrentsize size must be large enough to hold the largest + * IB header (currently 96 bytes) that we expect to handle (plus of + * course the 2 dwords of RHF). + */ + if (egrsize == 2048) + dd->ipath_tidtemplate = 1U << 29; + else if (egrsize == 4096) + dd->ipath_tidtemplate = 2U << 29; + else { + egrsize = 4096; + dev_info(&dd->pcidev->dev, "BUG: unsupported egrbufsize " + "%u, using %u\n", dd->ipath_rcvegrbufsize, + egrsize); + dd->ipath_tidtemplate = 2U << 29; + } + dd->ipath_tidinvalid = 0; +} + +static int ipath_pe_early_init(struct ipath_devdata *dd) +{ + dd->ipath_flags |= IPATH_4BYTE_TID; + + /* + * For openib, we need to be able to handle an IB header of 96 bytes + * or 24 dwords. HT-400 has arbitrary sized receive buffers, so we + * made them the same size as the PIO buffers. The PE-800 does not + * handle arbitrary size buffers, so we need the header large enough + * to handle largest IB header, but still have room for a 2KB MTU + * standard IB packet. + */ + dd->ipath_rcvhdrentsize = 24; + dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; + + /* For HT-400, we allocate a somewhat overly large eager buffer, + * such that we can guarantee that we can receive the largest packet + * that we can send out. To truly support a 4KB MTU, we need to + * bump this to a larger value. We'll do this when I get around to + * testing 4KB sends on the PE-800, which I have not yet done. + */ + dd->ipath_rcvegrbufsize = 2048; + /* + * the min() check here is currently a nop, but it may not always + * be, depending on just how we do ipath_rcvegrbufsize + */ + dd->ipath_ibmaxlen = min(dd->ipath_piosize2k, + dd->ipath_rcvegrbufsize + + (dd->ipath_rcvhdrentsize << 2)); + dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen; + + /* + * For PE-800, we can request a receive interrupt for 1 or + * more packets from current offset. For now, we set this + * up for a single packet, to match the HT-400 behavior. + */ + dd->ipath_rhdrhead_intr_off = 1ULL<<32; + + return 0; +} + +int __attribute__((weak)) ipath_unordered_wc(void) +{ + return 0; +} + +/** + * ipath_init_pe_get_base_info - set chip-specific flags for user code + * @dd: the infinipath device + * @kbase: ipath_base_info pointer + * + * We set the PCIE flag because the lower bandwidth on PCIe vs + * HyperTransport can affect some user packet algorithims. + */ +static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase) +{ + struct ipath_base_info *kinfo = kbase; + + if (ipath_unordered_wc()) { + kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER; + ipath_cdbg(PROC, "Intel processor, forcing WC order\n"); + } + else + ipath_cdbg(PROC, "Not Intel processor, WC ordered\n"); + + kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE; + + return 0; +} + +/** + * ipath_init_pe800_funcs - set up the chip-specific function pointers + * @dd: the infinipath device + * + * This is global, and is called directly at init to set up the + * chip-specific function pointers for later use. + */ +void ipath_init_pe800_funcs(struct ipath_devdata *dd) +{ + dd->ipath_f_intrsetup = ipath_pe_intconfig; + dd->ipath_f_bus = ipath_setup_pe_config; + dd->ipath_f_reset = ipath_setup_pe_reset; + dd->ipath_f_get_boardname = ipath_pe_boardname; + dd->ipath_f_init_hwerrors = ipath_pe_init_hwerrors; + dd->ipath_f_early_init = ipath_pe_early_init; + dd->ipath_f_handle_hwerrors = ipath_pe_handle_hwerrors; + dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes; + dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes; + dd->ipath_f_clear_tids = ipath_pe_clear_tids; + dd->ipath_f_put_tid = ipath_pe_put_tid; + dd->ipath_f_cleanup = ipath_setup_pe_cleanup; + dd->ipath_f_setextled = ipath_setup_pe_setextled; + dd->ipath_f_get_base_info = ipath_pe_get_base_info; + + /* initialize chip-specific variables */ + dd->ipath_f_tidtemplate = ipath_pe_tidtemplate; + + /* + * setup the register offsets, since they are different for each + * chip + */ + dd->ipath_kregs = &ipath_pe_kregs; + dd->ipath_cregs = &ipath_pe_cregs; + + ipath_init_pe_variables(); +} + diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c new file mode 100644 index 000000000000..6058d70d7577 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -0,0 +1,913 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "ipath_verbs.h" +#include "ips_common.h" + +#define BITS_PER_PAGE (PAGE_SIZE*BITS_PER_BYTE) +#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) +#define mk_qpn(qpt, map, off) (((map) - (qpt)->map) * BITS_PER_PAGE + \ + (off)) +#define find_next_offset(map, off) find_next_zero_bit((map)->page, \ + BITS_PER_PAGE, off) + +#define TRANS_INVALID 0 +#define TRANS_ANY2RST 1 +#define TRANS_RST2INIT 2 +#define TRANS_INIT2INIT 3 +#define TRANS_INIT2RTR 4 +#define TRANS_RTR2RTS 5 +#define TRANS_RTS2RTS 6 +#define TRANS_SQERR2RTS 7 +#define TRANS_ANY2ERR 8 +#define TRANS_RTS2SQD 9 /* XXX Wait for expected ACKs & signal event */ +#define TRANS_SQD2SQD 10 /* error if not drained & parameter change */ +#define TRANS_SQD2RTS 11 /* error if not drained */ + +/* + * Convert the AETH credit code into the number of credits. + */ +static u32 credit_table[31] = { + 0, /* 0 */ + 1, /* 1 */ + 2, /* 2 */ + 3, /* 3 */ + 4, /* 4 */ + 6, /* 5 */ + 8, /* 6 */ + 12, /* 7 */ + 16, /* 8 */ + 24, /* 9 */ + 32, /* A */ + 48, /* B */ + 64, /* C */ + 96, /* D */ + 128, /* E */ + 192, /* F */ + 256, /* 10 */ + 384, /* 11 */ + 512, /* 12 */ + 768, /* 13 */ + 1024, /* 14 */ + 1536, /* 15 */ + 2048, /* 16 */ + 3072, /* 17 */ + 4096, /* 18 */ + 6144, /* 19 */ + 8192, /* 1A */ + 12288, /* 1B */ + 16384, /* 1C */ + 24576, /* 1D */ + 32768 /* 1E */ +}; + +static u32 alloc_qpn(struct ipath_qp_table *qpt) +{ + u32 i, offset, max_scan, qpn; + struct qpn_map *map; + u32 ret; + + qpn = qpt->last + 1; + if (qpn >= QPN_MAX) + qpn = 2; + offset = qpn & BITS_PER_PAGE_MASK; + map = &qpt->map[qpn / BITS_PER_PAGE]; + max_scan = qpt->nmaps - !offset; + for (i = 0;;) { + if (unlikely(!map->page)) { + unsigned long page = get_zeroed_page(GFP_KERNEL); + unsigned long flags; + + /* + * Free the page if someone raced with us + * installing it: + */ + spin_lock_irqsave(&qpt->lock, flags); + if (map->page) + free_page(page); + else + map->page = (void *)page; + spin_unlock_irqrestore(&qpt->lock, flags); + if (unlikely(!map->page)) + break; + } + if (likely(atomic_read(&map->n_free))) { + do { + if (!test_and_set_bit(offset, map->page)) { + atomic_dec(&map->n_free); + qpt->last = qpn; + ret = qpn; + goto bail; + } + offset = find_next_offset(map, offset); + qpn = mk_qpn(qpt, map, offset); + /* + * This test differs from alloc_pidmap(). + * If find_next_offset() does find a zero + * bit, we don't need to check for QPN + * wrapping around past our starting QPN. + * We just need to be sure we don't loop + * forever. + */ + } while (offset < BITS_PER_PAGE && qpn < QPN_MAX); + } + /* + * In order to keep the number of pages allocated to a + * minimum, we scan the all existing pages before increasing + * the size of the bitmap table. + */ + if (++i > max_scan) { + if (qpt->nmaps == QPNMAP_ENTRIES) + break; + map = &qpt->map[qpt->nmaps++]; + offset = 0; + } else if (map < &qpt->map[qpt->nmaps]) { + ++map; + offset = 0; + } else { + map = &qpt->map[0]; + offset = 2; + } + qpn = mk_qpn(qpt, map, offset); + } + + ret = 0; + +bail: + return ret; +} + +static void free_qpn(struct ipath_qp_table *qpt, u32 qpn) +{ + struct qpn_map *map; + + map = qpt->map + qpn / BITS_PER_PAGE; + if (map->page) + clear_bit(qpn & BITS_PER_PAGE_MASK, map->page); + atomic_inc(&map->n_free); +} + +/** + * ipath_alloc_qpn - allocate a QP number + * @qpt: the QP table + * @qp: the QP + * @type: the QP type (IB_QPT_SMI and IB_QPT_GSI are special) + * + * Allocate the next available QPN and put the QP into the hash table. + * The hash table holds a reference to the QP. + */ +int ipath_alloc_qpn(struct ipath_qp_table *qpt, struct ipath_qp *qp, + enum ib_qp_type type) +{ + unsigned long flags; + u32 qpn; + int ret; + + if (type == IB_QPT_SMI) + qpn = 0; + else if (type == IB_QPT_GSI) + qpn = 1; + else { + /* Allocate the next available QPN */ + qpn = alloc_qpn(qpt); + if (qpn == 0) { + ret = -ENOMEM; + goto bail; + } + } + qp->ibqp.qp_num = qpn; + + /* Add the QP to the hash table. */ + spin_lock_irqsave(&qpt->lock, flags); + + qpn %= qpt->max; + qp->next = qpt->table[qpn]; + qpt->table[qpn] = qp; + atomic_inc(&qp->refcount); + + spin_unlock_irqrestore(&qpt->lock, flags); + ret = 0; + +bail: + return ret; +} + +/** + * ipath_free_qp - remove a QP from the QP table + * @qpt: the QP table + * @qp: the QP to remove + * + * Remove the QP from the table so it can't be found asynchronously by + * the receive interrupt routine. + */ +void ipath_free_qp(struct ipath_qp_table *qpt, struct ipath_qp *qp) +{ + struct ipath_qp *q, **qpp; + unsigned long flags; + int fnd = 0; + + spin_lock_irqsave(&qpt->lock, flags); + + /* Remove QP from the hash table. */ + qpp = &qpt->table[qp->ibqp.qp_num % qpt->max]; + for (; (q = *qpp) != NULL; qpp = &q->next) { + if (q == qp) { + *qpp = qp->next; + qp->next = NULL; + atomic_dec(&qp->refcount); + fnd = 1; + break; + } + } + + spin_unlock_irqrestore(&qpt->lock, flags); + + if (!fnd) + return; + + /* If QPN is not reserved, mark QPN free in the bitmap. */ + if (qp->ibqp.qp_num > 1) + free_qpn(qpt, qp->ibqp.qp_num); + + wait_event(qp->wait, !atomic_read(&qp->refcount)); +} + +/** + * ipath_free_all_qps - remove all QPs from the table + * @qpt: the QP table to empty + */ +void ipath_free_all_qps(struct ipath_qp_table *qpt) +{ + unsigned long flags; + struct ipath_qp *qp, *nqp; + u32 n; + + for (n = 0; n < qpt->max; n++) { + spin_lock_irqsave(&qpt->lock, flags); + qp = qpt->table[n]; + qpt->table[n] = NULL; + spin_unlock_irqrestore(&qpt->lock, flags); + + while (qp) { + nqp = qp->next; + if (qp->ibqp.qp_num > 1) + free_qpn(qpt, qp->ibqp.qp_num); + if (!atomic_dec_and_test(&qp->refcount) || + !ipath_destroy_qp(&qp->ibqp)) + _VERBS_INFO("QP memory leak!\n"); + qp = nqp; + } + } + + for (n = 0; n < ARRAY_SIZE(qpt->map); n++) { + if (qpt->map[n].page) + free_page((unsigned long)qpt->map[n].page); + } +} + +/** + * ipath_lookup_qpn - return the QP with the given QPN + * @qpt: the QP table + * @qpn: the QP number to look up + * + * The caller is responsible for decrementing the QP reference count + * when done. + */ +struct ipath_qp *ipath_lookup_qpn(struct ipath_qp_table *qpt, u32 qpn) +{ + unsigned long flags; + struct ipath_qp *qp; + + spin_lock_irqsave(&qpt->lock, flags); + + for (qp = qpt->table[qpn % qpt->max]; qp; qp = qp->next) { + if (qp->ibqp.qp_num == qpn) { + atomic_inc(&qp->refcount); + break; + } + } + + spin_unlock_irqrestore(&qpt->lock, flags); + return qp; +} + +/** + * ipath_reset_qp - initialize the QP state to the reset state + * @qp: the QP to reset + */ +static void ipath_reset_qp(struct ipath_qp *qp) +{ + qp->remote_qpn = 0; + qp->qkey = 0; + qp->qp_access_flags = 0; + qp->s_hdrwords = 0; + qp->s_psn = 0; + qp->r_psn = 0; + atomic_set(&qp->msn, 0); + if (qp->ibqp.qp_type == IB_QPT_RC) { + qp->s_state = IB_OPCODE_RC_SEND_LAST; + qp->r_state = IB_OPCODE_RC_SEND_LAST; + } else { + qp->s_state = IB_OPCODE_UC_SEND_LAST; + qp->r_state = IB_OPCODE_UC_SEND_LAST; + } + qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE; + qp->s_nak_state = 0; + qp->s_rnr_timeout = 0; + qp->s_head = 0; + qp->s_tail = 0; + qp->s_cur = 0; + qp->s_last = 0; + qp->s_ssn = 1; + qp->s_lsn = 0; + qp->r_rq.head = 0; + qp->r_rq.tail = 0; + qp->r_reuse_sge = 0; +} + +/** + * ipath_modify_qp - modify the attributes of a queue pair + * @ibqp: the queue pair who's attributes we're modifying + * @attr: the new attributes + * @attr_mask: the mask of attributes to modify + * + * Returns 0 on success, otherwise returns an errno. + */ +int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask) +{ + struct ipath_qp *qp = to_iqp(ibqp); + enum ib_qp_state cur_state, new_state; + unsigned long flags; + int ret; + + spin_lock_irqsave(&qp->r_rq.lock, flags); + spin_lock(&qp->s_lock); + + cur_state = attr_mask & IB_QP_CUR_STATE ? + attr->cur_qp_state : qp->state; + new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; + + if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, + attr_mask)) + goto inval; + + switch (new_state) { + case IB_QPS_RESET: + ipath_reset_qp(qp); + break; + + case IB_QPS_ERR: + ipath_error_qp(qp); + break; + + default: + break; + + } + + if (attr_mask & IB_QP_PKEY_INDEX) { + struct ipath_ibdev *dev = to_idev(ibqp->device); + + if (attr->pkey_index >= ipath_layer_get_npkeys(dev->dd)) + goto inval; + qp->s_pkey_index = attr->pkey_index; + } + + if (attr_mask & IB_QP_DEST_QPN) + qp->remote_qpn = attr->dest_qp_num; + + if (attr_mask & IB_QP_SQ_PSN) { + qp->s_next_psn = attr->sq_psn; + qp->s_last_psn = qp->s_next_psn - 1; + } + + if (attr_mask & IB_QP_RQ_PSN) + qp->r_psn = attr->rq_psn; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + qp->qp_access_flags = attr->qp_access_flags; + + if (attr_mask & IB_QP_AV) { + if (attr->ah_attr.dlid == 0 || + attr->ah_attr.dlid >= IPS_MULTICAST_LID_BASE) + goto inval; + qp->remote_ah_attr = attr->ah_attr; + } + + if (attr_mask & IB_QP_PATH_MTU) + qp->path_mtu = attr->path_mtu; + + if (attr_mask & IB_QP_RETRY_CNT) + qp->s_retry = qp->s_retry_cnt = attr->retry_cnt; + + if (attr_mask & IB_QP_RNR_RETRY) { + qp->s_rnr_retry = attr->rnr_retry; + if (qp->s_rnr_retry > 7) + qp->s_rnr_retry = 7; + qp->s_rnr_retry_cnt = qp->s_rnr_retry; + } + + if (attr_mask & IB_QP_MIN_RNR_TIMER) { + if (attr->min_rnr_timer > 31) + goto inval; + qp->s_min_rnr_timer = attr->min_rnr_timer; + } + + if (attr_mask & IB_QP_QKEY) + qp->qkey = attr->qkey; + + if (attr_mask & IB_QP_PKEY_INDEX) + qp->s_pkey_index = attr->pkey_index; + + qp->state = new_state; + spin_unlock(&qp->s_lock); + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + + /* + * If QP1 changed to the RTS state, try to move to the link to INIT + * even if it was ACTIVE so the SM will reinitialize the SMA's + * state. + */ + if (qp->ibqp.qp_num == 1 && new_state == IB_QPS_RTS) { + struct ipath_ibdev *dev = to_idev(ibqp->device); + + ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKDOWN); + } + ret = 0; + goto bail; + +inval: + spin_unlock(&qp->s_lock); + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + ret = -EINVAL; + +bail: + return ret; +} + +int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_qp_init_attr *init_attr) +{ + struct ipath_qp *qp = to_iqp(ibqp); + + attr->qp_state = qp->state; + attr->cur_qp_state = attr->qp_state; + attr->path_mtu = qp->path_mtu; + attr->path_mig_state = 0; + attr->qkey = qp->qkey; + attr->rq_psn = qp->r_psn; + attr->sq_psn = qp->s_next_psn; + attr->dest_qp_num = qp->remote_qpn; + attr->qp_access_flags = qp->qp_access_flags; + attr->cap.max_send_wr = qp->s_size - 1; + attr->cap.max_recv_wr = qp->r_rq.size - 1; + attr->cap.max_send_sge = qp->s_max_sge; + attr->cap.max_recv_sge = qp->r_rq.max_sge; + attr->cap.max_inline_data = 0; + attr->ah_attr = qp->remote_ah_attr; + memset(&attr->alt_ah_attr, 0, sizeof(attr->alt_ah_attr)); + attr->pkey_index = qp->s_pkey_index; + attr->alt_pkey_index = 0; + attr->en_sqd_async_notify = 0; + attr->sq_draining = 0; + attr->max_rd_atomic = 1; + attr->max_dest_rd_atomic = 1; + attr->min_rnr_timer = qp->s_min_rnr_timer; + attr->port_num = 1; + attr->timeout = 0; + attr->retry_cnt = qp->s_retry_cnt; + attr->rnr_retry = qp->s_rnr_retry; + attr->alt_port_num = 0; + attr->alt_timeout = 0; + + init_attr->event_handler = qp->ibqp.event_handler; + init_attr->qp_context = qp->ibqp.qp_context; + init_attr->send_cq = qp->ibqp.send_cq; + init_attr->recv_cq = qp->ibqp.recv_cq; + init_attr->srq = qp->ibqp.srq; + init_attr->cap = attr->cap; + init_attr->sq_sig_type = + (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR)) + ? IB_SIGNAL_REQ_WR : 0; + init_attr->qp_type = qp->ibqp.qp_type; + init_attr->port_num = 1; + return 0; +} + +/** + * ipath_compute_aeth - compute the AETH (syndrome + MSN) + * @qp: the queue pair to compute the AETH for + * + * Returns the AETH. + * + * The QP s_lock should be held. + */ +__be32 ipath_compute_aeth(struct ipath_qp *qp) +{ + u32 aeth = atomic_read(&qp->msn) & IPS_MSN_MASK; + + if (qp->s_nak_state) { + aeth |= qp->s_nak_state << IPS_AETH_CREDIT_SHIFT; + } else if (qp->ibqp.srq) { + /* + * Shared receive queues don't generate credits. + * Set the credit field to the invalid value. + */ + aeth |= IPS_AETH_CREDIT_INVAL << IPS_AETH_CREDIT_SHIFT; + } else { + u32 min, max, x; + u32 credits; + + /* + * Compute the number of credits available (RWQEs). + * XXX Not holding the r_rq.lock here so there is a small + * chance that the pair of reads are not atomic. + */ + credits = qp->r_rq.head - qp->r_rq.tail; + if ((int)credits < 0) + credits += qp->r_rq.size; + /* + * Binary search the credit table to find the code to + * use. + */ + min = 0; + max = 31; + for (;;) { + x = (min + max) / 2; + if (credit_table[x] == credits) + break; + if (credit_table[x] > credits) + max = x; + else if (min == x) + break; + else + min = x; + } + aeth |= x << IPS_AETH_CREDIT_SHIFT; + } + return cpu_to_be32(aeth); +} + +/** + * ipath_create_qp - create a queue pair for a device + * @ibpd: the protection domain who's device we create the queue pair for + * @init_attr: the attributes of the queue pair + * @udata: unused by InfiniPath + * + * Returns the queue pair on success, otherwise returns an errno. + * + * Called by the ib_create_qp() core verbs function. + */ +struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata) +{ + struct ipath_qp *qp; + int err; + struct ipath_swqe *swq = NULL; + struct ipath_ibdev *dev; + size_t sz; + struct ib_qp *ret; + + if (init_attr->cap.max_send_sge > 255 || + init_attr->cap.max_recv_sge > 255) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + switch (init_attr->qp_type) { + case IB_QPT_UC: + case IB_QPT_RC: + sz = sizeof(struct ipath_sge) * + init_attr->cap.max_send_sge + + sizeof(struct ipath_swqe); + swq = vmalloc((init_attr->cap.max_send_wr + 1) * sz); + if (swq == NULL) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + /* FALLTHROUGH */ + case IB_QPT_UD: + case IB_QPT_SMI: + case IB_QPT_GSI: + qp = kmalloc(sizeof(*qp), GFP_KERNEL); + if (!qp) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + qp->r_rq.size = init_attr->cap.max_recv_wr + 1; + sz = sizeof(struct ipath_sge) * + init_attr->cap.max_recv_sge + + sizeof(struct ipath_rwqe); + qp->r_rq.wq = vmalloc(qp->r_rq.size * sz); + if (!qp->r_rq.wq) { + kfree(qp); + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + /* + * ib_create_qp() will initialize qp->ibqp + * except for qp->ibqp.qp_num. + */ + spin_lock_init(&qp->s_lock); + spin_lock_init(&qp->r_rq.lock); + atomic_set(&qp->refcount, 0); + init_waitqueue_head(&qp->wait); + tasklet_init(&qp->s_task, + init_attr->qp_type == IB_QPT_RC ? + ipath_do_rc_send : ipath_do_uc_send, + (unsigned long)qp); + qp->piowait.next = LIST_POISON1; + qp->piowait.prev = LIST_POISON2; + qp->timerwait.next = LIST_POISON1; + qp->timerwait.prev = LIST_POISON2; + qp->state = IB_QPS_RESET; + qp->s_wq = swq; + qp->s_size = init_attr->cap.max_send_wr + 1; + qp->s_max_sge = init_attr->cap.max_send_sge; + qp->r_rq.max_sge = init_attr->cap.max_recv_sge; + qp->s_flags = init_attr->sq_sig_type == IB_SIGNAL_REQ_WR ? + 1 << IPATH_S_SIGNAL_REQ_WR : 0; + dev = to_idev(ibpd->device); + err = ipath_alloc_qpn(&dev->qp_table, qp, + init_attr->qp_type); + if (err) { + vfree(swq); + vfree(qp->r_rq.wq); + kfree(qp); + ret = ERR_PTR(err); + goto bail; + } + ipath_reset_qp(qp); + + /* Tell the core driver that the kernel SMA is present. */ + if (qp->ibqp.qp_type == IB_QPT_SMI) + ipath_layer_set_verbs_flags(dev->dd, + IPATH_VERBS_KERNEL_SMA); + break; + + default: + /* Don't support raw QPs */ + ret = ERR_PTR(-ENOSYS); + goto bail; + } + + init_attr->cap.max_inline_data = 0; + + ret = &qp->ibqp; + +bail: + return ret; +} + +/** + * ipath_destroy_qp - destroy a queue pair + * @ibqp: the queue pair to destroy + * + * Returns 0 on success. + * + * Note that this can be called while the QP is actively sending or + * receiving! + */ +int ipath_destroy_qp(struct ib_qp *ibqp) +{ + struct ipath_qp *qp = to_iqp(ibqp); + struct ipath_ibdev *dev = to_idev(ibqp->device); + unsigned long flags; + + /* Tell the core driver that the kernel SMA is gone. */ + if (qp->ibqp.qp_type == IB_QPT_SMI) + ipath_layer_set_verbs_flags(dev->dd, 0); + + spin_lock_irqsave(&qp->r_rq.lock, flags); + spin_lock(&qp->s_lock); + qp->state = IB_QPS_ERR; + spin_unlock(&qp->s_lock); + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + + /* Stop the sending tasklet. */ + tasklet_kill(&qp->s_task); + + /* Make sure the QP isn't on the timeout list. */ + spin_lock_irqsave(&dev->pending_lock, flags); + if (qp->timerwait.next != LIST_POISON1) + list_del(&qp->timerwait); + if (qp->piowait.next != LIST_POISON1) + list_del(&qp->piowait); + spin_unlock_irqrestore(&dev->pending_lock, flags); + + /* + * Make sure that the QP is not in the QPN table so receive + * interrupts will discard packets for this QP. XXX Also remove QP + * from multicast table. + */ + if (atomic_read(&qp->refcount) != 0) + ipath_free_qp(&dev->qp_table, qp); + + vfree(qp->s_wq); + vfree(qp->r_rq.wq); + kfree(qp); + return 0; +} + +/** + * ipath_init_qp_table - initialize the QP table for a device + * @idev: the device who's QP table we're initializing + * @size: the size of the QP table + * + * Returns 0 on success, otherwise returns an errno. + */ +int ipath_init_qp_table(struct ipath_ibdev *idev, int size) +{ + int i; + int ret; + + idev->qp_table.last = 1; /* QPN 0 and 1 are special. */ + idev->qp_table.max = size; + idev->qp_table.nmaps = 1; + idev->qp_table.table = kzalloc(size * sizeof(*idev->qp_table.table), + GFP_KERNEL); + if (idev->qp_table.table == NULL) { + ret = -ENOMEM; + goto bail; + } + + for (i = 0; i < ARRAY_SIZE(idev->qp_table.map); i++) { + atomic_set(&idev->qp_table.map[i].n_free, BITS_PER_PAGE); + idev->qp_table.map[i].page = NULL; + } + + ret = 0; + +bail: + return ret; +} + +/** + * ipath_sqerror_qp - put a QP's send queue into an error state + * @qp: QP who's send queue will be put into an error state + * @wc: the WC responsible for putting the QP in this state + * + * Flushes the send work queue. + * The QP s_lock should be held. + */ + +void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc) +{ + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last); + + _VERBS_INFO("Send queue error on QP%d/%d: err: %d\n", + qp->ibqp.qp_num, qp->remote_qpn, wc->status); + + spin_lock(&dev->pending_lock); + /* XXX What if its already removed by the timeout code? */ + if (qp->timerwait.next != LIST_POISON1) + list_del(&qp->timerwait); + if (qp->piowait.next != LIST_POISON1) + list_del(&qp->piowait); + spin_unlock(&dev->pending_lock); + + ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 1); + if (++qp->s_last >= qp->s_size) + qp->s_last = 0; + + wc->status = IB_WC_WR_FLUSH_ERR; + + while (qp->s_last != qp->s_head) { + wc->wr_id = wqe->wr.wr_id; + wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 1); + if (++qp->s_last >= qp->s_size) + qp->s_last = 0; + wqe = get_swqe_ptr(qp, qp->s_last); + } + qp->s_cur = qp->s_tail = qp->s_head; + qp->state = IB_QPS_SQE; +} + +/** + * ipath_error_qp - put a QP into an error state + * @qp: the QP to put into an error state + * + * Flushes both send and receive work queues. + * QP r_rq.lock and s_lock should be held. + */ + +void ipath_error_qp(struct ipath_qp *qp) +{ + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + struct ib_wc wc; + + _VERBS_INFO("QP%d/%d in error state\n", + qp->ibqp.qp_num, qp->remote_qpn); + + spin_lock(&dev->pending_lock); + /* XXX What if its already removed by the timeout code? */ + if (qp->timerwait.next != LIST_POISON1) + list_del(&qp->timerwait); + if (qp->piowait.next != LIST_POISON1) + list_del(&qp->piowait); + spin_unlock(&dev->pending_lock); + + wc.status = IB_WC_WR_FLUSH_ERR; + wc.vendor_err = 0; + wc.byte_len = 0; + wc.imm_data = 0; + wc.qp_num = qp->ibqp.qp_num; + wc.src_qp = 0; + wc.wc_flags = 0; + wc.pkey_index = 0; + wc.slid = 0; + wc.sl = 0; + wc.dlid_path_bits = 0; + wc.port_num = 0; + + while (qp->s_last != qp->s_head) { + struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last); + + wc.wr_id = wqe->wr.wr_id; + wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + if (++qp->s_last >= qp->s_size) + qp->s_last = 0; + ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1); + } + qp->s_cur = qp->s_tail = qp->s_head; + qp->s_hdrwords = 0; + qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE; + + wc.opcode = IB_WC_RECV; + while (qp->r_rq.tail != qp->r_rq.head) { + wc.wr_id = get_rwqe_ptr(&qp->r_rq, qp->r_rq.tail)->wr_id; + if (++qp->r_rq.tail >= qp->r_rq.size) + qp->r_rq.tail = 0; + ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); + } +} + +/** + * ipath_get_credit - flush the send work queue of a QP + * @qp: the qp who's send work queue to flush + * @aeth: the Acknowledge Extended Transport Header + * + * The QP s_lock should be held. + */ +void ipath_get_credit(struct ipath_qp *qp, u32 aeth) +{ + u32 credit = (aeth >> IPS_AETH_CREDIT_SHIFT) & IPS_AETH_CREDIT_MASK; + + /* + * If the credit is invalid, we can send + * as many packets as we like. Otherwise, we have to + * honor the credit field. + */ + if (credit == IPS_AETH_CREDIT_INVAL) { + qp->s_lsn = (u32) -1; + } else if (qp->s_lsn != (u32) -1) { + /* Compute new LSN (i.e., MSN + credit) */ + credit = (aeth + credit_table[credit]) & IPS_MSN_MASK; + if (ipath_cmp24(credit, qp->s_lsn) > 0) + qp->s_lsn = credit; + } + + /* Restart sending if it was blocked due to lack of credits. */ + if (qp->s_cur != qp->s_head && + (qp->s_lsn == (u32) -1 || + ipath_cmp24(get_swqe_ptr(qp, qp->s_cur)->ssn, + qp->s_lsn + 1) <= 0)) + tasklet_hi_schedule(&qp->s_task); +} diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c new file mode 100644 index 000000000000..a4055ca00614 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -0,0 +1,1857 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ipath_verbs.h" +#include "ips_common.h" + +/* cut down ridiculously long IB macro names */ +#define OP(x) IB_OPCODE_RC_##x + +/** + * ipath_init_restart- initialize the qp->s_sge after a restart + * @qp: the QP who's SGE we're restarting + * @wqe: the work queue to initialize the QP's SGE from + * + * The QP s_lock should be held. + */ +static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe) +{ + struct ipath_ibdev *dev; + u32 len; + + len = ((qp->s_psn - wqe->psn) & IPS_PSN_MASK) * + ib_mtu_enum_to_int(qp->path_mtu); + qp->s_sge.sge = wqe->sg_list[0]; + qp->s_sge.sg_list = wqe->sg_list + 1; + qp->s_sge.num_sge = wqe->wr.num_sge; + ipath_skip_sge(&qp->s_sge, len); + qp->s_len = wqe->length - len; + dev = to_idev(qp->ibqp.device); + spin_lock(&dev->pending_lock); + if (qp->timerwait.next == LIST_POISON1) + list_add_tail(&qp->timerwait, + &dev->pending[dev->pending_index]); + spin_unlock(&dev->pending_lock); +} + +/** + * ipath_make_rc_ack - construct a response packet (ACK, NAK, or RDMA read) + * @qp: a pointer to the QP + * @ohdr: a pointer to the IB header being constructed + * @pmtu: the path MTU + * + * Return bth0 if constructed; otherwise, return 0. + * Note the QP s_lock must be held. + */ +static inline u32 ipath_make_rc_ack(struct ipath_qp *qp, + struct ipath_other_headers *ohdr, + u32 pmtu) +{ + struct ipath_sge_state *ss; + u32 hwords; + u32 len; + u32 bth0; + + /* header size in 32-bit words LRH+BTH = (8+12)/4. */ + hwords = 5; + + /* + * Send a response. Note that we are in the responder's + * side of the QP context. + */ + switch (qp->s_ack_state) { + case OP(RDMA_READ_REQUEST): + ss = &qp->s_rdma_sge; + len = qp->s_rdma_len; + if (len > pmtu) { + len = pmtu; + qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST); + } + else + qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY); + qp->s_rdma_len -= len; + bth0 = qp->s_ack_state << 24; + ohdr->u.aeth = ipath_compute_aeth(qp); + hwords++; + break; + + case OP(RDMA_READ_RESPONSE_FIRST): + qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE); + /* FALLTHROUGH */ + case OP(RDMA_READ_RESPONSE_MIDDLE): + ss = &qp->s_rdma_sge; + len = qp->s_rdma_len; + if (len > pmtu) + len = pmtu; + else { + ohdr->u.aeth = ipath_compute_aeth(qp); + hwords++; + qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST); + } + qp->s_rdma_len -= len; + bth0 = qp->s_ack_state << 24; + break; + + case OP(RDMA_READ_RESPONSE_LAST): + case OP(RDMA_READ_RESPONSE_ONLY): + /* + * We have to prevent new requests from changing + * the r_sge state while a ipath_verbs_send() + * is in progress. + * Changing r_state allows the receiver + * to continue processing new packets. + * We do it here now instead of above so + * that we are sure the packet was sent before + * changing the state. + */ + qp->r_state = OP(RDMA_READ_RESPONSE_LAST); + qp->s_ack_state = OP(ACKNOWLEDGE); + return 0; + + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): + ss = NULL; + len = 0; + qp->r_state = OP(SEND_LAST); + qp->s_ack_state = OP(ACKNOWLEDGE); + bth0 = IB_OPCODE_ATOMIC_ACKNOWLEDGE << 24; + ohdr->u.at.aeth = ipath_compute_aeth(qp); + ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->s_ack_atomic); + hwords += sizeof(ohdr->u.at) / 4; + break; + + default: + /* Send a regular ACK. */ + ss = NULL; + len = 0; + qp->s_ack_state = OP(ACKNOWLEDGE); + bth0 = qp->s_ack_state << 24; + ohdr->u.aeth = ipath_compute_aeth(qp); + hwords++; + } + qp->s_hdrwords = hwords; + qp->s_cur_sge = ss; + qp->s_cur_size = len; + + return bth0; +} + +/** + * ipath_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC) + * @qp: a pointer to the QP + * @ohdr: a pointer to the IB header being constructed + * @pmtu: the path MTU + * @bth0p: pointer to the BTH opcode word + * @bth2p: pointer to the BTH PSN word + * + * Return 1 if constructed; otherwise, return 0. + * Note the QP s_lock must be held. + */ +static inline int ipath_make_rc_req(struct ipath_qp *qp, + struct ipath_other_headers *ohdr, + u32 pmtu, u32 *bth0p, u32 *bth2p) +{ + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + struct ipath_sge_state *ss; + struct ipath_swqe *wqe; + u32 hwords; + u32 len; + u32 bth0; + u32 bth2; + char newreq; + + if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) || + qp->s_rnr_timeout) + goto done; + + /* header size in 32-bit words LRH+BTH = (8+12)/4. */ + hwords = 5; + bth0 = 0; + + /* Send a request. */ + wqe = get_swqe_ptr(qp, qp->s_cur); + switch (qp->s_state) { + default: + /* + * Resend an old request or start a new one. + * + * We keep track of the current SWQE so that + * we don't reset the "furthest progress" state + * if we need to back up. + */ + newreq = 0; + if (qp->s_cur == qp->s_tail) { + /* Check if send work queue is empty. */ + if (qp->s_tail == qp->s_head) + goto done; + qp->s_psn = wqe->psn = qp->s_next_psn; + newreq = 1; + } + /* + * Note that we have to be careful not to modify the + * original work request since we may need to resend + * it. + */ + qp->s_sge.sge = wqe->sg_list[0]; + qp->s_sge.sg_list = wqe->sg_list + 1; + qp->s_sge.num_sge = wqe->wr.num_sge; + qp->s_len = len = wqe->length; + ss = &qp->s_sge; + bth2 = 0; + switch (wqe->wr.opcode) { + case IB_WR_SEND: + case IB_WR_SEND_WITH_IMM: + /* If no credit, return. */ + if (qp->s_lsn != (u32) -1 && + ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) + goto done; + wqe->lpsn = wqe->psn; + if (len > pmtu) { + wqe->lpsn += (len - 1) / pmtu; + qp->s_state = OP(SEND_FIRST); + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_SEND) + qp->s_state = OP(SEND_ONLY); + else { + qp->s_state = OP(SEND_ONLY_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.imm_data; + hwords += 1; + } + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= 1 << 23; + bth2 = 1 << 31; /* Request ACK. */ + if (++qp->s_cur == qp->s_size) + qp->s_cur = 0; + break; + + case IB_WR_RDMA_WRITE: + if (newreq) + qp->s_lsn++; + /* FALLTHROUGH */ + case IB_WR_RDMA_WRITE_WITH_IMM: + /* If no credit, return. */ + if (qp->s_lsn != (u32) -1 && + ipath_cmp24(wqe->ssn, qp->s_lsn + 1) > 0) + goto done; + ohdr->u.rc.reth.vaddr = + cpu_to_be64(wqe->wr.wr.rdma.remote_addr); + ohdr->u.rc.reth.rkey = + cpu_to_be32(wqe->wr.wr.rdma.rkey); + ohdr->u.rc.reth.length = cpu_to_be32(len); + hwords += sizeof(struct ib_reth) / 4; + wqe->lpsn = wqe->psn; + if (len > pmtu) { + wqe->lpsn += (len - 1) / pmtu; + qp->s_state = OP(RDMA_WRITE_FIRST); + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_RDMA_WRITE) + qp->s_state = OP(RDMA_WRITE_ONLY); + else { + qp->s_state = + OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE); + /* Immediate data comes + * after RETH */ + ohdr->u.rc.imm_data = wqe->wr.imm_data; + hwords += 1; + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= 1 << 23; + } + bth2 = 1 << 31; /* Request ACK. */ + if (++qp->s_cur == qp->s_size) + qp->s_cur = 0; + break; + + case IB_WR_RDMA_READ: + ohdr->u.rc.reth.vaddr = + cpu_to_be64(wqe->wr.wr.rdma.remote_addr); + ohdr->u.rc.reth.rkey = + cpu_to_be32(wqe->wr.wr.rdma.rkey); + ohdr->u.rc.reth.length = cpu_to_be32(len); + qp->s_state = OP(RDMA_READ_REQUEST); + hwords += sizeof(ohdr->u.rc.reth) / 4; + if (newreq) { + qp->s_lsn++; + /* + * Adjust s_next_psn to count the + * expected number of responses. + */ + if (len > pmtu) + qp->s_next_psn += (len - 1) / pmtu; + wqe->lpsn = qp->s_next_psn++; + } + ss = NULL; + len = 0; + if (++qp->s_cur == qp->s_size) + qp->s_cur = 0; + break; + + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) + qp->s_state = OP(COMPARE_SWAP); + else + qp->s_state = OP(FETCH_ADD); + ohdr->u.atomic_eth.vaddr = cpu_to_be64( + wqe->wr.wr.atomic.remote_addr); + ohdr->u.atomic_eth.rkey = cpu_to_be32( + wqe->wr.wr.atomic.rkey); + ohdr->u.atomic_eth.swap_data = cpu_to_be64( + wqe->wr.wr.atomic.swap); + ohdr->u.atomic_eth.compare_data = cpu_to_be64( + wqe->wr.wr.atomic.compare_add); + hwords += sizeof(struct ib_atomic_eth) / 4; + if (newreq) { + qp->s_lsn++; + wqe->lpsn = wqe->psn; + } + if (++qp->s_cur == qp->s_size) + qp->s_cur = 0; + ss = NULL; + len = 0; + break; + + default: + goto done; + } + if (newreq) { + qp->s_tail++; + if (qp->s_tail >= qp->s_size) + qp->s_tail = 0; + } + bth2 |= qp->s_psn++ & IPS_PSN_MASK; + if ((int)(qp->s_psn - qp->s_next_psn) > 0) + qp->s_next_psn = qp->s_psn; + spin_lock(&dev->pending_lock); + if (qp->timerwait.next == LIST_POISON1) + list_add_tail(&qp->timerwait, + &dev->pending[dev->pending_index]); + spin_unlock(&dev->pending_lock); + break; + + case OP(RDMA_READ_RESPONSE_FIRST): + /* + * This case can only happen if a send is restarted. See + * ipath_restart_rc(). + */ + ipath_init_restart(qp, wqe); + /* FALLTHROUGH */ + case OP(SEND_FIRST): + qp->s_state = OP(SEND_MIDDLE); + /* FALLTHROUGH */ + case OP(SEND_MIDDLE): + bth2 = qp->s_psn++ & IPS_PSN_MASK; + if ((int)(qp->s_psn - qp->s_next_psn) > 0) + qp->s_next_psn = qp->s_psn; + ss = &qp->s_sge; + len = qp->s_len; + if (len > pmtu) { + /* + * Request an ACK every 1/2 MB to avoid retransmit + * timeouts. + */ + if (((wqe->length - len) % (512 * 1024)) == 0) + bth2 |= 1 << 31; + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_SEND) + qp->s_state = OP(SEND_LAST); + else { + qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.imm_data; + hwords += 1; + } + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= 1 << 23; + bth2 |= 1 << 31; /* Request ACK. */ + qp->s_cur++; + if (qp->s_cur >= qp->s_size) + qp->s_cur = 0; + break; + + case OP(RDMA_READ_RESPONSE_LAST): + /* + * This case can only happen if a RDMA write is restarted. + * See ipath_restart_rc(). + */ + ipath_init_restart(qp, wqe); + /* FALLTHROUGH */ + case OP(RDMA_WRITE_FIRST): + qp->s_state = OP(RDMA_WRITE_MIDDLE); + /* FALLTHROUGH */ + case OP(RDMA_WRITE_MIDDLE): + bth2 = qp->s_psn++ & IPS_PSN_MASK; + if ((int)(qp->s_psn - qp->s_next_psn) > 0) + qp->s_next_psn = qp->s_psn; + ss = &qp->s_sge; + len = qp->s_len; + if (len > pmtu) { + /* + * Request an ACK every 1/2 MB to avoid retransmit + * timeouts. + */ + if (((wqe->length - len) % (512 * 1024)) == 0) + bth2 |= 1 << 31; + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_RDMA_WRITE) + qp->s_state = OP(RDMA_WRITE_LAST); + else { + qp->s_state = OP(RDMA_WRITE_LAST_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.imm_data; + hwords += 1; + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= 1 << 23; + } + bth2 |= 1 << 31; /* Request ACK. */ + qp->s_cur++; + if (qp->s_cur >= qp->s_size) + qp->s_cur = 0; + break; + + case OP(RDMA_READ_RESPONSE_MIDDLE): + /* + * This case can only happen if a RDMA read is restarted. + * See ipath_restart_rc(). + */ + ipath_init_restart(qp, wqe); + len = ((qp->s_psn - wqe->psn) & IPS_PSN_MASK) * pmtu; + ohdr->u.rc.reth.vaddr = + cpu_to_be64(wqe->wr.wr.rdma.remote_addr + len); + ohdr->u.rc.reth.rkey = + cpu_to_be32(wqe->wr.wr.rdma.rkey); + ohdr->u.rc.reth.length = cpu_to_be32(qp->s_len); + qp->s_state = OP(RDMA_READ_REQUEST); + hwords += sizeof(ohdr->u.rc.reth) / 4; + bth2 = qp->s_psn++ & IPS_PSN_MASK; + if ((int)(qp->s_psn - qp->s_next_psn) > 0) + qp->s_next_psn = qp->s_psn; + ss = NULL; + len = 0; + qp->s_cur++; + if (qp->s_cur == qp->s_size) + qp->s_cur = 0; + break; + + case OP(RDMA_READ_REQUEST): + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): + /* + * We shouldn't start anything new until this request is + * finished. The ACK will handle rescheduling us. XXX The + * number of outstanding ones is negotiated at connection + * setup time (see pg. 258,289)? XXX Also, if we support + * multiple outstanding requests, we need to check the WQE + * IB_SEND_FENCE flag and not send a new request if a RDMA + * read or atomic is pending. + */ + goto done; + } + qp->s_len -= len; + qp->s_hdrwords = hwords; + qp->s_cur_sge = ss; + qp->s_cur_size = len; + *bth0p = bth0 | (qp->s_state << 24); + *bth2p = bth2; + return 1; + +done: + return 0; +} + +static inline void ipath_make_rc_grh(struct ipath_qp *qp, + struct ib_global_route *grh, + u32 nwords) +{ + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + + /* GRH header size in 32-bit words. */ + qp->s_hdrwords += 10; + qp->s_hdr.u.l.grh.version_tclass_flow = + cpu_to_be32((6 << 28) | + (grh->traffic_class << 20) | + grh->flow_label); + qp->s_hdr.u.l.grh.paylen = + cpu_to_be16(((qp->s_hdrwords - 12) + nwords + + SIZE_OF_CRC) << 2); + /* next_hdr is defined by C8-7 in ch. 8.4.1 */ + qp->s_hdr.u.l.grh.next_hdr = 0x1B; + qp->s_hdr.u.l.grh.hop_limit = grh->hop_limit; + /* The SGID is 32-bit aligned. */ + qp->s_hdr.u.l.grh.sgid.global.subnet_prefix = dev->gid_prefix; + qp->s_hdr.u.l.grh.sgid.global.interface_id = + ipath_layer_get_guid(dev->dd); + qp->s_hdr.u.l.grh.dgid = grh->dgid; +} + +/** + * ipath_do_rc_send - perform a send on an RC QP + * @data: contains a pointer to the QP + * + * Process entries in the send work queue until credit or queue is + * exhausted. Only allow one CPU to send a packet per QP (tasklet). + * Otherwise, after we drop the QP s_lock, two threads could send + * packets out of order. + */ +void ipath_do_rc_send(unsigned long data) +{ + struct ipath_qp *qp = (struct ipath_qp *)data; + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + unsigned long flags; + u16 lrh0; + u32 nwords; + u32 extra_bytes; + u32 bth0; + u32 bth2; + u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); + struct ipath_other_headers *ohdr; + + if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags)) + goto bail; + + if (unlikely(qp->remote_ah_attr.dlid == + ipath_layer_get_lid(dev->dd))) { + struct ib_wc wc; + + /* + * Pass in an uninitialized ib_wc to be consistent with + * other places where ipath_ruc_loopback() is called. + */ + ipath_ruc_loopback(qp, &wc); + goto clear; + } + + ohdr = &qp->s_hdr.u.oth; + if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) + ohdr = &qp->s_hdr.u.l.oth; + +again: + /* Check for a constructed packet to be sent. */ + if (qp->s_hdrwords != 0) { + /* + * If no PIO bufs are available, return. An interrupt will + * call ipath_ib_piobufavail() when one is available. + */ + _VERBS_INFO("h %u %p\n", qp->s_hdrwords, &qp->s_hdr); + _VERBS_INFO("d %u %p %u %p %u %u %u %u\n", qp->s_cur_size, + qp->s_cur_sge->sg_list, + qp->s_cur_sge->num_sge, + qp->s_cur_sge->sge.vaddr, + qp->s_cur_sge->sge.sge_length, + qp->s_cur_sge->sge.length, + qp->s_cur_sge->sge.m, + qp->s_cur_sge->sge.n); + if (ipath_verbs_send(dev->dd, qp->s_hdrwords, + (u32 *) &qp->s_hdr, qp->s_cur_size, + qp->s_cur_sge)) { + ipath_no_bufs_available(qp, dev); + goto bail; + } + dev->n_unicast_xmit++; + /* Record that we sent the packet and s_hdr is empty. */ + qp->s_hdrwords = 0; + } + + /* + * The lock is needed to synchronize between setting + * qp->s_ack_state, resend timer, and post_send(). + */ + spin_lock_irqsave(&qp->s_lock, flags); + + /* Sending responses has higher priority over sending requests. */ + if (qp->s_ack_state != OP(ACKNOWLEDGE) && + (bth0 = ipath_make_rc_ack(qp, ohdr, pmtu)) != 0) + bth2 = qp->s_ack_psn++ & IPS_PSN_MASK; + else if (!ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2)) + goto done; + + spin_unlock_irqrestore(&qp->s_lock, flags); + + /* Construct the header. */ + extra_bytes = (4 - qp->s_cur_size) & 3; + nwords = (qp->s_cur_size + extra_bytes) >> 2; + lrh0 = IPS_LRH_BTH; + if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) { + ipath_make_rc_grh(qp, &qp->remote_ah_attr.grh, nwords); + lrh0 = IPS_LRH_GRH; + } + lrh0 |= qp->remote_ah_attr.sl << 4; + qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); + qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); + qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + + SIZE_OF_CRC); + qp->s_hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd)); + bth0 |= ipath_layer_get_pkey(dev->dd, qp->s_pkey_index); + bth0 |= extra_bytes << 20; + ohdr->bth[0] = cpu_to_be32(bth0); + ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); + ohdr->bth[2] = cpu_to_be32(bth2); + + /* Check for more work to do. */ + goto again; + +done: + spin_unlock_irqrestore(&qp->s_lock, flags); +clear: + clear_bit(IPATH_S_BUSY, &qp->s_flags); +bail: + return; +} + +static void send_rc_ack(struct ipath_qp *qp) +{ + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + u16 lrh0; + u32 bth0; + struct ipath_other_headers *ohdr; + + /* Construct the header. */ + ohdr = &qp->s_hdr.u.oth; + lrh0 = IPS_LRH_BTH; + /* header size in 32-bit words LRH+BTH+AETH = (8+12+4)/4. */ + qp->s_hdrwords = 6; + if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) { + ipath_make_rc_grh(qp, &qp->remote_ah_attr.grh, 0); + ohdr = &qp->s_hdr.u.l.oth; + lrh0 = IPS_LRH_GRH; + } + bth0 = ipath_layer_get_pkey(dev->dd, qp->s_pkey_index); + ohdr->u.aeth = ipath_compute_aeth(qp); + if (qp->s_ack_state >= OP(COMPARE_SWAP)) { + bth0 |= IB_OPCODE_ATOMIC_ACKNOWLEDGE << 24; + ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->s_ack_atomic); + qp->s_hdrwords += sizeof(ohdr->u.at.atomic_ack_eth) / 4; + } + else + bth0 |= OP(ACKNOWLEDGE) << 24; + lrh0 |= qp->remote_ah_attr.sl << 4; + qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); + qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); + qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + SIZE_OF_CRC); + qp->s_hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd)); + ohdr->bth[0] = cpu_to_be32(bth0); + ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); + ohdr->bth[2] = cpu_to_be32(qp->s_ack_psn & IPS_PSN_MASK); + + /* + * If we can send the ACK, clear the ACK state. + */ + if (ipath_verbs_send(dev->dd, qp->s_hdrwords, (u32 *) &qp->s_hdr, + 0, NULL) == 0) { + qp->s_ack_state = OP(ACKNOWLEDGE); + dev->n_rc_qacks++; + dev->n_unicast_xmit++; + } +} + +/** + * ipath_restart_rc - back up requester to resend the last un-ACKed request + * @qp: the QP to restart + * @psn: packet sequence number for the request + * @wc: the work completion request + * + * The QP s_lock should be held. + */ +void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc) +{ + struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last); + struct ipath_ibdev *dev; + u32 n; + + /* + * If there are no requests pending, we are done. + */ + if (ipath_cmp24(psn, qp->s_next_psn) >= 0 || + qp->s_last == qp->s_tail) + goto done; + + if (qp->s_retry == 0) { + wc->wr_id = wqe->wr.wr_id; + wc->status = IB_WC_RETRY_EXC_ERR; + wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + wc->vendor_err = 0; + wc->byte_len = 0; + wc->qp_num = qp->ibqp.qp_num; + wc->src_qp = qp->remote_qpn; + wc->pkey_index = 0; + wc->slid = qp->remote_ah_attr.dlid; + wc->sl = qp->remote_ah_attr.sl; + wc->dlid_path_bits = 0; + wc->port_num = 0; + ipath_sqerror_qp(qp, wc); + goto bail; + } + qp->s_retry--; + + /* + * Remove the QP from the timeout queue. + * Note: it may already have been removed by ipath_ib_timer(). + */ + dev = to_idev(qp->ibqp.device); + spin_lock(&dev->pending_lock); + if (qp->timerwait.next != LIST_POISON1) + list_del(&qp->timerwait); + spin_unlock(&dev->pending_lock); + + if (wqe->wr.opcode == IB_WR_RDMA_READ) + dev->n_rc_resends++; + else + dev->n_rc_resends += (int)qp->s_psn - (int)psn; + + /* + * If we are starting the request from the beginning, let the normal + * send code handle initialization. + */ + qp->s_cur = qp->s_last; + if (ipath_cmp24(psn, wqe->psn) <= 0) { + qp->s_state = OP(SEND_LAST); + qp->s_psn = wqe->psn; + } else { + n = qp->s_cur; + for (;;) { + if (++n == qp->s_size) + n = 0; + if (n == qp->s_tail) { + if (ipath_cmp24(psn, qp->s_next_psn) >= 0) { + qp->s_cur = n; + wqe = get_swqe_ptr(qp, n); + } + break; + } + wqe = get_swqe_ptr(qp, n); + if (ipath_cmp24(psn, wqe->psn) < 0) + break; + qp->s_cur = n; + } + qp->s_psn = psn; + + /* + * Reset the state to restart in the middle of a request. + * Don't change the s_sge, s_cur_sge, or s_cur_size. + * See ipath_do_rc_send(). + */ + switch (wqe->wr.opcode) { + case IB_WR_SEND: + case IB_WR_SEND_WITH_IMM: + qp->s_state = OP(RDMA_READ_RESPONSE_FIRST); + break; + + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + qp->s_state = OP(RDMA_READ_RESPONSE_LAST); + break; + + case IB_WR_RDMA_READ: + qp->s_state = + OP(RDMA_READ_RESPONSE_MIDDLE); + break; + + default: + /* + * This case shouldn't happen since its only + * one PSN per req. + */ + qp->s_state = OP(SEND_LAST); + } + } + +done: + tasklet_hi_schedule(&qp->s_task); + +bail: + return; +} + +/** + * reset_psn - reset the QP state to send starting from PSN + * @qp: the QP + * @psn: the packet sequence number to restart at + * + * This is called from ipath_rc_rcv() to process an incoming RC ACK + * for the given QP. + * Called at interrupt level with the QP s_lock held. + */ +static void reset_psn(struct ipath_qp *qp, u32 psn) +{ + struct ipath_swqe *wqe; + u32 n; + + n = qp->s_cur; + wqe = get_swqe_ptr(qp, n); + for (;;) { + if (++n == qp->s_size) + n = 0; + if (n == qp->s_tail) { + if (ipath_cmp24(psn, qp->s_next_psn) >= 0) { + qp->s_cur = n; + wqe = get_swqe_ptr(qp, n); + } + break; + } + wqe = get_swqe_ptr(qp, n); + if (ipath_cmp24(psn, wqe->psn) < 0) + break; + qp->s_cur = n; + } + qp->s_psn = psn; + + /* + * Set the state to restart in the middle of a + * request. Don't change the s_sge, s_cur_sge, or + * s_cur_size. See ipath_do_rc_send(). + */ + switch (wqe->wr.opcode) { + case IB_WR_SEND: + case IB_WR_SEND_WITH_IMM: + qp->s_state = OP(RDMA_READ_RESPONSE_FIRST); + break; + + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + qp->s_state = OP(RDMA_READ_RESPONSE_LAST); + break; + + case IB_WR_RDMA_READ: + qp->s_state = OP(RDMA_READ_RESPONSE_MIDDLE); + break; + + default: + /* + * This case shouldn't happen since its only + * one PSN per req. + */ + qp->s_state = OP(SEND_LAST); + } +} + +/** + * do_rc_ack - process an incoming RC ACK + * @qp: the QP the ACK came in on + * @psn: the packet sequence number of the ACK + * @opcode: the opcode of the request that resulted in the ACK + * + * This is called from ipath_rc_rcv() to process an incoming RC ACK + * for the given QP. + * Called at interrupt level with the QP s_lock held. + * Returns 1 if OK, 0 if current operation should be aborted (NAK). + */ +static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode) +{ + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + struct ib_wc wc; + struct ipath_swqe *wqe; + int ret = 0; + + /* + * Remove the QP from the timeout queue (or RNR timeout queue). + * If ipath_ib_timer() has already removed it, + * it's OK since we hold the QP s_lock and ipath_restart_rc() + * just won't find anything to restart if we ACK everything. + */ + spin_lock(&dev->pending_lock); + if (qp->timerwait.next != LIST_POISON1) + list_del(&qp->timerwait); + spin_unlock(&dev->pending_lock); + + /* + * Note that NAKs implicitly ACK outstanding SEND and RDMA write + * requests and implicitly NAK RDMA read and atomic requests issued + * before the NAK'ed request. The MSN won't include the NAK'ed + * request but will include an ACK'ed request(s). + */ + wqe = get_swqe_ptr(qp, qp->s_last); + + /* Nothing is pending to ACK/NAK. */ + if (qp->s_last == qp->s_tail) + goto bail; + + /* + * The MSN might be for a later WQE than the PSN indicates so + * only complete WQEs that the PSN finishes. + */ + while (ipath_cmp24(psn, wqe->lpsn) >= 0) { + /* If we are ACKing a WQE, the MSN should be >= the SSN. */ + if (ipath_cmp24(aeth, wqe->ssn) < 0) + break; + /* + * If this request is a RDMA read or atomic, and the ACK is + * for a later operation, this ACK NAKs the RDMA read or + * atomic. In other words, only a RDMA_READ_LAST or ONLY + * can ACK a RDMA read and likewise for atomic ops. Note + * that the NAK case can only happen if relaxed ordering is + * used and requests are sent after an RDMA read or atomic + * is sent but before the response is received. + */ + if ((wqe->wr.opcode == IB_WR_RDMA_READ && + opcode != OP(RDMA_READ_RESPONSE_LAST)) || + ((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP || + wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) && + (opcode != OP(ATOMIC_ACKNOWLEDGE) || + ipath_cmp24(wqe->psn, psn) != 0))) { + /* + * The last valid PSN seen is the previous + * request's. + */ + qp->s_last_psn = wqe->psn - 1; + /* Retry this request. */ + ipath_restart_rc(qp, wqe->psn, &wc); + /* + * No need to process the ACK/NAK since we are + * restarting an earlier request. + */ + goto bail; + } + /* Post a send completion queue entry if requested. */ + if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) || + (wqe->wr.send_flags & IB_SEND_SIGNALED)) { + wc.wr_id = wqe->wr.wr_id; + wc.status = IB_WC_SUCCESS; + wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + wc.vendor_err = 0; + wc.byte_len = wqe->length; + wc.qp_num = qp->ibqp.qp_num; + wc.src_qp = qp->remote_qpn; + wc.pkey_index = 0; + wc.slid = qp->remote_ah_attr.dlid; + wc.sl = qp->remote_ah_attr.sl; + wc.dlid_path_bits = 0; + wc.port_num = 0; + ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0); + } + qp->s_retry = qp->s_retry_cnt; + /* + * If we are completing a request which is in the process of + * being resent, we can stop resending it since we know the + * responder has already seen it. + */ + if (qp->s_last == qp->s_cur) { + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; + wqe = get_swqe_ptr(qp, qp->s_cur); + qp->s_state = OP(SEND_LAST); + qp->s_psn = wqe->psn; + } + if (++qp->s_last >= qp->s_size) + qp->s_last = 0; + wqe = get_swqe_ptr(qp, qp->s_last); + if (qp->s_last == qp->s_tail) + break; + } + + switch (aeth >> 29) { + case 0: /* ACK */ + dev->n_rc_acks++; + /* If this is a partial ACK, reset the retransmit timer. */ + if (qp->s_last != qp->s_tail) { + spin_lock(&dev->pending_lock); + list_add_tail(&qp->timerwait, + &dev->pending[dev->pending_index]); + spin_unlock(&dev->pending_lock); + } + ipath_get_credit(qp, aeth); + qp->s_rnr_retry = qp->s_rnr_retry_cnt; + qp->s_retry = qp->s_retry_cnt; + qp->s_last_psn = psn; + ret = 1; + goto bail; + + case 1: /* RNR NAK */ + dev->n_rnr_naks++; + if (qp->s_rnr_retry == 0) { + if (qp->s_last == qp->s_tail) + goto bail; + + wc.status = IB_WC_RNR_RETRY_EXC_ERR; + goto class_b; + } + if (qp->s_rnr_retry_cnt < 7) + qp->s_rnr_retry--; + if (qp->s_last == qp->s_tail) + goto bail; + + /* The last valid PSN seen is the previous request's. */ + qp->s_last_psn = wqe->psn - 1; + + dev->n_rc_resends += (int)qp->s_psn - (int)psn; + + /* + * If we are starting the request from the beginning, let + * the normal send code handle initialization. + */ + qp->s_cur = qp->s_last; + wqe = get_swqe_ptr(qp, qp->s_cur); + if (ipath_cmp24(psn, wqe->psn) <= 0) { + qp->s_state = OP(SEND_LAST); + qp->s_psn = wqe->psn; + } else + reset_psn(qp, psn); + + qp->s_rnr_timeout = + ib_ipath_rnr_table[(aeth >> IPS_AETH_CREDIT_SHIFT) & + IPS_AETH_CREDIT_MASK]; + ipath_insert_rnr_queue(qp); + goto bail; + + case 3: /* NAK */ + /* The last valid PSN seen is the previous request's. */ + if (qp->s_last != qp->s_tail) + qp->s_last_psn = wqe->psn - 1; + switch ((aeth >> IPS_AETH_CREDIT_SHIFT) & + IPS_AETH_CREDIT_MASK) { + case 0: /* PSN sequence error */ + dev->n_seq_naks++; + /* + * Back up to the responder's expected PSN. XXX + * Note that we might get a NAK in the middle of an + * RDMA READ response which terminates the RDMA + * READ. + */ + if (qp->s_last == qp->s_tail) + break; + + if (ipath_cmp24(psn, wqe->psn) < 0) + break; + + /* Retry the request. */ + ipath_restart_rc(qp, psn, &wc); + break; + + case 1: /* Invalid Request */ + wc.status = IB_WC_REM_INV_REQ_ERR; + dev->n_other_naks++; + goto class_b; + + case 2: /* Remote Access Error */ + wc.status = IB_WC_REM_ACCESS_ERR; + dev->n_other_naks++; + goto class_b; + + case 3: /* Remote Operation Error */ + wc.status = IB_WC_REM_OP_ERR; + dev->n_other_naks++; + class_b: + wc.wr_id = wqe->wr.wr_id; + wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + wc.vendor_err = 0; + wc.byte_len = 0; + wc.qp_num = qp->ibqp.qp_num; + wc.src_qp = qp->remote_qpn; + wc.pkey_index = 0; + wc.slid = qp->remote_ah_attr.dlid; + wc.sl = qp->remote_ah_attr.sl; + wc.dlid_path_bits = 0; + wc.port_num = 0; + ipath_sqerror_qp(qp, &wc); + break; + + default: + /* Ignore other reserved NAK error codes */ + goto reserved; + } + qp->s_rnr_retry = qp->s_rnr_retry_cnt; + goto bail; + + default: /* 2: reserved */ + reserved: + /* Ignore reserved NAK codes. */ + goto bail; + } + +bail: + return ret; +} + +/** + * ipath_rc_rcv_resp - process an incoming RC response packet + * @dev: the device this packet came in on + * @ohdr: the other headers for this packet + * @data: the packet data + * @tlen: the packet length + * @qp: the QP for this packet + * @opcode: the opcode for this packet + * @psn: the packet sequence number for this packet + * @hdrsize: the header length + * @pmtu: the path MTU + * @header_in_data: true if part of the header data is in the data buffer + * + * This is called from ipath_rc_rcv() to process an incoming RC response + * packet for the given QP. + * Called at interrupt level. + */ +static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev, + struct ipath_other_headers *ohdr, + void *data, u32 tlen, + struct ipath_qp *qp, + u32 opcode, + u32 psn, u32 hdrsize, u32 pmtu, + int header_in_data) +{ + unsigned long flags; + struct ib_wc wc; + int diff; + u32 pad; + u32 aeth; + + spin_lock_irqsave(&qp->s_lock, flags); + + /* Ignore invalid responses. */ + if (ipath_cmp24(psn, qp->s_next_psn) >= 0) + goto ack_done; + + /* Ignore duplicate responses. */ + diff = ipath_cmp24(psn, qp->s_last_psn); + if (unlikely(diff <= 0)) { + /* Update credits for "ghost" ACKs */ + if (diff == 0 && opcode == OP(ACKNOWLEDGE)) { + if (!header_in_data) + aeth = be32_to_cpu(ohdr->u.aeth); + else { + aeth = be32_to_cpu(((__be32 *) data)[0]); + data += sizeof(__be32); + } + if ((aeth >> 29) == 0) + ipath_get_credit(qp, aeth); + } + goto ack_done; + } + + switch (opcode) { + case OP(ACKNOWLEDGE): + case OP(ATOMIC_ACKNOWLEDGE): + case OP(RDMA_READ_RESPONSE_FIRST): + if (!header_in_data) + aeth = be32_to_cpu(ohdr->u.aeth); + else { + aeth = be32_to_cpu(((__be32 *) data)[0]); + data += sizeof(__be32); + } + if (opcode == OP(ATOMIC_ACKNOWLEDGE)) + *(u64 *) qp->s_sge.sge.vaddr = *(u64 *) data; + if (!do_rc_ack(qp, aeth, psn, opcode) || + opcode != OP(RDMA_READ_RESPONSE_FIRST)) + goto ack_done; + hdrsize += 4; + /* + * do_rc_ack() has already checked the PSN so skip + * the sequence check. + */ + goto rdma_read; + + case OP(RDMA_READ_RESPONSE_MIDDLE): + /* no AETH, no ACK */ + if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) { + dev->n_rdma_seq++; + ipath_restart_rc(qp, qp->s_last_psn + 1, &wc); + goto ack_done; + } + rdma_read: + if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST))) + goto ack_done; + if (unlikely(tlen != (hdrsize + pmtu + 4))) + goto ack_done; + if (unlikely(pmtu >= qp->s_len)) + goto ack_done; + /* We got a response so update the timeout. */ + if (unlikely(qp->s_last == qp->s_tail || + get_swqe_ptr(qp, qp->s_last)->wr.opcode != + IB_WR_RDMA_READ)) + goto ack_done; + spin_lock(&dev->pending_lock); + if (qp->s_rnr_timeout == 0 && + qp->timerwait.next != LIST_POISON1) + list_move_tail(&qp->timerwait, + &dev->pending[dev->pending_index]); + spin_unlock(&dev->pending_lock); + /* + * Update the RDMA receive state but do the copy w/o holding the + * locks and blocking interrupts. XXX Yet another place that + * affects relaxed RDMA order since we don't want s_sge modified. + */ + qp->s_len -= pmtu; + qp->s_last_psn = psn; + spin_unlock_irqrestore(&qp->s_lock, flags); + ipath_copy_sge(&qp->s_sge, data, pmtu); + goto bail; + + case OP(RDMA_READ_RESPONSE_LAST): + /* ACKs READ req. */ + if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) { + dev->n_rdma_seq++; + ipath_restart_rc(qp, qp->s_last_psn + 1, &wc); + goto ack_done; + } + /* FALLTHROUGH */ + case OP(RDMA_READ_RESPONSE_ONLY): + if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST))) + goto ack_done; + /* + * Get the number of bytes the message was padded by. + */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* + * Check that the data size is >= 1 && <= pmtu. + * Remember to account for the AETH header (4) and + * ICRC (4). + */ + if (unlikely(tlen <= (hdrsize + pad + 8))) { + /* + * XXX Need to generate an error CQ + * entry. + */ + goto ack_done; + } + tlen -= hdrsize + pad + 8; + if (unlikely(tlen != qp->s_len)) { + /* + * XXX Need to generate an error CQ + * entry. + */ + goto ack_done; + } + if (!header_in_data) + aeth = be32_to_cpu(ohdr->u.aeth); + else { + aeth = be32_to_cpu(((__be32 *) data)[0]); + data += sizeof(__be32); + } + ipath_copy_sge(&qp->s_sge, data, tlen); + if (do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST))) { + /* + * Change the state so we contimue + * processing new requests. + */ + qp->s_state = OP(SEND_LAST); + } + goto ack_done; + } + +ack_done: + spin_unlock_irqrestore(&qp->s_lock, flags); +bail: + return; +} + +/** + * ipath_rc_rcv_error - process an incoming duplicate or error RC packet + * @dev: the device this packet came in on + * @ohdr: the other headers for this packet + * @data: the packet data + * @qp: the QP for this packet + * @opcode: the opcode for this packet + * @psn: the packet sequence number for this packet + * @diff: the difference between the PSN and the expected PSN + * @header_in_data: true if part of the header data is in the data buffer + * + * This is called from ipath_rc_rcv() to process an unexpected + * incoming RC packet for the given QP. + * Called at interrupt level. + * Return 1 if no more processing is needed; otherwise return 0 to + * schedule a response to be sent and the s_lock unlocked. + */ +static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev, + struct ipath_other_headers *ohdr, + void *data, + struct ipath_qp *qp, + u32 opcode, + u32 psn, + int diff, + int header_in_data) +{ + struct ib_reth *reth; + + if (diff > 0) { + /* + * Packet sequence error. + * A NAK will ACK earlier sends and RDMA writes. + * Don't queue the NAK if a RDMA read, atomic, or + * NAK is pending though. + */ + spin_lock(&qp->s_lock); + if ((qp->s_ack_state >= OP(RDMA_READ_REQUEST) && + qp->s_ack_state != IB_OPCODE_ACKNOWLEDGE) || + qp->s_nak_state != 0) { + spin_unlock(&qp->s_lock); + goto done; + } + qp->s_ack_state = OP(SEND_ONLY); + qp->s_nak_state = IB_NAK_PSN_ERROR; + /* Use the expected PSN. */ + qp->s_ack_psn = qp->r_psn; + goto resched; + } + + /* + * Handle a duplicate request. Don't re-execute SEND, RDMA + * write or atomic op. Don't NAK errors, just silently drop + * the duplicate request. Note that r_sge, r_len, and + * r_rcv_len may be in use so don't modify them. + * + * We are supposed to ACK the earliest duplicate PSN but we + * can coalesce an outstanding duplicate ACK. We have to + * send the earliest so that RDMA reads can be restarted at + * the requester's expected PSN. + */ + spin_lock(&qp->s_lock); + if (qp->s_ack_state != IB_OPCODE_ACKNOWLEDGE && + ipath_cmp24(psn, qp->s_ack_psn) >= 0) { + if (qp->s_ack_state < IB_OPCODE_RDMA_READ_REQUEST) + qp->s_ack_psn = psn; + spin_unlock(&qp->s_lock); + goto done; + } + switch (opcode) { + case OP(RDMA_READ_REQUEST): + /* + * We have to be careful to not change s_rdma_sge + * while ipath_do_rc_send() is using it and not + * holding the s_lock. + */ + if (qp->s_ack_state != OP(ACKNOWLEDGE) && + qp->s_ack_state >= IB_OPCODE_RDMA_READ_REQUEST) { + spin_unlock(&qp->s_lock); + dev->n_rdma_dup_busy++; + goto done; + } + /* RETH comes after BTH */ + if (!header_in_data) + reth = &ohdr->u.rc.reth; + else { + reth = (struct ib_reth *)data; + data += sizeof(*reth); + } + qp->s_rdma_len = be32_to_cpu(reth->length); + if (qp->s_rdma_len != 0) { + u32 rkey = be32_to_cpu(reth->rkey); + u64 vaddr = be64_to_cpu(reth->vaddr); + int ok; + + /* + * Address range must be a subset of the original + * request and start on pmtu boundaries. + */ + ok = ipath_rkey_ok(dev, &qp->s_rdma_sge, + qp->s_rdma_len, vaddr, rkey, + IB_ACCESS_REMOTE_READ); + if (unlikely(!ok)) + goto done; + } else { + qp->s_rdma_sge.sg_list = NULL; + qp->s_rdma_sge.num_sge = 0; + qp->s_rdma_sge.sge.mr = NULL; + qp->s_rdma_sge.sge.vaddr = NULL; + qp->s_rdma_sge.sge.length = 0; + qp->s_rdma_sge.sge.sge_length = 0; + } + break; + + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): + /* + * Check for the PSN of the last atomic operations + * performed and resend the result if found. + */ + if ((psn & IPS_PSN_MASK) != qp->r_atomic_psn) { + spin_unlock(&qp->s_lock); + goto done; + } + qp->s_ack_atomic = qp->r_atomic_data; + break; + } + qp->s_ack_state = opcode; + qp->s_nak_state = 0; + qp->s_ack_psn = psn; +resched: + return 0; + +done: + return 1; +} + +/** + * ipath_rc_rcv - process an incoming RC packet + * @dev: the device this packet came in on + * @hdr: the header of this packet + * @has_grh: true if the header has a GRH + * @data: the packet data + * @tlen: the packet length + * @qp: the QP for this packet + * + * This is called from ipath_qp_rcv() to process an incoming RC packet + * for the given QP. + * Called at interrupt level. + */ +void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, + int has_grh, void *data, u32 tlen, struct ipath_qp *qp) +{ + struct ipath_other_headers *ohdr; + u32 opcode; + u32 hdrsize; + u32 psn; + u32 pad; + unsigned long flags; + struct ib_wc wc; + u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); + int diff; + struct ib_reth *reth; + int header_in_data; + + /* Check for GRH */ + if (!has_grh) { + ohdr = &hdr->u.oth; + hdrsize = 8 + 12; /* LRH + BTH */ + psn = be32_to_cpu(ohdr->bth[2]); + header_in_data = 0; + } else { + ohdr = &hdr->u.l.oth; + hdrsize = 8 + 40 + 12; /* LRH + GRH + BTH */ + /* + * The header with GRH is 60 bytes and the core driver sets + * the eager header buffer size to 56 bytes so the last 4 + * bytes of the BTH header (PSN) is in the data buffer. + */ + header_in_data = + ipath_layer_get_rcvhdrentsize(dev->dd) == 16; + if (header_in_data) { + psn = be32_to_cpu(((__be32 *) data)[0]); + data += sizeof(__be32); + } else + psn = be32_to_cpu(ohdr->bth[2]); + } + /* + * The opcode is in the low byte when its in network order + * (top byte when in host order). + */ + opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + + /* + * Process responses (ACKs) before anything else. Note that the + * packet sequence number will be for something in the send work + * queue rather than the expected receive packet sequence number. + * In other words, this QP is the requester. + */ + if (opcode >= OP(RDMA_READ_RESPONSE_FIRST) && + opcode <= OP(ATOMIC_ACKNOWLEDGE)) { + ipath_rc_rcv_resp(dev, ohdr, data, tlen, qp, opcode, psn, + hdrsize, pmtu, header_in_data); + goto bail; + } + + spin_lock_irqsave(&qp->r_rq.lock, flags); + + /* Compute 24 bits worth of difference. */ + diff = ipath_cmp24(psn, qp->r_psn); + if (unlikely(diff)) { + if (ipath_rc_rcv_error(dev, ohdr, data, qp, opcode, + psn, diff, header_in_data)) + goto done; + goto resched; + } + + /* Check for opcode sequence errors. */ + switch (qp->r_state) { + case OP(SEND_FIRST): + case OP(SEND_MIDDLE): + if (opcode == OP(SEND_MIDDLE) || + opcode == OP(SEND_LAST) || + opcode == OP(SEND_LAST_WITH_IMMEDIATE)) + break; + nack_inv: + /* + * A NAK will ACK earlier sends and RDMA writes. Don't queue the + * NAK if a RDMA read, atomic, or NAK is pending though. + */ + spin_lock(&qp->s_lock); + if (qp->s_ack_state >= OP(RDMA_READ_REQUEST) && + qp->s_ack_state != IB_OPCODE_ACKNOWLEDGE) { + spin_unlock(&qp->s_lock); + goto done; + } + /* XXX Flush WQEs */ + qp->state = IB_QPS_ERR; + qp->s_ack_state = OP(SEND_ONLY); + qp->s_nak_state = IB_NAK_INVALID_REQUEST; + qp->s_ack_psn = qp->r_psn; + goto resched; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_MIDDLE): + if (opcode == OP(RDMA_WRITE_MIDDLE) || + opcode == OP(RDMA_WRITE_LAST) || + opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) + break; + goto nack_inv; + + case OP(RDMA_READ_REQUEST): + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): + /* + * Drop all new requests until a response has been sent. A + * new request then ACKs the RDMA response we sent. Relaxed + * ordering would allow new requests to be processed but we + * would need to keep a queue of rwqe's for all that are in + * progress. Note that we can't RNR NAK this request since + * the RDMA READ or atomic response is already queued to be + * sent (unless we implement a response send queue). + */ + goto done; + + default: + if (opcode == OP(SEND_MIDDLE) || + opcode == OP(SEND_LAST) || + opcode == OP(SEND_LAST_WITH_IMMEDIATE) || + opcode == OP(RDMA_WRITE_MIDDLE) || + opcode == OP(RDMA_WRITE_LAST) || + opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) + goto nack_inv; + break; + } + + wc.imm_data = 0; + wc.wc_flags = 0; + + /* OK, process the packet. */ + switch (opcode) { + case OP(SEND_FIRST): + if (!ipath_get_rwqe(qp, 0)) { + rnr_nak: + /* + * A RNR NAK will ACK earlier sends and RDMA writes. + * Don't queue the NAK if a RDMA read or atomic + * is pending though. + */ + spin_lock(&qp->s_lock); + if (qp->s_ack_state >= + OP(RDMA_READ_REQUEST) && + qp->s_ack_state != IB_OPCODE_ACKNOWLEDGE) { + spin_unlock(&qp->s_lock); + goto done; + } + qp->s_ack_state = OP(SEND_ONLY); + qp->s_nak_state = IB_RNR_NAK | qp->s_min_rnr_timer; + qp->s_ack_psn = qp->r_psn; + goto resched; + } + qp->r_rcv_len = 0; + /* FALLTHROUGH */ + case OP(SEND_MIDDLE): + case OP(RDMA_WRITE_MIDDLE): + send_middle: + /* Check for invalid length PMTU or posted rwqe len. */ + if (unlikely(tlen != (hdrsize + pmtu + 4))) + goto nack_inv; + qp->r_rcv_len += pmtu; + if (unlikely(qp->r_rcv_len > qp->r_len)) + goto nack_inv; + ipath_copy_sge(&qp->r_sge, data, pmtu); + break; + + case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): + /* consume RWQE */ + if (!ipath_get_rwqe(qp, 1)) + goto rnr_nak; + goto send_last_imm; + + case OP(SEND_ONLY): + case OP(SEND_ONLY_WITH_IMMEDIATE): + if (!ipath_get_rwqe(qp, 0)) + goto rnr_nak; + qp->r_rcv_len = 0; + if (opcode == OP(SEND_ONLY)) + goto send_last; + /* FALLTHROUGH */ + case OP(SEND_LAST_WITH_IMMEDIATE): + send_last_imm: + if (header_in_data) { + wc.imm_data = *(__be32 *) data; + data += sizeof(__be32); + } else { + /* Immediate data comes after BTH */ + wc.imm_data = ohdr->u.imm_data; + } + hdrsize += 4; + wc.wc_flags = IB_WC_WITH_IMM; + /* FALLTHROUGH */ + case OP(SEND_LAST): + case OP(RDMA_WRITE_LAST): + send_last: + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* Check for invalid length. */ + /* XXX LAST len should be >= 1 */ + if (unlikely(tlen < (hdrsize + pad + 4))) + goto nack_inv; + /* Don't count the CRC. */ + tlen -= (hdrsize + pad + 4); + wc.byte_len = tlen + qp->r_rcv_len; + if (unlikely(wc.byte_len > qp->r_len)) + goto nack_inv; + ipath_copy_sge(&qp->r_sge, data, tlen); + atomic_inc(&qp->msn); + if (opcode == OP(RDMA_WRITE_LAST) || + opcode == OP(RDMA_WRITE_ONLY)) + break; + wc.wr_id = qp->r_wr_id; + wc.status = IB_WC_SUCCESS; + wc.opcode = IB_WC_RECV; + wc.vendor_err = 0; + wc.qp_num = qp->ibqp.qp_num; + wc.src_qp = qp->remote_qpn; + wc.pkey_index = 0; + wc.slid = qp->remote_ah_attr.dlid; + wc.sl = qp->remote_ah_attr.sl; + wc.dlid_path_bits = 0; + wc.port_num = 0; + /* Signal completion event if the solicited bit is set. */ + ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + (ohdr->bth[0] & + __constant_cpu_to_be32(1 << 23)) != 0); + break; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_ONLY): + case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): + /* consume RWQE */ + /* RETH comes after BTH */ + if (!header_in_data) + reth = &ohdr->u.rc.reth; + else { + reth = (struct ib_reth *)data; + data += sizeof(*reth); + } + hdrsize += sizeof(*reth); + qp->r_len = be32_to_cpu(reth->length); + qp->r_rcv_len = 0; + if (qp->r_len != 0) { + u32 rkey = be32_to_cpu(reth->rkey); + u64 vaddr = be64_to_cpu(reth->vaddr); + int ok; + + /* Check rkey & NAK */ + ok = ipath_rkey_ok(dev, &qp->r_sge, + qp->r_len, vaddr, rkey, + IB_ACCESS_REMOTE_WRITE); + if (unlikely(!ok)) { + nack_acc: + /* + * A NAK will ACK earlier sends and RDMA + * writes. Don't queue the NAK if a RDMA + * read, atomic, or NAK is pending though. + */ + spin_lock(&qp->s_lock); + if (qp->s_ack_state >= + OP(RDMA_READ_REQUEST) && + qp->s_ack_state != + IB_OPCODE_ACKNOWLEDGE) { + spin_unlock(&qp->s_lock); + goto done; + } + /* XXX Flush WQEs */ + qp->state = IB_QPS_ERR; + qp->s_ack_state = OP(RDMA_WRITE_ONLY); + qp->s_nak_state = + IB_NAK_REMOTE_ACCESS_ERROR; + qp->s_ack_psn = qp->r_psn; + goto resched; + } + } else { + qp->r_sge.sg_list = NULL; + qp->r_sge.sge.mr = NULL; + qp->r_sge.sge.vaddr = NULL; + qp->r_sge.sge.length = 0; + qp->r_sge.sge.sge_length = 0; + } + if (unlikely(!(qp->qp_access_flags & + IB_ACCESS_REMOTE_WRITE))) + goto nack_acc; + if (opcode == OP(RDMA_WRITE_FIRST)) + goto send_middle; + else if (opcode == OP(RDMA_WRITE_ONLY)) + goto send_last; + if (!ipath_get_rwqe(qp, 1)) + goto rnr_nak; + goto send_last_imm; + + case OP(RDMA_READ_REQUEST): + /* RETH comes after BTH */ + if (!header_in_data) + reth = &ohdr->u.rc.reth; + else { + reth = (struct ib_reth *)data; + data += sizeof(*reth); + } + spin_lock(&qp->s_lock); + if (qp->s_ack_state != OP(ACKNOWLEDGE) && + qp->s_ack_state >= IB_OPCODE_RDMA_READ_REQUEST) { + spin_unlock(&qp->s_lock); + goto done; + } + qp->s_rdma_len = be32_to_cpu(reth->length); + if (qp->s_rdma_len != 0) { + u32 rkey = be32_to_cpu(reth->rkey); + u64 vaddr = be64_to_cpu(reth->vaddr); + int ok; + + /* Check rkey & NAK */ + ok = ipath_rkey_ok(dev, &qp->s_rdma_sge, + qp->s_rdma_len, vaddr, rkey, + IB_ACCESS_REMOTE_READ); + if (unlikely(!ok)) { + spin_unlock(&qp->s_lock); + goto nack_acc; + } + /* + * Update the next expected PSN. We add 1 later + * below, so only add the remainder here. + */ + if (qp->s_rdma_len > pmtu) + qp->r_psn += (qp->s_rdma_len - 1) / pmtu; + } else { + qp->s_rdma_sge.sg_list = NULL; + qp->s_rdma_sge.num_sge = 0; + qp->s_rdma_sge.sge.mr = NULL; + qp->s_rdma_sge.sge.vaddr = NULL; + qp->s_rdma_sge.sge.length = 0; + qp->s_rdma_sge.sge.sge_length = 0; + } + if (unlikely(!(qp->qp_access_flags & + IB_ACCESS_REMOTE_READ))) + goto nack_acc; + /* + * We need to increment the MSN here instead of when we + * finish sending the result since a duplicate request would + * increment it more than once. + */ + atomic_inc(&qp->msn); + qp->s_ack_state = opcode; + qp->s_nak_state = 0; + qp->s_ack_psn = psn; + qp->r_psn++; + qp->r_state = opcode; + goto rdmadone; + + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): { + struct ib_atomic_eth *ateth; + u64 vaddr; + u64 sdata; + u32 rkey; + + if (!header_in_data) + ateth = &ohdr->u.atomic_eth; + else { + ateth = (struct ib_atomic_eth *)data; + data += sizeof(*ateth); + } + vaddr = be64_to_cpu(ateth->vaddr); + if (unlikely(vaddr & (sizeof(u64) - 1))) + goto nack_inv; + rkey = be32_to_cpu(ateth->rkey); + /* Check rkey & NAK */ + if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, + sizeof(u64), vaddr, rkey, + IB_ACCESS_REMOTE_ATOMIC))) + goto nack_acc; + if (unlikely(!(qp->qp_access_flags & + IB_ACCESS_REMOTE_ATOMIC))) + goto nack_acc; + /* Perform atomic OP and save result. */ + sdata = be64_to_cpu(ateth->swap_data); + spin_lock(&dev->pending_lock); + qp->r_atomic_data = *(u64 *) qp->r_sge.sge.vaddr; + if (opcode == OP(FETCH_ADD)) + *(u64 *) qp->r_sge.sge.vaddr = + qp->r_atomic_data + sdata; + else if (qp->r_atomic_data == + be64_to_cpu(ateth->compare_data)) + *(u64 *) qp->r_sge.sge.vaddr = sdata; + spin_unlock(&dev->pending_lock); + atomic_inc(&qp->msn); + qp->r_atomic_psn = psn & IPS_PSN_MASK; + psn |= 1 << 31; + break; + } + + default: + /* Drop packet for unknown opcodes. */ + goto done; + } + qp->r_psn++; + qp->r_state = opcode; + /* Send an ACK if requested or required. */ + if (psn & (1 << 31)) { + /* + * Coalesce ACKs unless there is a RDMA READ or + * ATOMIC pending. + */ + spin_lock(&qp->s_lock); + if (qp->s_ack_state == OP(ACKNOWLEDGE) || + qp->s_ack_state < IB_OPCODE_RDMA_READ_REQUEST) { + qp->s_ack_state = opcode; + qp->s_nak_state = 0; + qp->s_ack_psn = psn; + qp->s_ack_atomic = qp->r_atomic_data; + goto resched; + } + spin_unlock(&qp->s_lock); + } +done: + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + goto bail; + +resched: + /* + * Try to send ACK right away but not if ipath_do_rc_send() is + * active. + */ + if (qp->s_hdrwords == 0 && + (qp->s_ack_state < IB_OPCODE_RDMA_READ_REQUEST || + qp->s_ack_state >= IB_OPCODE_COMPARE_SWAP)) + send_rc_ack(qp); + +rdmadone: + spin_unlock(&qp->s_lock); + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + + /* Call ipath_do_rc_send() in another thread. */ + tasklet_hi_schedule(&qp->s_task); + +bail: + return; +} diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h new file mode 100644 index 000000000000..1e59750c5f63 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_registers.h @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _IPATH_REGISTERS_H +#define _IPATH_REGISTERS_H + +/* + * This file should only be included by kernel source, and by the diags. + * It defines the registers, and their contents, for the InfiniPath HT-400 chip + */ + +/* + * These are the InfiniPath register and buffer bit definitions, + * that are visible to software, and needed only by the kernel + * and diag code. A few, that are visible to protocol and user + * code are in ipath_common.h. Some bits are specific + * to a given chip implementation, and have been moved to the + * chip-specific source file + */ + +/* kr_revision bits */ +#define INFINIPATH_R_CHIPREVMINOR_MASK 0xFF +#define INFINIPATH_R_CHIPREVMINOR_SHIFT 0 +#define INFINIPATH_R_CHIPREVMAJOR_MASK 0xFF +#define INFINIPATH_R_CHIPREVMAJOR_SHIFT 8 +#define INFINIPATH_R_ARCH_MASK 0xFF +#define INFINIPATH_R_ARCH_SHIFT 16 +#define INFINIPATH_R_SOFTWARE_MASK 0xFF +#define INFINIPATH_R_SOFTWARE_SHIFT 24 +#define INFINIPATH_R_BOARDID_MASK 0xFF +#define INFINIPATH_R_BOARDID_SHIFT 32 + +/* kr_control bits */ +#define INFINIPATH_C_FREEZEMODE 0x00000002 +#define INFINIPATH_C_LINKENABLE 0x00000004 +#define INFINIPATH_C_RESET 0x00000001 + +/* kr_sendctrl bits */ +#define INFINIPATH_S_DISARMPIOBUF_SHIFT 16 + +#define IPATH_S_ABORT 0 +#define IPATH_S_PIOINTBUFAVAIL 1 +#define IPATH_S_PIOBUFAVAILUPD 2 +#define IPATH_S_PIOENABLE 3 +#define IPATH_S_DISARM 31 + +#define INFINIPATH_S_ABORT (1U << IPATH_S_ABORT) +#define INFINIPATH_S_PIOINTBUFAVAIL (1U << IPATH_S_PIOINTBUFAVAIL) +#define INFINIPATH_S_PIOBUFAVAILUPD (1U << IPATH_S_PIOBUFAVAILUPD) +#define INFINIPATH_S_PIOENABLE (1U << IPATH_S_PIOENABLE) +#define INFINIPATH_S_DISARM (1U << IPATH_S_DISARM) + +/* kr_rcvctrl bits */ +#define INFINIPATH_R_PORTENABLE_SHIFT 0 +#define INFINIPATH_R_INTRAVAIL_SHIFT 16 +#define INFINIPATH_R_TAILUPD 0x80000000 + +/* kr_intstatus, kr_intclear, kr_intmask bits */ +#define INFINIPATH_I_RCVURG_SHIFT 0 +#define INFINIPATH_I_RCVAVAIL_SHIFT 12 +#define INFINIPATH_I_ERROR 0x80000000 +#define INFINIPATH_I_SPIOSENT 0x40000000 +#define INFINIPATH_I_SPIOBUFAVAIL 0x20000000 +#define INFINIPATH_I_GPIO 0x10000000 + +/* kr_errorstatus, kr_errorclear, kr_errormask bits */ +#define INFINIPATH_E_RFORMATERR 0x0000000000000001ULL +#define INFINIPATH_E_RVCRC 0x0000000000000002ULL +#define INFINIPATH_E_RICRC 0x0000000000000004ULL +#define INFINIPATH_E_RMINPKTLEN 0x0000000000000008ULL +#define INFINIPATH_E_RMAXPKTLEN 0x0000000000000010ULL +#define INFINIPATH_E_RLONGPKTLEN 0x0000000000000020ULL +#define INFINIPATH_E_RSHORTPKTLEN 0x0000000000000040ULL +#define INFINIPATH_E_RUNEXPCHAR 0x0000000000000080ULL +#define INFINIPATH_E_RUNSUPVL 0x0000000000000100ULL +#define INFINIPATH_E_REBP 0x0000000000000200ULL +#define INFINIPATH_E_RIBFLOW 0x0000000000000400ULL +#define INFINIPATH_E_RBADVERSION 0x0000000000000800ULL +#define INFINIPATH_E_RRCVEGRFULL 0x0000000000001000ULL +#define INFINIPATH_E_RRCVHDRFULL 0x0000000000002000ULL +#define INFINIPATH_E_RBADTID 0x0000000000004000ULL +#define INFINIPATH_E_RHDRLEN 0x0000000000008000ULL +#define INFINIPATH_E_RHDR 0x0000000000010000ULL +#define INFINIPATH_E_RIBLOSTLINK 0x0000000000020000ULL +#define INFINIPATH_E_SMINPKTLEN 0x0000000020000000ULL +#define INFINIPATH_E_SMAXPKTLEN 0x0000000040000000ULL +#define INFINIPATH_E_SUNDERRUN 0x0000000080000000ULL +#define INFINIPATH_E_SPKTLEN 0x0000000100000000ULL +#define INFINIPATH_E_SDROPPEDSMPPKT 0x0000000200000000ULL +#define INFINIPATH_E_SDROPPEDDATAPKT 0x0000000400000000ULL +#define INFINIPATH_E_SPIOARMLAUNCH 0x0000000800000000ULL +#define INFINIPATH_E_SUNEXPERRPKTNUM 0x0000001000000000ULL +#define INFINIPATH_E_SUNSUPVL 0x0000002000000000ULL +#define INFINIPATH_E_IBSTATUSCHANGED 0x0001000000000000ULL +#define INFINIPATH_E_INVALIDADDR 0x0002000000000000ULL +#define INFINIPATH_E_RESET 0x0004000000000000ULL +#define INFINIPATH_E_HARDWARE 0x0008000000000000ULL + +/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */ +/* TXEMEMPARITYERR bit 0: PIObuf, 1: PIOpbc, 2: launchfifo + * RXEMEMPARITYERR bit 0: rcvbuf, 1: lookupq, 2: eagerTID, 3: expTID + * bit 4: flag buffer, 5: datainfo, 6: header info */ +#define INFINIPATH_HWE_TXEMEMPARITYERR_MASK 0xFULL +#define INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT 40 +#define INFINIPATH_HWE_RXEMEMPARITYERR_MASK 0x7FULL +#define INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT 44 +#define INFINIPATH_HWE_RXDSYNCMEMPARITYERR 0x0000000400000000ULL +#define INFINIPATH_HWE_MEMBISTFAILED 0x0040000000000000ULL +#define INFINIPATH_HWE_IBCBUSTOSPCPARITYERR 0x4000000000000000ULL +#define INFINIPATH_HWE_IBCBUSFRSPCPARITYERR 0x8000000000000000ULL + +/* kr_hwdiagctrl bits */ +#define INFINIPATH_DC_FORCETXEMEMPARITYERR_MASK 0xFULL +#define INFINIPATH_DC_FORCETXEMEMPARITYERR_SHIFT 40 +#define INFINIPATH_DC_FORCERXEMEMPARITYERR_MASK 0x7FULL +#define INFINIPATH_DC_FORCERXEMEMPARITYERR_SHIFT 44 +#define INFINIPATH_DC_FORCERXDSYNCMEMPARITYERR 0x0000000400000000ULL +#define INFINIPATH_DC_COUNTERDISABLE 0x1000000000000000ULL +#define INFINIPATH_DC_COUNTERWREN 0x2000000000000000ULL +#define INFINIPATH_DC_FORCEIBCBUSTOSPCPARITYERR 0x4000000000000000ULL +#define INFINIPATH_DC_FORCEIBCBUSFRSPCPARITYERR 0x8000000000000000ULL + +/* kr_ibcctrl bits */ +#define INFINIPATH_IBCC_FLOWCTRLPERIOD_MASK 0xFFULL +#define INFINIPATH_IBCC_FLOWCTRLPERIOD_SHIFT 0 +#define INFINIPATH_IBCC_FLOWCTRLWATERMARK_MASK 0xFFULL +#define INFINIPATH_IBCC_FLOWCTRLWATERMARK_SHIFT 8 +#define INFINIPATH_IBCC_LINKINITCMD_MASK 0x3ULL +#define INFINIPATH_IBCC_LINKINITCMD_DISABLE 1 +#define INFINIPATH_IBCC_LINKINITCMD_POLL 2 /* cycle through TS1/TS2 till OK */ +#define INFINIPATH_IBCC_LINKINITCMD_SLEEP 3 /* wait for TS1, then go on */ +#define INFINIPATH_IBCC_LINKINITCMD_SHIFT 16 +#define INFINIPATH_IBCC_LINKCMD_MASK 0x3ULL +#define INFINIPATH_IBCC_LINKCMD_INIT 1 /* move to 0x11 */ +#define INFINIPATH_IBCC_LINKCMD_ARMED 2 /* move to 0x21 */ +#define INFINIPATH_IBCC_LINKCMD_ACTIVE 3 /* move to 0x31 */ +#define INFINIPATH_IBCC_LINKCMD_SHIFT 18 +#define INFINIPATH_IBCC_MAXPKTLEN_MASK 0x7FFULL +#define INFINIPATH_IBCC_MAXPKTLEN_SHIFT 20 +#define INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK 0xFULL +#define INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT 32 +#define INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK 0xFULL +#define INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT 36 +#define INFINIPATH_IBCC_CREDITSCALE_MASK 0x7ULL +#define INFINIPATH_IBCC_CREDITSCALE_SHIFT 40 +#define INFINIPATH_IBCC_LOOPBACK 0x8000000000000000ULL +#define INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE 0x4000000000000000ULL + +/* kr_ibcstatus bits */ +#define INFINIPATH_IBCS_LINKTRAININGSTATE_MASK 0xF +#define INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT 0 +#define INFINIPATH_IBCS_LINKSTATE_MASK 0x7 +#define INFINIPATH_IBCS_LINKSTATE_SHIFT 4 +#define INFINIPATH_IBCS_TXREADY 0x40000000 +#define INFINIPATH_IBCS_TXCREDITOK 0x80000000 +/* link training states (shift by INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) */ +#define INFINIPATH_IBCS_LT_STATE_DISABLED 0x00 +#define INFINIPATH_IBCS_LT_STATE_LINKUP 0x01 +#define INFINIPATH_IBCS_LT_STATE_POLLACTIVE 0x02 +#define INFINIPATH_IBCS_LT_STATE_POLLQUIET 0x03 +#define INFINIPATH_IBCS_LT_STATE_SLEEPDELAY 0x04 +#define INFINIPATH_IBCS_LT_STATE_SLEEPQUIET 0x05 +#define INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE 0x08 +#define INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG 0x09 +#define INFINIPATH_IBCS_LT_STATE_CFGWAITRMT 0x0a +#define INFINIPATH_IBCS_LT_STATE_CFGIDLE 0x0b +#define INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN 0x0c +#define INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT 0x0e +#define INFINIPATH_IBCS_LT_STATE_RECOVERIDLE 0x0f +/* link state machine states (shift by INFINIPATH_IBCS_LINKSTATE_SHIFT) */ +#define INFINIPATH_IBCS_L_STATE_DOWN 0x0 +#define INFINIPATH_IBCS_L_STATE_INIT 0x1 +#define INFINIPATH_IBCS_L_STATE_ARM 0x2 +#define INFINIPATH_IBCS_L_STATE_ACTIVE 0x3 +#define INFINIPATH_IBCS_L_STATE_ACT_DEFER 0x4 + +/* combination link status states that we use with some frequency */ +#define IPATH_IBSTATE_MASK ((INFINIPATH_IBCS_LINKTRAININGSTATE_MASK \ + << INFINIPATH_IBCS_LINKSTATE_SHIFT) | \ + (INFINIPATH_IBCS_LINKSTATE_MASK \ + <ibqp.device); + unsigned long flags; + + spin_lock_irqsave(&dev->pending_lock, flags); + if (list_empty(&dev->rnrwait)) + list_add(&qp->timerwait, &dev->rnrwait); + else { + struct list_head *l = &dev->rnrwait; + struct ipath_qp *nqp = list_entry(l->next, struct ipath_qp, + timerwait); + + while (qp->s_rnr_timeout >= nqp->s_rnr_timeout) { + qp->s_rnr_timeout -= nqp->s_rnr_timeout; + l = l->next; + if (l->next == &dev->rnrwait) + break; + nqp = list_entry(l->next, struct ipath_qp, + timerwait); + } + list_add(&qp->timerwait, l); + } + spin_unlock_irqrestore(&dev->pending_lock, flags); +} + +/** + * ipath_get_rwqe - copy the next RWQE into the QP's RWQE + * @qp: the QP + * @wr_id_only: update wr_id only, not SGEs + * + * Return 0 if no RWQE is available, otherwise return 1. + * + * Called at interrupt level with the QP r_rq.lock held. + */ +int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only) +{ + struct ipath_rq *rq; + struct ipath_srq *srq; + struct ipath_rwqe *wqe; + int ret; + + if (!qp->ibqp.srq) { + rq = &qp->r_rq; + if (unlikely(rq->tail == rq->head)) { + ret = 0; + goto bail; + } + wqe = get_rwqe_ptr(rq, rq->tail); + qp->r_wr_id = wqe->wr_id; + if (!wr_id_only) { + qp->r_sge.sge = wqe->sg_list[0]; + qp->r_sge.sg_list = wqe->sg_list + 1; + qp->r_sge.num_sge = wqe->num_sge; + qp->r_len = wqe->length; + } + if (++rq->tail >= rq->size) + rq->tail = 0; + ret = 1; + goto bail; + } + + srq = to_isrq(qp->ibqp.srq); + rq = &srq->rq; + spin_lock(&rq->lock); + if (unlikely(rq->tail == rq->head)) { + spin_unlock(&rq->lock); + ret = 0; + goto bail; + } + wqe = get_rwqe_ptr(rq, rq->tail); + qp->r_wr_id = wqe->wr_id; + if (!wr_id_only) { + qp->r_sge.sge = wqe->sg_list[0]; + qp->r_sge.sg_list = wqe->sg_list + 1; + qp->r_sge.num_sge = wqe->num_sge; + qp->r_len = wqe->length; + } + if (++rq->tail >= rq->size) + rq->tail = 0; + if (srq->ibsrq.event_handler) { + struct ib_event ev; + u32 n; + + if (rq->head < rq->tail) + n = rq->size + rq->head - rq->tail; + else + n = rq->head - rq->tail; + if (n < srq->limit) { + srq->limit = 0; + spin_unlock(&rq->lock); + ev.device = qp->ibqp.device; + ev.element.srq = qp->ibqp.srq; + ev.event = IB_EVENT_SRQ_LIMIT_REACHED; + srq->ibsrq.event_handler(&ev, + srq->ibsrq.srq_context); + } else + spin_unlock(&rq->lock); + } else + spin_unlock(&rq->lock); + ret = 1; + +bail: + return ret; +} + +/** + * ipath_ruc_loopback - handle UC and RC lookback requests + * @sqp: the loopback QP + * @wc: the work completion entry + * + * This is called from ipath_do_uc_send() or ipath_do_rc_send() to + * forward a WQE addressed to the same HCA. + * Note that although we are single threaded due to the tasklet, we still + * have to protect against post_send(). We don't have to worry about + * receive interrupts since this is a connected protocol and all packets + * will pass through here. + */ +void ipath_ruc_loopback(struct ipath_qp *sqp, struct ib_wc *wc) +{ + struct ipath_ibdev *dev = to_idev(sqp->ibqp.device); + struct ipath_qp *qp; + struct ipath_swqe *wqe; + struct ipath_sge *sge; + unsigned long flags; + u64 sdata; + + qp = ipath_lookup_qpn(&dev->qp_table, sqp->remote_qpn); + if (!qp) { + dev->n_pkt_drops++; + return; + } + +again: + spin_lock_irqsave(&sqp->s_lock, flags); + + if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_SEND_OK)) { + spin_unlock_irqrestore(&sqp->s_lock, flags); + goto done; + } + + /* Get the next send request. */ + if (sqp->s_last == sqp->s_head) { + /* Send work queue is empty. */ + spin_unlock_irqrestore(&sqp->s_lock, flags); + goto done; + } + + /* + * We can rely on the entry not changing without the s_lock + * being held until we update s_last. + */ + wqe = get_swqe_ptr(sqp, sqp->s_last); + spin_unlock_irqrestore(&sqp->s_lock, flags); + + wc->wc_flags = 0; + wc->imm_data = 0; + + sqp->s_sge.sge = wqe->sg_list[0]; + sqp->s_sge.sg_list = wqe->sg_list + 1; + sqp->s_sge.num_sge = wqe->wr.num_sge; + sqp->s_len = wqe->length; + switch (wqe->wr.opcode) { + case IB_WR_SEND_WITH_IMM: + wc->wc_flags = IB_WC_WITH_IMM; + wc->imm_data = wqe->wr.imm_data; + /* FALLTHROUGH */ + case IB_WR_SEND: + spin_lock_irqsave(&qp->r_rq.lock, flags); + if (!ipath_get_rwqe(qp, 0)) { + rnr_nak: + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + /* Handle RNR NAK */ + if (qp->ibqp.qp_type == IB_QPT_UC) + goto send_comp; + if (sqp->s_rnr_retry == 0) { + wc->status = IB_WC_RNR_RETRY_EXC_ERR; + goto err; + } + if (sqp->s_rnr_retry_cnt < 7) + sqp->s_rnr_retry--; + dev->n_rnr_naks++; + sqp->s_rnr_timeout = + ib_ipath_rnr_table[sqp->s_min_rnr_timer]; + ipath_insert_rnr_queue(sqp); + goto done; + } + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + break; + + case IB_WR_RDMA_WRITE_WITH_IMM: + wc->wc_flags = IB_WC_WITH_IMM; + wc->imm_data = wqe->wr.imm_data; + spin_lock_irqsave(&qp->r_rq.lock, flags); + if (!ipath_get_rwqe(qp, 1)) + goto rnr_nak; + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + /* FALLTHROUGH */ + case IB_WR_RDMA_WRITE: + if (wqe->length == 0) + break; + if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, wqe->length, + wqe->wr.wr.rdma.remote_addr, + wqe->wr.wr.rdma.rkey, + IB_ACCESS_REMOTE_WRITE))) { + acc_err: + wc->status = IB_WC_REM_ACCESS_ERR; + err: + wc->wr_id = wqe->wr.wr_id; + wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + wc->vendor_err = 0; + wc->byte_len = 0; + wc->qp_num = sqp->ibqp.qp_num; + wc->src_qp = sqp->remote_qpn; + wc->pkey_index = 0; + wc->slid = sqp->remote_ah_attr.dlid; + wc->sl = sqp->remote_ah_attr.sl; + wc->dlid_path_bits = 0; + wc->port_num = 0; + ipath_sqerror_qp(sqp, wc); + goto done; + } + break; + + case IB_WR_RDMA_READ: + if (unlikely(!ipath_rkey_ok(dev, &sqp->s_sge, wqe->length, + wqe->wr.wr.rdma.remote_addr, + wqe->wr.wr.rdma.rkey, + IB_ACCESS_REMOTE_READ))) + goto acc_err; + if (unlikely(!(qp->qp_access_flags & + IB_ACCESS_REMOTE_READ))) + goto acc_err; + qp->r_sge.sge = wqe->sg_list[0]; + qp->r_sge.sg_list = wqe->sg_list + 1; + qp->r_sge.num_sge = wqe->wr.num_sge; + break; + + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, sizeof(u64), + wqe->wr.wr.rdma.remote_addr, + wqe->wr.wr.rdma.rkey, + IB_ACCESS_REMOTE_ATOMIC))) + goto acc_err; + /* Perform atomic OP and save result. */ + sdata = wqe->wr.wr.atomic.swap; + spin_lock_irqsave(&dev->pending_lock, flags); + qp->r_atomic_data = *(u64 *) qp->r_sge.sge.vaddr; + if (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) + *(u64 *) qp->r_sge.sge.vaddr = + qp->r_atomic_data + sdata; + else if (qp->r_atomic_data == wqe->wr.wr.atomic.compare_add) + *(u64 *) qp->r_sge.sge.vaddr = sdata; + spin_unlock_irqrestore(&dev->pending_lock, flags); + *(u64 *) sqp->s_sge.sge.vaddr = qp->r_atomic_data; + goto send_comp; + + default: + goto done; + } + + sge = &sqp->s_sge.sge; + while (sqp->s_len) { + u32 len = sqp->s_len; + + if (len > sge->length) + len = sge->length; + BUG_ON(len == 0); + ipath_copy_sge(&qp->r_sge, sge->vaddr, len); + sge->vaddr += len; + sge->length -= len; + sge->sge_length -= len; + if (sge->sge_length == 0) { + if (--sqp->s_sge.num_sge) + *sge = *sqp->s_sge.sg_list++; + } else if (sge->length == 0 && sge->mr != NULL) { + if (++sge->n >= IPATH_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + break; + sge->n = 0; + } + sge->vaddr = + sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = + sge->mr->map[sge->m]->segs[sge->n].length; + } + sqp->s_len -= len; + } + + if (wqe->wr.opcode == IB_WR_RDMA_WRITE || + wqe->wr.opcode == IB_WR_RDMA_READ) + goto send_comp; + + if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM) + wc->opcode = IB_WC_RECV_RDMA_WITH_IMM; + else + wc->opcode = IB_WC_RECV; + wc->wr_id = qp->r_wr_id; + wc->status = IB_WC_SUCCESS; + wc->vendor_err = 0; + wc->byte_len = wqe->length; + wc->qp_num = qp->ibqp.qp_num; + wc->src_qp = qp->remote_qpn; + /* XXX do we know which pkey matched? Only needed for GSI. */ + wc->pkey_index = 0; + wc->slid = qp->remote_ah_attr.dlid; + wc->sl = qp->remote_ah_attr.sl; + wc->dlid_path_bits = 0; + /* Signal completion event if the solicited bit is set. */ + ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc, + wqe->wr.send_flags & IB_SEND_SOLICITED); + +send_comp: + sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; + + if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &sqp->s_flags) || + (wqe->wr.send_flags & IB_SEND_SIGNALED)) { + wc->wr_id = wqe->wr.wr_id; + wc->status = IB_WC_SUCCESS; + wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + wc->vendor_err = 0; + wc->byte_len = wqe->length; + wc->qp_num = sqp->ibqp.qp_num; + wc->src_qp = 0; + wc->pkey_index = 0; + wc->slid = 0; + wc->sl = 0; + wc->dlid_path_bits = 0; + wc->port_num = 0; + ipath_cq_enter(to_icq(sqp->ibqp.send_cq), wc, 0); + } + + /* Update s_last now that we are finished with the SWQE */ + spin_lock_irqsave(&sqp->s_lock, flags); + if (++sqp->s_last >= sqp->s_size) + sqp->s_last = 0; + spin_unlock_irqrestore(&sqp->s_lock, flags); + goto again; + +done: + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); +} + +/** + * ipath_no_bufs_available - tell the layer driver we need buffers + * @qp: the QP that caused the problem + * @dev: the device we ran out of buffers on + * + * Called when we run out of PIO buffers. + */ +void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->pending_lock, flags); + if (qp->piowait.next == LIST_POISON1) + list_add_tail(&qp->piowait, &dev->piowait); + spin_unlock_irqrestore(&dev->pending_lock, flags); + /* + * Note that as soon as ipath_layer_want_buffer() is called and + * possibly before it returns, ipath_ib_piobufavail() + * could be called. If we are still in the tasklet function, + * tasklet_hi_schedule() will not call us until the next time + * tasklet_hi_schedule() is called. + * We clear the tasklet flag now since we are committing to return + * from the tasklet function. + */ + clear_bit(IPATH_S_BUSY, &qp->s_flags); + tasklet_unlock(&qp->s_task); + ipath_layer_want_buffer(dev->dd); + dev->n_piowait++; +} + +/** + * ipath_post_rc_send - post RC and UC sends + * @qp: the QP to post on + * @wr: the work request to send + */ +int ipath_post_rc_send(struct ipath_qp *qp, struct ib_send_wr *wr) +{ + struct ipath_swqe *wqe; + unsigned long flags; + u32 next; + int i, j; + int acc; + int ret; + + /* + * Don't allow RDMA reads or atomic operations on UC or + * undefined operations. + * Make sure buffer is large enough to hold the result for atomics. + */ + if (qp->ibqp.qp_type == IB_QPT_UC) { + if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) { + ret = -EINVAL; + goto bail; + } + } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) { + ret = -EINVAL; + goto bail; + } else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP && + (wr->num_sge == 0 || + wr->sg_list[0].length < sizeof(u64) || + wr->sg_list[0].addr & (sizeof(u64) - 1))) { + ret = -EINVAL; + goto bail; + } + /* IB spec says that num_sge == 0 is OK. */ + if (wr->num_sge > qp->s_max_sge) { + ret = -ENOMEM; + goto bail; + } + spin_lock_irqsave(&qp->s_lock, flags); + next = qp->s_head + 1; + if (next >= qp->s_size) + next = 0; + if (next == qp->s_last) { + spin_unlock_irqrestore(&qp->s_lock, flags); + ret = -EINVAL; + goto bail; + } + + wqe = get_swqe_ptr(qp, qp->s_head); + wqe->wr = *wr; + wqe->ssn = qp->s_ssn++; + wqe->sg_list[0].mr = NULL; + wqe->sg_list[0].vaddr = NULL; + wqe->sg_list[0].length = 0; + wqe->sg_list[0].sge_length = 0; + wqe->length = 0; + acc = wr->opcode >= IB_WR_RDMA_READ ? IB_ACCESS_LOCAL_WRITE : 0; + for (i = 0, j = 0; i < wr->num_sge; i++) { + if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) { + spin_unlock_irqrestore(&qp->s_lock, flags); + ret = -EINVAL; + goto bail; + } + if (wr->sg_list[i].length == 0) + continue; + if (!ipath_lkey_ok(&to_idev(qp->ibqp.device)->lk_table, + &wqe->sg_list[j], &wr->sg_list[i], + acc)) { + spin_unlock_irqrestore(&qp->s_lock, flags); + ret = -EINVAL; + goto bail; + } + wqe->length += wr->sg_list[i].length; + j++; + } + wqe->wr.num_sge = j; + qp->s_head = next; + /* + * Wake up the send tasklet if the QP is not waiting + * for an RNR timeout. + */ + next = qp->s_rnr_timeout; + spin_unlock_irqrestore(&qp->s_lock, flags); + + if (next == 0) { + if (qp->ibqp.qp_type == IB_QPT_UC) + ipath_do_uc_send((unsigned long) qp); + else + ipath_do_rc_send((unsigned long) qp); + } + + ret = 0; + +bail: + return ret; +} diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c new file mode 100644 index 000000000000..01c4c6c56118 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_srq.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "ipath_verbs.h" + +/** + * ipath_post_srq_receive - post a receive on a shared receive queue + * @ibsrq: the SRQ to post the receive on + * @wr: the list of work requests to post + * @bad_wr: the first WR to cause a problem is put here + * + * This may be called from interrupt context. + */ +int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct ipath_srq *srq = to_isrq(ibsrq); + struct ipath_ibdev *dev = to_idev(ibsrq->device); + unsigned long flags; + int ret; + + for (; wr; wr = wr->next) { + struct ipath_rwqe *wqe; + u32 next; + int i, j; + + if (wr->num_sge > srq->rq.max_sge) { + *bad_wr = wr; + ret = -ENOMEM; + goto bail; + } + + spin_lock_irqsave(&srq->rq.lock, flags); + next = srq->rq.head + 1; + if (next >= srq->rq.size) + next = 0; + if (next == srq->rq.tail) { + spin_unlock_irqrestore(&srq->rq.lock, flags); + *bad_wr = wr; + ret = -ENOMEM; + goto bail; + } + + wqe = get_rwqe_ptr(&srq->rq, srq->rq.head); + wqe->wr_id = wr->wr_id; + wqe->sg_list[0].mr = NULL; + wqe->sg_list[0].vaddr = NULL; + wqe->sg_list[0].length = 0; + wqe->sg_list[0].sge_length = 0; + wqe->length = 0; + for (i = 0, j = 0; i < wr->num_sge; i++) { + /* Check LKEY */ + if (to_ipd(srq->ibsrq.pd)->user && + wr->sg_list[i].lkey == 0) { + spin_unlock_irqrestore(&srq->rq.lock, + flags); + *bad_wr = wr; + ret = -EINVAL; + goto bail; + } + if (wr->sg_list[i].length == 0) + continue; + if (!ipath_lkey_ok(&dev->lk_table, + &wqe->sg_list[j], + &wr->sg_list[i], + IB_ACCESS_LOCAL_WRITE)) { + spin_unlock_irqrestore(&srq->rq.lock, + flags); + *bad_wr = wr; + ret = -EINVAL; + goto bail; + } + wqe->length += wr->sg_list[i].length; + j++; + } + wqe->num_sge = j; + srq->rq.head = next; + spin_unlock_irqrestore(&srq->rq.lock, flags); + } + ret = 0; + +bail: + return ret; +} + +/** + * ipath_create_srq - create a shared receive queue + * @ibpd: the protection domain of the SRQ to create + * @attr: the attributes of the SRQ + * @udata: not used by the InfiniPath verbs driver + */ +struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_udata *udata) +{ + struct ipath_srq *srq; + u32 sz; + struct ib_srq *ret; + + if (srq_init_attr->attr.max_sge < 1) { + ret = ERR_PTR(-EINVAL); + goto bail; + } + + srq = kmalloc(sizeof(*srq), GFP_KERNEL); + if (!srq) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + /* + * Need to use vmalloc() if we want to support large #s of entries. + */ + srq->rq.size = srq_init_attr->attr.max_wr + 1; + sz = sizeof(struct ipath_sge) * srq_init_attr->attr.max_sge + + sizeof(struct ipath_rwqe); + srq->rq.wq = vmalloc(srq->rq.size * sz); + if (!srq->rq.wq) { + kfree(srq); + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + /* + * ib_create_srq() will initialize srq->ibsrq. + */ + spin_lock_init(&srq->rq.lock); + srq->rq.head = 0; + srq->rq.tail = 0; + srq->rq.max_sge = srq_init_attr->attr.max_sge; + srq->limit = srq_init_attr->attr.srq_limit; + + ret = &srq->ibsrq; + +bail: + return ret; +} + +/** + * ipath_modify_srq - modify a shared receive queue + * @ibsrq: the SRQ to modify + * @attr: the new attributes of the SRQ + * @attr_mask: indicates which attributes to modify + */ +int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask) +{ + struct ipath_srq *srq = to_isrq(ibsrq); + unsigned long flags; + int ret; + + if (attr_mask & IB_SRQ_LIMIT) { + spin_lock_irqsave(&srq->rq.lock, flags); + srq->limit = attr->srq_limit; + spin_unlock_irqrestore(&srq->rq.lock, flags); + } + if (attr_mask & IB_SRQ_MAX_WR) { + u32 size = attr->max_wr + 1; + struct ipath_rwqe *wq, *p; + u32 n; + u32 sz; + + if (attr->max_sge < srq->rq.max_sge) { + ret = -EINVAL; + goto bail; + } + + sz = sizeof(struct ipath_rwqe) + + attr->max_sge * sizeof(struct ipath_sge); + wq = vmalloc(size * sz); + if (!wq) { + ret = -ENOMEM; + goto bail; + } + + spin_lock_irqsave(&srq->rq.lock, flags); + if (srq->rq.head < srq->rq.tail) + n = srq->rq.size + srq->rq.head - srq->rq.tail; + else + n = srq->rq.head - srq->rq.tail; + if (size <= n || size <= srq->limit) { + spin_unlock_irqrestore(&srq->rq.lock, flags); + vfree(wq); + ret = -EINVAL; + goto bail; + } + n = 0; + p = wq; + while (srq->rq.tail != srq->rq.head) { + struct ipath_rwqe *wqe; + int i; + + wqe = get_rwqe_ptr(&srq->rq, srq->rq.tail); + p->wr_id = wqe->wr_id; + p->length = wqe->length; + p->num_sge = wqe->num_sge; + for (i = 0; i < wqe->num_sge; i++) + p->sg_list[i] = wqe->sg_list[i]; + n++; + p = (struct ipath_rwqe *)((char *) p + sz); + if (++srq->rq.tail >= srq->rq.size) + srq->rq.tail = 0; + } + vfree(srq->rq.wq); + srq->rq.wq = wq; + srq->rq.size = size; + srq->rq.head = n; + srq->rq.tail = 0; + srq->rq.max_sge = attr->max_sge; + spin_unlock_irqrestore(&srq->rq.lock, flags); + } + + ret = 0; + +bail: + return ret; +} + +int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr) +{ + struct ipath_srq *srq = to_isrq(ibsrq); + + attr->max_wr = srq->rq.size - 1; + attr->max_sge = srq->rq.max_sge; + attr->srq_limit = srq->limit; + return 0; +} + +/** + * ipath_destroy_srq - destroy a shared receive queue + * @ibsrq: the SRQ to destroy + */ +int ipath_destroy_srq(struct ib_srq *ibsrq) +{ + struct ipath_srq *srq = to_isrq(ibsrq); + + vfree(srq->rq.wq); + kfree(srq); + + return 0; +} diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c new file mode 100644 index 000000000000..fe209137ee74 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_stats.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "ipath_kernel.h" + +struct infinipath_stats ipath_stats; + +/** + * ipath_snap_cntr - snapshot a chip counter + * @dd: the infinipath device + * @creg: the counter to snapshot + * + * called from add_timer and user counter read calls, to deal with + * counters that wrap in "human time". The words sent and received, and + * the packets sent and received are all that we worry about. For now, + * at least, we don't worry about error counters, because if they wrap + * that quickly, we probably don't care. We may eventually just make this + * handle all the counters. word counters can wrap in about 20 seconds + * of full bandwidth traffic, packet counters in a few hours. + */ + +u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg) +{ + u32 val, reg64 = 0; + u64 val64; + unsigned long t0, t1; + u64 ret; + + t0 = jiffies; + /* If fast increment counters are only 32 bits, snapshot them, + * and maintain them as 64bit values in the driver */ + if (!(dd->ipath_flags & IPATH_32BITCOUNTERS) && + (creg == dd->ipath_cregs->cr_wordsendcnt || + creg == dd->ipath_cregs->cr_wordrcvcnt || + creg == dd->ipath_cregs->cr_pktsendcnt || + creg == dd->ipath_cregs->cr_pktrcvcnt)) { + val64 = ipath_read_creg(dd, creg); + val = val64 == ~0ULL ? ~0U : 0; + reg64 = 1; + } else /* val64 just to keep gcc quiet... */ + val64 = val = ipath_read_creg32(dd, creg); + /* + * See if a second has passed. This is just a way to detect things + * that are quite broken. Normally this should take just a few + * cycles (the check is for long enough that we don't care if we get + * pre-empted.) An Opteron HT O read timeout is 4 seconds with + * normal NB values + */ + t1 = jiffies; + if (time_before(t0 + HZ, t1) && val == -1) { + ipath_dev_err(dd, "Error! Read counter 0x%x timed out\n", + creg); + ret = 0ULL; + goto bail; + } + if (reg64) { + ret = val64; + goto bail; + } + + if (creg == dd->ipath_cregs->cr_wordsendcnt) { + if (val != dd->ipath_lastsword) { + dd->ipath_sword += val - dd->ipath_lastsword; + dd->ipath_lastsword = val; + } + val64 = dd->ipath_sword; + } else if (creg == dd->ipath_cregs->cr_wordrcvcnt) { + if (val != dd->ipath_lastrword) { + dd->ipath_rword += val - dd->ipath_lastrword; + dd->ipath_lastrword = val; + } + val64 = dd->ipath_rword; + } else if (creg == dd->ipath_cregs->cr_pktsendcnt) { + if (val != dd->ipath_lastspkts) { + dd->ipath_spkts += val - dd->ipath_lastspkts; + dd->ipath_lastspkts = val; + } + val64 = dd->ipath_spkts; + } else if (creg == dd->ipath_cregs->cr_pktrcvcnt) { + if (val != dd->ipath_lastrpkts) { + dd->ipath_rpkts += val - dd->ipath_lastrpkts; + dd->ipath_lastrpkts = val; + } + val64 = dd->ipath_rpkts; + } else + val64 = (u64) val; + + ret = val64; + +bail: + return ret; +} + +/** + * ipath_qcheck - print delta of egrfull/hdrqfull errors for kernel ports + * @dd: the infinipath device + * + * print the delta of egrfull/hdrqfull errors for kernel ports no more than + * every 5 seconds. User processes are printed at close, but kernel doesn't + * close, so... Separate routine so may call from other places someday, and + * so function name when printed by _IPATH_INFO is meaningfull + */ +static void ipath_qcheck(struct ipath_devdata *dd) +{ + static u64 last_tot_hdrqfull; + size_t blen = 0; + char buf[128]; + + *buf = 0; + if (dd->ipath_pd[0]->port_hdrqfull != dd->ipath_p0_hdrqfull) { + blen = snprintf(buf, sizeof buf, "port 0 hdrqfull %u", + dd->ipath_pd[0]->port_hdrqfull - + dd->ipath_p0_hdrqfull); + dd->ipath_p0_hdrqfull = dd->ipath_pd[0]->port_hdrqfull; + } + if (ipath_stats.sps_etidfull != dd->ipath_last_tidfull) { + blen += snprintf(buf + blen, sizeof buf - blen, + "%srcvegrfull %llu", + blen ? ", " : "", + (unsigned long long) + (ipath_stats.sps_etidfull - + dd->ipath_last_tidfull)); + dd->ipath_last_tidfull = ipath_stats.sps_etidfull; + } + + /* + * this is actually the number of hdrq full interrupts, not actual + * events, but at the moment that's mostly what I'm interested in. + * Actual count, etc. is in the counters, if needed. For production + * users this won't ordinarily be printed. + */ + + if ((ipath_debug & (__IPATH_PKTDBG | __IPATH_DBG)) && + ipath_stats.sps_hdrqfull != last_tot_hdrqfull) { + blen += snprintf(buf + blen, sizeof buf - blen, + "%shdrqfull %llu (all ports)", + blen ? ", " : "", + (unsigned long long) + (ipath_stats.sps_hdrqfull - + last_tot_hdrqfull)); + last_tot_hdrqfull = ipath_stats.sps_hdrqfull; + } + if (blen) + ipath_dbg("%s\n", buf); + + if (dd->ipath_port0head != (u32) + le64_to_cpu(*dd->ipath_hdrqtailptr)) { + if (dd->ipath_lastport0rcv_cnt == + ipath_stats.sps_port0pkts) { + ipath_cdbg(PKT, "missing rcv interrupts? " + "port0 hd=%llx tl=%x; port0pkts %llx\n", + (unsigned long long) + le64_to_cpu(*dd->ipath_hdrqtailptr), + dd->ipath_port0head, + (unsigned long long) + ipath_stats.sps_port0pkts); + ipath_kreceive(dd); + } + dd->ipath_lastport0rcv_cnt = ipath_stats.sps_port0pkts; + } +} + +/** + * ipath_get_faststats - get word counters from chip before they overflow + * @opaque - contains a pointer to the infinipath device ipath_devdata + * + * called from add_timer + */ +void ipath_get_faststats(unsigned long opaque) +{ + struct ipath_devdata *dd = (struct ipath_devdata *) opaque; + u32 val; + static unsigned cnt; + + /* + * don't access the chip while running diags, or memory diags can + * fail + */ + if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT) || + ipath_diag_inuse) + /* but re-arm the timer, for diags case; won't hurt other */ + goto done; + + if (dd->ipath_flags & IPATH_32BITCOUNTERS) { + ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt); + ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt); + ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt); + ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt); + } + + ipath_qcheck(dd); + + /* + * deal with repeat error suppression. Doesn't really matter if + * last error was almost a full interval ago, or just a few usecs + * ago; still won't get more than 2 per interval. We may want + * longer intervals for this eventually, could do with mod, counter + * or separate timer. Also see code in ipath_handle_errors() and + * ipath_handle_hwerrors(). + */ + + if (dd->ipath_lasterror) + dd->ipath_lasterror = 0; + if (dd->ipath_lasthwerror) + dd->ipath_lasthwerror = 0; + if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) + && time_after(jiffies, dd->ipath_unmasktime)) { + char ebuf[256]; + ipath_decode_err(ebuf, sizeof ebuf, + (dd->ipath_maskederrs & ~dd-> + ipath_ignorederrs)); + if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) & + ~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL)) + ipath_dev_err(dd, "Re-enabling masked errors " + "(%s)\n", ebuf); + else { + /* + * rcvegrfull and rcvhdrqfull are "normal", for some + * types of processes (mostly benchmarks) that send + * huge numbers of messages, while not processing + * them. So only complain about these at debug + * level. + */ + ipath_dbg("Disabling frequent queue full errors " + "(%s)\n", ebuf); + } + dd->ipath_maskederrs = dd->ipath_ignorederrs; + ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, + ~dd->ipath_maskederrs); + } + + /* limit qfull messages to ~one per minute per port */ + if ((++cnt & 0x10)) { + for (val = dd->ipath_cfgports - 1; ((int)val) >= 0; + val--) { + if (dd->ipath_lastegrheads[val] != -1) + dd->ipath_lastegrheads[val] = -1; + if (dd->ipath_lastrcvhdrqtails[val] != -1) + dd->ipath_lastrcvhdrqtails[val] = -1; + } + } + + if (dd->ipath_nosma_bufs) { + dd->ipath_nosma_secs += 5; + if (dd->ipath_nosma_secs >= 30) { + ipath_cdbg(SMA, "No SMA bufs avail %u seconds; " + "cancelling pending sends\n", + dd->ipath_nosma_secs); + /* + * issue an abort as well, in case we have a packet + * stuck in launch fifo. This could corrupt an + * outgoing user packet in the worst case, + * but this is a pretty catastrophic, anyway. + */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + INFINIPATH_S_ABORT); + ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf, + dd->ipath_piobcnt2k + + dd->ipath_piobcnt4k - + dd->ipath_lastport_piobuf); + /* start again, if necessary */ + dd->ipath_nosma_secs = 0; + } else + ipath_cdbg(SMA, "No SMA bufs avail %u tries, " + "after %u seconds\n", + dd->ipath_nosma_bufs, + dd->ipath_nosma_secs); + } + +done: + mod_timer(&dd->ipath_stats_timer, jiffies + HZ * 5); +} diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c new file mode 100644 index 000000000000..32acd8048b49 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c @@ -0,0 +1,778 @@ +/* + * Copyright (c) 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "ipath_kernel.h" +#include "ips_common.h" +#include "ipath_layer.h" + +/** + * ipath_parse_ushort - parse an unsigned short value in an arbitrary base + * @str: the string containing the number + * @valp: where to put the result + * + * returns the number of bytes consumed, or negative value on error + */ +int ipath_parse_ushort(const char *str, unsigned short *valp) +{ + unsigned long val; + char *end; + int ret; + + if (!isdigit(str[0])) { + ret = -EINVAL; + goto bail; + } + + val = simple_strtoul(str, &end, 0); + + if (val > 0xffff) { + ret = -EINVAL; + goto bail; + } + + *valp = val; + + ret = end + 1 - str; + if (ret == 0) + ret = -EINVAL; + +bail: + return ret; +} + +static ssize_t show_version(struct device_driver *dev, char *buf) +{ + /* The string printed here is already newline-terminated. */ + return scnprintf(buf, PAGE_SIZE, "%s", ipath_core_version); +} + +static ssize_t show_num_units(struct device_driver *dev, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", + ipath_count_units(NULL, NULL, NULL)); +} + +#define DRIVER_STAT(name, attr) \ + static ssize_t show_stat_##name(struct device_driver *dev, \ + char *buf) \ + { \ + return scnprintf( \ + buf, PAGE_SIZE, "%llu\n", \ + (unsigned long long) ipath_stats.sps_ ##attr); \ + } \ + static DRIVER_ATTR(name, S_IRUGO, show_stat_##name, NULL) + +DRIVER_STAT(intrs, ints); +DRIVER_STAT(err_intrs, errints); +DRIVER_STAT(errs, errs); +DRIVER_STAT(pkt_errs, pkterrs); +DRIVER_STAT(crc_errs, crcerrs); +DRIVER_STAT(hw_errs, hwerrs); +DRIVER_STAT(ib_link, iblink); +DRIVER_STAT(port0_pkts, port0pkts); +DRIVER_STAT(ether_spkts, ether_spkts); +DRIVER_STAT(ether_rpkts, ether_rpkts); +DRIVER_STAT(sma_spkts, sma_spkts); +DRIVER_STAT(sma_rpkts, sma_rpkts); +DRIVER_STAT(hdrq_full, hdrqfull); +DRIVER_STAT(etid_full, etidfull); +DRIVER_STAT(no_piobufs, nopiobufs); +DRIVER_STAT(ports, ports); +DRIVER_STAT(pkey0, pkeys[0]); +DRIVER_STAT(pkey1, pkeys[1]); +DRIVER_STAT(pkey2, pkeys[2]); +DRIVER_STAT(pkey3, pkeys[3]); +/* XXX fix the following when dynamic table of devices used */ +DRIVER_STAT(lid0, lid[0]); +DRIVER_STAT(lid1, lid[1]); +DRIVER_STAT(lid2, lid[2]); +DRIVER_STAT(lid3, lid[3]); + +DRIVER_STAT(nports, nports); +DRIVER_STAT(null_intr, nullintr); +DRIVER_STAT(max_pkts_call, maxpkts_call); +DRIVER_STAT(avg_pkts_call, avgpkts_call); +DRIVER_STAT(page_locks, pagelocks); +DRIVER_STAT(page_unlocks, pageunlocks); +DRIVER_STAT(krdrops, krdrops); +/* XXX fix the following when dynamic table of devices used */ +DRIVER_STAT(mlid0, mlid[0]); +DRIVER_STAT(mlid1, mlid[1]); +DRIVER_STAT(mlid2, mlid[2]); +DRIVER_STAT(mlid3, mlid[3]); + +static struct attribute *driver_stat_attributes[] = { + &driver_attr_intrs.attr, + &driver_attr_err_intrs.attr, + &driver_attr_errs.attr, + &driver_attr_pkt_errs.attr, + &driver_attr_crc_errs.attr, + &driver_attr_hw_errs.attr, + &driver_attr_ib_link.attr, + &driver_attr_port0_pkts.attr, + &driver_attr_ether_spkts.attr, + &driver_attr_ether_rpkts.attr, + &driver_attr_sma_spkts.attr, + &driver_attr_sma_rpkts.attr, + &driver_attr_hdrq_full.attr, + &driver_attr_etid_full.attr, + &driver_attr_no_piobufs.attr, + &driver_attr_ports.attr, + &driver_attr_pkey0.attr, + &driver_attr_pkey1.attr, + &driver_attr_pkey2.attr, + &driver_attr_pkey3.attr, + &driver_attr_lid0.attr, + &driver_attr_lid1.attr, + &driver_attr_lid2.attr, + &driver_attr_lid3.attr, + &driver_attr_nports.attr, + &driver_attr_null_intr.attr, + &driver_attr_max_pkts_call.attr, + &driver_attr_avg_pkts_call.attr, + &driver_attr_page_locks.attr, + &driver_attr_page_unlocks.attr, + &driver_attr_krdrops.attr, + &driver_attr_mlid0.attr, + &driver_attr_mlid1.attr, + &driver_attr_mlid2.attr, + &driver_attr_mlid3.attr, + NULL +}; + +static struct attribute_group driver_stat_attr_group = { + .name = "stats", + .attrs = driver_stat_attributes +}; + +static ssize_t show_status(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + ssize_t ret; + + if (!dd->ipath_statusp) { + ret = -EINVAL; + goto bail; + } + + ret = scnprintf(buf, PAGE_SIZE, "0x%llx\n", + (unsigned long long) *(dd->ipath_statusp)); + +bail: + return ret; +} + +static const char *ipath_status_str[] = { + "Initted", + "Disabled", + "Admin_Disabled", + "OIB_SMA", + "SMA", + "Present", + "IB_link_up", + "IB_configured", + "NoIBcable", + "Fatal_Hardware_Error", + NULL, +}; + +static ssize_t show_status_str(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int i, any; + u64 s; + ssize_t ret; + + if (!dd->ipath_statusp) { + ret = -EINVAL; + goto bail; + } + + s = *(dd->ipath_statusp); + *buf = '\0'; + for (any = i = 0; s && ipath_status_str[i]; i++) { + if (s & 1) { + if (any && strlcat(buf, " ", PAGE_SIZE) >= + PAGE_SIZE) + /* overflow */ + break; + if (strlcat(buf, ipath_status_str[i], + PAGE_SIZE) >= PAGE_SIZE) + break; + any = 1; + } + s >>= 1; + } + if (any) + strlcat(buf, "\n", PAGE_SIZE); + + ret = strlen(buf); + +bail: + return ret; +} + +static ssize_t show_boardversion(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + /* The string printed here is already newline-terminated. */ + return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion); +} + +static ssize_t show_lid(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "0x%x\n", dd->ipath_lid); +} + +static ssize_t store_lid(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + u16 lid; + int ret; + + ret = ipath_parse_ushort(buf, &lid); + if (ret < 0) + goto invalid; + + if (lid == 0 || lid >= 0xc000) { + ret = -EINVAL; + goto invalid; + } + + ipath_set_sps_lid(dd, lid, 0); + + goto bail; +invalid: + ipath_dev_err(dd, "attempt to set invalid LID\n"); +bail: + return ret; +} + +static ssize_t show_mlid(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "0x%x\n", dd->ipath_mlid); +} + +static ssize_t store_mlid(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int unit; + u16 mlid; + int ret; + + ret = ipath_parse_ushort(buf, &mlid); + if (ret < 0) + goto invalid; + + unit = dd->ipath_unit; + + dd->ipath_mlid = mlid; + ipath_stats.sps_mlid[unit] = mlid; + ipath_layer_intr(dd, IPATH_LAYER_INT_BCAST); + + goto bail; +invalid: + ipath_dev_err(dd, "attempt to set invalid MLID\n"); +bail: + return ret; +} + +static ssize_t show_guid(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + u8 *guid; + + guid = (u8 *) & (dd->ipath_guid); + + return scnprintf(buf, PAGE_SIZE, + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + guid[0], guid[1], guid[2], guid[3], + guid[4], guid[5], guid[6], guid[7]); +} + +static ssize_t store_guid(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + ssize_t ret; + unsigned short guid[8]; + __be64 nguid; + u8 *ng; + int i; + + if (sscanf(buf, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx", + &guid[0], &guid[1], &guid[2], &guid[3], + &guid[4], &guid[5], &guid[6], &guid[7]) != 8) + goto invalid; + + ng = (u8 *) &nguid; + + for (i = 0; i < 8; i++) { + if (guid[i] > 0xff) + goto invalid; + ng[i] = guid[i]; + } + + dd->ipath_guid = nguid; + dd->ipath_nguid = 1; + + ret = strlen(buf); + goto bail; + +invalid: + ipath_dev_err(dd, "attempt to set invalid GUID\n"); + ret = -EINVAL; + +bail: + return ret; +} + +static ssize_t show_nguid(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_nguid); +} + +static ssize_t show_serial(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + + buf[sizeof dd->ipath_serial] = '\0'; + memcpy(buf, dd->ipath_serial, sizeof dd->ipath_serial); + strcat(buf, "\n"); + return strlen(buf); +} + +static ssize_t show_unit(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit); +} + +#define DEVICE_COUNTER(name, attr) \ + static ssize_t show_counter_##name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + struct ipath_devdata *dd = dev_get_drvdata(dev); \ + return scnprintf(\ + buf, PAGE_SIZE, "%llu\n", (unsigned long long) \ + ipath_snap_cntr( \ + dd, offsetof(struct infinipath_counters, \ + attr) / sizeof(u64))); \ + } \ + static DEVICE_ATTR(name, S_IRUGO, show_counter_##name, NULL); + +DEVICE_COUNTER(ib_link_downeds, IBLinkDownedCnt); +DEVICE_COUNTER(ib_link_err_recoveries, IBLinkErrRecoveryCnt); +DEVICE_COUNTER(ib_status_changes, IBStatusChangeCnt); +DEVICE_COUNTER(ib_symbol_errs, IBSymbolErrCnt); +DEVICE_COUNTER(lb_flow_stalls, LBFlowStallCnt); +DEVICE_COUNTER(lb_ints, LBIntCnt); +DEVICE_COUNTER(rx_bad_formats, RxBadFormatCnt); +DEVICE_COUNTER(rx_buf_ovfls, RxBufOvflCnt); +DEVICE_COUNTER(rx_data_pkts, RxDataPktCnt); +DEVICE_COUNTER(rx_dropped_pkts, RxDroppedPktCnt); +DEVICE_COUNTER(rx_dwords, RxDwordCnt); +DEVICE_COUNTER(rx_ebps, RxEBPCnt); +DEVICE_COUNTER(rx_flow_ctrl_errs, RxFlowCtrlErrCnt); +DEVICE_COUNTER(rx_flow_pkts, RxFlowPktCnt); +DEVICE_COUNTER(rx_icrc_errs, RxICRCErrCnt); +DEVICE_COUNTER(rx_len_errs, RxLenErrCnt); +DEVICE_COUNTER(rx_link_problems, RxLinkProblemCnt); +DEVICE_COUNTER(rx_lpcrc_errs, RxLPCRCErrCnt); +DEVICE_COUNTER(rx_max_min_len_errs, RxMaxMinLenErrCnt); +DEVICE_COUNTER(rx_p0_hdr_egr_ovfls, RxP0HdrEgrOvflCnt); +DEVICE_COUNTER(rx_p1_hdr_egr_ovfls, RxP1HdrEgrOvflCnt); +DEVICE_COUNTER(rx_p2_hdr_egr_ovfls, RxP2HdrEgrOvflCnt); +DEVICE_COUNTER(rx_p3_hdr_egr_ovfls, RxP3HdrEgrOvflCnt); +DEVICE_COUNTER(rx_p4_hdr_egr_ovfls, RxP4HdrEgrOvflCnt); +DEVICE_COUNTER(rx_p5_hdr_egr_ovfls, RxP5HdrEgrOvflCnt); +DEVICE_COUNTER(rx_p6_hdr_egr_ovfls, RxP6HdrEgrOvflCnt); +DEVICE_COUNTER(rx_p7_hdr_egr_ovfls, RxP7HdrEgrOvflCnt); +DEVICE_COUNTER(rx_p8_hdr_egr_ovfls, RxP8HdrEgrOvflCnt); +DEVICE_COUNTER(rx_pkey_mismatches, RxPKeyMismatchCnt); +DEVICE_COUNTER(rx_tid_full_errs, RxTIDFullErrCnt); +DEVICE_COUNTER(rx_tid_valid_errs, RxTIDValidErrCnt); +DEVICE_COUNTER(rx_vcrc_errs, RxVCRCErrCnt); +DEVICE_COUNTER(tx_data_pkts, TxDataPktCnt); +DEVICE_COUNTER(tx_dropped_pkts, TxDroppedPktCnt); +DEVICE_COUNTER(tx_dwords, TxDwordCnt); +DEVICE_COUNTER(tx_flow_pkts, TxFlowPktCnt); +DEVICE_COUNTER(tx_flow_stalls, TxFlowStallCnt); +DEVICE_COUNTER(tx_len_errs, TxLenErrCnt); +DEVICE_COUNTER(tx_max_min_len_errs, TxMaxMinLenErrCnt); +DEVICE_COUNTER(tx_underruns, TxUnderrunCnt); +DEVICE_COUNTER(tx_unsup_vl_errs, TxUnsupVLErrCnt); + +static struct attribute *dev_counter_attributes[] = { + &dev_attr_ib_link_downeds.attr, + &dev_attr_ib_link_err_recoveries.attr, + &dev_attr_ib_status_changes.attr, + &dev_attr_ib_symbol_errs.attr, + &dev_attr_lb_flow_stalls.attr, + &dev_attr_lb_ints.attr, + &dev_attr_rx_bad_formats.attr, + &dev_attr_rx_buf_ovfls.attr, + &dev_attr_rx_data_pkts.attr, + &dev_attr_rx_dropped_pkts.attr, + &dev_attr_rx_dwords.attr, + &dev_attr_rx_ebps.attr, + &dev_attr_rx_flow_ctrl_errs.attr, + &dev_attr_rx_flow_pkts.attr, + &dev_attr_rx_icrc_errs.attr, + &dev_attr_rx_len_errs.attr, + &dev_attr_rx_link_problems.attr, + &dev_attr_rx_lpcrc_errs.attr, + &dev_attr_rx_max_min_len_errs.attr, + &dev_attr_rx_p0_hdr_egr_ovfls.attr, + &dev_attr_rx_p1_hdr_egr_ovfls.attr, + &dev_attr_rx_p2_hdr_egr_ovfls.attr, + &dev_attr_rx_p3_hdr_egr_ovfls.attr, + &dev_attr_rx_p4_hdr_egr_ovfls.attr, + &dev_attr_rx_p5_hdr_egr_ovfls.attr, + &dev_attr_rx_p6_hdr_egr_ovfls.attr, + &dev_attr_rx_p7_hdr_egr_ovfls.attr, + &dev_attr_rx_p8_hdr_egr_ovfls.attr, + &dev_attr_rx_pkey_mismatches.attr, + &dev_attr_rx_tid_full_errs.attr, + &dev_attr_rx_tid_valid_errs.attr, + &dev_attr_rx_vcrc_errs.attr, + &dev_attr_tx_data_pkts.attr, + &dev_attr_tx_dropped_pkts.attr, + &dev_attr_tx_dwords.attr, + &dev_attr_tx_flow_pkts.attr, + &dev_attr_tx_flow_stalls.attr, + &dev_attr_tx_len_errs.attr, + &dev_attr_tx_max_min_len_errs.attr, + &dev_attr_tx_underruns.attr, + &dev_attr_tx_unsup_vl_errs.attr, + NULL +}; + +static struct attribute_group dev_counter_attr_group = { + .name = "counters", + .attrs = dev_counter_attributes +}; + +static ssize_t store_reset(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret; + + if (count < 5 || memcmp(buf, "reset", 5)) { + ret = -EINVAL; + goto bail; + } + + if (dd->ipath_flags & IPATH_DISABLED) { + /* + * post-reset init would re-enable interrupts, etc. + * so don't allow reset on disabled devices. Not + * perfect error, but about the best choice. + */ + dev_info(dev,"Unit %d is disabled, can't reset\n", + dd->ipath_unit); + ret = -EINVAL; + } + ret = ipath_reset_device(dd->ipath_unit); +bail: + return ret<0 ? ret : count; +} + +static ssize_t store_link_state(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret, r; + u16 state; + + ret = ipath_parse_ushort(buf, &state); + if (ret < 0) + goto invalid; + + r = ipath_layer_set_linkstate(dd, state); + if (r < 0) { + ret = r; + goto bail; + } + + goto bail; +invalid: + ipath_dev_err(dd, "attempt to set invalid link state\n"); +bail: + return ret; +} + +static ssize_t show_mtu(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_ibmtu); +} + +static ssize_t store_mtu(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + ssize_t ret; + u16 mtu = 0; + int r; + + ret = ipath_parse_ushort(buf, &mtu); + if (ret < 0) + goto invalid; + + r = ipath_layer_set_mtu(dd, mtu); + if (r < 0) + ret = r; + + goto bail; +invalid: + ipath_dev_err(dd, "attempt to set invalid MTU\n"); +bail: + return ret; +} + +static ssize_t show_enabled(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + return scnprintf(buf, PAGE_SIZE, "%u\n", + (dd->ipath_flags & IPATH_DISABLED) ? 0 : 1); +} + +static ssize_t store_enabled(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + ssize_t ret; + u16 enable = 0; + + ret = ipath_parse_ushort(buf, &enable); + if (ret < 0) { + ipath_dev_err(dd, "attempt to use non-numeric on enable\n"); + goto bail; + } + + if (enable) { + if (!(dd->ipath_flags & IPATH_DISABLED)) + goto bail; + + dev_info(dev, "Enabling unit %d\n", dd->ipath_unit); + /* same as post-reset */ + ret = ipath_init_chip(dd, 1); + if (ret) + ipath_dev_err(dd, "Failed to enable unit %d\n", + dd->ipath_unit); + else { + dd->ipath_flags &= ~IPATH_DISABLED; + *dd->ipath_statusp &= ~IPATH_STATUS_ADMIN_DISABLED; + } + } + else if (!(dd->ipath_flags & IPATH_DISABLED)) { + dev_info(dev, "Disabling unit %d\n", dd->ipath_unit); + ipath_shutdown_device(dd); + dd->ipath_flags |= IPATH_DISABLED; + *dd->ipath_statusp |= IPATH_STATUS_ADMIN_DISABLED; + } + +bail: + return ret; +} + +static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL); +static DRIVER_ATTR(version, S_IRUGO, show_version, NULL); + +static struct attribute *driver_attributes[] = { + &driver_attr_num_units.attr, + &driver_attr_version.attr, + NULL +}; + +static struct attribute_group driver_attr_group = { + .attrs = driver_attributes +}; + +static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid); +static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid); +static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state); +static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid); +static DEVICE_ATTR(mtu, S_IWUSR | S_IRUGO, show_mtu, store_mtu); +static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO, show_enabled, store_enabled); +static DEVICE_ATTR(nguid, S_IRUGO, show_nguid, NULL); +static DEVICE_ATTR(reset, S_IWUSR, NULL, store_reset); +static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); +static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); +static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL); +static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); +static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL); + +static struct attribute *dev_attributes[] = { + &dev_attr_guid.attr, + &dev_attr_lid.attr, + &dev_attr_link_state.attr, + &dev_attr_mlid.attr, + &dev_attr_mtu.attr, + &dev_attr_nguid.attr, + &dev_attr_serial.attr, + &dev_attr_status.attr, + &dev_attr_status_str.attr, + &dev_attr_boardversion.attr, + &dev_attr_unit.attr, + &dev_attr_enabled.attr, + NULL +}; + +static struct attribute_group dev_attr_group = { + .attrs = dev_attributes +}; + +/** + * ipath_expose_reset - create a device reset file + * @dev: the device structure + * + * Only expose a file that lets us reset the device after someone + * enters diag mode. A device reset is quite likely to crash the + * machine entirely, so we don't want to normally make it + * available. + */ +int ipath_expose_reset(struct device *dev) +{ + return device_create_file(dev, &dev_attr_reset); +} + +int ipath_driver_create_group(struct device_driver *drv) +{ + int ret; + + ret = sysfs_create_group(&drv->kobj, &driver_attr_group); + if (ret) + goto bail; + + ret = sysfs_create_group(&drv->kobj, &driver_stat_attr_group); + if (ret) + sysfs_remove_group(&drv->kobj, &driver_attr_group); + +bail: + return ret; +} + +void ipath_driver_remove_group(struct device_driver *drv) +{ + sysfs_remove_group(&drv->kobj, &driver_stat_attr_group); + sysfs_remove_group(&drv->kobj, &driver_attr_group); +} + +int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) +{ + int ret; + char unit[5]; + + ret = sysfs_create_group(&dev->kobj, &dev_attr_group); + if (ret) + goto bail; + + ret = sysfs_create_group(&dev->kobj, &dev_counter_attr_group); + if (ret) + goto bail_attrs; + + snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); + ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit); + if (ret == 0) + goto bail; + + sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); +bail_attrs: + sysfs_remove_group(&dev->kobj, &dev_attr_group); +bail: + return ret; +} + +void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd) +{ + char unit[5]; + + snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); + sysfs_remove_link(&dev->driver->kobj, unit); + + sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); + sysfs_remove_group(&dev->kobj, &dev_attr_group); + + device_remove_file(dev, &dev_attr_reset); +} diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c new file mode 100644 index 000000000000..0d6dbc0a541e --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_uc.c @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ipath_verbs.h" +#include "ips_common.h" + +/* cut down ridiculously long IB macro names */ +#define OP(x) IB_OPCODE_UC_##x + +static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe, + struct ib_wc *wc) +{ + if (++qp->s_last == qp->s_size) + qp->s_last = 0; + if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) || + (wqe->wr.send_flags & IB_SEND_SIGNALED)) { + wc->wr_id = wqe->wr.wr_id; + wc->status = IB_WC_SUCCESS; + wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode]; + wc->vendor_err = 0; + wc->byte_len = wqe->length; + wc->qp_num = qp->ibqp.qp_num; + wc->src_qp = qp->remote_qpn; + wc->pkey_index = 0; + wc->slid = qp->remote_ah_attr.dlid; + wc->sl = qp->remote_ah_attr.sl; + wc->dlid_path_bits = 0; + wc->port_num = 0; + ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 0); + } + wqe = get_swqe_ptr(qp, qp->s_last); +} + +/** + * ipath_do_uc_send - do a send on a UC queue + * @data: contains a pointer to the QP to send on + * + * Process entries in the send work queue until the queue is exhausted. + * Only allow one CPU to send a packet per QP (tasklet). + * Otherwise, after we drop the QP lock, two threads could send + * packets out of order. + * This is similar to ipath_do_rc_send() below except we don't have + * timeouts or resends. + */ +void ipath_do_uc_send(unsigned long data) +{ + struct ipath_qp *qp = (struct ipath_qp *)data; + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + struct ipath_swqe *wqe; + unsigned long flags; + u16 lrh0; + u32 hwords; + u32 nwords; + u32 extra_bytes; + u32 bth0; + u32 bth2; + u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); + u32 len; + struct ipath_other_headers *ohdr; + struct ib_wc wc; + + if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags)) + goto bail; + + if (unlikely(qp->remote_ah_attr.dlid == + ipath_layer_get_lid(dev->dd))) { + /* Pass in an uninitialized ib_wc to save stack space. */ + ipath_ruc_loopback(qp, &wc); + clear_bit(IPATH_S_BUSY, &qp->s_flags); + goto bail; + } + + ohdr = &qp->s_hdr.u.oth; + if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) + ohdr = &qp->s_hdr.u.l.oth; + +again: + /* Check for a constructed packet to be sent. */ + if (qp->s_hdrwords != 0) { + /* + * If no PIO bufs are available, return. + * An interrupt will call ipath_ib_piobufavail() + * when one is available. + */ + if (ipath_verbs_send(dev->dd, qp->s_hdrwords, + (u32 *) &qp->s_hdr, + qp->s_cur_size, + qp->s_cur_sge)) { + ipath_no_bufs_available(qp, dev); + goto bail; + } + dev->n_unicast_xmit++; + /* Record that we sent the packet and s_hdr is empty. */ + qp->s_hdrwords = 0; + } + + lrh0 = IPS_LRH_BTH; + /* header size in 32-bit words LRH+BTH = (8+12)/4. */ + hwords = 5; + + /* + * The lock is needed to synchronize between + * setting qp->s_ack_state and post_send(). + */ + spin_lock_irqsave(&qp->s_lock, flags); + + if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) + goto done; + + bth0 = ipath_layer_get_pkey(dev->dd, qp->s_pkey_index); + + /* Send a request. */ + wqe = get_swqe_ptr(qp, qp->s_last); + switch (qp->s_state) { + default: + /* + * Signal the completion of the last send (if there is + * one). + */ + if (qp->s_last != qp->s_tail) + complete_last_send(qp, wqe, &wc); + + /* Check if send work queue is empty. */ + if (qp->s_tail == qp->s_head) + goto done; + /* + * Start a new request. + */ + qp->s_psn = wqe->psn = qp->s_next_psn; + qp->s_sge.sge = wqe->sg_list[0]; + qp->s_sge.sg_list = wqe->sg_list + 1; + qp->s_sge.num_sge = wqe->wr.num_sge; + qp->s_len = len = wqe->length; + switch (wqe->wr.opcode) { + case IB_WR_SEND: + case IB_WR_SEND_WITH_IMM: + if (len > pmtu) { + qp->s_state = OP(SEND_FIRST); + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_SEND) + qp->s_state = OP(SEND_ONLY); + else { + qp->s_state = + OP(SEND_ONLY_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.imm_data; + hwords += 1; + } + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= 1 << 23; + break; + + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + ohdr->u.rc.reth.vaddr = + cpu_to_be64(wqe->wr.wr.rdma.remote_addr); + ohdr->u.rc.reth.rkey = + cpu_to_be32(wqe->wr.wr.rdma.rkey); + ohdr->u.rc.reth.length = cpu_to_be32(len); + hwords += sizeof(struct ib_reth) / 4; + if (len > pmtu) { + qp->s_state = OP(RDMA_WRITE_FIRST); + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_RDMA_WRITE) + qp->s_state = OP(RDMA_WRITE_ONLY); + else { + qp->s_state = + OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE); + /* Immediate data comes after the RETH */ + ohdr->u.rc.imm_data = wqe->wr.imm_data; + hwords += 1; + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= 1 << 23; + } + break; + + default: + goto done; + } + if (++qp->s_tail >= qp->s_size) + qp->s_tail = 0; + break; + + case OP(SEND_FIRST): + qp->s_state = OP(SEND_MIDDLE); + /* FALLTHROUGH */ + case OP(SEND_MIDDLE): + len = qp->s_len; + if (len > pmtu) { + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_SEND) + qp->s_state = OP(SEND_LAST); + else { + qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.imm_data; + hwords += 1; + } + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= 1 << 23; + break; + + case OP(RDMA_WRITE_FIRST): + qp->s_state = OP(RDMA_WRITE_MIDDLE); + /* FALLTHROUGH */ + case OP(RDMA_WRITE_MIDDLE): + len = qp->s_len; + if (len > pmtu) { + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_RDMA_WRITE) + qp->s_state = OP(RDMA_WRITE_LAST); + else { + qp->s_state = + OP(RDMA_WRITE_LAST_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.imm_data; + hwords += 1; + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= 1 << 23; + } + break; + } + bth2 = qp->s_next_psn++ & IPS_PSN_MASK; + qp->s_len -= len; + bth0 |= qp->s_state << 24; + + spin_unlock_irqrestore(&qp->s_lock, flags); + + /* Construct the header. */ + extra_bytes = (4 - len) & 3; + nwords = (len + extra_bytes) >> 2; + if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) { + /* Header size in 32-bit words. */ + hwords += 10; + lrh0 = IPS_LRH_GRH; + qp->s_hdr.u.l.grh.version_tclass_flow = + cpu_to_be32((6 << 28) | + (qp->remote_ah_attr.grh.traffic_class + << 20) | + qp->remote_ah_attr.grh.flow_label); + qp->s_hdr.u.l.grh.paylen = + cpu_to_be16(((hwords - 12) + nwords + + SIZE_OF_CRC) << 2); + /* next_hdr is defined by C8-7 in ch. 8.4.1 */ + qp->s_hdr.u.l.grh.next_hdr = 0x1B; + qp->s_hdr.u.l.grh.hop_limit = + qp->remote_ah_attr.grh.hop_limit; + /* The SGID is 32-bit aligned. */ + qp->s_hdr.u.l.grh.sgid.global.subnet_prefix = + dev->gid_prefix; + qp->s_hdr.u.l.grh.sgid.global.interface_id = + ipath_layer_get_guid(dev->dd); + qp->s_hdr.u.l.grh.dgid = qp->remote_ah_attr.grh.dgid; + } + qp->s_hdrwords = hwords; + qp->s_cur_sge = &qp->s_sge; + qp->s_cur_size = len; + lrh0 |= qp->remote_ah_attr.sl << 4; + qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); + /* DEST LID */ + qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); + qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC); + qp->s_hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd)); + bth0 |= extra_bytes << 20; + ohdr->bth[0] = cpu_to_be32(bth0); + ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); + ohdr->bth[2] = cpu_to_be32(bth2); + + /* Check for more work to do. */ + goto again; + +done: + spin_unlock_irqrestore(&qp->s_lock, flags); + clear_bit(IPATH_S_BUSY, &qp->s_flags); + +bail: + return; +} + +/** + * ipath_uc_rcv - handle an incoming UC packet + * @dev: the device the packet came in on + * @hdr: the header of the packet + * @has_grh: true if the packet has a GRH + * @data: the packet data + * @tlen: the length of the packet + * @qp: the QP for this packet. + * + * This is called from ipath_qp_rcv() to process an incoming UC packet + * for the given QP. + * Called at interrupt level. + */ +void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, + int has_grh, void *data, u32 tlen, struct ipath_qp *qp) +{ + struct ipath_other_headers *ohdr; + int opcode; + u32 hdrsize; + u32 psn; + u32 pad; + unsigned long flags; + struct ib_wc wc; + u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu); + struct ib_reth *reth; + int header_in_data; + + /* Check for GRH */ + if (!has_grh) { + ohdr = &hdr->u.oth; + hdrsize = 8 + 12; /* LRH + BTH */ + psn = be32_to_cpu(ohdr->bth[2]); + header_in_data = 0; + } else { + ohdr = &hdr->u.l.oth; + hdrsize = 8 + 40 + 12; /* LRH + GRH + BTH */ + /* + * The header with GRH is 60 bytes and the + * core driver sets the eager header buffer + * size to 56 bytes so the last 4 bytes of + * the BTH header (PSN) is in the data buffer. + */ + header_in_data = + ipath_layer_get_rcvhdrentsize(dev->dd) == 16; + if (header_in_data) { + psn = be32_to_cpu(((__be32 *) data)[0]); + data += sizeof(__be32); + } else + psn = be32_to_cpu(ohdr->bth[2]); + } + /* + * The opcode is in the low byte when its in network order + * (top byte when in host order). + */ + opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + + wc.imm_data = 0; + wc.wc_flags = 0; + + spin_lock_irqsave(&qp->r_rq.lock, flags); + + /* Compare the PSN verses the expected PSN. */ + if (unlikely(ipath_cmp24(psn, qp->r_psn) != 0)) { + /* + * Handle a sequence error. + * Silently drop any current message. + */ + qp->r_psn = psn; + inv: + qp->r_state = OP(SEND_LAST); + switch (opcode) { + case OP(SEND_FIRST): + case OP(SEND_ONLY): + case OP(SEND_ONLY_WITH_IMMEDIATE): + goto send_first; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_ONLY): + case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): + goto rdma_first; + + default: + dev->n_pkt_drops++; + goto done; + } + } + + /* Check for opcode sequence errors. */ + switch (qp->r_state) { + case OP(SEND_FIRST): + case OP(SEND_MIDDLE): + if (opcode == OP(SEND_MIDDLE) || + opcode == OP(SEND_LAST) || + opcode == OP(SEND_LAST_WITH_IMMEDIATE)) + break; + goto inv; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_MIDDLE): + if (opcode == OP(RDMA_WRITE_MIDDLE) || + opcode == OP(RDMA_WRITE_LAST) || + opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) + break; + goto inv; + + default: + if (opcode == OP(SEND_FIRST) || + opcode == OP(SEND_ONLY) || + opcode == OP(SEND_ONLY_WITH_IMMEDIATE) || + opcode == OP(RDMA_WRITE_FIRST) || + opcode == OP(RDMA_WRITE_ONLY) || + opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) + break; + goto inv; + } + + /* OK, process the packet. */ + switch (opcode) { + case OP(SEND_FIRST): + case OP(SEND_ONLY): + case OP(SEND_ONLY_WITH_IMMEDIATE): + send_first: + if (qp->r_reuse_sge) { + qp->r_reuse_sge = 0; + qp->r_sge = qp->s_rdma_sge; + } else if (!ipath_get_rwqe(qp, 0)) { + dev->n_pkt_drops++; + goto done; + } + /* Save the WQE so we can reuse it in case of an error. */ + qp->s_rdma_sge = qp->r_sge; + qp->r_rcv_len = 0; + if (opcode == OP(SEND_ONLY)) + goto send_last; + else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE)) + goto send_last_imm; + /* FALLTHROUGH */ + case OP(SEND_MIDDLE): + /* Check for invalid length PMTU or posted rwqe len. */ + if (unlikely(tlen != (hdrsize + pmtu + 4))) { + qp->r_reuse_sge = 1; + dev->n_pkt_drops++; + goto done; + } + qp->r_rcv_len += pmtu; + if (unlikely(qp->r_rcv_len > qp->r_len)) { + qp->r_reuse_sge = 1; + dev->n_pkt_drops++; + goto done; + } + ipath_copy_sge(&qp->r_sge, data, pmtu); + break; + + case OP(SEND_LAST_WITH_IMMEDIATE): + send_last_imm: + if (header_in_data) { + wc.imm_data = *(__be32 *) data; + data += sizeof(__be32); + } else { + /* Immediate data comes after BTH */ + wc.imm_data = ohdr->u.imm_data; + } + hdrsize += 4; + wc.wc_flags = IB_WC_WITH_IMM; + /* FALLTHROUGH */ + case OP(SEND_LAST): + send_last: + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* Check for invalid length. */ + /* XXX LAST len should be >= 1 */ + if (unlikely(tlen < (hdrsize + pad + 4))) { + qp->r_reuse_sge = 1; + dev->n_pkt_drops++; + goto done; + } + /* Don't count the CRC. */ + tlen -= (hdrsize + pad + 4); + wc.byte_len = tlen + qp->r_rcv_len; + if (unlikely(wc.byte_len > qp->r_len)) { + qp->r_reuse_sge = 1; + dev->n_pkt_drops++; + goto done; + } + /* XXX Need to free SGEs */ + last_imm: + ipath_copy_sge(&qp->r_sge, data, tlen); + wc.wr_id = qp->r_wr_id; + wc.status = IB_WC_SUCCESS; + wc.opcode = IB_WC_RECV; + wc.vendor_err = 0; + wc.qp_num = qp->ibqp.qp_num; + wc.src_qp = qp->remote_qpn; + wc.pkey_index = 0; + wc.slid = qp->remote_ah_attr.dlid; + wc.sl = qp->remote_ah_attr.sl; + wc.dlid_path_bits = 0; + wc.port_num = 0; + /* Signal completion event if the solicited bit is set. */ + ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + (ohdr->bth[0] & + __constant_cpu_to_be32(1 << 23)) != 0); + break; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_ONLY): + case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): /* consume RWQE */ + rdma_first: + /* RETH comes after BTH */ + if (!header_in_data) + reth = &ohdr->u.rc.reth; + else { + reth = (struct ib_reth *)data; + data += sizeof(*reth); + } + hdrsize += sizeof(*reth); + qp->r_len = be32_to_cpu(reth->length); + qp->r_rcv_len = 0; + if (qp->r_len != 0) { + u32 rkey = be32_to_cpu(reth->rkey); + u64 vaddr = be64_to_cpu(reth->vaddr); + + /* Check rkey */ + if (unlikely(!ipath_rkey_ok( + dev, &qp->r_sge, qp->r_len, + vaddr, rkey, + IB_ACCESS_REMOTE_WRITE))) { + dev->n_pkt_drops++; + goto done; + } + } else { + qp->r_sge.sg_list = NULL; + qp->r_sge.sge.mr = NULL; + qp->r_sge.sge.vaddr = NULL; + qp->r_sge.sge.length = 0; + qp->r_sge.sge.sge_length = 0; + } + if (unlikely(!(qp->qp_access_flags & + IB_ACCESS_REMOTE_WRITE))) { + dev->n_pkt_drops++; + goto done; + } + if (opcode == OP(RDMA_WRITE_ONLY)) + goto rdma_last; + else if (opcode == + OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) + goto rdma_last_imm; + /* FALLTHROUGH */ + case OP(RDMA_WRITE_MIDDLE): + /* Check for invalid length PMTU or posted rwqe len. */ + if (unlikely(tlen != (hdrsize + pmtu + 4))) { + dev->n_pkt_drops++; + goto done; + } + qp->r_rcv_len += pmtu; + if (unlikely(qp->r_rcv_len > qp->r_len)) { + dev->n_pkt_drops++; + goto done; + } + ipath_copy_sge(&qp->r_sge, data, pmtu); + break; + + case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): + rdma_last_imm: + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* Check for invalid length. */ + /* XXX LAST len should be >= 1 */ + if (unlikely(tlen < (hdrsize + pad + 4))) { + dev->n_pkt_drops++; + goto done; + } + /* Don't count the CRC. */ + tlen -= (hdrsize + pad + 4); + if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) { + dev->n_pkt_drops++; + goto done; + } + if (qp->r_reuse_sge) { + qp->r_reuse_sge = 0; + } else if (!ipath_get_rwqe(qp, 1)) { + dev->n_pkt_drops++; + goto done; + } + if (header_in_data) { + wc.imm_data = *(__be32 *) data; + data += sizeof(__be32); + } else { + /* Immediate data comes after BTH */ + wc.imm_data = ohdr->u.imm_data; + } + hdrsize += 4; + wc.wc_flags = IB_WC_WITH_IMM; + wc.byte_len = 0; + goto last_imm; + + case OP(RDMA_WRITE_LAST): + rdma_last: + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* Check for invalid length. */ + /* XXX LAST len should be >= 1 */ + if (unlikely(tlen < (hdrsize + pad + 4))) { + dev->n_pkt_drops++; + goto done; + } + /* Don't count the CRC. */ + tlen -= (hdrsize + pad + 4); + if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) { + dev->n_pkt_drops++; + goto done; + } + ipath_copy_sge(&qp->r_sge, data, tlen); + break; + + default: + /* Drop packet for unknown opcodes. */ + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + dev->n_pkt_drops++; + goto bail; + } + qp->r_psn++; + qp->r_state = opcode; +done: + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + +bail: + return; +} diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c new file mode 100644 index 000000000000..5ff3de6128b2 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "ipath_verbs.h" +#include "ips_common.h" + +/** + * ipath_ud_loopback - handle send on loopback QPs + * @sqp: the QP + * @ss: the SGE state + * @length: the length of the data to send + * @wr: the work request + * @wc: the work completion entry + * + * This is called from ipath_post_ud_send() to forward a WQE addressed + * to the same HCA. + */ +void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_sge_state *ss, + u32 length, struct ib_send_wr *wr, struct ib_wc *wc) +{ + struct ipath_ibdev *dev = to_idev(sqp->ibqp.device); + struct ipath_qp *qp; + struct ib_ah_attr *ah_attr; + unsigned long flags; + struct ipath_rq *rq; + struct ipath_srq *srq; + struct ipath_sge_state rsge; + struct ipath_sge *sge; + struct ipath_rwqe *wqe; + + qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn); + if (!qp) + return; + + /* + * Check that the qkey matches (except for QP0, see 9.6.1.4.1). + * Qkeys with the high order bit set mean use the + * qkey from the QP context instead of the WR (see 10.2.5). + */ + if (unlikely(qp->ibqp.qp_num && + ((int) wr->wr.ud.remote_qkey < 0 + ? qp->qkey : wr->wr.ud.remote_qkey) != qp->qkey)) { + /* XXX OK to lose a count once in a while. */ + dev->qkey_violations++; + dev->n_pkt_drops++; + goto done; + } + + /* + * A GRH is expected to preceed the data even if not + * present on the wire. + */ + wc->byte_len = length + sizeof(struct ib_grh); + + if (wr->opcode == IB_WR_SEND_WITH_IMM) { + wc->wc_flags = IB_WC_WITH_IMM; + wc->imm_data = wr->imm_data; + } else { + wc->wc_flags = 0; + wc->imm_data = 0; + } + + /* + * Get the next work request entry to find where to put the data. + * Note that it is safe to drop the lock after changing rq->tail + * since ipath_post_receive() won't fill the empty slot. + */ + if (qp->ibqp.srq) { + srq = to_isrq(qp->ibqp.srq); + rq = &srq->rq; + } else { + srq = NULL; + rq = &qp->r_rq; + } + spin_lock_irqsave(&rq->lock, flags); + if (rq->tail == rq->head) { + spin_unlock_irqrestore(&rq->lock, flags); + dev->n_pkt_drops++; + goto done; + } + /* Silently drop packets which are too big. */ + wqe = get_rwqe_ptr(rq, rq->tail); + if (wc->byte_len > wqe->length) { + spin_unlock_irqrestore(&rq->lock, flags); + dev->n_pkt_drops++; + goto done; + } + wc->wr_id = wqe->wr_id; + rsge.sge = wqe->sg_list[0]; + rsge.sg_list = wqe->sg_list + 1; + rsge.num_sge = wqe->num_sge; + if (++rq->tail >= rq->size) + rq->tail = 0; + if (srq && srq->ibsrq.event_handler) { + u32 n; + + if (rq->head < rq->tail) + n = rq->size + rq->head - rq->tail; + else + n = rq->head - rq->tail; + if (n < srq->limit) { + struct ib_event ev; + + srq->limit = 0; + spin_unlock_irqrestore(&rq->lock, flags); + ev.device = qp->ibqp.device; + ev.element.srq = qp->ibqp.srq; + ev.event = IB_EVENT_SRQ_LIMIT_REACHED; + srq->ibsrq.event_handler(&ev, + srq->ibsrq.srq_context); + } else + spin_unlock_irqrestore(&rq->lock, flags); + } else + spin_unlock_irqrestore(&rq->lock, flags); + ah_attr = &to_iah(wr->wr.ud.ah)->attr; + if (ah_attr->ah_flags & IB_AH_GRH) { + ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh)); + wc->wc_flags |= IB_WC_GRH; + } else + ipath_skip_sge(&rsge, sizeof(struct ib_grh)); + sge = &ss->sge; + while (length) { + u32 len = sge->length; + + if (len > length) + len = length; + BUG_ON(len == 0); + ipath_copy_sge(&rsge, sge->vaddr, len); + sge->vaddr += len; + sge->length -= len; + sge->sge_length -= len; + if (sge->sge_length == 0) { + if (--ss->num_sge) + *sge = *ss->sg_list++; + } else if (sge->length == 0 && sge->mr != NULL) { + if (++sge->n >= IPATH_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + break; + sge->n = 0; + } + sge->vaddr = + sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = + sge->mr->map[sge->m]->segs[sge->n].length; + } + length -= len; + } + wc->status = IB_WC_SUCCESS; + wc->opcode = IB_WC_RECV; + wc->vendor_err = 0; + wc->qp_num = qp->ibqp.qp_num; + wc->src_qp = sqp->ibqp.qp_num; + /* XXX do we know which pkey matched? Only needed for GSI. */ + wc->pkey_index = 0; + wc->slid = ipath_layer_get_lid(dev->dd) | + (ah_attr->src_path_bits & + ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1)); + wc->sl = ah_attr->sl; + wc->dlid_path_bits = + ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + /* Signal completion event if the solicited bit is set. */ + ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc, + wr->send_flags & IB_SEND_SOLICITED); + +done: + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); +} + +/** + * ipath_post_ud_send - post a UD send on QP + * @qp: the QP + * @wr: the work request + * + * Note that we actually send the data as it is posted instead of putting + * the request into a ring buffer. If we wanted to use a ring buffer, + * we would need to save a reference to the destination address in the SWQE. + */ +int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr) +{ + struct ipath_ibdev *dev = to_idev(qp->ibqp.device); + struct ipath_other_headers *ohdr; + struct ib_ah_attr *ah_attr; + struct ipath_sge_state ss; + struct ipath_sge *sg_list; + struct ib_wc wc; + u32 hwords; + u32 nwords; + u32 len; + u32 extra_bytes; + u32 bth0; + u16 lrh0; + u16 lid; + int i; + int ret; + + if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) { + ret = 0; + goto bail; + } + + /* IB spec says that num_sge == 0 is OK. */ + if (wr->num_sge > qp->s_max_sge) { + ret = -EINVAL; + goto bail; + } + + if (wr->num_sge > 1) { + sg_list = kmalloc((qp->s_max_sge - 1) * sizeof(*sg_list), + GFP_ATOMIC); + if (!sg_list) { + ret = -ENOMEM; + goto bail; + } + } else + sg_list = NULL; + + /* Check the buffer to send. */ + ss.sg_list = sg_list; + ss.sge.mr = NULL; + ss.sge.vaddr = NULL; + ss.sge.length = 0; + ss.sge.sge_length = 0; + ss.num_sge = 0; + len = 0; + for (i = 0; i < wr->num_sge; i++) { + /* Check LKEY */ + if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) { + ret = -EINVAL; + goto bail; + } + + if (wr->sg_list[i].length == 0) + continue; + if (!ipath_lkey_ok(&dev->lk_table, ss.num_sge ? + sg_list + ss.num_sge - 1 : &ss.sge, + &wr->sg_list[i], 0)) { + ret = -EINVAL; + goto bail; + } + len += wr->sg_list[i].length; + ss.num_sge++; + } + extra_bytes = (4 - len) & 3; + nwords = (len + extra_bytes) >> 2; + + /* Construct the header. */ + ah_attr = &to_iah(wr->wr.ud.ah)->attr; + if (ah_attr->dlid == 0) { + ret = -EINVAL; + goto bail; + } + if (ah_attr->dlid >= IPS_MULTICAST_LID_BASE) { + if (ah_attr->dlid != IPS_PERMISSIVE_LID) + dev->n_multicast_xmit++; + else + dev->n_unicast_xmit++; + } else { + dev->n_unicast_xmit++; + lid = ah_attr->dlid & + ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + if (unlikely(lid == ipath_layer_get_lid(dev->dd))) { + /* + * Pass in an uninitialized ib_wc to save stack + * space. + */ + ipath_ud_loopback(qp, &ss, len, wr, &wc); + goto done; + } + } + if (ah_attr->ah_flags & IB_AH_GRH) { + /* Header size in 32-bit words. */ + hwords = 17; + lrh0 = IPS_LRH_GRH; + ohdr = &qp->s_hdr.u.l.oth; + qp->s_hdr.u.l.grh.version_tclass_flow = + cpu_to_be32((6 << 28) | + (ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); + qp->s_hdr.u.l.grh.paylen = + cpu_to_be16(((wr->opcode == + IB_WR_SEND_WITH_IMM ? 6 : 5) + + nwords + SIZE_OF_CRC) << 2); + /* next_hdr is defined by C8-7 in ch. 8.4.1 */ + qp->s_hdr.u.l.grh.next_hdr = 0x1B; + qp->s_hdr.u.l.grh.hop_limit = ah_attr->grh.hop_limit; + /* The SGID is 32-bit aligned. */ + qp->s_hdr.u.l.grh.sgid.global.subnet_prefix = + dev->gid_prefix; + qp->s_hdr.u.l.grh.sgid.global.interface_id = + ipath_layer_get_guid(dev->dd); + qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid; + /* + * Don't worry about sending to locally attached multicast + * QPs. It is unspecified by the spec. what happens. + */ + } else { + /* Header size in 32-bit words. */ + hwords = 7; + lrh0 = IPS_LRH_BTH; + ohdr = &qp->s_hdr.u.oth; + } + if (wr->opcode == IB_WR_SEND_WITH_IMM) { + ohdr->u.ud.imm_data = wr->imm_data; + wc.imm_data = wr->imm_data; + hwords += 1; + bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24; + } else if (wr->opcode == IB_WR_SEND) { + wc.imm_data = 0; + bth0 = IB_OPCODE_UD_SEND_ONLY << 24; + } else { + ret = -EINVAL; + goto bail; + } + lrh0 |= ah_attr->sl << 4; + if (qp->ibqp.qp_type == IB_QPT_SMI) + lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */ + qp->s_hdr.lrh[0] = cpu_to_be16(lrh0); + qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */ + qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC); + lid = ipath_layer_get_lid(dev->dd); + if (lid) { + lid |= ah_attr->src_path_bits & + ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + qp->s_hdr.lrh[3] = cpu_to_be16(lid); + } else + qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE; + if (wr->send_flags & IB_SEND_SOLICITED) + bth0 |= 1 << 23; + bth0 |= extra_bytes << 20; + bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPS_DEFAULT_P_KEY : + ipath_layer_get_pkey(dev->dd, qp->s_pkey_index); + ohdr->bth[0] = cpu_to_be32(bth0); + /* + * Use the multicast QP if the destination LID is a multicast LID. + */ + ohdr->bth[1] = ah_attr->dlid >= IPS_MULTICAST_LID_BASE && + ah_attr->dlid != IPS_PERMISSIVE_LID ? + __constant_cpu_to_be32(IPS_MULTICAST_QPN) : + cpu_to_be32(wr->wr.ud.remote_qpn); + /* XXX Could lose a PSN count but not worth locking */ + ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPS_PSN_MASK); + /* + * Qkeys with the high order bit set mean use the + * qkey from the QP context instead of the WR (see 10.2.5). + */ + ohdr->u.ud.deth[0] = cpu_to_be32((int)wr->wr.ud.remote_qkey < 0 ? + qp->qkey : wr->wr.ud.remote_qkey); + ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num); + if (ipath_verbs_send(dev->dd, hwords, (u32 *) &qp->s_hdr, + len, &ss)) + dev->n_no_piobuf++; + +done: + /* Queue the completion status entry. */ + if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) || + (wr->send_flags & IB_SEND_SIGNALED)) { + wc.wr_id = wr->wr_id; + wc.status = IB_WC_SUCCESS; + wc.vendor_err = 0; + wc.opcode = IB_WC_SEND; + wc.byte_len = len; + wc.qp_num = qp->ibqp.qp_num; + wc.src_qp = 0; + wc.wc_flags = 0; + /* XXX initialize other fields? */ + ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0); + } + kfree(sg_list); + + ret = 0; + +bail: + return ret; +} + +/** + * ipath_ud_rcv - receive an incoming UD packet + * @dev: the device the packet came in on + * @hdr: the packet header + * @has_grh: true if the packet has a GRH + * @data: the packet data + * @tlen: the packet length + * @qp: the QP the packet came on + * + * This is called from ipath_qp_rcv() to process an incoming UD packet + * for the given QP. + * Called at interrupt level. + */ +void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, + int has_grh, void *data, u32 tlen, struct ipath_qp *qp) +{ + struct ipath_other_headers *ohdr; + int opcode; + u32 hdrsize; + u32 pad; + unsigned long flags; + struct ib_wc wc; + u32 qkey; + u32 src_qp; + struct ipath_rq *rq; + struct ipath_srq *srq; + struct ipath_rwqe *wqe; + u16 dlid; + int header_in_data; + + /* Check for GRH */ + if (!has_grh) { + ohdr = &hdr->u.oth; + hdrsize = 8 + 12 + 8; /* LRH + BTH + DETH */ + qkey = be32_to_cpu(ohdr->u.ud.deth[0]); + src_qp = be32_to_cpu(ohdr->u.ud.deth[1]); + header_in_data = 0; + } else { + ohdr = &hdr->u.l.oth; + hdrsize = 8 + 40 + 12 + 8; /* LRH + GRH + BTH + DETH */ + /* + * The header with GRH is 68 bytes and the core driver sets + * the eager header buffer size to 56 bytes so the last 12 + * bytes of the IB header is in the data buffer. + */ + header_in_data = + ipath_layer_get_rcvhdrentsize(dev->dd) == 16; + if (header_in_data) { + qkey = be32_to_cpu(((__be32 *) data)[1]); + src_qp = be32_to_cpu(((__be32 *) data)[2]); + data += 12; + } else { + qkey = be32_to_cpu(ohdr->u.ud.deth[0]); + src_qp = be32_to_cpu(ohdr->u.ud.deth[1]); + } + } + src_qp &= IPS_QPN_MASK; + + /* + * Check that the permissive LID is only used on QP0 + * and the QKEY matches (see 9.6.1.4.1 and 9.6.1.5.1). + */ + if (qp->ibqp.qp_num) { + if (unlikely(hdr->lrh[1] == IB_LID_PERMISSIVE || + hdr->lrh[3] == IB_LID_PERMISSIVE)) { + dev->n_pkt_drops++; + goto bail; + } + if (unlikely(qkey != qp->qkey)) { + /* XXX OK to lose a count once in a while. */ + dev->qkey_violations++; + dev->n_pkt_drops++; + goto bail; + } + } else if (hdr->lrh[1] == IB_LID_PERMISSIVE || + hdr->lrh[3] == IB_LID_PERMISSIVE) { + struct ib_smp *smp = (struct ib_smp *) data; + + if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + dev->n_pkt_drops++; + goto bail; + } + } + + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + if (unlikely(tlen < (hdrsize + pad + 4))) { + /* Drop incomplete packets. */ + dev->n_pkt_drops++; + goto bail; + } + tlen -= hdrsize + pad + 4; + + /* Drop invalid MAD packets (see 13.5.3.1). */ + if (unlikely((qp->ibqp.qp_num == 0 && + (tlen != 256 || + (be16_to_cpu(hdr->lrh[0]) >> 12) != 15)) || + (qp->ibqp.qp_num == 1 && + (tlen != 256 || + (be16_to_cpu(hdr->lrh[0]) >> 12) == 15)))) { + dev->n_pkt_drops++; + goto bail; + } + + /* + * A GRH is expected to preceed the data even if not + * present on the wire. + */ + wc.byte_len = tlen + sizeof(struct ib_grh); + + /* + * The opcode is in the low byte when its in network order + * (top byte when in host order). + */ + opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + if (qp->ibqp.qp_num > 1 && + opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) { + if (header_in_data) { + wc.imm_data = *(__be32 *) data; + data += sizeof(__be32); + } else + wc.imm_data = ohdr->u.ud.imm_data; + wc.wc_flags = IB_WC_WITH_IMM; + hdrsize += sizeof(u32); + } else if (opcode == IB_OPCODE_UD_SEND_ONLY) { + wc.imm_data = 0; + wc.wc_flags = 0; + } else { + dev->n_pkt_drops++; + goto bail; + } + + /* + * Get the next work request entry to find where to put the data. + * Note that it is safe to drop the lock after changing rq->tail + * since ipath_post_receive() won't fill the empty slot. + */ + if (qp->ibqp.srq) { + srq = to_isrq(qp->ibqp.srq); + rq = &srq->rq; + } else { + srq = NULL; + rq = &qp->r_rq; + } + spin_lock_irqsave(&rq->lock, flags); + if (rq->tail == rq->head) { + spin_unlock_irqrestore(&rq->lock, flags); + dev->n_pkt_drops++; + goto bail; + } + /* Silently drop packets which are too big. */ + wqe = get_rwqe_ptr(rq, rq->tail); + if (wc.byte_len > wqe->length) { + spin_unlock_irqrestore(&rq->lock, flags); + dev->n_pkt_drops++; + goto bail; + } + wc.wr_id = wqe->wr_id; + qp->r_sge.sge = wqe->sg_list[0]; + qp->r_sge.sg_list = wqe->sg_list + 1; + qp->r_sge.num_sge = wqe->num_sge; + if (++rq->tail >= rq->size) + rq->tail = 0; + if (srq && srq->ibsrq.event_handler) { + u32 n; + + if (rq->head < rq->tail) + n = rq->size + rq->head - rq->tail; + else + n = rq->head - rq->tail; + if (n < srq->limit) { + struct ib_event ev; + + srq->limit = 0; + spin_unlock_irqrestore(&rq->lock, flags); + ev.device = qp->ibqp.device; + ev.element.srq = qp->ibqp.srq; + ev.event = IB_EVENT_SRQ_LIMIT_REACHED; + srq->ibsrq.event_handler(&ev, + srq->ibsrq.srq_context); + } else + spin_unlock_irqrestore(&rq->lock, flags); + } else + spin_unlock_irqrestore(&rq->lock, flags); + if (has_grh) { + ipath_copy_sge(&qp->r_sge, &hdr->u.l.grh, + sizeof(struct ib_grh)); + wc.wc_flags |= IB_WC_GRH; + } else + ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh)); + ipath_copy_sge(&qp->r_sge, data, + wc.byte_len - sizeof(struct ib_grh)); + wc.status = IB_WC_SUCCESS; + wc.opcode = IB_WC_RECV; + wc.vendor_err = 0; + wc.qp_num = qp->ibqp.qp_num; + wc.src_qp = src_qp; + /* XXX do we know which pkey matched? Only needed for GSI. */ + wc.pkey_index = 0; + wc.slid = be16_to_cpu(hdr->lrh[3]); + wc.sl = (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF; + dlid = be16_to_cpu(hdr->lrh[1]); + /* + * Save the LMC lower bits if the destination LID is a unicast LID. + */ + wc.dlid_path_bits = dlid >= IPS_MULTICAST_LID_BASE ? 0 : + dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + /* Signal completion event if the solicited bit is set. */ + ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + (ohdr->bth[0] & + __constant_cpu_to_be32(1 << 23)) != 0); + +bail:; +} diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c new file mode 100644 index 000000000000..2bb08afc86d0 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "ipath_kernel.h" + +static void __ipath_release_user_pages(struct page **p, size_t num_pages, + int dirty) +{ + size_t i; + + for (i = 0; i < num_pages; i++) { + ipath_cdbg(MM, "%lu/%lu put_page %p\n", (unsigned long) i, + (unsigned long) num_pages, p[i]); + if (dirty) + set_page_dirty_lock(p[i]); + put_page(p[i]); + } +} + +/* call with current->mm->mmap_sem held */ +static int __get_user_pages(unsigned long start_page, size_t num_pages, + struct page **p, struct vm_area_struct **vma) +{ + unsigned long lock_limit; + size_t got; + int ret; + +#if 0 + /* + * XXX - causes MPI programs to fail, haven't had time to check + * yet + */ + if (!capable(CAP_IPC_LOCK)) { + ret = -EPERM; + goto bail; + } +#endif + + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> + PAGE_SHIFT; + + if (num_pages > lock_limit) { + ret = -ENOMEM; + goto bail; + } + + ipath_cdbg(VERBOSE, "pin %lx pages from vaddr %lx\n", + (unsigned long) num_pages, start_page); + + for (got = 0; got < num_pages; got += ret) { + ret = get_user_pages(current, current->mm, + start_page + got * PAGE_SIZE, + num_pages - got, 1, 1, + p + got, vma); + if (ret < 0) + goto bail_release; + } + + current->mm->locked_vm += num_pages; + + ret = 0; + goto bail; + +bail_release: + __ipath_release_user_pages(p, got, 0); +bail: + return ret; +} + +/** + * ipath_get_user_pages - lock user pages into memory + * @start_page: the start page + * @num_pages: the number of pages + * @p: the output page structures + * + * This function takes a given start page (page aligned user virtual + * address) and pins it and the following specified number of pages. For + * now, num_pages is always 1, but that will probably change at some point + * (because caller is doing expected sends on a single virtually contiguous + * buffer, so we can do all pages at once). + */ +int ipath_get_user_pages(unsigned long start_page, size_t num_pages, + struct page **p) +{ + int ret; + + down_write(¤t->mm->mmap_sem); + + ret = __get_user_pages(start_page, num_pages, p, NULL); + + up_write(¤t->mm->mmap_sem); + + return ret; +} + +/** + * ipath_get_user_pages_nocopy - lock a single page for I/O and mark shared + * @start_page: the page to lock + * @p: the output page structure + * + * This is similar to ipath_get_user_pages, but it's always one page, and we + * mark the page as locked for I/O, and shared. This is used for the user + * process page that contains the destination address for the rcvhdrq tail + * update, so we need to have the vma. If we don't do this, the page can be + * taken away from us on fork, even if the child never touches it, and then + * the user process never sees the tail register updates. + */ +int ipath_get_user_pages_nocopy(unsigned long page, struct page **p) +{ + struct vm_area_struct *vma; + int ret; + + down_write(¤t->mm->mmap_sem); + + ret = __get_user_pages(page, 1, p, &vma); + + up_write(¤t->mm->mmap_sem); + + return ret; +} + +void ipath_release_user_pages(struct page **p, size_t num_pages) +{ + down_write(¤t->mm->mmap_sem); + + __ipath_release_user_pages(p, num_pages, 1); + + current->mm->locked_vm -= num_pages; + + up_write(¤t->mm->mmap_sem); +} + +struct ipath_user_pages_work { + struct work_struct work; + struct mm_struct *mm; + unsigned long num_pages; +}; + +static void user_pages_account(void *ptr) +{ + struct ipath_user_pages_work *work = ptr; + + down_write(&work->mm->mmap_sem); + work->mm->locked_vm -= work->num_pages; + up_write(&work->mm->mmap_sem); + mmput(work->mm); + kfree(work); +} + +void ipath_release_user_pages_on_close(struct page **p, size_t num_pages) +{ + struct ipath_user_pages_work *work; + struct mm_struct *mm; + + __ipath_release_user_pages(p, num_pages, 1); + + mm = get_task_mm(current); + if (!mm) + goto bail; + + work = kmalloc(sizeof(*work), GFP_KERNEL); + if (!work) + goto bail_mm; + + goto bail; + + INIT_WORK(&work->work, user_pages_account, work); + work->mm = mm; + work->num_pages = num_pages; + +bail_mm: + mmput(mm); +bail: + return; +} diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c new file mode 100644 index 000000000000..9f27fd35cdbb --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -0,0 +1,1222 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include + +#include "ipath_kernel.h" +#include "ipath_verbs.h" +#include "ips_common.h" + +/* Not static, because we don't want the compiler removing it */ +const char ipath_verbs_version[] = "ipath_verbs " IPATH_IDSTR; + +unsigned int ib_ipath_qp_table_size = 251; +module_param_named(qp_table_size, ib_ipath_qp_table_size, uint, S_IRUGO); +MODULE_PARM_DESC(qp_table_size, "QP table size"); + +unsigned int ib_ipath_lkey_table_size = 12; +module_param_named(lkey_table_size, ib_ipath_lkey_table_size, uint, + S_IRUGO); +MODULE_PARM_DESC(lkey_table_size, + "LKEY table size in bits (2^n, 1 <= n <= 23)"); + +unsigned int ib_ipath_debug; /* debug mask */ +module_param_named(debug, ib_ipath_debug, uint, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(debug, "Verbs debug mask"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("PathScale "); +MODULE_DESCRIPTION("Pathscale InfiniPath driver"); + +const int ib_ipath_state_ops[IB_QPS_ERR + 1] = { + [IB_QPS_RESET] = 0, + [IB_QPS_INIT] = IPATH_POST_RECV_OK, + [IB_QPS_RTR] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK, + [IB_QPS_RTS] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK | + IPATH_POST_SEND_OK | IPATH_PROCESS_SEND_OK, + [IB_QPS_SQD] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK | + IPATH_POST_SEND_OK, + [IB_QPS_SQE] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK, + [IB_QPS_ERR] = 0, +}; + +/* + * Translate ib_wr_opcode into ib_wc_opcode. + */ +const enum ib_wc_opcode ib_ipath_wc_opcode[] = { + [IB_WR_RDMA_WRITE] = IB_WC_RDMA_WRITE, + [IB_WR_RDMA_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE, + [IB_WR_SEND] = IB_WC_SEND, + [IB_WR_SEND_WITH_IMM] = IB_WC_SEND, + [IB_WR_RDMA_READ] = IB_WC_RDMA_READ, + [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP, + [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD +}; + +/* + * System image GUID. + */ +__be64 sys_image_guid; + +/** + * ipath_copy_sge - copy data to SGE memory + * @ss: the SGE state + * @data: the data to copy + * @length: the length of the data + */ +void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length) +{ + struct ipath_sge *sge = &ss->sge; + + while (length) { + u32 len = sge->length; + + BUG_ON(len == 0); + if (len > length) + len = length; + memcpy(sge->vaddr, data, len); + sge->vaddr += len; + sge->length -= len; + sge->sge_length -= len; + if (sge->sge_length == 0) { + if (--ss->num_sge) + *sge = *ss->sg_list++; + } else if (sge->length == 0 && sge->mr != NULL) { + if (++sge->n >= IPATH_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + break; + sge->n = 0; + } + sge->vaddr = + sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = + sge->mr->map[sge->m]->segs[sge->n].length; + } + data += len; + length -= len; + } +} + +/** + * ipath_skip_sge - skip over SGE memory - XXX almost dup of prev func + * @ss: the SGE state + * @length: the number of bytes to skip + */ +void ipath_skip_sge(struct ipath_sge_state *ss, u32 length) +{ + struct ipath_sge *sge = &ss->sge; + + while (length > sge->sge_length) { + length -= sge->sge_length; + ss->sge = *ss->sg_list++; + } + while (length) { + u32 len = sge->length; + + BUG_ON(len == 0); + if (len > length) + len = length; + sge->vaddr += len; + sge->length -= len; + sge->sge_length -= len; + if (sge->sge_length == 0) { + if (--ss->num_sge) + *sge = *ss->sg_list++; + } else if (sge->length == 0 && sge->mr != NULL) { + if (++sge->n >= IPATH_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + break; + sge->n = 0; + } + sge->vaddr = + sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = + sge->mr->map[sge->m]->segs[sge->n].length; + } + length -= len; + } +} + +/** + * ipath_post_send - post a send on a QP + * @ibqp: the QP to post the send on + * @wr: the list of work requests to post + * @bad_wr: the first bad WR is put here + * + * This may be called from interrupt context. + */ +static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + struct ipath_qp *qp = to_iqp(ibqp); + int err = 0; + + /* Check that state is OK to post send. */ + if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) { + *bad_wr = wr; + err = -EINVAL; + goto bail; + } + + for (; wr; wr = wr->next) { + switch (qp->ibqp.qp_type) { + case IB_QPT_UC: + case IB_QPT_RC: + err = ipath_post_rc_send(qp, wr); + break; + + case IB_QPT_SMI: + case IB_QPT_GSI: + case IB_QPT_UD: + err = ipath_post_ud_send(qp, wr); + break; + + default: + err = -EINVAL; + } + if (err) { + *bad_wr = wr; + break; + } + } + +bail: + return err; +} + +/** + * ipath_post_receive - post a receive on a QP + * @ibqp: the QP to post the receive on + * @wr: the WR to post + * @bad_wr: the first bad WR is put here + * + * This may be called from interrupt context. + */ +static int ipath_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct ipath_qp *qp = to_iqp(ibqp); + unsigned long flags; + int ret; + + /* Check that state is OK to post receive. */ + if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK)) { + *bad_wr = wr; + ret = -EINVAL; + goto bail; + } + + for (; wr; wr = wr->next) { + struct ipath_rwqe *wqe; + u32 next; + int i, j; + + if (wr->num_sge > qp->r_rq.max_sge) { + *bad_wr = wr; + ret = -ENOMEM; + goto bail; + } + + spin_lock_irqsave(&qp->r_rq.lock, flags); + next = qp->r_rq.head + 1; + if (next >= qp->r_rq.size) + next = 0; + if (next == qp->r_rq.tail) { + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + *bad_wr = wr; + ret = -ENOMEM; + goto bail; + } + + wqe = get_rwqe_ptr(&qp->r_rq, qp->r_rq.head); + wqe->wr_id = wr->wr_id; + wqe->sg_list[0].mr = NULL; + wqe->sg_list[0].vaddr = NULL; + wqe->sg_list[0].length = 0; + wqe->sg_list[0].sge_length = 0; + wqe->length = 0; + for (i = 0, j = 0; i < wr->num_sge; i++) { + /* Check LKEY */ + if (to_ipd(qp->ibqp.pd)->user && + wr->sg_list[i].lkey == 0) { + spin_unlock_irqrestore(&qp->r_rq.lock, + flags); + *bad_wr = wr; + ret = -EINVAL; + goto bail; + } + if (wr->sg_list[i].length == 0) + continue; + if (!ipath_lkey_ok( + &to_idev(qp->ibqp.device)->lk_table, + &wqe->sg_list[j], &wr->sg_list[i], + IB_ACCESS_LOCAL_WRITE)) { + spin_unlock_irqrestore(&qp->r_rq.lock, + flags); + *bad_wr = wr; + ret = -EINVAL; + goto bail; + } + wqe->length += wr->sg_list[i].length; + j++; + } + wqe->num_sge = j; + qp->r_rq.head = next; + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + } + ret = 0; + +bail: + return ret; +} + +/** + * ipath_qp_rcv - processing an incoming packet on a QP + * @dev: the device the packet came on + * @hdr: the packet header + * @has_grh: true if the packet has a GRH + * @data: the packet data + * @tlen: the packet length + * @qp: the QP the packet came on + * + * This is called from ipath_ib_rcv() to process an incoming packet + * for the given QP. + * Called at interrupt level. + */ +static void ipath_qp_rcv(struct ipath_ibdev *dev, + struct ipath_ib_header *hdr, int has_grh, + void *data, u32 tlen, struct ipath_qp *qp) +{ + /* Check for valid receive state. */ + if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) { + dev->n_pkt_drops++; + return; + } + + switch (qp->ibqp.qp_type) { + case IB_QPT_SMI: + case IB_QPT_GSI: + case IB_QPT_UD: + ipath_ud_rcv(dev, hdr, has_grh, data, tlen, qp); + break; + + case IB_QPT_RC: + ipath_rc_rcv(dev, hdr, has_grh, data, tlen, qp); + break; + + case IB_QPT_UC: + ipath_uc_rcv(dev, hdr, has_grh, data, tlen, qp); + break; + + default: + break; + } +} + +/** + * ipath_ib_rcv - process and incoming packet + * @arg: the device pointer + * @rhdr: the header of the packet + * @data: the packet data + * @tlen: the packet length + * + * This is called from ipath_kreceive() to process an incoming packet at + * interrupt level. Tlen is the length of the header + data + CRC in bytes. + */ +static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen) +{ + struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; + struct ipath_ib_header *hdr = rhdr; + struct ipath_other_headers *ohdr; + struct ipath_qp *qp; + u32 qp_num; + int lnh; + u8 opcode; + u16 lid; + + if (unlikely(dev == NULL)) + goto bail; + + if (unlikely(tlen < 24)) { /* LRH+BTH+CRC */ + dev->rcv_errors++; + goto bail; + } + + /* Check for a valid destination LID (see ch. 7.11.1). */ + lid = be16_to_cpu(hdr->lrh[1]); + if (lid < IPS_MULTICAST_LID_BASE) { + lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); + if (unlikely(lid != ipath_layer_get_lid(dev->dd))) { + dev->rcv_errors++; + goto bail; + } + } + + /* Check for GRH */ + lnh = be16_to_cpu(hdr->lrh[0]) & 3; + if (lnh == IPS_LRH_BTH) + ohdr = &hdr->u.oth; + else if (lnh == IPS_LRH_GRH) + ohdr = &hdr->u.l.oth; + else { + dev->rcv_errors++; + goto bail; + } + + opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + dev->opstats[opcode].n_bytes += tlen; + dev->opstats[opcode].n_packets++; + + /* Get the destination QP number. */ + qp_num = be32_to_cpu(ohdr->bth[1]) & IPS_QPN_MASK; + if (qp_num == IPS_MULTICAST_QPN) { + struct ipath_mcast *mcast; + struct ipath_mcast_qp *p; + + mcast = ipath_mcast_find(&hdr->u.l.grh.dgid); + if (mcast == NULL) { + dev->n_pkt_drops++; + goto bail; + } + dev->n_multicast_rcv++; + list_for_each_entry_rcu(p, &mcast->qp_list, list) + ipath_qp_rcv(dev, hdr, lnh == IPS_LRH_GRH, data, + tlen, p->qp); + /* + * Notify ipath_multicast_detach() if it is waiting for us + * to finish. + */ + if (atomic_dec_return(&mcast->refcount) <= 1) + wake_up(&mcast->wait); + } else { + qp = ipath_lookup_qpn(&dev->qp_table, qp_num); + if (qp) { + dev->n_unicast_rcv++; + ipath_qp_rcv(dev, hdr, lnh == IPS_LRH_GRH, data, + tlen, qp); + /* + * Notify ipath_destroy_qp() if it is waiting + * for us to finish. + */ + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); + } else + dev->n_pkt_drops++; + } + +bail:; +} + +/** + * ipath_ib_timer - verbs timer + * @arg: the device pointer + * + * This is called from ipath_do_rcv_timer() at interrupt level to check for + * QPs which need retransmits and to collect performance numbers. + */ +static void ipath_ib_timer(void *arg) +{ + struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; + struct ipath_qp *resend = NULL; + struct ipath_qp *rnr = NULL; + struct list_head *last; + struct ipath_qp *qp; + unsigned long flags; + + if (dev == NULL) + return; + + spin_lock_irqsave(&dev->pending_lock, flags); + /* Start filling the next pending queue. */ + if (++dev->pending_index >= ARRAY_SIZE(dev->pending)) + dev->pending_index = 0; + /* Save any requests still in the new queue, they have timed out. */ + last = &dev->pending[dev->pending_index]; + while (!list_empty(last)) { + qp = list_entry(last->next, struct ipath_qp, timerwait); + if (last->next == LIST_POISON1 || + last->next != &qp->timerwait || + qp->timerwait.prev != last) { + INIT_LIST_HEAD(last); + } else { + list_del(&qp->timerwait); + qp->timerwait.prev = (struct list_head *) resend; + resend = qp; + atomic_inc(&qp->refcount); + } + } + last = &dev->rnrwait; + if (!list_empty(last)) { + qp = list_entry(last->next, struct ipath_qp, timerwait); + if (--qp->s_rnr_timeout == 0) { + do { + if (last->next == LIST_POISON1 || + last->next != &qp->timerwait || + qp->timerwait.prev != last) { + INIT_LIST_HEAD(last); + break; + } + list_del(&qp->timerwait); + qp->timerwait.prev = + (struct list_head *) rnr; + rnr = qp; + if (list_empty(last)) + break; + qp = list_entry(last->next, struct ipath_qp, + timerwait); + } while (qp->s_rnr_timeout == 0); + } + } + /* + * We should only be in the started state if pma_sample_start != 0 + */ + if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_STARTED && + --dev->pma_sample_start == 0) { + dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING; + ipath_layer_snapshot_counters(dev->dd, &dev->ipath_sword, + &dev->ipath_rword, + &dev->ipath_spkts, + &dev->ipath_rpkts, + &dev->ipath_xmit_wait); + } + if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_RUNNING) { + if (dev->pma_sample_interval == 0) { + u64 ta, tb, tc, td, te; + + dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE; + ipath_layer_snapshot_counters(dev->dd, &ta, &tb, + &tc, &td, &te); + + dev->ipath_sword = ta - dev->ipath_sword; + dev->ipath_rword = tb - dev->ipath_rword; + dev->ipath_spkts = tc - dev->ipath_spkts; + dev->ipath_rpkts = td - dev->ipath_rpkts; + dev->ipath_xmit_wait = te - dev->ipath_xmit_wait; + } + else + dev->pma_sample_interval--; + } + spin_unlock_irqrestore(&dev->pending_lock, flags); + + /* XXX What if timer fires again while this is running? */ + for (qp = resend; qp != NULL; + qp = (struct ipath_qp *) qp->timerwait.prev) { + struct ib_wc wc; + + spin_lock_irqsave(&qp->s_lock, flags); + if (qp->s_last != qp->s_tail && qp->state == IB_QPS_RTS) { + dev->n_timeouts++; + ipath_restart_rc(qp, qp->s_last_psn + 1, &wc); + } + spin_unlock_irqrestore(&qp->s_lock, flags); + + /* Notify ipath_destroy_qp() if it is waiting. */ + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); + } + for (qp = rnr; qp != NULL; + qp = (struct ipath_qp *) qp->timerwait.prev) + tasklet_hi_schedule(&qp->s_task); +} + +/** + * ipath_ib_piobufavail - callback when a PIO buffer is available + * @arg: the device pointer + * + * This is called from ipath_intr() at interrupt level when a PIO buffer is + * available after ipath_verbs_send() returned an error that no buffers were + * available. Return 0 if we consumed all the PIO buffers and we still have + * QPs waiting for buffers (for now, just do a tasklet_hi_schedule and + * return one). + */ +static int ipath_ib_piobufavail(void *arg) +{ + struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; + struct ipath_qp *qp; + unsigned long flags; + + if (dev == NULL) + goto bail; + + spin_lock_irqsave(&dev->pending_lock, flags); + while (!list_empty(&dev->piowait)) { + qp = list_entry(dev->piowait.next, struct ipath_qp, + piowait); + list_del(&qp->piowait); + tasklet_hi_schedule(&qp->s_task); + } + spin_unlock_irqrestore(&dev->pending_lock, flags); + +bail: + return 1; +} + +static int ipath_query_device(struct ib_device *ibdev, + struct ib_device_attr *props) +{ + struct ipath_ibdev *dev = to_idev(ibdev); + u32 vendor, boardrev, majrev, minrev; + + memset(props, 0, sizeof(*props)); + + props->device_cap_flags = IB_DEVICE_BAD_PKEY_CNTR | + IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT | + IB_DEVICE_SYS_IMAGE_GUID; + ipath_layer_query_device(dev->dd, &vendor, &boardrev, + &majrev, &minrev); + props->vendor_id = vendor; + props->vendor_part_id = boardrev; + props->hw_ver = boardrev << 16 | majrev << 8 | minrev; + + props->sys_image_guid = dev->sys_image_guid; + + props->max_mr_size = ~0ull; + props->max_qp = 0xffff; + props->max_qp_wr = 0xffff; + props->max_sge = 255; + props->max_cq = 0xffff; + props->max_cqe = 0xffff; + props->max_mr = 0xffff; + props->max_pd = 0xffff; + props->max_qp_rd_atom = 1; + props->max_qp_init_rd_atom = 1; + /* props->max_res_rd_atom */ + props->max_srq = 0xffff; + props->max_srq_wr = 0xffff; + props->max_srq_sge = 255; + /* props->local_ca_ack_delay */ + props->atomic_cap = IB_ATOMIC_HCA; + props->max_pkeys = ipath_layer_get_npkeys(dev->dd); + props->max_mcast_grp = 0xffff; + props->max_mcast_qp_attach = 0xffff; + props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * + props->max_mcast_grp; + + return 0; +} + +const u8 ipath_cvt_physportstate[16] = { + [INFINIPATH_IBCS_LT_STATE_DISABLED] = 3, + [INFINIPATH_IBCS_LT_STATE_LINKUP] = 5, + [INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = 2, + [INFINIPATH_IBCS_LT_STATE_POLLQUIET] = 2, + [INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = 1, + [INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = 1, + [INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = 4, + [INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = 4, + [INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = 4, + [INFINIPATH_IBCS_LT_STATE_CFGIDLE] = 4, + [INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = 6, + [INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = 6, + [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6, +}; + +static int ipath_query_port(struct ib_device *ibdev, + u8 port, struct ib_port_attr *props) +{ + struct ipath_ibdev *dev = to_idev(ibdev); + enum ib_mtu mtu; + u16 lid = ipath_layer_get_lid(dev->dd); + u64 ibcstat; + + memset(props, 0, sizeof(*props)); + props->lid = lid ? lid : __constant_be16_to_cpu(IB_LID_PERMISSIVE); + props->lmc = dev->mkeyprot_resv_lmc & 7; + props->sm_lid = dev->sm_lid; + props->sm_sl = dev->sm_sl; + ibcstat = ipath_layer_get_lastibcstat(dev->dd); + props->state = ((ibcstat >> 4) & 0x3) + 1; + /* See phys_state_show() */ + props->phys_state = ipath_cvt_physportstate[ + ipath_layer_get_lastibcstat(dev->dd) & 0xf]; + props->port_cap_flags = dev->port_cap_flags; + props->gid_tbl_len = 1; + props->max_msg_sz = 4096; + props->pkey_tbl_len = ipath_layer_get_npkeys(dev->dd); + props->bad_pkey_cntr = ipath_layer_get_cr_errpkey(dev->dd) - + dev->n_pkey_violations; + props->qkey_viol_cntr = dev->qkey_violations; + props->active_width = IB_WIDTH_4X; + /* See rate_show() */ + props->active_speed = 1; /* Regular 10Mbs speed. */ + props->max_vl_num = 1; /* VLCap = VL0 */ + props->init_type_reply = 0; + + props->max_mtu = IB_MTU_4096; + switch (ipath_layer_get_ibmtu(dev->dd)) { + case 4096: + mtu = IB_MTU_4096; + break; + case 2048: + mtu = IB_MTU_2048; + break; + case 1024: + mtu = IB_MTU_1024; + break; + case 512: + mtu = IB_MTU_512; + break; + case 256: + mtu = IB_MTU_256; + break; + default: + mtu = IB_MTU_2048; + } + props->active_mtu = mtu; + props->subnet_timeout = dev->subnet_timeout; + + return 0; +} + +static int ipath_modify_device(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify) +{ + int ret; + + if (device_modify_mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID | + IB_DEVICE_MODIFY_NODE_DESC)) { + ret = -EOPNOTSUPP; + goto bail; + } + + if (device_modify_mask & IB_DEVICE_MODIFY_NODE_DESC) + memcpy(device->node_desc, device_modify->node_desc, 64); + + if (device_modify_mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID) + to_idev(device)->sys_image_guid = + cpu_to_be64(device_modify->sys_image_guid); + + ret = 0; + +bail: + return ret; +} + +static int ipath_modify_port(struct ib_device *ibdev, + u8 port, int port_modify_mask, + struct ib_port_modify *props) +{ + struct ipath_ibdev *dev = to_idev(ibdev); + + dev->port_cap_flags |= props->set_port_cap_mask; + dev->port_cap_flags &= ~props->clr_port_cap_mask; + if (port_modify_mask & IB_PORT_SHUTDOWN) + ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKDOWN); + if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR) + dev->qkey_violations = 0; + return 0; +} + +static int ipath_query_gid(struct ib_device *ibdev, u8 port, + int index, union ib_gid *gid) +{ + struct ipath_ibdev *dev = to_idev(ibdev); + int ret; + + if (index >= 1) { + ret = -EINVAL; + goto bail; + } + gid->global.subnet_prefix = dev->gid_prefix; + gid->global.interface_id = ipath_layer_get_guid(dev->dd); + + ret = 0; + +bail: + return ret; +} + +static struct ib_pd *ipath_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct ipath_pd *pd; + struct ib_pd *ret; + + pd = kmalloc(sizeof *pd, GFP_KERNEL); + if (!pd) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + /* ib_alloc_pd() will initialize pd->ibpd. */ + pd->user = udata != NULL; + + ret = &pd->ibpd; + +bail: + return ret; +} + +static int ipath_dealloc_pd(struct ib_pd *ibpd) +{ + struct ipath_pd *pd = to_ipd(ibpd); + + kfree(pd); + + return 0; +} + +/** + * ipath_create_ah - create an address handle + * @pd: the protection domain + * @ah_attr: the attributes of the AH + * + * This may be called from interrupt context. + */ +static struct ib_ah *ipath_create_ah(struct ib_pd *pd, + struct ib_ah_attr *ah_attr) +{ + struct ipath_ah *ah; + struct ib_ah *ret; + + /* A multicast address requires a GRH (see ch. 8.4.1). */ + if (ah_attr->dlid >= IPS_MULTICAST_LID_BASE && + ah_attr->dlid != IPS_PERMISSIVE_LID && + !(ah_attr->ah_flags & IB_AH_GRH)) { + ret = ERR_PTR(-EINVAL); + goto bail; + } + + ah = kmalloc(sizeof *ah, GFP_ATOMIC); + if (!ah) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + /* ib_create_ah() will initialize ah->ibah. */ + ah->attr = *ah_attr; + + ret = &ah->ibah; + +bail: + return ret; +} + +/** + * ipath_destroy_ah - destroy an address handle + * @ibah: the AH to destroy + * + * This may be called from interrupt context. + */ +static int ipath_destroy_ah(struct ib_ah *ibah) +{ + struct ipath_ah *ah = to_iah(ibah); + + kfree(ah); + + return 0; +} + +static int ipath_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) +{ + struct ipath_ah *ah = to_iah(ibah); + + *ah_attr = ah->attr; + + return 0; +} + +static int ipath_query_pkey(struct ib_device *ibdev, u8 port, u16 index, + u16 *pkey) +{ + struct ipath_ibdev *dev = to_idev(ibdev); + int ret; + + if (index >= ipath_layer_get_npkeys(dev->dd)) { + ret = -EINVAL; + goto bail; + } + + *pkey = ipath_layer_get_pkey(dev->dd, index); + ret = 0; + +bail: + return ret; +} + + +/** + * ipath_alloc_ucontext - allocate a ucontest + * @ibdev: the infiniband device + * @udata: not used by the InfiniPath driver + */ + +static struct ib_ucontext *ipath_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata) +{ + struct ipath_ucontext *context; + struct ib_ucontext *ret; + + context = kmalloc(sizeof *context, GFP_KERNEL); + if (!context) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + ret = &context->ibucontext; + +bail: + return ret; +} + +static int ipath_dealloc_ucontext(struct ib_ucontext *context) +{ + kfree(to_iucontext(context)); + return 0; +} + +static int ipath_verbs_register_sysfs(struct ib_device *dev); + +/** + * ipath_register_ib_device - register our device with the infiniband core + * @unit: the device number to register + * @dd: the device data structure + * Return the allocated ipath_ibdev pointer or NULL on error. + */ +static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd) +{ + struct ipath_ibdev *idev; + struct ib_device *dev; + int ret; + + idev = (struct ipath_ibdev *)ib_alloc_device(sizeof *idev); + if (idev == NULL) + goto bail; + + dev = &idev->ibdev; + + /* Only need to initialize non-zero fields. */ + spin_lock_init(&idev->qp_table.lock); + spin_lock_init(&idev->lk_table.lock); + idev->sm_lid = __constant_be16_to_cpu(IB_LID_PERMISSIVE); + /* Set the prefix to the default value (see ch. 4.1.1) */ + idev->gid_prefix = __constant_cpu_to_be64(0xfe80000000000000ULL); + + ret = ipath_init_qp_table(idev, ib_ipath_qp_table_size); + if (ret) + goto err_qp; + + /* + * The top ib_ipath_lkey_table_size bits are used to index the + * table. The lower 8 bits can be owned by the user (copied from + * the LKEY). The remaining bits act as a generation number or tag. + */ + idev->lk_table.max = 1 << ib_ipath_lkey_table_size; + idev->lk_table.table = kzalloc(idev->lk_table.max * + sizeof(*idev->lk_table.table), + GFP_KERNEL); + if (idev->lk_table.table == NULL) { + ret = -ENOMEM; + goto err_lk; + } + spin_lock_init(&idev->pending_lock); + INIT_LIST_HEAD(&idev->pending[0]); + INIT_LIST_HEAD(&idev->pending[1]); + INIT_LIST_HEAD(&idev->pending[2]); + INIT_LIST_HEAD(&idev->piowait); + INIT_LIST_HEAD(&idev->rnrwait); + idev->pending_index = 0; + idev->port_cap_flags = + IB_PORT_SYS_IMAGE_GUID_SUP | IB_PORT_CLIENT_REG_SUP; + idev->pma_counter_select[0] = IB_PMA_PORT_XMIT_DATA; + idev->pma_counter_select[1] = IB_PMA_PORT_RCV_DATA; + idev->pma_counter_select[2] = IB_PMA_PORT_XMIT_PKTS; + idev->pma_counter_select[3] = IB_PMA_PORT_RCV_PKTS; + idev->pma_counter_select[5] = IB_PMA_PORT_XMIT_WAIT; + idev->link_width_enabled = 3; /* 1x or 4x */ + + /* + * The system image GUID is supposed to be the same for all + * IB HCAs in a single system but since there can be other + * device types in the system, we can't be sure this is unique. + */ + if (!sys_image_guid) + sys_image_guid = ipath_layer_get_guid(dd); + idev->sys_image_guid = sys_image_guid; + idev->ib_unit = unit; + idev->dd = dd; + + strlcpy(dev->name, "ipath%d", IB_DEVICE_NAME_MAX); + dev->node_guid = ipath_layer_get_guid(dd); + dev->uverbs_abi_ver = IPATH_UVERBS_ABI_VERSION; + dev->uverbs_cmd_mask = + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_CREATE_AH) | + (1ull << IB_USER_VERBS_CMD_DESTROY_AH) | + (1ull << IB_USER_VERBS_CMD_QUERY_AH) | + (1ull << IB_USER_VERBS_CMD_REG_MR) | + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | + (1ull << IB_USER_VERBS_CMD_POLL_CQ) | + (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) | + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | + (1ull << IB_USER_VERBS_CMD_QUERY_QP) | + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | + (1ull << IB_USER_VERBS_CMD_POST_SEND) | + (1ull << IB_USER_VERBS_CMD_POST_RECV) | + (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | + (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | + (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) | + (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV); + dev->node_type = IB_NODE_CA; + dev->phys_port_cnt = 1; + dev->dma_device = ipath_layer_get_device(dd); + dev->class_dev.dev = dev->dma_device; + dev->query_device = ipath_query_device; + dev->modify_device = ipath_modify_device; + dev->query_port = ipath_query_port; + dev->modify_port = ipath_modify_port; + dev->query_pkey = ipath_query_pkey; + dev->query_gid = ipath_query_gid; + dev->alloc_ucontext = ipath_alloc_ucontext; + dev->dealloc_ucontext = ipath_dealloc_ucontext; + dev->alloc_pd = ipath_alloc_pd; + dev->dealloc_pd = ipath_dealloc_pd; + dev->create_ah = ipath_create_ah; + dev->destroy_ah = ipath_destroy_ah; + dev->query_ah = ipath_query_ah; + dev->create_srq = ipath_create_srq; + dev->modify_srq = ipath_modify_srq; + dev->query_srq = ipath_query_srq; + dev->destroy_srq = ipath_destroy_srq; + dev->create_qp = ipath_create_qp; + dev->modify_qp = ipath_modify_qp; + dev->query_qp = ipath_query_qp; + dev->destroy_qp = ipath_destroy_qp; + dev->post_send = ipath_post_send; + dev->post_recv = ipath_post_receive; + dev->post_srq_recv = ipath_post_srq_receive; + dev->create_cq = ipath_create_cq; + dev->destroy_cq = ipath_destroy_cq; + dev->resize_cq = ipath_resize_cq; + dev->poll_cq = ipath_poll_cq; + dev->req_notify_cq = ipath_req_notify_cq; + dev->get_dma_mr = ipath_get_dma_mr; + dev->reg_phys_mr = ipath_reg_phys_mr; + dev->reg_user_mr = ipath_reg_user_mr; + dev->dereg_mr = ipath_dereg_mr; + dev->alloc_fmr = ipath_alloc_fmr; + dev->map_phys_fmr = ipath_map_phys_fmr; + dev->unmap_fmr = ipath_unmap_fmr; + dev->dealloc_fmr = ipath_dealloc_fmr; + dev->attach_mcast = ipath_multicast_attach; + dev->detach_mcast = ipath_multicast_detach; + dev->process_mad = ipath_process_mad; + + snprintf(dev->node_desc, sizeof(dev->node_desc), + IPATH_IDSTR " %s kernel_SMA", system_utsname.nodename); + + ret = ib_register_device(dev); + if (ret) + goto err_reg; + + if (ipath_verbs_register_sysfs(dev)) + goto err_class; + + ipath_layer_enable_timer(dd); + + goto bail; + +err_class: + ib_unregister_device(dev); +err_reg: + kfree(idev->lk_table.table); +err_lk: + kfree(idev->qp_table.table); +err_qp: + ib_dealloc_device(dev); + _VERBS_ERROR("ib_ipath%d cannot register verbs (%d)!\n", + unit, -ret); + idev = NULL; + +bail: + return idev; +} + +static void ipath_unregister_ib_device(void *arg) +{ + struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; + struct ib_device *ibdev = &dev->ibdev; + + ipath_layer_disable_timer(dev->dd); + + ib_unregister_device(ibdev); + + if (!list_empty(&dev->pending[0]) || + !list_empty(&dev->pending[1]) || + !list_empty(&dev->pending[2])) + _VERBS_ERROR("ipath%d pending list not empty!\n", + dev->ib_unit); + if (!list_empty(&dev->piowait)) + _VERBS_ERROR("ipath%d piowait list not empty!\n", + dev->ib_unit); + if (!list_empty(&dev->rnrwait)) + _VERBS_ERROR("ipath%d rnrwait list not empty!\n", + dev->ib_unit); + if (!ipath_mcast_tree_empty()) + _VERBS_ERROR("ipath%d multicast table memory leak!\n", + dev->ib_unit); + /* + * Note that ipath_unregister_ib_device() can be called before all + * the QPs are destroyed! + */ + ipath_free_all_qps(&dev->qp_table); + kfree(dev->qp_table.table); + kfree(dev->lk_table.table); + ib_dealloc_device(ibdev); +} + +int __init ipath_verbs_init(void) +{ + return ipath_verbs_register(ipath_register_ib_device, + ipath_unregister_ib_device, + ipath_ib_piobufavail, ipath_ib_rcv, + ipath_ib_timer); +} + +void __exit ipath_verbs_cleanup(void) +{ + ipath_verbs_unregister(); +} + +static ssize_t show_rev(struct class_device *cdev, char *buf) +{ + struct ipath_ibdev *dev = + container_of(cdev, struct ipath_ibdev, ibdev.class_dev); + int vendor, boardrev, majrev, minrev; + + ipath_layer_query_device(dev->dd, &vendor, &boardrev, + &majrev, &minrev); + return sprintf(buf, "%d.%d\n", majrev, minrev); +} + +static ssize_t show_hca(struct class_device *cdev, char *buf) +{ + struct ipath_ibdev *dev = + container_of(cdev, struct ipath_ibdev, ibdev.class_dev); + int ret; + + ret = ipath_layer_get_boardname(dev->dd, buf, 128); + if (ret < 0) + goto bail; + strcat(buf, "\n"); + ret = strlen(buf); + +bail: + return ret; +} + +static ssize_t show_stats(struct class_device *cdev, char *buf) +{ + struct ipath_ibdev *dev = + container_of(cdev, struct ipath_ibdev, ibdev.class_dev); + int i; + int len; + + len = sprintf(buf, + "RC resends %d\n" + "RC QACKs %d\n" + "RC ACKs %d\n" + "RC SEQ NAKs %d\n" + "RC RDMA seq %d\n" + "RC RNR NAKs %d\n" + "RC OTH NAKs %d\n" + "RC timeouts %d\n" + "RC RDMA dup %d\n" + "piobuf wait %d\n" + "no piobuf %d\n" + "PKT drops %d\n" + "WQE errs %d\n", + dev->n_rc_resends, dev->n_rc_qacks, dev->n_rc_acks, + dev->n_seq_naks, dev->n_rdma_seq, dev->n_rnr_naks, + dev->n_other_naks, dev->n_timeouts, + dev->n_rdma_dup_busy, dev->n_piowait, + dev->n_no_piobuf, dev->n_pkt_drops, dev->n_wqe_errs); + for (i = 0; i < ARRAY_SIZE(dev->opstats); i++) { + const struct ipath_opcode_stats *si = &dev->opstats[i]; + + if (!si->n_packets && !si->n_bytes) + continue; + len += sprintf(buf + len, "%02x %llu/%llu\n", i, + (unsigned long long) si->n_packets, + (unsigned long long) si->n_bytes); + } + return len; +} + +static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); +static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); +static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_hca, NULL); +static CLASS_DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL); + +static struct class_device_attribute *ipath_class_attributes[] = { + &class_device_attr_hw_rev, + &class_device_attr_hca_type, + &class_device_attr_board_id, + &class_device_attr_stats +}; + +static int ipath_verbs_register_sysfs(struct ib_device *dev) +{ + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(ipath_class_attributes); ++i) + if (class_device_create_file(&dev->class_dev, + ipath_class_attributes[i])) { + ret = 1; + goto bail; + } + + ret = 0; + +bail: + return ret; +} + +module_init(ipath_verbs_init); +module_exit(ipath_verbs_cleanup); diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h new file mode 100644 index 000000000000..b824632b2a8c --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IPATH_VERBS_H +#define IPATH_VERBS_H + +#include +#include +#include +#include +#include + +#include "ipath_layer.h" +#include "verbs_debug.h" + +#define QPN_MAX (1 << 24) +#define QPNMAP_ENTRIES (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE) + +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define IPATH_UVERBS_ABI_VERSION 1 + +/* + * Define an ib_cq_notify value that is not valid so we know when CQ + * notifications are armed. + */ +#define IB_CQ_NONE (IB_CQ_NEXT_COMP + 1) + +#define IB_RNR_NAK 0x20 +#define IB_NAK_PSN_ERROR 0x60 +#define IB_NAK_INVALID_REQUEST 0x61 +#define IB_NAK_REMOTE_ACCESS_ERROR 0x62 +#define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63 +#define IB_NAK_INVALID_RD_REQUEST 0x64 + +#define IPATH_POST_SEND_OK 0x01 +#define IPATH_POST_RECV_OK 0x02 +#define IPATH_PROCESS_RECV_OK 0x04 +#define IPATH_PROCESS_SEND_OK 0x08 + +/* IB Performance Manager status values */ +#define IB_PMA_SAMPLE_STATUS_DONE 0x00 +#define IB_PMA_SAMPLE_STATUS_STARTED 0x01 +#define IB_PMA_SAMPLE_STATUS_RUNNING 0x02 + +/* Mandatory IB performance counter select values. */ +#define IB_PMA_PORT_XMIT_DATA __constant_htons(0x0001) +#define IB_PMA_PORT_RCV_DATA __constant_htons(0x0002) +#define IB_PMA_PORT_XMIT_PKTS __constant_htons(0x0003) +#define IB_PMA_PORT_RCV_PKTS __constant_htons(0x0004) +#define IB_PMA_PORT_XMIT_WAIT __constant_htons(0x0005) + +struct ib_reth { + __be64 vaddr; + __be32 rkey; + __be32 length; +} __attribute__ ((packed)); + +struct ib_atomic_eth { + __be64 vaddr; + __be32 rkey; + __be64 swap_data; + __be64 compare_data; +} __attribute__ ((packed)); + +struct ipath_other_headers { + __be32 bth[3]; + union { + struct { + __be32 deth[2]; + __be32 imm_data; + } ud; + struct { + struct ib_reth reth; + __be32 imm_data; + } rc; + struct { + __be32 aeth; + __be64 atomic_ack_eth; + } at; + __be32 imm_data; + __be32 aeth; + struct ib_atomic_eth atomic_eth; + } u; +} __attribute__ ((packed)); + +/* + * Note that UD packets with a GRH header are 8+40+12+8 = 68 bytes + * long (72 w/ imm_data). Only the first 56 bytes of the IB header + * will be in the eager header buffer. The remaining 12 or 16 bytes + * are in the data buffer. + */ +struct ipath_ib_header { + __be16 lrh[4]; + union { + struct { + struct ib_grh grh; + struct ipath_other_headers oth; + } l; + struct ipath_other_headers oth; + } u; +} __attribute__ ((packed)); + +/* + * There is one struct ipath_mcast for each multicast GID. + * All attached QPs are then stored as a list of + * struct ipath_mcast_qp. + */ +struct ipath_mcast_qp { + struct list_head list; + struct ipath_qp *qp; +}; + +struct ipath_mcast { + struct rb_node rb_node; + union ib_gid mgid; + struct list_head qp_list; + wait_queue_head_t wait; + atomic_t refcount; +}; + +/* Memory region */ +struct ipath_mr { + struct ib_mr ibmr; + struct ipath_mregion mr; /* must be last */ +}; + +/* Fast memory region */ +struct ipath_fmr { + struct ib_fmr ibfmr; + u8 page_shift; + struct ipath_mregion mr; /* must be last */ +}; + +/* Protection domain */ +struct ipath_pd { + struct ib_pd ibpd; + int user; /* non-zero if created from user space */ +}; + +/* Address Handle */ +struct ipath_ah { + struct ib_ah ibah; + struct ib_ah_attr attr; +}; + +/* + * Quick description of our CQ/QP locking scheme: + * + * We have one global lock that protects dev->cq/qp_table. Each + * struct ipath_cq/qp also has its own lock. An individual qp lock + * may be taken inside of an individual cq lock. Both cqs attached to + * a qp may be locked, with the send cq locked first. No other + * nesting should be done. + * + * Each struct ipath_cq/qp also has an atomic_t ref count. The + * pointer from the cq/qp_table to the struct counts as one reference. + * This reference also is good for access through the consumer API, so + * modifying the CQ/QP etc doesn't need to take another reference. + * Access because of a completion being polled does need a reference. + * + * Finally, each struct ipath_cq/qp has a wait_queue_head_t for the + * destroy function to sleep on. + * + * This means that access from the consumer API requires nothing but + * taking the struct's lock. + * + * Access because of a completion event should go as follows: + * - lock cq/qp_table and look up struct + * - increment ref count in struct + * - drop cq/qp_table lock + * - lock struct, do your thing, and unlock struct + * - decrement ref count; if zero, wake up waiters + * + * To destroy a CQ/QP, we can do the following: + * - lock cq/qp_table, remove pointer, unlock cq/qp_table lock + * - decrement ref count + * - wait_event until ref count is zero + * + * It is the consumer's responsibilty to make sure that no QP + * operations (WQE posting or state modification) are pending when the + * QP is destroyed. Also, the consumer must make sure that calls to + * qp_modify are serialized. + * + * Possible optimizations (wait for profile data to see if/where we + * have locks bouncing between CPUs): + * - split cq/qp table lock into n separate (cache-aligned) locks, + * indexed (say) by the page in the table + */ + +struct ipath_cq { + struct ib_cq ibcq; + struct tasklet_struct comptask; + spinlock_t lock; + u8 notify; + u8 triggered; + u32 head; /* new records added to the head */ + u32 tail; /* poll_cq() reads from here. */ + struct ib_wc *queue; /* this is actually ibcq.cqe + 1 */ +}; + +/* + * Send work request queue entry. + * The size of the sg_list is determined when the QP is created and stored + * in qp->s_max_sge. + */ +struct ipath_swqe { + struct ib_send_wr wr; /* don't use wr.sg_list */ + u32 psn; /* first packet sequence number */ + u32 lpsn; /* last packet sequence number */ + u32 ssn; /* send sequence number */ + u32 length; /* total length of data in sg_list */ + struct ipath_sge sg_list[0]; +}; + +/* + * Receive work request queue entry. + * The size of the sg_list is determined when the QP is created and stored + * in qp->r_max_sge. + */ +struct ipath_rwqe { + u64 wr_id; + u32 length; /* total length of data in sg_list */ + u8 num_sge; + struct ipath_sge sg_list[0]; +}; + +struct ipath_rq { + spinlock_t lock; + u32 head; /* new work requests posted to the head */ + u32 tail; /* receives pull requests from here. */ + u32 size; /* size of RWQE array */ + u8 max_sge; + struct ipath_rwqe *wq; /* RWQE array */ +}; + +struct ipath_srq { + struct ib_srq ibsrq; + struct ipath_rq rq; + /* send signal when number of RWQEs < limit */ + u32 limit; +}; + +/* + * Variables prefixed with s_ are for the requester (sender). + * Variables prefixed with r_ are for the responder (receiver). + * Variables prefixed with ack_ are for responder replies. + * + * Common variables are protected by both r_rq.lock and s_lock in that order + * which only happens in modify_qp() or changing the QP 'state'. + */ +struct ipath_qp { + struct ib_qp ibqp; + struct ipath_qp *next; /* link list for QPN hash table */ + struct list_head piowait; /* link for wait PIO buf */ + struct list_head timerwait; /* link for waiting for timeouts */ + struct ib_ah_attr remote_ah_attr; + struct ipath_ib_header s_hdr; /* next packet header to send */ + atomic_t refcount; + wait_queue_head_t wait; + struct tasklet_struct s_task; + struct ipath_sge_state *s_cur_sge; + struct ipath_sge_state s_sge; /* current send request data */ + /* current RDMA read send data */ + struct ipath_sge_state s_rdma_sge; + struct ipath_sge_state r_sge; /* current receive data */ + spinlock_t s_lock; + unsigned long s_flags; + u32 s_hdrwords; /* size of s_hdr in 32 bit words */ + u32 s_cur_size; /* size of send packet in bytes */ + u32 s_len; /* total length of s_sge */ + u32 s_rdma_len; /* total length of s_rdma_sge */ + u32 s_next_psn; /* PSN for next request */ + u32 s_last_psn; /* last response PSN processed */ + u32 s_psn; /* current packet sequence number */ + u32 s_rnr_timeout; /* number of milliseconds for RNR timeout */ + u32 s_ack_psn; /* PSN for next ACK or RDMA_READ */ + u64 s_ack_atomic; /* data for atomic ACK */ + u64 r_wr_id; /* ID for current receive WQE */ + u64 r_atomic_data; /* data for last atomic op */ + u32 r_atomic_psn; /* PSN of last atomic op */ + u32 r_len; /* total length of r_sge */ + u32 r_rcv_len; /* receive data len processed */ + u32 r_psn; /* expected rcv packet sequence number */ + u8 state; /* QP state */ + u8 s_state; /* opcode of last packet sent */ + u8 s_ack_state; /* opcode of packet to ACK */ + u8 s_nak_state; /* non-zero if NAK is pending */ + u8 r_state; /* opcode of last packet received */ + u8 r_reuse_sge; /* for UC receive errors */ + u8 r_sge_inx; /* current index into sg_list */ + u8 s_max_sge; /* size of s_wq->sg_list */ + u8 qp_access_flags; + u8 s_retry_cnt; /* number of times to retry */ + u8 s_rnr_retry_cnt; + u8 s_min_rnr_timer; + u8 s_retry; /* requester retry counter */ + u8 s_rnr_retry; /* requester RNR retry counter */ + u8 s_pkey_index; /* PKEY index to use */ + enum ib_mtu path_mtu; + atomic_t msn; /* message sequence number */ + u32 remote_qpn; + u32 qkey; /* QKEY for this QP (for UD or RD) */ + u32 s_size; /* send work queue size */ + u32 s_head; /* new entries added here */ + u32 s_tail; /* next entry to process */ + u32 s_cur; /* current work queue entry */ + u32 s_last; /* last un-ACK'ed entry */ + u32 s_ssn; /* SSN of tail entry */ + u32 s_lsn; /* limit sequence number (credit) */ + struct ipath_swqe *s_wq; /* send work queue */ + struct ipath_rq r_rq; /* receive work queue */ +}; + +/* + * Bit definitions for s_flags. + */ +#define IPATH_S_BUSY 0 +#define IPATH_S_SIGNAL_REQ_WR 1 + +/* + * Since struct ipath_swqe is not a fixed size, we can't simply index into + * struct ipath_qp.s_wq. This function does the array index computation. + */ +static inline struct ipath_swqe *get_swqe_ptr(struct ipath_qp *qp, + unsigned n) +{ + return (struct ipath_swqe *)((char *)qp->s_wq + + (sizeof(struct ipath_swqe) + + qp->s_max_sge * + sizeof(struct ipath_sge)) * n); +} + +/* + * Since struct ipath_rwqe is not a fixed size, we can't simply index into + * struct ipath_rq.wq. This function does the array index computation. + */ +static inline struct ipath_rwqe *get_rwqe_ptr(struct ipath_rq *rq, + unsigned n) +{ + return (struct ipath_rwqe *) + ((char *) rq->wq + + (sizeof(struct ipath_rwqe) + + rq->max_sge * sizeof(struct ipath_sge)) * n); +} + +/* + * QPN-map pages start out as NULL, they get allocated upon + * first use and are never deallocated. This way, + * large bitmaps are not allocated unless large numbers of QPs are used. + */ +struct qpn_map { + atomic_t n_free; + void *page; +}; + +struct ipath_qp_table { + spinlock_t lock; + u32 last; /* last QP number allocated */ + u32 max; /* size of the hash table */ + u32 nmaps; /* size of the map table */ + struct ipath_qp **table; + /* bit map of free numbers */ + struct qpn_map map[QPNMAP_ENTRIES]; +}; + +struct ipath_lkey_table { + spinlock_t lock; + u32 next; /* next unused index (speeds search) */ + u32 gen; /* generation count */ + u32 max; /* size of the table */ + struct ipath_mregion **table; +}; + +struct ipath_opcode_stats { + u64 n_packets; /* number of packets */ + u64 n_bytes; /* total number of bytes */ +}; + +struct ipath_ibdev { + struct ib_device ibdev; + struct list_head dev_list; + struct ipath_devdata *dd; + int ib_unit; /* This is the device number */ + u16 sm_lid; /* in host order */ + u8 sm_sl; + u8 mkeyprot_resv_lmc; + /* non-zero when timer is set */ + unsigned long mkey_lease_timeout; + + /* The following fields are really per port. */ + struct ipath_qp_table qp_table; + struct ipath_lkey_table lk_table; + struct list_head pending[3]; /* FIFO of QPs waiting for ACKs */ + struct list_head piowait; /* list for wait PIO buf */ + /* list of QPs waiting for RNR timer */ + struct list_head rnrwait; + spinlock_t pending_lock; + __be64 sys_image_guid; /* in network order */ + __be64 gid_prefix; /* in network order */ + __be64 mkey; + u64 ipath_sword; /* total dwords sent (sample result) */ + u64 ipath_rword; /* total dwords received (sample result) */ + u64 ipath_spkts; /* total packets sent (sample result) */ + u64 ipath_rpkts; /* total packets received (sample result) */ + /* # of ticks no data sent (sample result) */ + u64 ipath_xmit_wait; + u64 rcv_errors; /* # of packets with SW detected rcv errs */ + u64 n_unicast_xmit; /* total unicast packets sent */ + u64 n_unicast_rcv; /* total unicast packets received */ + u64 n_multicast_xmit; /* total multicast packets sent */ + u64 n_multicast_rcv; /* total multicast packets received */ + u64 n_symbol_error_counter; /* starting count for PMA */ + u64 n_link_error_recovery_counter; /* starting count for PMA */ + u64 n_link_downed_counter; /* starting count for PMA */ + u64 n_port_rcv_errors; /* starting count for PMA */ + u64 n_port_rcv_remphys_errors; /* starting count for PMA */ + u64 n_port_xmit_discards; /* starting count for PMA */ + u64 n_port_xmit_data; /* starting count for PMA */ + u64 n_port_rcv_data; /* starting count for PMA */ + u64 n_port_xmit_packets; /* starting count for PMA */ + u64 n_port_rcv_packets; /* starting count for PMA */ + u32 n_pkey_violations; /* starting count for PMA */ + u32 n_rc_resends; + u32 n_rc_acks; + u32 n_rc_qacks; + u32 n_seq_naks; + u32 n_rdma_seq; + u32 n_rnr_naks; + u32 n_other_naks; + u32 n_timeouts; + u32 n_pkt_drops; + u32 n_wqe_errs; + u32 n_rdma_dup_busy; + u32 n_piowait; + u32 n_no_piobuf; + u32 port_cap_flags; + u32 pma_sample_start; + u32 pma_sample_interval; + __be16 pma_counter_select[5]; + u16 pma_tag; + u16 qkey_violations; + u16 mkey_violations; + u16 mkey_lease_period; + u16 pending_index; /* which pending queue is active */ + u8 pma_sample_status; + u8 subnet_timeout; + u8 link_width_enabled; + u8 vl_high_limit; + struct ipath_opcode_stats opstats[128]; +}; + +struct ipath_ucontext { + struct ib_ucontext ibucontext; +}; + +static inline struct ipath_mr *to_imr(struct ib_mr *ibmr) +{ + return container_of(ibmr, struct ipath_mr, ibmr); +} + +static inline struct ipath_fmr *to_ifmr(struct ib_fmr *ibfmr) +{ + return container_of(ibfmr, struct ipath_fmr, ibfmr); +} + +static inline struct ipath_pd *to_ipd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct ipath_pd, ibpd); +} + +static inline struct ipath_ah *to_iah(struct ib_ah *ibah) +{ + return container_of(ibah, struct ipath_ah, ibah); +} + +static inline struct ipath_cq *to_icq(struct ib_cq *ibcq) +{ + return container_of(ibcq, struct ipath_cq, ibcq); +} + +static inline struct ipath_srq *to_isrq(struct ib_srq *ibsrq) +{ + return container_of(ibsrq, struct ipath_srq, ibsrq); +} + +static inline struct ipath_qp *to_iqp(struct ib_qp *ibqp) +{ + return container_of(ibqp, struct ipath_qp, ibqp); +} + +static inline struct ipath_ibdev *to_idev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct ipath_ibdev, ibdev); +} + +int ipath_process_mad(struct ib_device *ibdev, + int mad_flags, + u8 port_num, + struct ib_wc *in_wc, + struct ib_grh *in_grh, + struct ib_mad *in_mad, struct ib_mad *out_mad); + +static inline struct ipath_ucontext *to_iucontext(struct ib_ucontext + *ibucontext) +{ + return container_of(ibucontext, struct ipath_ucontext, ibucontext); +} + +/* + * Compare the lower 24 bits of the two values. + * Returns an integer <, ==, or > than zero. + */ +static inline int ipath_cmp24(u32 a, u32 b) +{ + return (((int) a) - ((int) b)) << 8; +} + +struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid); + +int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); + +int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); + +int ipath_mcast_tree_empty(void); + +__be32 ipath_compute_aeth(struct ipath_qp *qp); + +struct ipath_qp *ipath_lookup_qpn(struct ipath_qp_table *qpt, u32 qpn); + +struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata); + +int ipath_destroy_qp(struct ib_qp *ibqp); + +int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask); + +int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_qp_init_attr *init_attr); + +void ipath_free_all_qps(struct ipath_qp_table *qpt); + +int ipath_init_qp_table(struct ipath_ibdev *idev, int size); + +void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc); + +void ipath_error_qp(struct ipath_qp *qp); + +void ipath_get_credit(struct ipath_qp *qp, u32 aeth); + +void ipath_do_rc_send(unsigned long data); + +void ipath_do_uc_send(unsigned long data); + +void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig); + +int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss, + u32 len, u64 vaddr, u32 rkey, int acc); + +int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge, + struct ib_sge *sge, int acc); + +void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length); + +void ipath_skip_sge(struct ipath_sge_state *ss, u32 length); + +int ipath_post_rc_send(struct ipath_qp *qp, struct ib_send_wr *wr); + +void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, + int has_grh, void *data, u32 tlen, struct ipath_qp *qp); + +void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, + int has_grh, void *data, u32 tlen, struct ipath_qp *qp); + +void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc); + +void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_sge_state *ss, + u32 length, struct ib_send_wr *wr, struct ib_wc *wc); + +int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr); + +void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, + int has_grh, void *data, u32 tlen, struct ipath_qp *qp); + +int ipath_alloc_lkey(struct ipath_lkey_table *rkt, + struct ipath_mregion *mr); + +void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey); + +int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge, + struct ib_sge *sge, int acc); + +int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss, + u32 len, u64 vaddr, u32 rkey, int acc); + +int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); + +struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_udata *udata); + +int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask); + +int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr); + +int ipath_destroy_srq(struct ib_srq *ibsrq); + +void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig); + +int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); + +struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, + struct ib_ucontext *context, + struct ib_udata *udata); + +int ipath_destroy_cq(struct ib_cq *ibcq); + +int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify); + +int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata); + +struct ib_mr *ipath_get_dma_mr(struct ib_pd *pd, int acc); + +struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *buffer_list, + int num_phys_buf, int acc, u64 *iova_start); + +struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, + int mr_access_flags, + struct ib_udata *udata); + +int ipath_dereg_mr(struct ib_mr *ibmr); + +struct ib_fmr *ipath_alloc_fmr(struct ib_pd *pd, int mr_access_flags, + struct ib_fmr_attr *fmr_attr); + +int ipath_map_phys_fmr(struct ib_fmr *ibfmr, u64 * page_list, + int list_len, u64 iova); + +int ipath_unmap_fmr(struct list_head *fmr_list); + +int ipath_dealloc_fmr(struct ib_fmr *ibfmr); + +void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev); + +void ipath_insert_rnr_queue(struct ipath_qp *qp); + +int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only); + +void ipath_ruc_loopback(struct ipath_qp *sqp, struct ib_wc *wc); + +extern const enum ib_wc_opcode ib_ipath_wc_opcode[]; + +extern const u8 ipath_cvt_physportstate[]; + +extern const int ib_ipath_state_ops[]; + +extern unsigned int ib_ipath_lkey_table_size; + +extern const u32 ib_ipath_rnr_table[]; + +#endif /* IPATH_VERBS_H */ diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c new file mode 100644 index 000000000000..10b31d2c4f20 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "ipath_verbs.h" + +/* + * Global table of GID to attached QPs. + * The table is global to all ipath devices since a send from one QP/device + * needs to be locally routed to any locally attached QPs on the same + * or different device. + */ +static struct rb_root mcast_tree; +static DEFINE_SPINLOCK(mcast_lock); + +/** + * ipath_mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct + * @qp: the QP to link + */ +static struct ipath_mcast_qp *ipath_mcast_qp_alloc(struct ipath_qp *qp) +{ + struct ipath_mcast_qp *mqp; + + mqp = kmalloc(sizeof *mqp, GFP_KERNEL); + if (!mqp) + goto bail; + + mqp->qp = qp; + atomic_inc(&qp->refcount); + +bail: + return mqp; +} + +static void ipath_mcast_qp_free(struct ipath_mcast_qp *mqp) +{ + struct ipath_qp *qp = mqp->qp; + + /* Notify ipath_destroy_qp() if it is waiting. */ + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); + + kfree(mqp); +} + +/** + * ipath_mcast_alloc - allocate the multicast GID structure + * @mgid: the multicast GID + * + * A list of QPs will be attached to this structure. + */ +static struct ipath_mcast *ipath_mcast_alloc(union ib_gid *mgid) +{ + struct ipath_mcast *mcast; + + mcast = kmalloc(sizeof *mcast, GFP_KERNEL); + if (!mcast) + goto bail; + + mcast->mgid = *mgid; + INIT_LIST_HEAD(&mcast->qp_list); + init_waitqueue_head(&mcast->wait); + atomic_set(&mcast->refcount, 0); + +bail: + return mcast; +} + +static void ipath_mcast_free(struct ipath_mcast *mcast) +{ + struct ipath_mcast_qp *p, *tmp; + + list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) + ipath_mcast_qp_free(p); + + kfree(mcast); +} + +/** + * ipath_mcast_find - search the global table for the given multicast GID + * @mgid: the multicast GID to search for + * + * Returns NULL if not found. + * + * The caller is responsible for decrementing the reference count if found. + */ +struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid) +{ + struct rb_node *n; + unsigned long flags; + struct ipath_mcast *mcast; + + spin_lock_irqsave(&mcast_lock, flags); + n = mcast_tree.rb_node; + while (n) { + int ret; + + mcast = rb_entry(n, struct ipath_mcast, rb_node); + + ret = memcmp(mgid->raw, mcast->mgid.raw, + sizeof(union ib_gid)); + if (ret < 0) + n = n->rb_left; + else if (ret > 0) + n = n->rb_right; + else { + atomic_inc(&mcast->refcount); + spin_unlock_irqrestore(&mcast_lock, flags); + goto bail; + } + } + spin_unlock_irqrestore(&mcast_lock, flags); + + mcast = NULL; + +bail: + return mcast; +} + +/** + * ipath_mcast_add - insert mcast GID into table and attach QP struct + * @mcast: the mcast GID table + * @mqp: the QP to attach + * + * Return zero if both were added. Return EEXIST if the GID was already in + * the table but the QP was added. Return ESRCH if the QP was already + * attached and neither structure was added. + */ +static int ipath_mcast_add(struct ipath_mcast *mcast, + struct ipath_mcast_qp *mqp) +{ + struct rb_node **n = &mcast_tree.rb_node; + struct rb_node *pn = NULL; + unsigned long flags; + int ret; + + spin_lock_irqsave(&mcast_lock, flags); + + while (*n) { + struct ipath_mcast *tmcast; + struct ipath_mcast_qp *p; + + pn = *n; + tmcast = rb_entry(pn, struct ipath_mcast, rb_node); + + ret = memcmp(mcast->mgid.raw, tmcast->mgid.raw, + sizeof(union ib_gid)); + if (ret < 0) { + n = &pn->rb_left; + continue; + } + if (ret > 0) { + n = &pn->rb_right; + continue; + } + + /* Search the QP list to see if this is already there. */ + list_for_each_entry_rcu(p, &tmcast->qp_list, list) { + if (p->qp == mqp->qp) { + spin_unlock_irqrestore(&mcast_lock, flags); + ret = ESRCH; + goto bail; + } + } + list_add_tail_rcu(&mqp->list, &tmcast->qp_list); + spin_unlock_irqrestore(&mcast_lock, flags); + ret = EEXIST; + goto bail; + } + + list_add_tail_rcu(&mqp->list, &mcast->qp_list); + + atomic_inc(&mcast->refcount); + rb_link_node(&mcast->rb_node, pn, n); + rb_insert_color(&mcast->rb_node, &mcast_tree); + + spin_unlock_irqrestore(&mcast_lock, flags); + + ret = 0; + +bail: + return ret; +} + +int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + struct ipath_qp *qp = to_iqp(ibqp); + struct ipath_mcast *mcast; + struct ipath_mcast_qp *mqp; + int ret; + + /* + * Allocate data structures since its better to do this outside of + * spin locks and it will most likely be needed. + */ + mcast = ipath_mcast_alloc(gid); + if (mcast == NULL) { + ret = -ENOMEM; + goto bail; + } + mqp = ipath_mcast_qp_alloc(qp); + if (mqp == NULL) { + ipath_mcast_free(mcast); + ret = -ENOMEM; + goto bail; + } + switch (ipath_mcast_add(mcast, mqp)) { + case ESRCH: + /* Neither was used: can't attach the same QP twice. */ + ipath_mcast_qp_free(mqp); + ipath_mcast_free(mcast); + ret = -EINVAL; + goto bail; + case EEXIST: /* The mcast wasn't used */ + ipath_mcast_free(mcast); + break; + default: + break; + } + + ret = 0; + +bail: + return ret; +} + +int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + struct ipath_qp *qp = to_iqp(ibqp); + struct ipath_mcast *mcast = NULL; + struct ipath_mcast_qp *p, *tmp; + struct rb_node *n; + unsigned long flags; + int last = 0; + int ret; + + spin_lock_irqsave(&mcast_lock, flags); + + /* Find the GID in the mcast table. */ + n = mcast_tree.rb_node; + while (1) { + if (n == NULL) { + spin_unlock_irqrestore(&mcast_lock, flags); + ret = 0; + goto bail; + } + + mcast = rb_entry(n, struct ipath_mcast, rb_node); + ret = memcmp(gid->raw, mcast->mgid.raw, + sizeof(union ib_gid)); + if (ret < 0) + n = n->rb_left; + else if (ret > 0) + n = n->rb_right; + else + break; + } + + /* Search the QP list. */ + list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) { + if (p->qp != qp) + continue; + /* + * We found it, so remove it, but don't poison the forward + * link until we are sure there are no list walkers. + */ + list_del_rcu(&p->list); + + /* If this was the last attached QP, remove the GID too. */ + if (list_empty(&mcast->qp_list)) { + rb_erase(&mcast->rb_node, &mcast_tree); + last = 1; + } + break; + } + + spin_unlock_irqrestore(&mcast_lock, flags); + + if (p) { + /* + * Wait for any list walkers to finish before freeing the + * list element. + */ + wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); + ipath_mcast_qp_free(p); + } + if (last) { + atomic_dec(&mcast->refcount); + wait_event(mcast->wait, !atomic_read(&mcast->refcount)); + ipath_mcast_free(mcast); + } + + ret = 0; + +bail: + return ret; +} + +int ipath_mcast_tree_empty(void) +{ + return mcast_tree.rb_node == NULL; +} diff --git a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c new file mode 100644 index 000000000000..adc5322f15c1 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + * This file is conditionally built on x86_64 only. Otherwise weak symbol + * versions of the functions exported from here are used. + */ + +#include +#include +#include + +#include "ipath_kernel.h" + +/** + * ipath_enable_wc - enable write combining for MMIO writes to the device + * @dd: infinipath device + * + * This routine is x86_64-specific; it twiddles the CPU's MTRRs to enable + * write combining. + */ +int ipath_enable_wc(struct ipath_devdata *dd) +{ + int ret = 0; + u64 pioaddr, piolen; + unsigned bits; + const unsigned long addr = pci_resource_start(dd->pcidev, 0); + const size_t len = pci_resource_len(dd->pcidev, 0); + + /* + * Set the PIO buffers to be WCCOMB, so we get HT bursts to the + * chip. Linux (possibly the hardware) requires it to be on a power + * of 2 address matching the length (which has to be a power of 2). + * For rev1, that means the base address, for rev2, it will be just + * the PIO buffers themselves. + */ + pioaddr = addr + dd->ipath_piobufbase; + piolen = (dd->ipath_piobcnt2k + + dd->ipath_piobcnt4k) * + ALIGN(dd->ipath_piobcnt2k + + dd->ipath_piobcnt4k, dd->ipath_palign); + + for (bits = 0; !(piolen & (1ULL << bits)); bits++) + /* do nothing */ ; + + if (piolen != (1ULL << bits)) { + piolen >>= bits; + while (piolen >>= 1) + bits++; + piolen = 1ULL << (bits + 1); + } + if (pioaddr & (piolen - 1)) { + u64 atmp; + ipath_dbg("pioaddr %llx not on right boundary for size " + "%llx, fixing\n", + (unsigned long long) pioaddr, + (unsigned long long) piolen); + atmp = pioaddr & ~(piolen - 1); + if (atmp < addr || (atmp + piolen) > (addr + len)) { + ipath_dev_err(dd, "No way to align address/size " + "(%llx/%llx), no WC mtrr\n", + (unsigned long long) atmp, + (unsigned long long) piolen << 1); + ret = -ENODEV; + } else { + ipath_dbg("changing WC base from %llx to %llx, " + "len from %llx to %llx\n", + (unsigned long long) pioaddr, + (unsigned long long) atmp, + (unsigned long long) piolen, + (unsigned long long) piolen << 1); + pioaddr = atmp; + piolen <<= 1; + } + } + + if (!ret) { + int cookie; + ipath_cdbg(VERBOSE, "Setting mtrr for chip to WC " + "(addr %llx, len=0x%llx)\n", + (unsigned long long) pioaddr, + (unsigned long long) piolen); + cookie = mtrr_add(pioaddr, piolen, MTRR_TYPE_WRCOMB, 0); + if (cookie < 0) { + { + dev_info(&dd->pcidev->dev, + "mtrr_add() WC for PIO bufs " + "failed (%d)\n", + cookie); + ret = -EINVAL; + } + } else { + ipath_cdbg(VERBOSE, "Set mtrr for chip to WC, " + "cookie is %d\n", cookie); + dd->ipath_wc_cookie = cookie; + } + } + + return ret; +} + +/** + * ipath_disable_wc - disable write combining for MMIO writes to the device + * @dd: infinipath device + */ +void ipath_disable_wc(struct ipath_devdata *dd) +{ + if (dd->ipath_wc_cookie) { + ipath_cdbg(VERBOSE, "undoing WCCOMB on pio buffers\n"); + mtrr_del(dd->ipath_wc_cookie, 0, 0); + dd->ipath_wc_cookie = 0; + } +} + +/** + * ipath_unordered_wc - indicate whether write combining is ordered + * + * Because our performance depends on our ability to do write combining mmio + * writes in the most efficient way, we need to know if we are on an Intel + * or AMD x86_64 processor. AMD x86_64 processors flush WC buffers out in + * the order completed, and so no special flushing is required to get + * correct ordering. Intel processors, however, will flush write buffers + * out in "random" orders, and so explicit ordering is needed at times. + */ +int ipath_unordered_wc(void) +{ + return boot_cpu_data.x86_vendor != X86_VENDOR_AMD; +} diff --git a/drivers/infiniband/hw/ipath/ips_common.h b/drivers/infiniband/hw/ipath/ips_common.h new file mode 100644 index 000000000000..410a764dfcef --- /dev/null +++ b/drivers/infiniband/hw/ipath/ips_common.h @@ -0,0 +1,263 @@ +#ifndef IPS_COMMON_H +#define IPS_COMMON_H +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "ipath_common.h" + +struct ipath_header { + /* + * Version - 4 bits, Port - 4 bits, TID - 10 bits and Offset - + * 14 bits before ECO change ~28 Dec 03. After that, Vers 4, + * Port 3, TID 11, offset 14. + */ + __le32 ver_port_tid_offset; + __le16 chksum; + __le16 pkt_flags; +}; + +struct ips_message_header { + __be16 lrh[4]; + __be32 bth[3]; + /* fields below this point are in host byte order */ + struct ipath_header iph; + __u8 sub_opcode; + __u8 flags; + __u16 src_rank; + /* 24 bits. The upper 8 bit is available for other use */ + union { + struct { + unsigned ack_seq_num:24; + unsigned port:4; + unsigned unused:4; + }; + __u32 ack_seq_num_org; + }; + __u8 expected_tid_session_id; + __u8 tinylen; /* to aid MPI */ + union { + __u16 tag; /* to aid MPI */ + __u16 mqhdr; /* for PSM MQ */ + }; + union { + __u32 mpi[4]; /* to aid MPI */ + __u32 data[4]; + __u64 mq[2]; /* for PSM MQ */ + struct { + __u16 mtu; + __u8 major_ver; + __u8 minor_ver; + __u32 not_used; //free + __u32 run_id; + __u32 client_ver; + }; + }; +}; + +struct ether_header { + __be16 lrh[4]; + __be32 bth[3]; + struct ipath_header iph; + __u8 sub_opcode; + __u8 cmd; + __be16 lid; + __u16 mac[3]; + __u8 frag_num; + __u8 seq_num; + __le32 len; + /* MUST be of word size due to PIO write requirements */ + __u32 csum; + __le16 csum_offset; + __le16 flags; + __u16 first_2_bytes; + __u8 unused[2]; /* currently unused */ +}; + +/* + * The PIO buffer used for sending infinipath messages must only be written + * in 32-bit words, all the data must be written, and no writes can occur + * after the last word is written (which transfers "ownership" of the buffer + * to the chip and triggers the message to be sent). + * Since the Linux sk_buff structure can be recursive, non-aligned, and + * any number of bytes in each segment, we use the following structure + * to keep information about the overall state of the copy operation. + * This is used to save the information needed to store the checksum + * in the right place before sending the last word to the hardware and + * to buffer the last 0-3 bytes of non-word sized segments. + */ +struct copy_data_s { + struct ether_header *hdr; + /* addr of PIO buf to write csum to */ + __u32 __iomem *csum_pio; + __u32 __iomem *to; /* addr of PIO buf to write data to */ + __u32 device; /* which device to allocate PIO bufs from */ + __s32 error; /* set if there is an error. */ + __s32 extra; /* amount of data saved in u.buf below */ + __u32 len; /* total length to send in bytes */ + __u32 flen; /* frament length in words */ + __u32 csum; /* partial IP checksum */ + __u32 pos; /* position for partial checksum */ + __u32 offset; /* offset to where data currently starts */ + __s32 checksum_calc; /* set to 1 when csum has been calculated */ + struct sk_buff *skb; + union { + __u32 w; + __u8 buf[4]; + } u; +}; + +/* IB - LRH header consts */ +#define IPS_LRH_GRH 0x0003 /* 1. word of IB LRH - next header: GRH */ +#define IPS_LRH_BTH 0x0002 /* 1. word of IB LRH - next header: BTH */ + +#define IPS_OFFSET 0 + +/* + * defines the cut-off point between the header queue and eager/expected + * TID queue + */ +#define NUM_OF_EXTRA_WORDS_IN_HEADER_QUEUE \ + ((sizeof(struct ips_message_header) - \ + offsetof(struct ips_message_header, iph)) >> 2) + +/* OpCodes */ +#define OPCODE_IPS 0xC0 +#define OPCODE_ITH4X 0xC1 + +/* OpCode 30 is use by stand-alone test programs */ +#define OPCODE_RAW_DATA 0xDE +/* last OpCode (31) is reserved for test */ +#define OPCODE_TEST 0xDF + +/* sub OpCodes - ips */ +#define OPCODE_SEQ_DATA 0x01 +#define OPCODE_SEQ_CTRL 0x02 + +#define OPCODE_SEQ_MQ_DATA 0x03 +#define OPCODE_SEQ_MQ_CTRL 0x04 + +#define OPCODE_ACK 0x10 +#define OPCODE_NAK 0x11 + +#define OPCODE_ERR_CHK 0x20 +#define OPCODE_ERR_CHK_PLS 0x21 + +#define OPCODE_STARTUP 0x30 +#define OPCODE_STARTUP_ACK 0x31 +#define OPCODE_STARTUP_NAK 0x32 + +#define OPCODE_STARTUP_EXT 0x34 +#define OPCODE_STARTUP_ACK_EXT 0x35 +#define OPCODE_STARTUP_NAK_EXT 0x36 + +#define OPCODE_TIDS_RELEASE 0x40 +#define OPCODE_TIDS_RELEASE_CONFIRM 0x41 + +#define OPCODE_CLOSE 0x50 +#define OPCODE_CLOSE_ACK 0x51 +/* + * like OPCODE_CLOSE, but no complaint if other side has already closed. + * Used when doing abort(), MPI_Abort(), etc. + */ +#define OPCODE_ABORT 0x52 + +/* sub OpCodes - ith4x */ +#define OPCODE_ENCAP 0x81 +#define OPCODE_LID_ARP 0x82 + +/* Receive Header Queue: receive type (from infinipath) */ +#define RCVHQ_RCV_TYPE_EXPECTED 0 +#define RCVHQ_RCV_TYPE_EAGER 1 +#define RCVHQ_RCV_TYPE_NON_KD 2 +#define RCVHQ_RCV_TYPE_ERROR 3 + +/* misc. */ +#define SIZE_OF_CRC 1 + +#define EAGER_TID_ID INFINIPATH_I_TID_MASK + +#define IPS_DEFAULT_P_KEY 0xFFFF + +#define IPS_PERMISSIVE_LID 0xFFFF +#define IPS_MULTICAST_LID_BASE 0xC000 + +#define IPS_AETH_CREDIT_SHIFT 24 +#define IPS_AETH_CREDIT_MASK 0x1F +#define IPS_AETH_CREDIT_INVAL 0x1F + +#define IPS_PSN_MASK 0xFFFFFF +#define IPS_MSN_MASK 0xFFFFFF +#define IPS_QPN_MASK 0xFFFFFF +#define IPS_MULTICAST_QPN 0xFFFFFF + +/* functions for extracting fields from rcvhdrq entries */ +static inline __u32 ips_get_hdr_err_flags(const __le32 * rbuf) +{ + return __le32_to_cpu(rbuf[1]); +} + +static inline __u32 ips_get_index(const __le32 * rbuf) +{ + return (__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_EGRINDEX_SHIFT) + & INFINIPATH_RHF_EGRINDEX_MASK; +} + +static inline __u32 ips_get_rcv_type(const __le32 * rbuf) +{ + return (__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_RCVTYPE_SHIFT) + & INFINIPATH_RHF_RCVTYPE_MASK; +} + +static inline __u32 ips_get_length_in_bytes(const __le32 * rbuf) +{ + return ((__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_LENGTH_SHIFT) + & INFINIPATH_RHF_LENGTH_MASK) << 2; +} + +static inline void *ips_get_first_protocol_header(const __u32 * rbuf) +{ + return (void *)&rbuf[2]; +} + +static inline struct ips_message_header *ips_get_ips_header(const __u32 * + rbuf) +{ + return (struct ips_message_header *)&rbuf[2]; +} + +static inline __u32 ips_get_ipath_ver(__le32 hdrword) +{ + return (__le32_to_cpu(hdrword) >> INFINIPATH_I_VERS_SHIFT) + & INFINIPATH_I_VERS_MASK; +} + +#endif /* IPS_COMMON_H */ diff --git a/drivers/infiniband/hw/ipath/verbs_debug.h b/drivers/infiniband/hw/ipath/verbs_debug.h new file mode 100644 index 000000000000..40d693cf3f94 --- /dev/null +++ b/drivers/infiniband/hw/ipath/verbs_debug.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _VERBS_DEBUG_H +#define _VERBS_DEBUG_H + +/* + * This file contains tracing code for the ib_ipath kernel module. + */ +#ifndef _VERBS_DEBUGGING /* tracing enabled or not */ +#define _VERBS_DEBUGGING 1 +#endif + +extern unsigned ib_ipath_debug; + +#define _VERBS_ERROR(fmt,...) \ + do { \ + printk(KERN_ERR "%s: " fmt, "ib_ipath", ##__VA_ARGS__); \ + } while(0) + +#define _VERBS_UNIT_ERROR(unit,fmt,...) \ + do { \ + printk(KERN_ERR "%s: " fmt, "ib_ipath", ##__VA_ARGS__); \ + } while(0) + +#if _VERBS_DEBUGGING + +/* + * Mask values for debugging. The scheme allows us to compile out any + * of the debug tracing stuff, and if compiled in, to enable or + * disable dynamically. + * This can be set at modprobe time also: + * modprobe ib_path ib_ipath_debug=3 + */ + +#define __VERBS_INFO 0x1 /* generic low verbosity stuff */ +#define __VERBS_DBG 0x2 /* generic debug */ +#define __VERBS_VDBG 0x4 /* verbose debug */ +#define __VERBS_SMADBG 0x8000 /* sma packet debug */ + +#define _VERBS_INFO(fmt,...) \ + do { \ + if (unlikely(ib_ipath_debug&__VERBS_INFO)) \ + printk(KERN_INFO "%s: " fmt,"ib_ipath", \ + ##__VA_ARGS__); \ + } while(0) + +#define _VERBS_DBG(fmt,...) \ + do { \ + if (unlikely(ib_ipath_debug&__VERBS_DBG)) \ + printk(KERN_DEBUG "%s: " fmt, __func__, \ + ##__VA_ARGS__); \ + } while(0) + +#define _VERBS_VDBG(fmt,...) \ + do { \ + if (unlikely(ib_ipath_debug&__VERBS_VDBG)) \ + printk(KERN_DEBUG "%s: " fmt, __func__, \ + ##__VA_ARGS__); \ + } while(0) + +#define _VERBS_SMADBG(fmt,...) \ + do { \ + if (unlikely(ib_ipath_debug&__VERBS_SMADBG)) \ + printk(KERN_DEBUG "%s: " fmt, __func__, \ + ##__VA_ARGS__); \ + } while(0) + +#else /* ! _VERBS_DEBUGGING */ + +#define _VERBS_INFO(fmt,...) +#define _VERBS_DBG(fmt,...) +#define _VERBS_VDBG(fmt,...) +#define _VERBS_SMADBG(fmt,...) + +#endif /* _VERBS_DEBUGGING */ + +#endif /* _VERBS_DEBUG_H */ diff --git a/drivers/infiniband/hw/mthca/Kconfig b/drivers/infiniband/hw/mthca/Kconfig index e88be85b3d5c..9aa5a4468a75 100644 --- a/drivers/infiniband/hw/mthca/Kconfig +++ b/drivers/infiniband/hw/mthca/Kconfig @@ -7,10 +7,11 @@ config INFINIBAND_MTHCA ("Tavor") and the MT25208 PCI Express HCA ("Arbel"). config INFINIBAND_MTHCA_DEBUG - bool "Verbose debugging output" + bool "Verbose debugging output" if EMBEDDED depends on INFINIBAND_MTHCA - default n + default y ---help--- - This option causes the mthca driver produce a bunch of debug - messages. Select this is you are developing the driver or - trying to diagnose a problem. + This option causes debugging code to be compiled into the + mthca driver. The output can be turned on via the + debug_level module parameter (which can also be set after + the driver is loaded through sysfs). diff --git a/drivers/infiniband/hw/mthca/Makefile b/drivers/infiniband/hw/mthca/Makefile index 47ec5a7cba0b..e388d95d0cf1 100644 --- a/drivers/infiniband/hw/mthca/Makefile +++ b/drivers/infiniband/hw/mthca/Makefile @@ -1,7 +1,3 @@ -ifdef CONFIG_INFINIBAND_MTHCA_DEBUG -EXTRA_CFLAGS += -DDEBUG -endif - obj-$(CONFIG_INFINIBAND_MTHCA) += ib_mthca.o ib_mthca-y := mthca_main.o mthca_cmd.o mthca_profile.o mthca_reset.o \ diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c index f023d3936518..b12aa03be251 100644 --- a/drivers/infiniband/hw/mthca/mthca_av.c +++ b/drivers/infiniband/hw/mthca/mthca_av.c @@ -42,6 +42,20 @@ #include "mthca_dev.h" +enum { + MTHCA_RATE_TAVOR_FULL = 0, + MTHCA_RATE_TAVOR_1X = 1, + MTHCA_RATE_TAVOR_4X = 2, + MTHCA_RATE_TAVOR_1X_DDR = 3 +}; + +enum { + MTHCA_RATE_MEMFREE_FULL = 0, + MTHCA_RATE_MEMFREE_QUARTER = 1, + MTHCA_RATE_MEMFREE_EIGHTH = 2, + MTHCA_RATE_MEMFREE_HALF = 3 +}; + struct mthca_av { __be32 port_pd; u8 reserved1; @@ -55,6 +69,90 @@ struct mthca_av { __be32 dgid[4]; }; +static enum ib_rate memfree_rate_to_ib(u8 mthca_rate, u8 port_rate) +{ + switch (mthca_rate) { + case MTHCA_RATE_MEMFREE_EIGHTH: + return mult_to_ib_rate(port_rate >> 3); + case MTHCA_RATE_MEMFREE_QUARTER: + return mult_to_ib_rate(port_rate >> 2); + case MTHCA_RATE_MEMFREE_HALF: + return mult_to_ib_rate(port_rate >> 1); + case MTHCA_RATE_MEMFREE_FULL: + default: + return mult_to_ib_rate(port_rate); + } +} + +static enum ib_rate tavor_rate_to_ib(u8 mthca_rate, u8 port_rate) +{ + switch (mthca_rate) { + case MTHCA_RATE_TAVOR_1X: return IB_RATE_2_5_GBPS; + case MTHCA_RATE_TAVOR_1X_DDR: return IB_RATE_5_GBPS; + case MTHCA_RATE_TAVOR_4X: return IB_RATE_10_GBPS; + default: return port_rate; + } +} + +enum ib_rate mthca_rate_to_ib(struct mthca_dev *dev, u8 mthca_rate, u8 port) +{ + if (mthca_is_memfree(dev)) { + /* Handle old Arbel FW */ + if (dev->limits.stat_rate_support == 0x3 && mthca_rate) + return IB_RATE_2_5_GBPS; + + return memfree_rate_to_ib(mthca_rate, dev->rate[port - 1]); + } else + return tavor_rate_to_ib(mthca_rate, dev->rate[port - 1]); +} + +static u8 ib_rate_to_memfree(u8 req_rate, u8 cur_rate) +{ + if (cur_rate <= req_rate) + return 0; + + /* + * Inter-packet delay (IPD) to get from rate X down to a rate + * no more than Y is (X - 1) / Y. + */ + switch ((cur_rate - 1) / req_rate) { + case 0: return MTHCA_RATE_MEMFREE_FULL; + case 1: return MTHCA_RATE_MEMFREE_HALF; + case 2: /* fall through */ + case 3: return MTHCA_RATE_MEMFREE_QUARTER; + default: return MTHCA_RATE_MEMFREE_EIGHTH; + } +} + +static u8 ib_rate_to_tavor(u8 static_rate) +{ + switch (static_rate) { + case IB_RATE_2_5_GBPS: return MTHCA_RATE_TAVOR_1X; + case IB_RATE_5_GBPS: return MTHCA_RATE_TAVOR_1X_DDR; + case IB_RATE_10_GBPS: return MTHCA_RATE_TAVOR_4X; + default: return MTHCA_RATE_TAVOR_FULL; + } +} + +u8 mthca_get_rate(struct mthca_dev *dev, int static_rate, u8 port) +{ + u8 rate; + + if (!static_rate || ib_rate_to_mult(static_rate) >= dev->rate[port - 1]) + return 0; + + if (mthca_is_memfree(dev)) + rate = ib_rate_to_memfree(ib_rate_to_mult(static_rate), + dev->rate[port - 1]); + else + rate = ib_rate_to_tavor(static_rate); + + if (!(dev->limits.stat_rate_support & (1 << rate))) + rate = 1; + + return rate; +} + int mthca_create_ah(struct mthca_dev *dev, struct mthca_pd *pd, struct ib_ah_attr *ah_attr, @@ -107,7 +205,7 @@ on_hca_fail: av->g_slid = ah_attr->src_path_bits; av->dlid = cpu_to_be16(ah_attr->dlid); av->msg_sr = (3 << 4) | /* 2K message */ - ah_attr->static_rate; + mthca_get_rate(dev, ah_attr->static_rate, ah_attr->port_num); av->sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 28); if (ah_attr->ah_flags & IB_AH_GRH) { av->g_slid |= 0x80; @@ -265,7 +363,7 @@ int __devinit mthca_init_av_table(struct mthca_dev *dev) return -ENOMEM; } -void __devexit mthca_cleanup_av_table(struct mthca_dev *dev) +void mthca_cleanup_av_table(struct mthca_dev *dev) { if (mthca_is_memfree(dev)) return; diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c index 343eca507870..1985b5dfa481 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.c +++ b/drivers/infiniband/hw/mthca/mthca_cmd.c @@ -965,6 +965,7 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, u32 *outbox; u8 field; u16 size; + u16 stat_rate; int err; #define QUERY_DEV_LIM_OUT_SIZE 0x100 @@ -995,6 +996,7 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, #define QUERY_DEV_LIM_MTU_WIDTH_OFFSET 0x36 #define QUERY_DEV_LIM_VL_PORT_OFFSET 0x37 #define QUERY_DEV_LIM_MAX_GID_OFFSET 0x3b +#define QUERY_DEV_LIM_RATE_SUPPORT_OFFSET 0x3c #define QUERY_DEV_LIM_MAX_PKEY_OFFSET 0x3f #define QUERY_DEV_LIM_FLAGS_OFFSET 0x44 #define QUERY_DEV_LIM_RSVD_UAR_OFFSET 0x48 @@ -1086,6 +1088,8 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev, dev_lim->num_ports = field & 0xf; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_GID_OFFSET); dev_lim->max_gids = 1 << (field & 0xf); + MTHCA_GET(stat_rate, outbox, QUERY_DEV_LIM_RATE_SUPPORT_OFFSET); + dev_lim->stat_rate_support = stat_rate; MTHCA_GET(field, outbox, QUERY_DEV_LIM_MAX_PKEY_OFFSET); dev_lim->max_pkeys = 1 << (field & 0xf); MTHCA_GET(dev_lim->flags, outbox, QUERY_DEV_LIM_FLAGS_OFFSET); diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h index e4ec35c40dd3..2f976f2051d6 100644 --- a/drivers/infiniband/hw/mthca/mthca_cmd.h +++ b/drivers/infiniband/hw/mthca/mthca_cmd.h @@ -146,6 +146,7 @@ struct mthca_dev_lim { int max_vl; int num_ports; int max_gids; + u16 stat_rate_support; int max_pkeys; u32 flags; int reserved_uars; diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 76aabc5bf371..312cf90731ea 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -973,7 +973,7 @@ int __devinit mthca_init_cq_table(struct mthca_dev *dev) return err; } -void __devexit mthca_cleanup_cq_table(struct mthca_dev *dev) +void mthca_cleanup_cq_table(struct mthca_dev *dev) { mthca_array_cleanup(&dev->cq_table.cq, dev->limits.num_cqs); mthca_alloc_cleanup(&dev->cq_table.alloc); diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index ad52edbefe98..4c1dcb4c1822 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -151,6 +151,7 @@ struct mthca_limits { int reserved_qps; int num_srqs; int max_srq_wqes; + int max_srq_sge; int reserved_srqs; int num_eecs; int reserved_eecs; @@ -172,6 +173,7 @@ struct mthca_limits { int reserved_pds; u32 page_size_cap; u32 flags; + u16 stat_rate_support; u8 port_width_cap; }; @@ -353,10 +355,24 @@ struct mthca_dev { struct ib_mad_agent *send_agent[MTHCA_MAX_PORTS][2]; struct ib_ah *sm_ah[MTHCA_MAX_PORTS]; spinlock_t sm_lock; + u8 rate[MTHCA_MAX_PORTS]; }; -#define mthca_dbg(mdev, format, arg...) \ - dev_dbg(&mdev->pdev->dev, format, ## arg) +#ifdef CONFIG_INFINIBAND_MTHCA_DEBUG +extern int mthca_debug_level; + +#define mthca_dbg(mdev, format, arg...) \ + do { \ + if (mthca_debug_level) \ + dev_printk(KERN_DEBUG, &mdev->pdev->dev, format, ## arg); \ + } while (0) + +#else /* CONFIG_INFINIBAND_MTHCA_DEBUG */ + +#define mthca_dbg(mdev, format, arg...) do { (void) mdev; } while (0) + +#endif /* CONFIG_INFINIBAND_MTHCA_DEBUG */ + #define mthca_err(mdev, format, arg...) \ dev_err(&mdev->pdev->dev, format, ## arg) #define mthca_info(mdev, format, arg...) \ @@ -492,6 +508,7 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq); int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, enum ib_srq_attr_mask attr_mask); int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr); +int mthca_max_srq_sge(struct mthca_dev *dev); void mthca_srq_event(struct mthca_dev *dev, u32 srqn, enum ib_event_type event_type); void mthca_free_srq_wqe(struct mthca_srq *srq, u32 wqe_addr); @@ -542,6 +559,8 @@ int mthca_read_ah(struct mthca_dev *dev, struct mthca_ah *ah, struct ib_ud_header *header); int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr); int mthca_ah_grh_present(struct mthca_ah *ah); +u8 mthca_get_rate(struct mthca_dev *dev, int static_rate, u8 port); +enum ib_rate mthca_rate_to_ib(struct mthca_dev *dev, u8 mthca_rate, u8 port); int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index cbdc348fb689..99f109c3815d 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -765,7 +765,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev) } -static void __devexit mthca_unmap_eq_regs(struct mthca_dev *dev) +static void mthca_unmap_eq_regs(struct mthca_dev *dev) { if (mthca_is_memfree(dev)) { mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) & @@ -821,7 +821,7 @@ int __devinit mthca_map_eq_icm(struct mthca_dev *dev, u64 icm_virt) return ret; } -void __devexit mthca_unmap_eq_icm(struct mthca_dev *dev) +void mthca_unmap_eq_icm(struct mthca_dev *dev) { u8 status; @@ -954,7 +954,7 @@ err_out_free: return err; } -void __devexit mthca_cleanup_eq_table(struct mthca_dev *dev) +void mthca_cleanup_eq_table(struct mthca_dev *dev) { u8 status; int i; diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c index 4ace6a392f41..f235c7ea42f0 100644 --- a/drivers/infiniband/hw/mthca/mthca_mad.c +++ b/drivers/infiniband/hw/mthca/mthca_mad.c @@ -49,6 +49,30 @@ enum { MTHCA_VENDOR_CLASS2 = 0xa }; +int mthca_update_rate(struct mthca_dev *dev, u8 port_num) +{ + struct ib_port_attr *tprops = NULL; + int ret; + + tprops = kmalloc(sizeof *tprops, GFP_KERNEL); + if (!tprops) + return -ENOMEM; + + ret = ib_query_port(&dev->ib_dev, port_num, tprops); + if (ret) { + printk(KERN_WARNING "ib_query_port failed (%d) for %s port %d\n", + ret, dev->ib_dev.name, port_num); + goto out; + } + + dev->rate[port_num - 1] = tprops->active_speed * + ib_width_enum_to_int(tprops->active_width); + +out: + kfree(tprops); + return ret; +} + static void update_sm_ah(struct mthca_dev *dev, u8 port_num, u16 lid, u8 sl) { @@ -90,6 +114,7 @@ static void smp_snoop(struct ib_device *ibdev, mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && mad->mad_hdr.method == IB_MGMT_METHOD_SET) { if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { + mthca_update_rate(to_mdev(ibdev), port_num); update_sm_ah(to_mdev(ibdev), port_num, be16_to_cpup((__be16 *) (mad->data + 58)), (*(u8 *) (mad->data + 76)) & 0xf); @@ -246,6 +271,7 @@ int mthca_create_agents(struct mthca_dev *dev) { struct ib_mad_agent *agent; int p, q; + int ret; spin_lock_init(&dev->sm_lock); @@ -255,11 +281,23 @@ int mthca_create_agents(struct mthca_dev *dev) q ? IB_QPT_GSI : IB_QPT_SMI, NULL, 0, send_handler, NULL, NULL); - if (IS_ERR(agent)) + if (IS_ERR(agent)) { + ret = PTR_ERR(agent); goto err; + } dev->send_agent[p][q] = agent; } + + for (p = 1; p <= dev->limits.num_ports; ++p) { + ret = mthca_update_rate(dev, p); + if (ret) { + mthca_err(dev, "Failed to obtain port %d rate." + " aborting.\n", p); + goto err; + } + } + return 0; err: @@ -268,10 +306,10 @@ err: if (dev->send_agent[p][q]) ib_unregister_mad_agent(dev->send_agent[p][q]); - return PTR_ERR(agent); + return ret; } -void mthca_free_agents(struct mthca_dev *dev) +void __devexit mthca_free_agents(struct mthca_dev *dev) { struct ib_mad_agent *agent; int p, q; diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 266f347c6707..9b9ff7bff357 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -52,6 +52,14 @@ MODULE_DESCRIPTION("Mellanox InfiniBand HCA low-level driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRV_VERSION); +#ifdef CONFIG_INFINIBAND_MTHCA_DEBUG + +int mthca_debug_level = 0; +module_param_named(debug_level, mthca_debug_level, int, 0644); +MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0"); + +#endif /* CONFIG_INFINIBAND_MTHCA_DEBUG */ + #ifdef CONFIG_PCI_MSI static int msi_x = 0; @@ -69,6 +77,10 @@ MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero"); #endif /* CONFIG_PCI_MSI */ +static int tune_pci = 0; +module_param(tune_pci, int, 0444); +MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero"); + static const char mthca_version[] __devinitdata = DRV_NAME ": Mellanox InfiniBand HCA driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; @@ -90,6 +102,9 @@ static int __devinit mthca_tune_pci(struct mthca_dev *mdev) int cap; u16 val; + if (!tune_pci) + return 0; + /* First try to max out Read Byte Count */ cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX); if (cap) { @@ -176,6 +191,7 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim mdev->limits.reserved_srqs = dev_lim->reserved_srqs; mdev->limits.reserved_eecs = dev_lim->reserved_eecs; mdev->limits.max_desc_sz = dev_lim->max_desc_sz; + mdev->limits.max_srq_sge = mthca_max_srq_sge(mdev); /* * Subtract 1 from the limit because we need to allocate a * spare CQE so the HCA HW can tell the difference between an @@ -191,6 +207,18 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim mdev->limits.port_width_cap = dev_lim->max_port_width; mdev->limits.page_size_cap = ~(u32) (dev_lim->min_page_sz - 1); mdev->limits.flags = dev_lim->flags; + /* + * For old FW that doesn't return static rate support, use a + * value of 0x3 (only static rate values of 0 or 1 are handled), + * except on Sinai, where even old FW can handle static rate + * values of 2 and 3. + */ + if (dev_lim->stat_rate_support) + mdev->limits.stat_rate_support = dev_lim->stat_rate_support; + else if (mdev->mthca_flags & MTHCA_FLAG_SINAI_OPT) + mdev->limits.stat_rate_support = 0xf; + else + mdev->limits.stat_rate_support = 0x3; /* IB_DEVICE_RESIZE_MAX_WR not supported by driver. May be doable since hardware supports it for SRQ. diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c index 9965bda9afed..47ca8a9b7247 100644 --- a/drivers/infiniband/hw/mthca/mthca_mcg.c +++ b/drivers/infiniband/hw/mthca/mthca_mcg.c @@ -388,7 +388,7 @@ int __devinit mthca_init_mcg_table(struct mthca_dev *dev) return 0; } -void __devexit mthca_cleanup_mcg_table(struct mthca_dev *dev) +void mthca_cleanup_mcg_table(struct mthca_dev *dev) { mthca_alloc_cleanup(&dev->mcg_table.alloc); } diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 698b62125765..25e1c1db9a40 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -170,7 +170,7 @@ err_out: return -ENOMEM; } -static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy) +static void mthca_buddy_cleanup(struct mthca_buddy *buddy) { int i; @@ -866,7 +866,7 @@ err_mtt_buddy: return err; } -void __devexit mthca_cleanup_mr_table(struct mthca_dev *dev) +void mthca_cleanup_mr_table(struct mthca_dev *dev) { /* XXX check if any MRs are still allocated? */ if (dev->limits.fmr_reserved_mtts) diff --git a/drivers/infiniband/hw/mthca/mthca_pd.c b/drivers/infiniband/hw/mthca/mthca_pd.c index 105fc5faaddf..59df51614c85 100644 --- a/drivers/infiniband/hw/mthca/mthca_pd.c +++ b/drivers/infiniband/hw/mthca/mthca_pd.c @@ -77,7 +77,7 @@ int __devinit mthca_init_pd_table(struct mthca_dev *dev) dev->limits.reserved_pds); } -void __devexit mthca_cleanup_pd_table(struct mthca_dev *dev) +void mthca_cleanup_pd_table(struct mthca_dev *dev) { /* XXX check if any PDs are still allocated? */ mthca_alloc_cleanup(&dev->pd_table.alloc); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 2c250bc11c33..565a24b1756f 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -106,7 +106,7 @@ static int mthca_query_device(struct ib_device *ibdev, props->max_res_rd_atom = props->max_qp_rd_atom * props->max_qp; props->max_srq = mdev->limits.num_srqs - mdev->limits.reserved_srqs; props->max_srq_wr = mdev->limits.max_srq_wqes; - props->max_srq_sge = mdev->limits.max_sg; + props->max_srq_sge = mdev->limits.max_srq_sge; props->local_ca_ack_delay = mdev->limits.local_ca_ack_delay; props->atomic_cap = mdev->limits.flags & DEV_LIM_FLAG_ATOMIC ? IB_ATOMIC_HCA : IB_ATOMIC_NONE; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 2e7f52136965..6676a786d690 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -257,6 +257,8 @@ struct mthca_qp { atomic_t refcount; u32 qpn; int is_direct; + u8 port; /* for SQP and memfree use only */ + u8 alt_port; /* for memfree use only */ u8 transport; u8 state; u8 atomic_rd_en; @@ -278,7 +280,6 @@ struct mthca_qp { struct mthca_sqp { struct mthca_qp qp; - int port; int pkey_index; u32 qkey; u32 send_psn; diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 1bc2678c2fae..f37b0e367323 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -248,6 +248,9 @@ void mthca_qp_event(struct mthca_dev *dev, u32 qpn, return; } + if (event_type == IB_EVENT_PATH_MIG) + qp->port = qp->alt_port; + event.device = &dev->ib_dev; event.event = event_type; event.element.qp = &qp->ibqp; @@ -392,10 +395,16 @@ static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr, { memset(ib_ah_attr, 0, sizeof *path); ib_ah_attr->port_num = (be32_to_cpu(path->port_pkey) >> 24) & 0x3; + + if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->limits.num_ports) + return; + ib_ah_attr->dlid = be16_to_cpu(path->rlid); ib_ah_attr->sl = be32_to_cpu(path->sl_tclass_flowlabel) >> 28; ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f; - ib_ah_attr->static_rate = path->static_rate & 0x7; + ib_ah_attr->static_rate = mthca_rate_to_ib(dev, + path->static_rate & 0x7, + ib_ah_attr->port_num); ib_ah_attr->ah_flags = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0; if (ib_ah_attr->ah_flags) { ib_ah_attr->grh.sgid_index = path->mgid_index & (dev->limits.gid_table_len - 1); @@ -455,8 +464,10 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m qp_attr->cap.max_recv_sge = qp->rq.max_gs; qp_attr->cap.max_inline_data = qp->max_inline_data; - to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path); - to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path); + if (qp->transport == RC || qp->transport == UC) { + to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path); + to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path); + } qp_attr->pkey_index = be32_to_cpu(context->pri_path.port_pkey) & 0x7f; qp_attr->alt_pkey_index = be32_to_cpu(context->alt_path.port_pkey) & 0x7f; @@ -484,11 +495,11 @@ out: } static int mthca_path_set(struct mthca_dev *dev, struct ib_ah_attr *ah, - struct mthca_qp_path *path) + struct mthca_qp_path *path, u8 port) { path->g_mylmc = ah->src_path_bits & 0x7f; path->rlid = cpu_to_be16(ah->dlid); - path->static_rate = !!ah->static_rate; + path->static_rate = mthca_get_rate(dev, ah->static_rate, port); if (ah->ah_flags & IB_AH_GRH) { if (ah->grh.sgid_index >= dev->limits.gid_table_len) { @@ -634,7 +645,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) if (qp->transport == MLX) qp_context->pri_path.port_pkey |= - cpu_to_be32(to_msqp(qp)->port << 24); + cpu_to_be32(qp->port << 24); else { if (attr_mask & IB_QP_PORT) { qp_context->pri_path.port_pkey |= @@ -657,7 +668,8 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) } if (attr_mask & IB_QP_AV) { - if (mthca_path_set(dev, &attr->ah_attr, &qp_context->pri_path)) + if (mthca_path_set(dev, &attr->ah_attr, &qp_context->pri_path, + attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) return -EINVAL; qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH); @@ -681,7 +693,8 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) return -EINVAL; } - if (mthca_path_set(dev, &attr->alt_ah_attr, &qp_context->alt_path)) + if (mthca_path_set(dev, &attr->alt_ah_attr, &qp_context->alt_path, + attr->alt_ah_attr.port_num)) return -EINVAL; qp_context->alt_path.port_pkey |= cpu_to_be32(attr->alt_pkey_index | @@ -791,6 +804,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) qp->atomic_rd_en = attr->qp_access_flags; if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) qp->resp_depth = attr->max_dest_rd_atomic; + if (attr_mask & IB_QP_PORT) + qp->port = attr->port_num; + if (attr_mask & IB_QP_ALT_PATH) + qp->alt_port = attr->alt_port_num; if (is_sqp(dev, qp)) store_attrs(to_msqp(qp), attr, attr_mask); @@ -802,13 +819,13 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) if (is_qp0(dev, qp)) { if (cur_state != IB_QPS_RTR && new_state == IB_QPS_RTR) - init_port(dev, to_msqp(qp)->port); + init_port(dev, qp->port); if (cur_state != IB_QPS_RESET && cur_state != IB_QPS_ERR && (new_state == IB_QPS_RESET || new_state == IB_QPS_ERR)) - mthca_CLOSE_IB(dev, to_msqp(qp)->port, &status); + mthca_CLOSE_IB(dev, qp->port, &status); } /* @@ -1212,6 +1229,9 @@ int mthca_alloc_qp(struct mthca_dev *dev, if (qp->qpn == -1) return -ENOMEM; + /* initialize port to zero for error-catching. */ + qp->port = 0; + err = mthca_alloc_qp_common(dev, pd, send_cq, recv_cq, send_policy, qp); if (err) { @@ -1261,7 +1281,7 @@ int mthca_alloc_sqp(struct mthca_dev *dev, if (err) goto err_out; - sqp->port = port; + sqp->qp.port = port; sqp->qp.qpn = mqpn; sqp->qp.transport = MLX; @@ -1404,10 +1424,10 @@ static int build_mlx_header(struct mthca_dev *dev, struct mthca_sqp *sqp, sqp->ud_header.lrh.source_lid = IB_LID_PERMISSIVE; sqp->ud_header.bth.solicited_event = !!(wr->send_flags & IB_SEND_SOLICITED); if (!sqp->qp.ibqp.qp_num) - ib_get_cached_pkey(&dev->ib_dev, sqp->port, + ib_get_cached_pkey(&dev->ib_dev, sqp->qp.port, sqp->pkey_index, &pkey); else - ib_get_cached_pkey(&dev->ib_dev, sqp->port, + ib_get_cached_pkey(&dev->ib_dev, sqp->qp.port, wr->wr.ud.pkey_index, &pkey); sqp->ud_header.bth.pkey = cpu_to_be16(pkey); sqp->ud_header.bth.destination_qpn = cpu_to_be32(wr->wr.ud.remote_qpn); @@ -2204,7 +2224,7 @@ int __devinit mthca_init_qp_table(struct mthca_dev *dev) return err; } -void __devexit mthca_cleanup_qp_table(struct mthca_dev *dev) +void mthca_cleanup_qp_table(struct mthca_dev *dev) { int i; u8 status; diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 0cfd15802217..adcaf85355ae 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -192,7 +192,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, /* Sanity check SRQ size before proceeding */ if (attr->max_wr > dev->limits.max_srq_wqes || - attr->max_sge > dev->limits.max_sg) + attr->max_sge > dev->limits.max_srq_sge) return -EINVAL; srq->max = attr->max_wr; @@ -206,7 +206,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, roundup_pow_of_two(sizeof (struct mthca_next_seg) + srq->max_gs * sizeof (struct mthca_data_seg))); - if (ds > dev->limits.max_desc_sz) + if (!mthca_is_memfree(dev) && (ds > dev->limits.max_desc_sz)) return -EINVAL; srq->wqe_shift = long_log2(ds); @@ -660,6 +660,31 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, return err; } +int mthca_max_srq_sge(struct mthca_dev *dev) +{ + if (mthca_is_memfree(dev)) + return dev->limits.max_sg; + + /* + * SRQ allocations are based on powers of 2 for Tavor, + * (although they only need to be multiples of 16 bytes). + * + * Therefore, we need to base the max number of sg entries on + * the largest power of 2 descriptor size that is <= to the + * actual max WQE descriptor size, rather than return the + * max_sg value given by the firmware (which is based on WQE + * sizes as multiples of 16, not powers of 2). + * + * If SRQ implementation is changed for Tavor to be based on + * multiples of 16, the calculation below can be deleted and + * the FW max_sg value returned. + */ + return min_t(int, dev->limits.max_sg, + ((1 << (fls(dev->limits.max_desc_sz) - 1)) - + sizeof (struct mthca_next_seg)) / + sizeof (struct mthca_data_seg)); +} + int __devinit mthca_init_srq_table(struct mthca_dev *dev) { int err; @@ -684,7 +709,7 @@ int __devinit mthca_init_srq_table(struct mthca_dev *dev) return err; } -void __devexit mthca_cleanup_srq_table(struct mthca_dev *dev) +void mthca_cleanup_srq_table(struct mthca_dev *dev) { if (!(dev->mthca_flags & MTHCA_FLAG_SRQ)) return; diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig index 8d2e04cac68e..13d6d01c72c0 100644 --- a/drivers/infiniband/ulp/ipoib/Kconfig +++ b/drivers/infiniband/ulp/ipoib/Kconfig @@ -10,8 +10,9 @@ config INFINIBAND_IPOIB group: . config INFINIBAND_IPOIB_DEBUG - bool "IP-over-InfiniBand debugging" + bool "IP-over-InfiniBand debugging" if EMBEDDED depends on INFINIBAND_IPOIB + default y ---help--- This option causes debugging code to be compiled into the IPoIB driver. The output can be turned on via the diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index b640107fb732..12a1e0572ef2 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -65,6 +65,8 @@ enum { IPOIB_RX_RING_SIZE = 128, IPOIB_TX_RING_SIZE = 64, + IPOIB_MAX_QUEUE_SIZE = 8192, + IPOIB_MIN_QUEUE_SIZE = 2, IPOIB_NUM_WC = 4, @@ -230,6 +232,9 @@ static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh) INFINIBAND_ALEN, sizeof(void *)); } +struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh); +void ipoib_neigh_free(struct ipoib_neigh *neigh); + extern struct workqueue_struct *ipoib_workqueue; /* functions */ @@ -329,6 +334,8 @@ static inline void ipoib_unregister_debugfs(void) { } #define ipoib_warn(priv, format, arg...) \ ipoib_printk(KERN_WARNING, priv, format , ## arg) +extern int ipoib_sendq_size; +extern int ipoib_recvq_size; #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG extern int ipoib_debug_level; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c index 685258e34034..5dde380e8dbe 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c @@ -213,7 +213,7 @@ static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr) gid_buf, path.pathrec.dlid ? "yes" : "no"); if (path.pathrec.dlid) { - rate = ib_sa_rate_enum_to_int(path.pathrec.rate) * 25; + rate = ib_rate_to_mult(path.pathrec.rate) * 25; seq_printf(file, " DLID: 0x%04x\n" diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index ed65202878d8..a54da42849ae 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -161,7 +161,7 @@ static int ipoib_ib_post_receives(struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(dev); int i; - for (i = 0; i < IPOIB_RX_RING_SIZE; ++i) { + for (i = 0; i < ipoib_recvq_size; ++i) { if (ipoib_alloc_rx_skb(dev, i)) { ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); return -ENOMEM; @@ -187,7 +187,7 @@ static void ipoib_ib_handle_wc(struct net_device *dev, if (wr_id & IPOIB_OP_RECV) { wr_id &= ~IPOIB_OP_RECV; - if (wr_id < IPOIB_RX_RING_SIZE) { + if (wr_id < ipoib_recvq_size) { struct sk_buff *skb = priv->rx_ring[wr_id].skb; dma_addr_t addr = priv->rx_ring[wr_id].mapping; @@ -252,9 +252,9 @@ static void ipoib_ib_handle_wc(struct net_device *dev, struct ipoib_tx_buf *tx_req; unsigned long flags; - if (wr_id >= IPOIB_TX_RING_SIZE) { + if (wr_id >= ipoib_sendq_size) { ipoib_warn(priv, "completion event with wrid %d (> %d)\n", - wr_id, IPOIB_TX_RING_SIZE); + wr_id, ipoib_sendq_size); return; } @@ -275,7 +275,7 @@ static void ipoib_ib_handle_wc(struct net_device *dev, spin_lock_irqsave(&priv->tx_lock, flags); ++priv->tx_tail; if (netif_queue_stopped(dev) && - priv->tx_head - priv->tx_tail <= IPOIB_TX_RING_SIZE / 2) + priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1) netif_wake_queue(dev); spin_unlock_irqrestore(&priv->tx_lock, flags); @@ -344,13 +344,13 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, * means we have to make sure everything is properly recorded and * our state is consistent before we call post_send(). */ - tx_req = &priv->tx_ring[priv->tx_head & (IPOIB_TX_RING_SIZE - 1)]; + tx_req = &priv->tx_ring[priv->tx_head & (ipoib_sendq_size - 1)]; tx_req->skb = skb; addr = dma_map_single(priv->ca->dma_device, skb->data, skb->len, DMA_TO_DEVICE); pci_unmap_addr_set(tx_req, mapping, addr); - if (unlikely(post_send(priv, priv->tx_head & (IPOIB_TX_RING_SIZE - 1), + if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1), address->ah, qpn, addr, skb->len))) { ipoib_warn(priv, "post_send failed\n"); ++priv->stats.tx_errors; @@ -363,7 +363,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, address->last_send = priv->tx_head; ++priv->tx_head; - if (priv->tx_head - priv->tx_tail == IPOIB_TX_RING_SIZE) { + if (priv->tx_head - priv->tx_tail == ipoib_sendq_size) { ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n"); netif_stop_queue(dev); } @@ -488,7 +488,7 @@ static int recvs_pending(struct net_device *dev) int pending = 0; int i; - for (i = 0; i < IPOIB_RX_RING_SIZE; ++i) + for (i = 0; i < ipoib_recvq_size; ++i) if (priv->rx_ring[i].skb) ++pending; @@ -527,7 +527,7 @@ int ipoib_ib_dev_stop(struct net_device *dev) */ while ((int) priv->tx_tail - (int) priv->tx_head < 0) { tx_req = &priv->tx_ring[priv->tx_tail & - (IPOIB_TX_RING_SIZE - 1)]; + (ipoib_sendq_size - 1)]; dma_unmap_single(priv->ca->dma_device, pci_unmap_addr(tx_req, mapping), tx_req->skb->len, @@ -536,7 +536,7 @@ int ipoib_ib_dev_stop(struct net_device *dev) ++priv->tx_tail; } - for (i = 0; i < IPOIB_RX_RING_SIZE; ++i) + for (i = 0; i < ipoib_recvq_size; ++i) if (priv->rx_ring[i].skb) { dma_unmap_single(priv->ca->dma_device, pci_unmap_addr(&priv->rx_ring[i], diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 53a32f65788d..cb078a7d0bf5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -41,6 +41,7 @@ #include #include #include +#include #include /* For ARPHRD_xxx */ @@ -53,6 +54,14 @@ MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("IP-over-InfiniBand net driver"); MODULE_LICENSE("Dual BSD/GPL"); +int ipoib_sendq_size __read_mostly = IPOIB_TX_RING_SIZE; +int ipoib_recvq_size __read_mostly = IPOIB_RX_RING_SIZE; + +module_param_named(send_queue_size, ipoib_sendq_size, int, 0444); +MODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue"); +module_param_named(recv_queue_size, ipoib_recvq_size, int, 0444); +MODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue"); + #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG int ipoib_debug_level; @@ -252,8 +261,8 @@ static void path_free(struct net_device *dev, struct ipoib_path *path) */ if (neigh->ah) ipoib_put_ah(neigh->ah); - *to_ipoib_neigh(neigh->neighbour) = NULL; - kfree(neigh); + + ipoib_neigh_free(neigh); } spin_unlock_irqrestore(&priv->lock, flags); @@ -327,9 +336,8 @@ void ipoib_flush_paths(struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_path *path, *tp; LIST_HEAD(remove_list); - unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); list_splice(&priv->path_list, &remove_list); INIT_LIST_HEAD(&priv->path_list); @@ -337,14 +345,15 @@ void ipoib_flush_paths(struct net_device *dev) list_for_each_entry(path, &remove_list, list) rb_erase(&path->rb_node, &priv->path_tree); - spin_unlock_irqrestore(&priv->lock, flags); - list_for_each_entry_safe(path, tp, &remove_list, list) { if (path->query) ib_sa_cancel_query(path->query_id, path->query); + spin_unlock_irq(&priv->lock); wait_for_completion(&path->done); path_free(dev, path); + spin_lock_irq(&priv->lock); } + spin_unlock_irq(&priv->lock); } static void path_rec_completion(int status, @@ -373,16 +382,9 @@ static void path_rec_completion(int status, struct ib_ah_attr av = { .dlid = be16_to_cpu(pathrec->dlid), .sl = pathrec->sl, - .port_num = priv->port + .port_num = priv->port, + .static_rate = pathrec->rate }; - int path_rate = ib_sa_rate_enum_to_int(pathrec->rate); - - if (path_rate > 0 && priv->local_rate > path_rate) - av.static_rate = (priv->local_rate - 1) / path_rate; - - ipoib_dbg(priv, "static_rate %d for local port %dX, path %dX\n", - av.static_rate, priv->local_rate, - ib_sa_rate_enum_to_int(pathrec->rate)); ah = ipoib_create_ah(dev, priv->pd, &av); } @@ -481,7 +483,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) struct ipoib_path *path; struct ipoib_neigh *neigh; - neigh = kmalloc(sizeof *neigh, GFP_ATOMIC); + neigh = ipoib_neigh_alloc(skb->dst->neighbour); if (!neigh) { ++priv->stats.tx_dropped; dev_kfree_skb_any(skb); @@ -489,8 +491,6 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) } skb_queue_head_init(&neigh->queue); - neigh->neighbour = skb->dst->neighbour; - *to_ipoib_neigh(skb->dst->neighbour) = neigh; /* * We can only be called from ipoib_start_xmit, so we're @@ -503,7 +503,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) path = path_rec_create(dev, (union ib_gid *) (skb->dst->neighbour->ha + 4)); if (!path) - goto err; + goto err_path; __path_add(dev, path); } @@ -521,17 +521,17 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) __skb_queue_tail(&neigh->queue, skb); if (!path->query && path_rec_start(dev, path)) - goto err; + goto err_list; } spin_unlock(&priv->lock); return; -err: - *to_ipoib_neigh(skb->dst->neighbour) = NULL; +err_list: list_del(&neigh->list); - kfree(neigh); +err_path: + ipoib_neigh_free(neigh); ++priv->stats.tx_dropped; dev_kfree_skb_any(skb); @@ -723,7 +723,7 @@ static int ipoib_hard_header(struct sk_buff *skb, * destination address onto the front of the skb so we can * figure out where to send the packet later. */ - if (!skb->dst || !skb->dst->neighbour) { + if ((!skb->dst || !skb->dst->neighbour) && daddr) { struct ipoib_pseudoheader *phdr = (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); @@ -763,8 +763,7 @@ static void ipoib_neigh_destructor(struct neighbour *n) if (neigh->ah) ah = neigh->ah; list_del(&neigh->list); - *to_ipoib_neigh(n) = NULL; - kfree(neigh); + ipoib_neigh_free(neigh); } spin_unlock_irqrestore(&priv->lock, flags); @@ -773,6 +772,26 @@ static void ipoib_neigh_destructor(struct neighbour *n) ipoib_put_ah(ah); } +struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour) +{ + struct ipoib_neigh *neigh; + + neigh = kmalloc(sizeof *neigh, GFP_ATOMIC); + if (!neigh) + return NULL; + + neigh->neighbour = neighbour; + *to_ipoib_neigh(neighbour) = neigh; + + return neigh; +} + +void ipoib_neigh_free(struct ipoib_neigh *neigh) +{ + *to_ipoib_neigh(neigh->neighbour) = NULL; + kfree(neigh); +} + static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms) { parms->neigh_destructor = ipoib_neigh_destructor; @@ -785,20 +804,19 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) struct ipoib_dev_priv *priv = netdev_priv(dev); /* Allocate RX/TX "rings" to hold queued skbs */ - - priv->rx_ring = kzalloc(IPOIB_RX_RING_SIZE * sizeof (struct ipoib_rx_buf), + priv->rx_ring = kzalloc(ipoib_recvq_size * sizeof *priv->rx_ring, GFP_KERNEL); if (!priv->rx_ring) { printk(KERN_WARNING "%s: failed to allocate RX ring (%d entries)\n", - ca->name, IPOIB_RX_RING_SIZE); + ca->name, ipoib_recvq_size); goto out; } - priv->tx_ring = kzalloc(IPOIB_TX_RING_SIZE * sizeof (struct ipoib_tx_buf), + priv->tx_ring = kzalloc(ipoib_sendq_size * sizeof *priv->tx_ring, GFP_KERNEL); if (!priv->tx_ring) { printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n", - ca->name, IPOIB_TX_RING_SIZE); + ca->name, ipoib_sendq_size); goto out_rx_ring_cleanup; } @@ -866,7 +884,7 @@ static void ipoib_setup(struct net_device *dev) dev->hard_header_len = IPOIB_ENCAP_LEN + INFINIBAND_ALEN; dev->addr_len = INFINIBAND_ALEN; dev->type = ARPHRD_INFINIBAND; - dev->tx_queue_len = IPOIB_TX_RING_SIZE * 2; + dev->tx_queue_len = ipoib_sendq_size * 2; dev->features = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX; /* MTU will be reset when mcast join happens */ @@ -1118,6 +1136,14 @@ static int __init ipoib_init_module(void) { int ret; + ipoib_recvq_size = roundup_pow_of_two(ipoib_recvq_size); + ipoib_recvq_size = min(ipoib_recvq_size, IPOIB_MAX_QUEUE_SIZE); + ipoib_recvq_size = max(ipoib_recvq_size, IPOIB_MIN_QUEUE_SIZE); + + ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); + ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); + ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE); + ret = ipoib_register_debugfs(); if (ret) return ret; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 93c462eaf4fd..1dae4b238252 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -114,8 +114,7 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) */ if (neigh->ah) ipoib_put_ah(neigh->ah); - *to_ipoib_neigh(neigh->neighbour) = NULL; - kfree(neigh); + ipoib_neigh_free(neigh); } spin_unlock_irqrestore(&priv->lock, flags); @@ -251,6 +250,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, .port_num = priv->port, .sl = mcast->mcmember.sl, .ah_flags = IB_AH_GRH, + .static_rate = mcast->mcmember.rate, .grh = { .flow_label = be32_to_cpu(mcast->mcmember.flow_label), .hop_limit = mcast->mcmember.hop_limit, @@ -258,17 +258,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, .traffic_class = mcast->mcmember.traffic_class } }; - int path_rate = ib_sa_rate_enum_to_int(mcast->mcmember.rate); - av.grh.dgid = mcast->mcmember.mgid; - if (path_rate > 0 && priv->local_rate > path_rate) - av.static_rate = (priv->local_rate - 1) / path_rate; - - ipoib_dbg_mcast(priv, "static_rate %d for local port %dX, mcmember %dX\n", - av.static_rate, priv->local_rate, - ib_sa_rate_enum_to_int(mcast->mcmember.rate)); - ah = ipoib_create_ah(dev, priv->pd, &av); if (!ah) { ipoib_warn(priv, "ib_address_create failed\n"); @@ -618,6 +609,22 @@ int ipoib_mcast_start_thread(struct net_device *dev) return 0; } +static void wait_for_mcast_join(struct ipoib_dev_priv *priv, + struct ipoib_mcast *mcast) +{ + spin_lock_irq(&priv->lock); + if (mcast && mcast->query) { + ib_sa_cancel_query(mcast->query_id, mcast->query); + mcast->query = NULL; + spin_unlock_irq(&priv->lock); + ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n", + IPOIB_GID_ARG(mcast->mcmember.mgid)); + wait_for_completion(&mcast->done); + } + else + spin_unlock_irq(&priv->lock); +} + int ipoib_mcast_stop_thread(struct net_device *dev, int flush) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -637,28 +644,10 @@ int ipoib_mcast_stop_thread(struct net_device *dev, int flush) if (flush) flush_workqueue(ipoib_workqueue); - spin_lock_irq(&priv->lock); - if (priv->broadcast && priv->broadcast->query) { - ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query); - priv->broadcast->query = NULL; - spin_unlock_irq(&priv->lock); - ipoib_dbg_mcast(priv, "waiting for bcast\n"); - wait_for_completion(&priv->broadcast->done); - } else - spin_unlock_irq(&priv->lock); + wait_for_mcast_join(priv, priv->broadcast); - list_for_each_entry(mcast, &priv->multicast_list, list) { - spin_lock_irq(&priv->lock); - if (mcast->query) { - ib_sa_cancel_query(mcast->query_id, mcast->query); - mcast->query = NULL; - spin_unlock_irq(&priv->lock); - ipoib_dbg_mcast(priv, "waiting for MGID " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); - wait_for_completion(&mcast->done); - } else - spin_unlock_irq(&priv->lock); - } + list_for_each_entry(mcast, &priv->multicast_list, list) + wait_for_mcast_join(priv, mcast); return 0; } @@ -772,13 +761,11 @@ out: if (skb->dst && skb->dst->neighbour && !*to_ipoib_neigh(skb->dst->neighbour)) { - struct ipoib_neigh *neigh = kmalloc(sizeof *neigh, GFP_ATOMIC); + struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour); if (neigh) { kref_get(&mcast->ah->ref); neigh->ah = mcast->ah; - neigh->neighbour = skb->dst->neighbour; - *to_ipoib_neigh(skb->dst->neighbour) = neigh; list_add_tail(&neigh->list, &mcast->neigh_list); } } @@ -913,6 +900,7 @@ void ipoib_mcast_restart_task(void *dev_ptr) /* We have to cancel outside of the spinlock */ list_for_each_entry_safe(mcast, tmcast, &remove_list, list) { + wait_for_mcast_join(priv, mcast); ipoib_mcast_leave(mcast->dev, mcast); ipoib_mcast_free(mcast); } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 5f0388027b25..1d49d1643c59 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -159,8 +159,8 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_init_attr init_attr = { .cap = { - .max_send_wr = IPOIB_TX_RING_SIZE, - .max_recv_wr = IPOIB_RX_RING_SIZE, + .max_send_wr = ipoib_sendq_size, + .max_recv_wr = ipoib_recvq_size, .max_send_sge = 1, .max_recv_sge = 1 }, @@ -175,7 +175,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) } priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, - IPOIB_TX_RING_SIZE + IPOIB_RX_RING_SIZE + 1); + ipoib_sendq_size + ipoib_recvq_size + 1); if (IS_ERR(priv->cq)) { printk(KERN_WARNING "%s: failed to create CQ\n", ca->name); goto out_free_pd; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 61924cc30e55..5f2b3f6e4c47 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -607,10 +607,10 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, */ if (likely(scmnd->use_sg)) { nents = scmnd->use_sg; - scat = (struct scatterlist *) scmnd->request_buffer; + scat = scmnd->request_buffer; } else { nents = 1; - scat = (struct scatterlist *) scmnd->request_buffer; + scat = &req->fake_sg; } dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents, @@ -1434,6 +1434,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) p = match_strdup(args); if (strlen(p) != 32) { printk(KERN_WARNING PFX "bad dest GID parameter '%s'\n", p); + kfree(p); goto out; } diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c index d7828936fd8f..07358fb51b82 100644 --- a/drivers/input/evbug.c +++ b/drivers/input/evbug.c @@ -49,9 +49,8 @@ static struct input_handle *evbug_connect(struct input_handler *handler, struct { struct input_handle *handle; - if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) return NULL; - memset(handle, 0, sizeof(struct input_handle)); handle->dev = dev; handle->handler = handler; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 745979f33dc2..a34e3d91d9ed 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -130,9 +130,8 @@ static int evdev_open(struct inode * inode, struct file * file) if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) return accept_err; - if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) + if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL))) return -ENOMEM; - memset(list, 0, sizeof(struct evdev_list)); list->evdev = evdev_table[i]; list_add_tail(&list->node, &evdev_table[i]->list); @@ -609,9 +608,8 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct return NULL; } - if (!(evdev = kmalloc(sizeof(struct evdev), GFP_KERNEL))) + if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL))) return NULL; - memset(evdev, 0, sizeof(struct evdev)); INIT_LIST_HEAD(&evdev->list); init_waitqueue_head(&evdev->wait); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index b765a155c008..36644bff379d 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -22,6 +22,7 @@ #include #include #include /* HZ */ +#include /*#include */ @@ -43,10 +44,10 @@ EXPORT_SYMBOL(gameport_start_polling); EXPORT_SYMBOL(gameport_stop_polling); /* - * gameport_sem protects entire gameport subsystem and is taken + * gameport_mutex protects entire gameport subsystem and is taken * every time gameport port or driver registrered or unregistered. */ -static DECLARE_MUTEX(gameport_sem); +static DEFINE_MUTEX(gameport_mutex); static LIST_HEAD(gameport_list); @@ -265,6 +266,7 @@ static void gameport_queue_event(void *object, struct module *owner, if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) { if (!try_module_get(owner)) { printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type); + kfree(event); goto out; } @@ -342,7 +344,7 @@ static void gameport_handle_event(void) struct gameport_event *event; struct gameport_driver *gameport_drv; - down(&gameport_sem); + mutex_lock(&gameport_mutex); /* * Note that we handle only one event here to give swsusp @@ -379,7 +381,7 @@ static void gameport_handle_event(void) gameport_free_event(event); } - up(&gameport_sem); + mutex_unlock(&gameport_mutex); } /* @@ -464,7 +466,7 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut struct device_driver *drv; int retval; - retval = down_interruptible(&gameport_sem); + retval = mutex_lock_interruptible(&gameport_mutex); if (retval) return retval; @@ -484,7 +486,7 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut retval = -EINVAL; } - up(&gameport_sem); + mutex_unlock(&gameport_mutex); return retval; } @@ -521,7 +523,7 @@ static void gameport_init_port(struct gameport *gameport) __module_get(THIS_MODULE); - init_MUTEX(&gameport->drv_sem); + mutex_init(&gameport->drv_mutex); device_initialize(&gameport->dev); snprintf(gameport->dev.bus_id, sizeof(gameport->dev.bus_id), "gameport%lu", (unsigned long)atomic_inc_return(&gameport_no) - 1); @@ -661,10 +663,10 @@ void __gameport_register_port(struct gameport *gameport, struct module *owner) */ void gameport_unregister_port(struct gameport *gameport) { - down(&gameport_sem); + mutex_lock(&gameport_mutex); gameport_disconnect_port(gameport); gameport_destroy_port(gameport); - up(&gameport_sem); + mutex_unlock(&gameport_mutex); } @@ -717,7 +719,7 @@ void gameport_unregister_driver(struct gameport_driver *drv) { struct gameport *gameport; - down(&gameport_sem); + mutex_lock(&gameport_mutex); drv->ignore = 1; /* so gameport_find_driver ignores it */ start_over: @@ -731,7 +733,7 @@ start_over: } driver_unregister(&drv->driver); - up(&gameport_sem); + mutex_unlock(&gameport_mutex); } static int gameport_bus_match(struct device *dev, struct device_driver *drv) @@ -743,9 +745,9 @@ static int gameport_bus_match(struct device *dev, struct device_driver *drv) static void gameport_set_drv(struct gameport *gameport, struct gameport_driver *drv) { - down(&gameport->drv_sem); + mutex_lock(&gameport->drv_mutex); gameport->drv = drv; - up(&gameport->drv_sem); + mutex_unlock(&gameport->drv_mutex); } int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mode) @@ -796,5 +798,5 @@ static void __exit gameport_exit(void) kthread_stop(gameport_task); } -module_init(gameport_init); +subsys_initcall(gameport_init); module_exit(gameport_exit); diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index d2e55dc956ba..3e2d28f263e9 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -252,14 +252,14 @@ static struct pnp_driver ns558_pnp_driver; #endif -static int pnp_registered = 0; - static int __init ns558_init(void) { int i = 0; + int error; - if (pnp_register_driver(&ns558_pnp_driver) >= 0) - pnp_registered = 1; + error = pnp_register_driver(&ns558_pnp_driver); + if (error && error != -ENODEV) /* should be ENOSYS really */ + return error; /* * Probe ISA ports after PnP, so that PnP ports that are already @@ -270,7 +270,7 @@ static int __init ns558_init(void) while (ns558_isa_portlist[i]) ns558_isa_probe(ns558_isa_portlist[i++]); - return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0; + return list_empty(&ns558_list) && error ? -ENODEV : 0; } static void __exit ns558_exit(void) @@ -283,8 +283,7 @@ static void __exit ns558_exit(void) kfree(ns558); } - if (pnp_registered) - pnp_unregister_driver(&ns558_pnp_driver); + pnp_unregister_driver(&ns558_pnp_driver); } module_init(ns558_init); diff --git a/drivers/input/input.c b/drivers/input/input.c index f8af0945964e..a935abeffffc 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -18,9 +18,11 @@ #include #include #include +#include #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Input core"); @@ -224,7 +226,7 @@ int input_open_device(struct input_handle *handle) struct input_dev *dev = handle->dev; int err; - err = down_interruptible(&dev->sem); + err = mutex_lock_interruptible(&dev->mutex); if (err) return err; @@ -236,7 +238,7 @@ int input_open_device(struct input_handle *handle) if (err) handle->open--; - up(&dev->sem); + mutex_unlock(&dev->mutex); return err; } @@ -255,13 +257,13 @@ void input_close_device(struct input_handle *handle) input_release_device(handle); - down(&dev->sem); + mutex_lock(&dev->mutex); if (!--dev->users && dev->close) dev->close(dev); handle->open--; - up(&dev->sem); + mutex_unlock(&dev->mutex); } static void input_link_handle(struct input_handle *handle) @@ -315,21 +317,6 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st return NULL; } -static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap, int max) -{ - int i; - int len = 0; - - for (i = NBITS(max) - 1; i > 0; i--) - if (bitmap[i]) - break; - - for (; i >= 0; i--) - len += snprintf(buf + len, max(buf_size - len, 0), - "%lx%s", bitmap[i], i > 0 ? " " : ""); - return len; -} - #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_bus_input_dir; @@ -342,7 +329,7 @@ static inline void input_wakeup_procfs_readers(void) wake_up(&input_devices_poll_wait); } -static unsigned int input_devices_poll(struct file *file, poll_table *wait) +static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait) { int state = input_devices_state; poll_wait(file, &input_devices_poll_wait, wait); @@ -351,115 +338,171 @@ static unsigned int input_devices_poll(struct file *file, poll_table *wait) return 0; } -#define SPRINTF_BIT(ev, bm) \ - do { \ - len += sprintf(buf + len, "B: %s=", #ev); \ - len += input_print_bitmap(buf + len, INT_MAX, \ - dev->bm##bit, ev##_MAX); \ - len += sprintf(buf + len, "\n"); \ - } while (0) - -#define TEST_AND_SPRINTF_BIT(ev, bm) \ - do { \ - if (test_bit(EV_##ev, dev->evbit)) \ - SPRINTF_BIT(ev, bm); \ - } while (0) - -static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +static struct list_head *list_get_nth_element(struct list_head *list, loff_t *pos) { - struct input_dev *dev; + struct list_head *node; + loff_t i = 0; + + list_for_each(node, list) + if (i++ == *pos) + return node; + + return NULL; +} + +static struct list_head *list_get_next_element(struct list_head *list, struct list_head *element, loff_t *pos) +{ + if (element->next == list) + return NULL; + + ++(*pos); + return element->next; +} + +static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos) +{ + /* acquire lock here ... Yes, we do need locking, I knowi, I know... */ + + return list_get_nth_element(&input_dev_list, pos); +} + +static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + return list_get_next_element(&input_dev_list, v, pos); +} + +static void input_devices_seq_stop(struct seq_file *seq, void *v) +{ + /* release lock here */ +} + +static void input_seq_print_bitmap(struct seq_file *seq, const char *name, + unsigned long *bitmap, int max) +{ + int i; + + for (i = NBITS(max) - 1; i > 0; i--) + if (bitmap[i]) + break; + + seq_printf(seq, "B: %s=", name); + for (; i >= 0; i--) + seq_printf(seq, "%lx%s", bitmap[i], i > 0 ? " " : ""); + seq_putc(seq, '\n'); +} + +static int input_devices_seq_show(struct seq_file *seq, void *v) +{ + struct input_dev *dev = container_of(v, struct input_dev, node); + const char *path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); struct input_handle *handle; - const char *path; - off_t at = 0; - int len, cnt = 0; + seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", + dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); - list_for_each_entry(dev, &input_dev_list, node) { + seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); + seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : ""); + seq_printf(seq, "S: Sysfs=%s\n", path ? path : ""); + seq_printf(seq, "H: Handlers="); - path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL); + list_for_each_entry(handle, &dev->h_list, d_node) + seq_printf(seq, "%s ", handle->name); + seq_putc(seq, '\n'); - len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", - dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); + input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX); + if (test_bit(EV_KEY, dev->evbit)) + input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX); + if (test_bit(EV_REL, dev->evbit)) + input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX); + if (test_bit(EV_ABS, dev->evbit)) + input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX); + if (test_bit(EV_MSC, dev->evbit)) + input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX); + if (test_bit(EV_LED, dev->evbit)) + input_seq_print_bitmap(seq, "LED", dev->ledbit, LED_MAX); + if (test_bit(EV_SND, dev->evbit)) + input_seq_print_bitmap(seq, "SND", dev->sndbit, SND_MAX); + if (test_bit(EV_FF, dev->evbit)) + input_seq_print_bitmap(seq, "FF", dev->ffbit, FF_MAX); + if (test_bit(EV_SW, dev->evbit)) + input_seq_print_bitmap(seq, "SW", dev->swbit, SW_MAX); - len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); - len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); - len += sprintf(buf + len, "S: Sysfs=%s\n", path ? path : ""); - len += sprintf(buf + len, "H: Handlers="); + seq_putc(seq, '\n'); - list_for_each_entry(handle, &dev->h_list, d_node) - len += sprintf(buf + len, "%s ", handle->name); - - len += sprintf(buf + len, "\n"); - - SPRINTF_BIT(EV, ev); - TEST_AND_SPRINTF_BIT(KEY, key); - TEST_AND_SPRINTF_BIT(REL, rel); - TEST_AND_SPRINTF_BIT(ABS, abs); - TEST_AND_SPRINTF_BIT(MSC, msc); - TEST_AND_SPRINTF_BIT(LED, led); - TEST_AND_SPRINTF_BIT(SND, snd); - TEST_AND_SPRINTF_BIT(FF, ff); - TEST_AND_SPRINTF_BIT(SW, sw); - - len += sprintf(buf + len, "\n"); - - at += len; - - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else cnt += len; - buf += len; - if (cnt >= count) - break; - } - - kfree(path); - } - - if (&dev->node == &input_dev_list) - *eof = 1; - - return (count > cnt) ? cnt : count; + kfree(path); + return 0; } -static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +static struct seq_operations input_devices_seq_ops = { + .start = input_devices_seq_start, + .next = input_devices_seq_next, + .stop = input_devices_seq_stop, + .show = input_devices_seq_show, +}; + +static int input_proc_devices_open(struct inode *inode, struct file *file) { - struct input_handler *handler; - - off_t at = 0; - int len = 0, cnt = 0; - int i = 0; - - list_for_each_entry(handler, &input_handler_list, node) { - - if (handler->fops) - len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n", - i++, handler->name, handler->minor); - else - len = sprintf(buf, "N: Number=%d Name=%s\n", - i++, handler->name); - - at += len; - - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else cnt += len; - buf += len; - if (cnt >= count) - break; - } - } - if (&handler->node == &input_handler_list) - *eof = 1; - - return (count > cnt) ? cnt : count; + return seq_open(file, &input_devices_seq_ops); } -static struct file_operations input_fileops; +static struct file_operations input_devices_fileops = { + .owner = THIS_MODULE, + .open = input_proc_devices_open, + .poll = input_proc_devices_poll, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos) +{ + /* acquire lock here ... Yes, we do need locking, I knowi, I know... */ + seq->private = (void *)(unsigned long)*pos; + return list_get_nth_element(&input_handler_list, pos); +} + +static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + seq->private = (void *)(unsigned long)(*pos + 1); + return list_get_next_element(&input_handler_list, v, pos); +} + +static void input_handlers_seq_stop(struct seq_file *seq, void *v) +{ + /* release lock here */ +} + +static int input_handlers_seq_show(struct seq_file *seq, void *v) +{ + struct input_handler *handler = container_of(v, struct input_handler, node); + + seq_printf(seq, "N: Number=%ld Name=%s", + (unsigned long)seq->private, handler->name); + if (handler->fops) + seq_printf(seq, " Minor=%d", handler->minor); + seq_putc(seq, '\n'); + + return 0; +} +static struct seq_operations input_handlers_seq_ops = { + .start = input_handlers_seq_start, + .next = input_handlers_seq_next, + .stop = input_handlers_seq_stop, + .show = input_handlers_seq_show, +}; + +static int input_proc_handlers_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &input_handlers_seq_ops); +} + +static struct file_operations input_handlers_fileops = { + .owner = THIS_MODULE, + .open = input_proc_handlers_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; static int __init input_proc_init(void) { @@ -471,20 +514,19 @@ static int __init input_proc_init(void) proc_bus_input_dir->owner = THIS_MODULE; - entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL); + entry = create_proc_entry("devices", 0, proc_bus_input_dir); if (!entry) goto fail1; entry->owner = THIS_MODULE; - input_fileops = *entry->proc_fops; - input_fileops.poll = input_devices_poll; - entry->proc_fops = &input_fileops; + entry->proc_fops = &input_devices_fileops; - entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL); + entry = create_proc_entry("handlers", 0, proc_bus_input_dir); if (!entry) goto fail2; entry->owner = THIS_MODULE; + entry->proc_fops = &input_handlers_fileops; return 0; @@ -512,13 +554,14 @@ static ssize_t input_dev_show_##name(struct class_device *dev, char *buf) \ struct input_dev *input_dev = to_input_dev(dev); \ int retval; \ \ - retval = down_interruptible(&input_dev->sem); \ + retval = mutex_lock_interruptible(&input_dev->mutex); \ if (retval) \ return retval; \ \ - retval = sprintf(buf, "%s\n", input_dev->name ? input_dev->name : ""); \ + retval = scnprintf(buf, PAGE_SIZE, \ + "%s\n", input_dev->name ? input_dev->name : ""); \ \ - up(&input_dev->sem); \ + mutex_unlock(&input_dev->mutex); \ \ return retval; \ } \ @@ -528,46 +571,51 @@ INPUT_DEV_STRING_ATTR_SHOW(name); INPUT_DEV_STRING_ATTR_SHOW(phys); INPUT_DEV_STRING_ATTR_SHOW(uniq); -static int print_modalias_bits(char *buf, int size, char prefix, unsigned long *arr, - unsigned int min, unsigned int max) +static int input_print_modalias_bits(char *buf, int size, + char name, unsigned long *bm, + unsigned int min_bit, unsigned int max_bit) { - int len, i; + int len = 0, i; - len = snprintf(buf, size, "%c", prefix); - for (i = min; i < max; i++) - if (arr[LONG(i)] & BIT(i)) - len += snprintf(buf + len, size - len, "%X,", i); + len += snprintf(buf, max(size, 0), "%c", name); + for (i = min_bit; i < max_bit; i++) + if (bm[LONG(i)] & BIT(i)) + len += snprintf(buf + len, max(size - len, 0), "%X,", i); return len; } -static int print_modalias(char *buf, int size, struct input_dev *id) +static int input_print_modalias(char *buf, int size, struct input_dev *id, + int add_cr) { int len; - len = snprintf(buf, size, "input:b%04Xv%04Xp%04Xe%04X-", - id->id.bustype, - id->id.vendor, - id->id.product, - id->id.version); + len = snprintf(buf, max(size, 0), + "input:b%04Xv%04Xp%04Xe%04X-", + id->id.bustype, id->id.vendor, + id->id.product, id->id.version); + + len += input_print_modalias_bits(buf + len, size - len, + 'e', id->evbit, 0, EV_MAX); + len += input_print_modalias_bits(buf + len, size - len, + 'k', id->keybit, KEY_MIN_INTERESTING, KEY_MAX); + len += input_print_modalias_bits(buf + len, size - len, + 'r', id->relbit, 0, REL_MAX); + len += input_print_modalias_bits(buf + len, size - len, + 'a', id->absbit, 0, ABS_MAX); + len += input_print_modalias_bits(buf + len, size - len, + 'm', id->mscbit, 0, MSC_MAX); + len += input_print_modalias_bits(buf + len, size - len, + 'l', id->ledbit, 0, LED_MAX); + len += input_print_modalias_bits(buf + len, size - len, + 's', id->sndbit, 0, SND_MAX); + len += input_print_modalias_bits(buf + len, size - len, + 'f', id->ffbit, 0, FF_MAX); + len += input_print_modalias_bits(buf + len, size - len, + 'w', id->swbit, 0, SW_MAX); + + if (add_cr) + len += snprintf(buf + len, max(size - len, 0), "\n"); - len += print_modalias_bits(buf + len, size - len, 'e', id->evbit, - 0, EV_MAX); - len += print_modalias_bits(buf + len, size - len, 'k', id->keybit, - KEY_MIN_INTERESTING, KEY_MAX); - len += print_modalias_bits(buf + len, size - len, 'r', id->relbit, - 0, REL_MAX); - len += print_modalias_bits(buf + len, size - len, 'a', id->absbit, - 0, ABS_MAX); - len += print_modalias_bits(buf + len, size - len, 'm', id->mscbit, - 0, MSC_MAX); - len += print_modalias_bits(buf + len, size - len, 'l', id->ledbit, - 0, LED_MAX); - len += print_modalias_bits(buf + len, size - len, 's', id->sndbit, - 0, SND_MAX); - len += print_modalias_bits(buf + len, size - len, 'f', id->ffbit, - 0, FF_MAX); - len += print_modalias_bits(buf + len, size - len, 'w', id->swbit, - 0, SW_MAX); return len; } @@ -576,9 +624,9 @@ static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf) struct input_dev *id = to_input_dev(dev); ssize_t len; - len = print_modalias(buf, PAGE_SIZE, id); - len += snprintf(buf + len, PAGE_SIZE-len, "\n"); - return len; + len = input_print_modalias(buf, PAGE_SIZE, id, 1); + + return max_t(int, len, PAGE_SIZE); } static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL); @@ -598,7 +646,7 @@ static struct attribute_group input_dev_attr_group = { static ssize_t input_dev_show_id_##name(struct class_device *dev, char *buf) \ { \ struct input_dev *input_dev = to_input_dev(dev); \ - return sprintf(buf, "%04x\n", input_dev->id.name); \ + return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name); \ } \ static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL); @@ -620,11 +668,33 @@ static struct attribute_group input_dev_id_attr_group = { .attrs = input_dev_id_attrs, }; +static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap, + int max, int add_cr) +{ + int i; + int len = 0; + + for (i = NBITS(max) - 1; i > 0; i--) + if (bitmap[i]) + break; + + for (; i >= 0; i--) + len += snprintf(buf + len, max(buf_size - len, 0), + "%lx%s", bitmap[i], i > 0 ? " " : ""); + + if (add_cr) + len += snprintf(buf + len, max(buf_size - len, 0), "\n"); + + return len; +} + #define INPUT_DEV_CAP_ATTR(ev, bm) \ static ssize_t input_dev_show_cap_##bm(struct class_device *dev, char *buf) \ { \ struct input_dev *input_dev = to_input_dev(dev); \ - return input_print_bitmap(buf, PAGE_SIZE, input_dev->bm##bit, ev##_MAX);\ + int len = input_print_bitmap(buf, PAGE_SIZE, \ + input_dev->bm##bit, ev##_MAX, 1); \ + return min_t(int, len, PAGE_SIZE); \ } \ static CLASS_DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL); @@ -669,8 +739,8 @@ static void input_dev_release(struct class_device *class_dev) * device bitfields. */ static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index, - char *buffer, int buffer_size, int *cur_len, - const char *name, unsigned long *bitmap, int max) + char *buffer, int buffer_size, int *cur_len, + const char *name, unsigned long *bitmap, int max) { if (*cur_index >= num_envp - 1) return -ENOMEM; @@ -678,12 +748,36 @@ static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index, envp[*cur_index] = buffer + *cur_len; *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name); - if (*cur_len > buffer_size) + if (*cur_len >= buffer_size) return -ENOMEM; *cur_len += input_print_bitmap(buffer + *cur_len, max(buffer_size - *cur_len, 0), - bitmap, max) + 1; + bitmap, max, 0) + 1; + if (*cur_len > buffer_size) + return -ENOMEM; + + (*cur_index)++; + return 0; +} + +static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index, + char *buffer, int buffer_size, int *cur_len, + struct input_dev *dev) +{ + if (*cur_index >= num_envp - 1) + return -ENOMEM; + + envp[*cur_index] = buffer + *cur_len; + + *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), + "MODALIAS="); + if (*cur_len >= buffer_size) + return -ENOMEM; + + *cur_len += input_print_modalias(buffer + *cur_len, + max(buffer_size - *cur_len, 0), + dev, 0) + 1; if (*cur_len > buffer_size) return -ENOMEM; @@ -693,7 +787,7 @@ static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index, #define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ do { \ - int err = add_uevent_var(envp, num_envp, &i, \ + int err = add_uevent_var(envp, num_envp, &i, \ buffer, buffer_size, &len, \ fmt, val); \ if (err) \ @@ -709,6 +803,16 @@ static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index, return err; \ } while (0) +#define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \ + do { \ + int err = input_add_uevent_modalias_var(envp, \ + num_envp, &i, \ + buffer, buffer_size, &len, \ + dev); \ + if (err) \ + return err; \ + } while (0) + static int input_dev_uevent(struct class_device *cdev, char **envp, int num_envp, char *buffer, int buffer_size) { @@ -744,9 +848,7 @@ static int input_dev_uevent(struct class_device *cdev, char **envp, if (test_bit(EV_SW, dev->evbit)) INPUT_ADD_HOTPLUG_BM_VAR("SW=", dev->swbit, SW_MAX); - envp[i++] = buffer + len; - len += snprintf(buffer + len, buffer_size - len, "MODALIAS="); - len += print_modalias(buffer + len, buffer_size - len, dev) + 1; + INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev); envp[i] = NULL; return 0; @@ -790,7 +892,7 @@ int input_register_device(struct input_dev *dev) return -EINVAL; } - init_MUTEX(&dev->sem); + mutex_init(&dev->mutex); set_bit(EV_SYN, dev->evbit); /* diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 20e2972b9204..949bdcef8c2b 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -171,9 +171,8 @@ static int joydev_open(struct inode *inode, struct file *file) if (i >= JOYDEV_MINORS || !joydev_table[i]) return -ENODEV; - if (!(list = kmalloc(sizeof(struct joydev_list), GFP_KERNEL))) + if (!(list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL))) return -ENOMEM; - memset(list, 0, sizeof(struct joydev_list)); list->joydev = joydev_table[i]; list_add_tail(&list->node, &joydev_table[i]->list); @@ -457,9 +456,8 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct return NULL; } - if (!(joydev = kmalloc(sizeof(struct joydev), GFP_KERNEL))) + if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL))) return NULL; - memset(joydev, 0, sizeof(struct joydev)); INIT_LIST_HEAD(&joydev->list); init_waitqueue_head(&joydev->wait); diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index ec55a29fc861..7249d324297b 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of , (default is __obsolete_setup("amijoy="); static int amijoy_used; -static DECLARE_MUTEX(amijoy_sem); +static DEFINE_MUTEX(amijoy_mutex); static struct input_dev *amijoy_dev[2]; static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" }; @@ -85,7 +86,7 @@ static int amijoy_open(struct input_dev *dev) { int err; - err = down_interruptible(&amijoy_sem); + err = mutex_lock_interruptible(&amijoy_mutex); if (err) return err; @@ -97,16 +98,16 @@ static int amijoy_open(struct input_dev *dev) amijoy_used++; out: - up(&amijoy_sem); + mutex_unlock(&amijoy_mutex); return err; } static void amijoy_close(struct input_dev *dev) { - down(&amijoy_sem); + mutex_lock(&amijoy_mutex); if (!--amijoy_used) free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt); - up(&amijoy_sem); + mutex_unlock(&amijoy_mutex); } static int __init amijoy_init(void) diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index dcffc34f30c3..e61894685cb1 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -38,6 +38,7 @@ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver"); @@ -111,7 +112,7 @@ struct db9 { struct pardevice *pd; int mode; int used; - struct semaphore sem; + struct mutex mutex; char phys[DB9_MAX_DEVICES][32]; }; @@ -525,7 +526,7 @@ static int db9_open(struct input_dev *dev) struct parport *port = db9->pd->port; int err; - err = down_interruptible(&db9->sem); + err = mutex_lock_interruptible(&db9->mutex); if (err) return err; @@ -539,7 +540,7 @@ static int db9_open(struct input_dev *dev) mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME); } - up(&db9->sem); + mutex_unlock(&db9->mutex); return 0; } @@ -548,14 +549,14 @@ static void db9_close(struct input_dev *dev) struct db9 *db9 = dev->private; struct parport *port = db9->pd->port; - down(&db9->sem); + mutex_lock(&db9->mutex); if (!--db9->used) { del_timer_sync(&db9->timer); parport_write_control(port, 0x00); parport_data_forward(port); parport_release(db9->pd); } - up(&db9->sem); + mutex_unlock(&db9->mutex); } static struct db9 __init *db9_probe(int parport, int mode) @@ -603,7 +604,7 @@ static struct db9 __init *db9_probe(int parport, int mode) goto err_unreg_pardev; } - init_MUTEX(&db9->sem); + mutex_init(&db9->mutex); db9->pd = pd; db9->mode = mode; init_timer(&db9->timer); diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 900587acdb47..ecbdb6b9bbd6 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -7,6 +7,7 @@ * Based on the work of: * Andree Borrmann John Dahlstrom * David Kuder Nathan Hand + * Raphael Assenat */ /* @@ -36,6 +37,7 @@ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver"); @@ -72,8 +74,9 @@ __obsolete_setup("gc_3="); #define GC_N64 6 #define GC_PSX 7 #define GC_DDR 8 +#define GC_SNESMOUSE 9 -#define GC_MAX 8 +#define GC_MAX 9 #define GC_REFRESH_TIME HZ/100 @@ -83,7 +86,7 @@ struct gc { struct timer_list timer; unsigned char pads[GC_MAX + 1]; int used; - struct semaphore sem; + struct mutex mutex; char phys[GC_MAX_DEVICES][32]; }; @@ -93,7 +96,7 @@ static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", "Multisystem 2-button joystick", "N64 controller", "PSX controller", - "PSX DDR controller" }; + "PSX DDR controller", "SNES mouse" }; /* * N64 support. */ @@ -205,9 +208,12 @@ static void gc_n64_process_packet(struct gc *gc) * NES/SNES support. */ -#define GC_NES_DELAY 6 /* Delay between bits - 6us */ -#define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */ -#define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */ +#define GC_NES_DELAY 6 /* Delay between bits - 6us */ +#define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */ +#define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the + last 4 bits are unused */ +#define GC_SNESMOUSE_LENGTH 32 /* The SNES mouse uses 32 bits, the first + 16 bits are equivalent to a gamepad */ #define GC_NES_POWER 0xfc #define GC_NES_CLOCK 0x01 @@ -242,11 +248,15 @@ static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data) static void gc_nes_process_packet(struct gc *gc) { - unsigned char data[GC_SNES_LENGTH]; + unsigned char data[GC_SNESMOUSE_LENGTH]; struct input_dev *dev; - int i, j, s; + int i, j, s, len; + char x_rel, y_rel; - gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data); + len = gc->pads[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH : + (gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH); + + gc_nes_read_packet(gc, len, data); for (i = 0; i < GC_MAX_DEVICES; i++) { @@ -269,6 +279,44 @@ static void gc_nes_process_packet(struct gc *gc) for (j = 0; j < 8; j++) input_report_key(dev, gc_snes_btn[j], s & data[gc_snes_bytes[j]]); + if (s & gc->pads[GC_SNESMOUSE]) { + /* + * The 4 unused bits from SNES controllers appear to be ID bits + * so use them to make sure iwe are dealing with a mouse. + * gamepad is connected. This is important since + * my SNES gamepad sends 1's for bits 16-31, which + * cause the mouse pointer to quickly move to the + * upper left corner of the screen. + */ + if (!(s & data[12]) && !(s & data[13]) && + !(s & data[14]) && (s & data[15])) { + input_report_key(dev, BTN_LEFT, s & data[9]); + input_report_key(dev, BTN_RIGHT, s & data[8]); + + x_rel = y_rel = 0; + for (j = 0; j < 7; j++) { + x_rel <<= 1; + if (data[25 + j] & s) + x_rel |= 1; + + y_rel <<= 1; + if (data[17 + j] & s) + y_rel |= 1; + } + + if (x_rel) { + if (data[24] & s) + x_rel = -x_rel; + input_report_rel(dev, REL_X, x_rel); + } + + if (y_rel) { + if (data[16] & s) + y_rel = -y_rel; + input_report_rel(dev, REL_Y, y_rel); + } + } + } input_sync(dev); } } @@ -524,10 +572,10 @@ static void gc_timer(unsigned long private) gc_n64_process_packet(gc); /* - * NES and SNES pads + * NES and SNES pads or mouse */ - if (gc->pads[GC_NES] || gc->pads[GC_SNES]) + if (gc->pads[GC_NES] || gc->pads[GC_SNES] || gc->pads[GC_SNESMOUSE]) gc_nes_process_packet(gc); /* @@ -552,7 +600,7 @@ static int gc_open(struct input_dev *dev) struct gc *gc = dev->private; int err; - err = down_interruptible(&gc->sem); + err = mutex_lock_interruptible(&gc->mutex); if (err) return err; @@ -562,7 +610,7 @@ static int gc_open(struct input_dev *dev) mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); } - up(&gc->sem); + mutex_unlock(&gc->mutex); return 0; } @@ -570,13 +618,13 @@ static void gc_close(struct input_dev *dev) { struct gc *gc = dev->private; - down(&gc->sem); + mutex_lock(&gc->mutex); if (!--gc->used) { del_timer_sync(&gc->timer); parport_write_control(gc->pd->port, 0x00); parport_release(gc->pd); } - up(&gc->sem); + mutex_unlock(&gc->mutex); } static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) @@ -609,10 +657,13 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) input_dev->open = gc_open; input_dev->close = gc_close; - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + if (pad_type != GC_SNESMOUSE) { + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - for (i = 0; i < 2; i++) - input_set_abs_params(input_dev, ABS_X + i, -1, 1, 0, 0); + for (i = 0; i < 2; i++) + input_set_abs_params(input_dev, ABS_X + i, -1, 1, 0, 0); + } else + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); gc->pads[0] |= gc_status_bit[idx]; gc->pads[pad_type] |= gc_status_bit[idx]; @@ -630,6 +681,13 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) break; + case GC_SNESMOUSE: + set_bit(BTN_LEFT, input_dev->keybit); + set_bit(BTN_RIGHT, input_dev->keybit); + set_bit(REL_X, input_dev->relbit); + set_bit(REL_Y, input_dev->relbit); + break; + case GC_SNES: for (i = 4; i < 8; i++) set_bit(gc_snes_btn[i], input_dev->keybit); @@ -693,7 +751,7 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads) goto err_unreg_pardev; } - init_MUTEX(&gc->sem); + mutex_init(&gc->mutex); gc->pd = pd; init_timer(&gc->timer); gc->timer.data = (long) gc; diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c index 4678b6dab43b..2b8e8456c9fa 100644 --- a/drivers/input/joystick/iforce/iforce-ff.c +++ b/drivers/input/joystick/iforce/iforce-ff.c @@ -42,14 +42,14 @@ static int make_magnitude_modifier(struct iforce* iforce, unsigned char data[3]; if (!no_alloc) { - down(&iforce->mem_mutex); + mutex_lock(&iforce->mem_mutex); if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, iforce->device_memory.start, iforce->device_memory.end, 2L, NULL, NULL)) { - up(&iforce->mem_mutex); + mutex_unlock(&iforce->mem_mutex); return -ENOMEM; } - up(&iforce->mem_mutex); + mutex_unlock(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); @@ -75,14 +75,14 @@ static int make_period_modifier(struct iforce* iforce, period = TIME_SCALE(period); if (!no_alloc) { - down(&iforce->mem_mutex); + mutex_lock(&iforce->mem_mutex); if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, iforce->device_memory.start, iforce->device_memory.end, 2L, NULL, NULL)) { - up(&iforce->mem_mutex); + mutex_unlock(&iforce->mem_mutex); return -ENOMEM; } - up(&iforce->mem_mutex); + mutex_unlock(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); @@ -115,14 +115,14 @@ static int make_envelope_modifier(struct iforce* iforce, fade_duration = TIME_SCALE(fade_duration); if (!no_alloc) { - down(&iforce->mem_mutex); + mutex_lock(&iforce->mem_mutex); if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, iforce->device_memory.start, iforce->device_memory.end, 2L, NULL, NULL)) { - up(&iforce->mem_mutex); + mutex_unlock(&iforce->mem_mutex); return -ENOMEM; } - up(&iforce->mem_mutex); + mutex_unlock(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); @@ -152,14 +152,14 @@ static int make_condition_modifier(struct iforce* iforce, unsigned char data[10]; if (!no_alloc) { - down(&iforce->mem_mutex); + mutex_lock(&iforce->mem_mutex); if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, iforce->device_memory.start, iforce->device_memory.end, 2L, NULL, NULL)) { - up(&iforce->mem_mutex); + mutex_unlock(&iforce->mem_mutex); return -ENOMEM; } - up(&iforce->mem_mutex); + mutex_unlock(&iforce->mem_mutex); } data[0] = LO(mod_chunk->start); diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index b6bc04998047..ab0a26b924ca 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -350,7 +350,7 @@ int iforce_init_device(struct iforce *iforce) init_waitqueue_head(&iforce->wait); spin_lock_init(&iforce->xmit_lock); - init_MUTEX(&iforce->mem_mutex); + mutex_init(&iforce->mem_mutex); iforce->xmit.buf = iforce->xmit_data; iforce->dev = input_dev; diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index 146f406b8f8a..668f24535ba0 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -37,7 +37,7 @@ #include #include #include -#include +#include /* This module provides arbitrary resource management routines. * I use it to manage the device's memory. @@ -45,6 +45,7 @@ */ #include + #define IFORCE_MAX_LENGTH 16 /* iforce::bus */ @@ -146,7 +147,7 @@ struct iforce { wait_queue_head_t wait; struct resource device_memory; struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; - struct semaphore mem_mutex; + struct mutex mem_mutex; }; /* Get hi and low bytes of a 16-bits int */ diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index b154938e88a4..5570fd5487c7 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -37,6 +37,7 @@ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("TurboGraFX parallel port interface driver"); @@ -86,7 +87,7 @@ static struct tgfx { char phys[TGFX_MAX_DEVICES][32]; int sticks; int used; - struct semaphore sem; + struct mutex sem; } *tgfx_base[TGFX_MAX_PORTS]; /* @@ -128,7 +129,7 @@ static int tgfx_open(struct input_dev *dev) struct tgfx *tgfx = dev->private; int err; - err = down_interruptible(&tgfx->sem); + err = mutex_lock_interruptible(&tgfx->sem); if (err) return err; @@ -138,7 +139,7 @@ static int tgfx_open(struct input_dev *dev) mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME); } - up(&tgfx->sem); + mutex_unlock(&tgfx->sem); return 0; } @@ -146,13 +147,13 @@ static void tgfx_close(struct input_dev *dev) { struct tgfx *tgfx = dev->private; - down(&tgfx->sem); + mutex_lock(&tgfx->sem); if (!--tgfx->used) { del_timer_sync(&tgfx->timer); parport_write_control(tgfx->pd->port, 0x00); parport_release(tgfx->pd); } - up(&tgfx->sem); + mutex_unlock(&tgfx->sem); } @@ -191,7 +192,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) goto err_unreg_pardev; } - init_MUTEX(&tgfx->sem); + mutex_init(&tgfx->sem); tgfx->pd = pd; init_timer(&tgfx->timer); tgfx->timer.data = (long) tgfx; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 3b0ac3b43c54..a9dda56f62c4 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -13,7 +13,7 @@ menuconfig INPUT_KEYBOARD if INPUT_KEYBOARD config KEYBOARD_ATKBD - tristate "AT keyboard" if !X86_PC + tristate "AT keyboard" if EMBEDDED || !X86_PC default y select SERIO select SERIO_LIBPS2 diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index ffacf6eca5f5..fad04b66d268 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -27,6 +27,7 @@ #include #include #include +#include #define DRIVER_DESC "AT and PS/2 keyboard driver" @@ -216,7 +217,7 @@ struct atkbd { unsigned long time; struct work_struct event_work; - struct semaphore event_sem; + struct mutex event_mutex; unsigned long event_mask; }; @@ -302,19 +303,19 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, if (atkbd->translated) { if (atkbd->emul || - !(code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1 || - code == ATKBD_RET_HANGUEL || code == ATKBD_RET_HANJA || - (code == ATKBD_RET_ERR && !atkbd->err_xl) || - (code == ATKBD_RET_BAT && !atkbd->bat_xl))) { + (code != ATKBD_RET_EMUL0 && code != ATKBD_RET_EMUL1 && + code != ATKBD_RET_HANGUEL && code != ATKBD_RET_HANJA && + (code != ATKBD_RET_ERR || atkbd->err_xl) && + (code != ATKBD_RET_BAT || atkbd->bat_xl))) { atkbd->release = code >> 7; code &= 0x7f; } if (!atkbd->emul) { if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f)) - atkbd->bat_xl = !atkbd->release; + atkbd->bat_xl = !(data >> 7); if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f)) - atkbd->err_xl = !atkbd->release; + atkbd->err_xl = !(data >> 7); } } @@ -449,7 +450,7 @@ static void atkbd_event_work(void *data) unsigned char param[2]; int i, j; - down(&atkbd->event_sem); + mutex_lock(&atkbd->event_mutex); if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) { param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) @@ -480,7 +481,7 @@ static void atkbd_event_work(void *data) ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP); } - up(&atkbd->event_sem); + mutex_unlock(&atkbd->event_mutex); } /* @@ -846,7 +847,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd->dev = dev; ps2_init(&atkbd->ps2dev, serio); INIT_WORK(&atkbd->event_work, atkbd_event_work, atkbd); - init_MUTEX(&atkbd->event_sem); + mutex_init(&atkbd->event_mutex); switch (serio->id.type) { @@ -862,9 +863,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd->softrepeat = atkbd_softrepeat; atkbd->scroll = atkbd_scroll; - if (!atkbd->write) - atkbd->softrepeat = 1; - if (atkbd->softrepeat) atkbd->softraw = 1; diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index e301ee4ca264..96c6bf77248a 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c @@ -29,11 +29,11 @@ #define KB_COLS 12 #define KB_ROWMASK(r) (1 << (r)) #define SCANCODE(r,c) ( ((r)<<4) + (c) + 1 ) -/* zero code, 124 scancodes + 3 hinge combinations */ -#define NR_SCANCODES ( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 +3 ) -#define SCAN_INTERVAL (HZ/10) +/* zero code, 124 scancodes */ +#define NR_SCANCODES ( SCANCODE(KB_ROWS-1,KB_COLS-1) +1 +1 ) -#define HINGE_SCAN_INTERVAL (HZ/4) +#define SCAN_INTERVAL (50) /* ms */ +#define HINGE_SCAN_INTERVAL (250) /* ms */ #define CORGI_KEY_CALENDER KEY_F1 #define CORGI_KEY_ADDRESS KEY_F2 @@ -49,9 +49,6 @@ #define CORGI_KEY_MAIL KEY_F10 #define CORGI_KEY_OK KEY_F11 #define CORGI_KEY_MENU KEY_F12 -#define CORGI_HINGE_0 KEY_KP0 -#define CORGI_HINGE_1 KEY_KP1 -#define CORGI_HINGE_2 KEY_KP2 static unsigned char corgikbd_keycode[NR_SCANCODES] = { 0, /* 0 */ @@ -63,7 +60,6 @@ static unsigned char corgikbd_keycode[NR_SCANCODES] = { CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */ KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */ CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0, /* 113-124 */ - CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2 /* 125-127 */ }; @@ -187,7 +183,7 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs /* if any keys are pressed, enable the timer */ if (num_pressed) - mod_timer(&corgikbd_data->timer, jiffies + SCAN_INTERVAL); + mod_timer(&corgikbd_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL)); spin_unlock_irqrestore(&corgikbd_data->lock, flags); } @@ -228,6 +224,7 @@ static void corgikbd_timer_callback(unsigned long data) * 0x0c - Keyboard and Screen Closed */ +#define READ_GPIO_BIT(x) (GPLR(x) & GPIO_bit(x)) #define HINGE_STABLE_COUNT 2 static int sharpsl_hinge_state; static int hinge_count; @@ -239,6 +236,7 @@ static void corgikbd_hinge_timer(unsigned long data) unsigned long flags; gprr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_GPRR) & (CORGI_SCP_SWA | CORGI_SCP_SWB); + gprr |= (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0); if (gprr != sharpsl_hinge_state) { hinge_count = 0; sharpsl_hinge_state = gprr; @@ -249,27 +247,38 @@ static void corgikbd_hinge_timer(unsigned long data) input_report_switch(corgikbd_data->input, SW_0, ((sharpsl_hinge_state & CORGI_SCP_SWA) != 0)); input_report_switch(corgikbd_data->input, SW_1, ((sharpsl_hinge_state & CORGI_SCP_SWB) != 0)); + input_report_switch(corgikbd_data->input, SW_2, (READ_GPIO_BIT(CORGI_GPIO_AK_INT) != 0)); input_sync(corgikbd_data->input); spin_unlock_irqrestore(&corgikbd_data->lock, flags); } } - mod_timer(&corgikbd_data->htimer, jiffies + HINGE_SCAN_INTERVAL); + mod_timer(&corgikbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); } #ifdef CONFIG_PM static int corgikbd_suspend(struct platform_device *dev, pm_message_t state) { + int i; struct corgikbd *corgikbd = platform_get_drvdata(dev); + corgikbd->suspended = 1; + /* strobe 0 is the power key so this can't be made an input for + powersaving therefore i = 1 */ + for (i = 1; i < CORGI_KEY_STROBE_NUM; i++) + pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_IN); return 0; } static int corgikbd_resume(struct platform_device *dev) { + int i; struct corgikbd *corgikbd = platform_get_drvdata(dev); + for (i = 1; i < CORGI_KEY_STROBE_NUM; i++) + pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH); + /* Upon resume, ignore the suspend key for a short while */ corgikbd->suspend_jiffies=jiffies; corgikbd->suspended = 0; @@ -333,10 +342,11 @@ static int __init corgikbd_probe(struct platform_device *pdev) clear_bit(0, input_dev->keybit); set_bit(SW_0, input_dev->swbit); set_bit(SW_1, input_dev->swbit); + set_bit(SW_2, input_dev->swbit); input_register_device(corgikbd->input); - mod_timer(&corgikbd->htimer, jiffies + HINGE_SCAN_INTERVAL); + mod_timer(&corgikbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) { @@ -351,6 +361,9 @@ static int __init corgikbd_probe(struct platform_device *pdev) for (i = 0; i < CORGI_KEY_STROBE_NUM; i++) pxa_gpio_mode(CORGI_GPIO_KEY_STROBE(i) | GPIO_OUT | GPIO_DFLT_HIGH); + /* Setup the headphone jack as an input */ + pxa_gpio_mode(CORGI_GPIO_AK_INT | GPIO_IN); + return 0; } diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 0a90962c38e7..1dca3cf42a54 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -66,7 +66,7 @@ static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] = static char hil_language[][16] = { HIL_LOCALE_MAP }; struct hil_kbd { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; /* Input buffer and index for packets from HIL bus. */ @@ -86,7 +86,7 @@ struct hil_kbd { /* Process a complete packet after transfer from the HIL */ static void hil_kbd_process_record(struct hil_kbd *kbd) { - struct input_dev *dev = &kbd->dev; + struct input_dev *dev = kbd->dev; hil_packet *data = kbd->data; hil_packet p; int idx, i, cnt; @@ -240,8 +240,8 @@ static void hil_kbd_disconnect(struct serio *serio) return; } - input_unregister_device(&kbd->dev); serio_close(serio); + input_unregister_device(kbd->dev); kfree(kbd); } @@ -250,17 +250,22 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) struct hil_kbd *kbd; uint8_t did, *idd; int i; - - kbd = kmalloc(sizeof(*kbd), GFP_KERNEL); + + kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); if (!kbd) return -ENOMEM; - memset(kbd, 0, sizeof(struct hil_kbd)); - if (serio_open(serio, drv)) goto bail0; + kbd->dev = input_allocate_device(); + if (!kbd->dev) + goto bail0; + + kbd->dev->private = kbd; + + if (serio_open(serio, drv)) + goto bail1; serio_set_drvdata(serio, kbd); kbd->serio = serio; - kbd->dev.private = kbd; init_MUTEX_LOCKED(&(kbd->sem)); @@ -302,38 +307,38 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) did, hil_language[did & HIL_IDD_DID_TYPE_KB_LANG_MASK]); break; default: - goto bail1; + goto bail2; } if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) { printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n"); - goto bail1; + goto bail2; } - kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - kbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - kbd->dev.keycodemax = HIL_KEYCODES_SET1_TBLSIZE; - kbd->dev.keycodesize = sizeof(hil_kbd_set1[0]); - kbd->dev.keycode = hil_kbd_set1; - kbd->dev.name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; - kbd->dev.phys = "hpkbd/input0"; /* XXX */ + kbd->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + kbd->dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; + kbd->dev->keycodesize = sizeof(hil_kbd_set1[0]); + kbd->dev->keycode = hil_kbd_set1; + kbd->dev->name = strlen(kbd->rnm) ? kbd->rnm : HIL_GENERIC_NAME; + kbd->dev->phys = "hpkbd/input0"; /* XXX */ - kbd->dev.id.bustype = BUS_HIL; - kbd->dev.id.vendor = PCI_VENDOR_ID_HP; - kbd->dev.id.product = 0x0001; /* TODO: get from kbd->rsc */ - kbd->dev.id.version = 0x0100; /* TODO: get from kbd->rsc */ - kbd->dev.dev = &serio->dev; + kbd->dev->id.bustype = BUS_HIL; + kbd->dev->id.vendor = PCI_VENDOR_ID_HP; + kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */ + kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */ + kbd->dev->dev = &serio->dev; for (i = 0; i < 128; i++) { - set_bit(hil_kbd_set1[i], kbd->dev.keybit); - set_bit(hil_kbd_set3[i], kbd->dev.keybit); + set_bit(hil_kbd_set1[i], kbd->dev->keybit); + set_bit(hil_kbd_set3[i], kbd->dev->keybit); } - clear_bit(0, kbd->dev.keybit); + clear_bit(0, kbd->dev->keybit); - input_register_device(&kbd->dev); + input_register_device(kbd->dev); printk(KERN_INFO "input: %s, ID: %d\n", - kbd->dev.name, did); + kbd->dev->name, did); serio->write(serio, 0); serio->write(serio, 0); @@ -343,8 +348,10 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv) up(&(kbd->sem)); return 0; - bail1: + bail2: serio_close(serio); + bail1: + input_free_device(kbd->dev); bail0: kfree(kbd); serio_set_drvdata(serio, NULL); diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index e95bc052e32a..33edd030aa75 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -3,7 +3,7 @@ * * Copyright (C) 1998 Philip Blundell * Copyright (C) 1999 Matthew Wilcox - * Copyright (C) 1999-2003 Helge Deller + * Copyright (C) 1999-2006 Helge Deller * * Very basic HP Human Interface Loop (HIL) driver. * This driver handles the keyboard on HP300 (m68k) and on some @@ -90,7 +90,7 @@ static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] = /* HIL structure */ static struct { - struct input_dev dev; + struct input_dev *dev; unsigned int curdev; @@ -117,7 +117,7 @@ static void poll_finished(void) down = (hil_dev.data[1] & 1) == 0; scode = hil_dev.data[1] >> 1; key = hphilkeyb_keycode[scode]; - input_report_key(&hil_dev.dev, key, down); + input_report_key(hil_dev.dev, key, down); break; } hil_dev.curdev = 0; @@ -207,9 +207,14 @@ hil_keyb_init(void) unsigned int i, kbid; wait_queue_head_t hil_wait; - if (hil_dev.dev.id.bustype) { + if (hil_dev.dev) { return -ENODEV; /* already initialized */ } + + hil_dev.dev = input_allocate_device(); + if (!hil_dev.dev) + return -ENOMEM; + hil_dev.dev->private = &hil_dev; #if defined(CONFIG_HP300) if (!hwreg_present((void *)(HILBASE + HIL_DATA))) @@ -247,28 +252,26 @@ hil_keyb_init(void) c = 0; hil_do(HIL_WRITEKBDSADR, &c, 1); - init_input_dev(&hil_dev.dev); - for (i = 0; i < HIL_KEYCODES_SET1_TBLSIZE; i++) if (hphilkeyb_keycode[i] != KEY_RESERVED) - set_bit(hphilkeyb_keycode[i], hil_dev.dev.keybit); + set_bit(hphilkeyb_keycode[i], hil_dev.dev->keybit); - hil_dev.dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); - hil_dev.dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - hil_dev.dev.keycodemax = HIL_KEYCODES_SET1_TBLSIZE; - hil_dev.dev.keycodesize = sizeof(hphilkeyb_keycode[0]); - hil_dev.dev.keycode = hphilkeyb_keycode; - hil_dev.dev.name = "HIL keyboard"; - hil_dev.dev.phys = "hpkbd/input0"; + hil_dev.dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + hil_dev.dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + hil_dev.dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE; + hil_dev.dev->keycodesize = sizeof(hphilkeyb_keycode[0]); + hil_dev.dev->keycode = hphilkeyb_keycode; + hil_dev.dev->name = "HIL keyboard"; + hil_dev.dev->phys = "hpkbd/input0"; - hil_dev.dev.id.bustype = BUS_HIL; - hil_dev.dev.id.vendor = PCI_VENDOR_ID_HP; - hil_dev.dev.id.product = 0x0001; - hil_dev.dev.id.version = 0x0010; + hil_dev.dev->id.bustype = BUS_HIL; + hil_dev.dev->id.vendor = PCI_VENDOR_ID_HP; + hil_dev.dev->id.product = 0x0001; + hil_dev.dev->id.version = 0x0010; - input_register_device(&hil_dev.dev); + input_register_device(hil_dev.dev); printk(KERN_INFO "input: %s, ID %d at 0x%08lx (irq %d) found and attached\n", - hil_dev.dev.name, kbid, HILBASE, HIL_IRQ); + hil_dev.dev->name, kbid, HILBASE, HIL_IRQ); return 0; } @@ -329,7 +332,9 @@ static void __exit hil_exit(void) /* Turn off interrupts */ hil_do(HIL_INTOFF, NULL, 0); - input_unregister_device(&hil_dev.dev); + input_unregister_device(hil_dev.dev); + + hil_dev.dev = NULL; #if defined(CONFIG_PARISC) unregister_parisc_driver(&hil_driver); diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index 83999d583122..bc61cf8cfc65 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -30,6 +30,7 @@ #define SCANCODE(r,c) (((r)<<4) + (c) + 1) #define NR_SCANCODES ((KB_ROWS<<4) + 1) +#define SCAN_INTERVAL (50) /* ms */ #define HINGE_SCAN_INTERVAL (150) /* ms */ #define SPITZ_KEY_CALENDER KEY_F1 @@ -230,7 +231,7 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs /* if any keys are pressed, enable the timer */ if (num_pressed) - mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(100)); + mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL)); spin_unlock_irqrestore(&spitzkbd_data->lock, flags); } @@ -287,6 +288,7 @@ static void spitzkbd_hinge_timer(unsigned long data) unsigned long flags; state = GPLR(SPITZ_GPIO_SWA) & (GPIO_bit(SPITZ_GPIO_SWA)|GPIO_bit(SPITZ_GPIO_SWB)); + state |= (GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)); if (state != sharpsl_hinge_state) { hinge_count = 0; sharpsl_hinge_state = state; @@ -299,6 +301,7 @@ static void spitzkbd_hinge_timer(unsigned long data) input_report_switch(spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0)); input_report_switch(spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0)); + input_report_switch(spitzkbd_data->input, SW_2, ((GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)) != 0)); input_sync(spitzkbd_data->input); spin_unlock_irqrestore(&spitzkbd_data->lock, flags); @@ -397,6 +400,7 @@ static int __init spitzkbd_probe(struct platform_device *dev) clear_bit(0, input_dev->keybit); set_bit(SW_0, input_dev->swbit); set_bit(SW_1, input_dev->swbit); + set_bit(SW_2, input_dev->swbit); input_register_device(input_dev); @@ -432,6 +436,9 @@ static int __init spitzkbd_probe(struct platform_device *dev) request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, "Spitzkbd SWB", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr, + SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING, + "Spitzkbd HP", spitzkbd); printk(KERN_INFO "input: Spitz Keyboard Registered\n"); @@ -450,6 +457,7 @@ static int spitzkbd_remove(struct platform_device *dev) free_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd); free_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd); free_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd); + free_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd); del_timer_sync(&spitzkbd->htimer); del_timer_sync(&spitzkbd->timer); diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 1ef477f4469c..afd322185bbf 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -24,7 +24,6 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("PC Speaker beeper driver"); MODULE_LICENSE("GPL"); -static struct platform_device *pcspkr_platform_device; static DEFINE_SPINLOCK(i8253_beep_lock); static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -135,35 +134,11 @@ static struct platform_driver pcspkr_platform_driver = { static int __init pcspkr_init(void) { - int err; - - err = platform_driver_register(&pcspkr_platform_driver); - if (err) - return err; - - pcspkr_platform_device = platform_device_alloc("pcspkr", -1); - if (!pcspkr_platform_device) { - err = -ENOMEM; - goto err_unregister_driver; - } - - err = platform_device_add(pcspkr_platform_device); - if (err) - goto err_free_device; - - return 0; - - err_free_device: - platform_device_put(pcspkr_platform_device); - err_unregister_driver: - platform_driver_unregister(&pcspkr_platform_driver); - - return err; + return platform_driver_register(&pcspkr_platform_driver); } static void __exit pcspkr_exit(void) { - platform_device_unregister(pcspkr_platform_device); platform_driver_unregister(&pcspkr_platform_driver); } diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 546ed9b4901d..d723e9ad7c41 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -194,7 +194,7 @@ static int uinput_open(struct inode *inode, struct file *file) if (!newdev) return -ENOMEM; - init_MUTEX(&newdev->sem); + mutex_init(&newdev->mutex); spin_lock_init(&newdev->requests_lock); init_waitqueue_head(&newdev->requests_waitq); init_waitqueue_head(&newdev->waitq); @@ -340,7 +340,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t struct uinput_device *udev = file->private_data; int retval; - retval = down_interruptible(&udev->sem); + retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; @@ -348,7 +348,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t uinput_inject_event(udev, buffer, count) : uinput_setup_device(udev, buffer, count); - up(&udev->sem); + mutex_unlock(&udev->mutex); return retval; } @@ -369,7 +369,7 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, if (retval) return retval; - retval = down_interruptible(&udev->sem); + retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; @@ -388,7 +388,7 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, } out: - up(&udev->sem); + mutex_unlock(&udev->mutex); return retval; } @@ -439,7 +439,7 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) udev = file->private_data; - retval = down_interruptible(&udev->sem); + retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; @@ -589,7 +589,7 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } out: - up(&udev->sem); + mutex_unlock(&udev->mutex); return retval; } diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c index c2bf2ed07dc6..69f02178c528 100644 --- a/drivers/input/mouse/hil_ptr.c +++ b/drivers/input/mouse/hil_ptr.c @@ -55,7 +55,7 @@ MODULE_LICENSE("Dual BSD/GPL"); #define HIL_PTR_MAX_LENGTH 16 struct hil_ptr { - struct input_dev dev; + struct input_dev *dev; struct serio *serio; /* Input buffer and index for packets from HIL bus. */ @@ -79,7 +79,7 @@ struct hil_ptr { /* Process a complete packet after transfer from the HIL */ static void hil_ptr_process_record(struct hil_ptr *ptr) { - struct input_dev *dev = &ptr->dev; + struct input_dev *dev = ptr->dev; hil_packet *data = ptr->data; hil_packet p; int idx, i, cnt, laxis; @@ -148,12 +148,12 @@ static void hil_ptr_process_record(struct hil_ptr *ptr) if (absdev) { val = lo + (hi<<8); #ifdef TABLET_AUTOADJUST - if (val < ptr->dev.absmin[ABS_X + i]) - ptr->dev.absmin[ABS_X + i] = val; - if (val > ptr->dev.absmax[ABS_X + i]) - ptr->dev.absmax[ABS_X + i] = val; + if (val < dev->absmin[ABS_X + i]) + dev->absmin[ABS_X + i] = val; + if (val > dev->absmax[ABS_X + i]) + dev->absmax[ABS_X + i] = val; #endif - if (i%3) val = ptr->dev.absmax[ABS_X + i] - val; + if (i%3) val = dev->absmax[ABS_X + i] - val; input_report_abs(dev, ABS_X + i, val); } else { val = (int) (((int8_t)lo) | ((int8_t)hi<<8)); @@ -233,26 +233,32 @@ static void hil_ptr_disconnect(struct serio *serio) return; } - input_unregister_device(&ptr->dev); serio_close(serio); + input_unregister_device(ptr->dev); kfree(ptr); } static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) { - struct hil_ptr *ptr; - char *txt; - unsigned int i, naxsets, btntype; - uint8_t did, *idd; + struct hil_ptr *ptr; + char *txt; + unsigned int i, naxsets, btntype; + uint8_t did, *idd; - if (!(ptr = kmalloc(sizeof(struct hil_ptr), GFP_KERNEL))) return -ENOMEM; - memset(ptr, 0, sizeof(struct hil_ptr)); + if (!(ptr = kzalloc(sizeof(struct hil_ptr), GFP_KERNEL))) + return -ENOMEM; - if (serio_open(serio, driver)) goto bail0; + ptr->dev = input_allocate_device(); + if (!ptr->dev) + goto bail0; + + ptr->dev->private = ptr; + + if (serio_open(serio, driver)) + goto bail1; serio_set_drvdata(serio, ptr); ptr->serio = serio; - ptr->dev.private = ptr; init_MUTEX_LOCKED(&(ptr->sem)); @@ -283,25 +289,24 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) up(&(ptr->sem)); - init_input_dev(&ptr->dev); did = ptr->idd[0]; idd = ptr->idd + 1; txt = "unknown"; if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { - ptr->dev.evbit[0] = BIT(EV_REL); + ptr->dev->evbit[0] = BIT(EV_REL); txt = "relative"; } if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_ABS) { - ptr->dev.evbit[0] = BIT(EV_ABS); + ptr->dev->evbit[0] = BIT(EV_ABS); txt = "absolute"; } - if (!ptr->dev.evbit[0]) { - goto bail1; + if (!ptr->dev->evbit[0]) { + goto bail2; } ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd); - if (ptr->nbtn) ptr->dev.evbit[0] |= BIT(EV_KEY); + if (ptr->nbtn) ptr->dev->evbit[0] |= BIT(EV_KEY); naxsets = HIL_IDD_NUM_AXSETS(*idd); ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd); @@ -325,7 +330,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) btntype = BTN_MOUSE; for (i = 0; i < ptr->nbtn; i++) { - set_bit(btntype | i, ptr->dev.keybit); + set_bit(btntype | i, ptr->dev->keybit); ptr->btnmap[i] = btntype | i; } @@ -337,50 +342,52 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver) if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) { for (i = 0; i < ptr->naxes; i++) { - set_bit(REL_X + i, ptr->dev.relbit); + set_bit(REL_X + i, ptr->dev->relbit); } for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) { - set_bit(REL_X + i, ptr->dev.relbit); + set_bit(REL_X + i, ptr->dev->relbit); } } else { for (i = 0; i < ptr->naxes; i++) { - set_bit(ABS_X + i, ptr->dev.absbit); - ptr->dev.absmin[ABS_X + i] = 0; - ptr->dev.absmax[ABS_X + i] = + set_bit(ABS_X + i, ptr->dev->absbit); + ptr->dev->absmin[ABS_X + i] = 0; + ptr->dev->absmax[ABS_X + i] = HIL_IDD_AXIS_MAX((ptr->idd + 1), i); } for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) { - set_bit(ABS_X + i, ptr->dev.absbit); - ptr->dev.absmin[ABS_X + i] = 0; - ptr->dev.absmax[ABS_X + i] = + set_bit(ABS_X + i, ptr->dev->absbit); + ptr->dev->absmin[ABS_X + i] = 0; + ptr->dev->absmax[ABS_X + i] = HIL_IDD_AXIS_MAX((ptr->idd + 1), (i - 3)); } #ifdef TABLET_AUTOADJUST for (i = 0; i < ABS_MAX; i++) { - int diff = ptr->dev.absmax[ABS_X + i] / 10; - ptr->dev.absmin[ABS_X + i] += diff; - ptr->dev.absmax[ABS_X + i] -= diff; + int diff = ptr->dev->absmax[ABS_X + i] / 10; + ptr->dev->absmin[ABS_X + i] += diff; + ptr->dev->absmax[ABS_X + i] -= diff; } #endif } - ptr->dev.name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME; + ptr->dev->name = strlen(ptr->rnm) ? ptr->rnm : HIL_GENERIC_NAME; - ptr->dev.id.bustype = BUS_HIL; - ptr->dev.id.vendor = PCI_VENDOR_ID_HP; - ptr->dev.id.product = 0x0001; /* TODO: get from ptr->rsc */ - ptr->dev.id.version = 0x0100; /* TODO: get from ptr->rsc */ - ptr->dev.dev = &serio->dev; + ptr->dev->id.bustype = BUS_HIL; + ptr->dev->id.vendor = PCI_VENDOR_ID_HP; + ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */ + ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */ + ptr->dev->dev = &serio->dev; - input_register_device(&ptr->dev); + input_register_device(ptr->dev); printk(KERN_INFO "input: %s (%s), ID: %d\n", - ptr->dev.name, + ptr->dev->name, (btntype == BTN_MOUSE) ? "HIL mouse":"HIL tablet or touchpad", did); return 0; - bail1: + bail2: serio_close(serio); + bail1: + input_free_device(ptr->dev); bail0: kfree(ptr); serio_set_drvdata(serio, NULL); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index ad6217467676..32d70ed8f41d 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -20,6 +20,8 @@ #include #include #include +#include + #include "psmouse.h" #include "synaptics.h" #include "logips2pp.h" @@ -98,13 +100,13 @@ __obsolete_setup("psmouse_resetafter="); __obsolete_setup("psmouse_rate="); /* - * psmouse_sem protects all operations changing state of mouse + * psmouse_mutex protects all operations changing state of mouse * (connecting, disconnecting, changing rate or resolution via * sysfs). We could use a per-device semaphore but since there * rarely more than one PS/2 mouse connected and since semaphore * is taken in "slow" paths it is not worth it. */ -static DECLARE_MUTEX(psmouse_sem); +static DEFINE_MUTEX(psmouse_mutex); static struct workqueue_struct *kpsmoused_wq; @@ -868,7 +870,7 @@ static void psmouse_resync(void *p) int failed = 0, enabled = 0; int i; - down(&psmouse_sem); + mutex_lock(&psmouse_mutex); if (psmouse->state != PSMOUSE_RESYNCING) goto out; @@ -948,7 +950,7 @@ static void psmouse_resync(void *p) if (parent) psmouse_activate(parent); out: - up(&psmouse_sem); + mutex_unlock(&psmouse_mutex); } /* @@ -974,14 +976,14 @@ static void psmouse_disconnect(struct serio *serio) sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group); - down(&psmouse_sem); + mutex_lock(&psmouse_mutex); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); /* make sure we don't have a resync in progress */ - up(&psmouse_sem); + mutex_unlock(&psmouse_mutex); flush_workqueue(kpsmoused_wq); - down(&psmouse_sem); + mutex_lock(&psmouse_mutex); if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); @@ -1004,7 +1006,7 @@ static void psmouse_disconnect(struct serio *serio) if (parent) psmouse_activate(parent); - up(&psmouse_sem); + mutex_unlock(&psmouse_mutex); } static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto) @@ -1076,7 +1078,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int retval = -ENOMEM; - down(&psmouse_sem); + mutex_lock(&psmouse_mutex); /* * If this is a pass-through port deactivate parent so the device @@ -1144,7 +1146,7 @@ out: if (parent) psmouse_activate(parent); - up(&psmouse_sem); + mutex_unlock(&psmouse_mutex); return retval; } @@ -1161,7 +1163,7 @@ static int psmouse_reconnect(struct serio *serio) return -1; } - down(&psmouse_sem); + mutex_lock(&psmouse_mutex); if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); @@ -1195,7 +1197,7 @@ out: if (parent) psmouse_activate(parent); - up(&psmouse_sem); + mutex_unlock(&psmouse_mutex); return rc; } @@ -1273,7 +1275,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev goto out_unpin; } - retval = down_interruptible(&psmouse_sem); + retval = mutex_lock_interruptible(&psmouse_mutex); if (retval) goto out_unpin; @@ -1281,7 +1283,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev if (psmouse->state == PSMOUSE_IGNORE) { retval = -ENODEV; - goto out_up; + goto out_unlock; } if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { @@ -1299,8 +1301,8 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev if (parent) psmouse_activate(parent); - out_up: - up(&psmouse_sem); + out_unlock: + mutex_unlock(&psmouse_mutex); out_unpin: serio_unpin_driver(serio); return retval; @@ -1357,11 +1359,11 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co return -EIO; } - up(&psmouse_sem); + mutex_unlock(&psmouse_mutex); serio_unpin_driver(serio); serio_unregister_child_port(serio); serio_pin_driver_uninterruptible(serio); - down(&psmouse_sem); + mutex_lock(&psmouse_mutex); if (serio->drv != &psmouse_drv) { input_free_device(new_dev); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 2051bec2c394..ad5d0a85e960 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -247,14 +247,12 @@ static void synaptics_pt_create(struct psmouse *psmouse) { struct serio *serio; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!serio) { printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); return; } - memset(serio, 0, sizeof(struct serio)); - serio->id.type = SERIO_PS_PSTHRU; strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); @@ -605,14 +603,21 @@ static struct dmi_system_id toshiba_dmi_table[] = { .ident = "Toshiba Satellite", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME , "Satellite"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"), }, }, { .ident = "Toshiba Dynabook", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME , "dynabook"), + DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"), + }, + }, + { + .ident = "Toshiba Portege M300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"), }, }, { } @@ -623,10 +628,9 @@ int synaptics_init(struct psmouse *psmouse) { struct synaptics_data *priv; - psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL); + psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); if (!priv) return -1; - memset(priv, 0, sizeof(struct synaptics_data)); if (synaptics_query_hardware(psmouse)) { printk(KERN_ERR "Unable to query Synaptics hardware.\n"); diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 9abed18d2ecf..b685a507955d 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -412,9 +412,8 @@ static int mousedev_open(struct inode * inode, struct file * file) if (i >= MOUSEDEV_MINORS || !mousedev_table[i]) return -ENODEV; - if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL))) + if (!(list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL))) return -ENOMEM; - memset(list, 0, sizeof(struct mousedev_list)); spin_lock_init(&list->packet_lock); list->pos_x = xres / 2; @@ -626,9 +625,8 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru return NULL; } - if (!(mousedev = kmalloc(sizeof(struct mousedev), GFP_KERNEL))) + if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL))) return NULL; - memset(mousedev, 0, sizeof(struct mousedev)); INIT_LIST_HEAD(&mousedev->list); init_waitqueue_head(&mousedev->wait); diff --git a/drivers/input/power.c b/drivers/input/power.c index bfc5c63ebffe..526e6070600c 100644 --- a/drivers/input/power.c +++ b/drivers/input/power.c @@ -103,9 +103,8 @@ static struct input_handle *power_connect(struct input_handler *handler, { struct input_handle *handle; - if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) + if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL))) return NULL; - memset(handle, 0, sizeof(struct input_handle)); handle->dev = dev; handle->handler = handler; diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index a7b0de0f92b2..c0b1e4becad3 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -1,7 +1,7 @@ /* * drivers/input/serio/gscps2.c * - * Copyright (c) 2004 Helge Deller + * Copyright (c) 2004-2006 Helge Deller * Copyright (c) 2002 Laurent Canet * Copyright (c) 2002 Thibaut Varene * @@ -354,7 +354,7 @@ static int __init gscps2_probe(struct parisc_device *dev) memset(serio, 0, sizeof(struct serio)); ps2port->port = serio; ps2port->padev = dev; - ps2port->addr = ioremap(hpa, GSC_STATUS + 4); + ps2port->addr = ioremap_nocache(hpa, GSC_STATUS + 4); spin_lock_init(&ps2port->lock); gscps2_reset(ps2port); diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index ea499783fb12..bbbe15e21904 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -872,9 +872,8 @@ int hil_mlc_register(hil_mlc *mlc) { for (i = 0; i < HIL_MLC_DEVMEM; i++) { struct serio *mlc_serio; hil_mlc_copy_di_scratch(mlc, i); - mlc_serio = kmalloc(sizeof(*mlc_serio), GFP_KERNEL); + mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL); mlc->serio[i] = mlc_serio; - memset(mlc_serio, 0, sizeof(*mlc_serio)); mlc_serio->id = hil_mlc_serio_id; mlc_serio->write = hil_mlc_serio_write; mlc_serio->open = hil_mlc_serio_open; diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index a4c6f3522723..f606e96bc2f4 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -192,7 +192,9 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { #include static int i8042_pnp_kbd_registered; +static unsigned int i8042_pnp_kbd_devices; static int i8042_pnp_aux_registered; +static unsigned int i8042_pnp_aux_devices; static int i8042_pnp_command_reg; static int i8042_pnp_data_reg; @@ -219,6 +221,7 @@ static int i8042_pnp_kbd_probe(struct pnp_dev *dev, const struct pnp_device_id * strncat(i8042_pnp_kbd_name, pnp_dev_name(dev), sizeof(i8042_pnp_kbd_name)); } + i8042_pnp_kbd_devices++; return 0; } @@ -239,6 +242,7 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id * strncat(i8042_pnp_aux_name, pnp_dev_name(dev), sizeof(i8042_pnp_aux_name)); } + i8042_pnp_aux_devices++; return 0; } @@ -287,21 +291,23 @@ static void i8042_pnp_exit(void) static int __init i8042_pnp_init(void) { - int result_kbd = 0, result_aux = 0; char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 }; + int err; if (i8042_nopnp) { printk(KERN_INFO "i8042: PNP detection disabled\n"); return 0; } - if ((result_kbd = pnp_register_driver(&i8042_pnp_kbd_driver)) >= 0) + err = pnp_register_driver(&i8042_pnp_kbd_driver); + if (!err) i8042_pnp_kbd_registered = 1; - if ((result_aux = pnp_register_driver(&i8042_pnp_aux_driver)) >= 0) + err = pnp_register_driver(&i8042_pnp_aux_driver); + if (!err) i8042_pnp_aux_registered = 1; - if (result_kbd <= 0 && result_aux <= 0) { + if (!i8042_pnp_kbd_devices && !i8042_pnp_aux_devices) { i8042_pnp_exit(); #if defined(__ia64__) return -ENODEV; @@ -311,24 +317,24 @@ static int __init i8042_pnp_init(void) #endif } - if (result_kbd > 0) + if (i8042_pnp_kbd_devices) snprintf(kbd_irq_str, sizeof(kbd_irq_str), "%d", i8042_pnp_kbd_irq); - if (result_aux > 0) + if (i8042_pnp_aux_devices) snprintf(aux_irq_str, sizeof(aux_irq_str), "%d", i8042_pnp_aux_irq); printk(KERN_INFO "PNP: PS/2 Controller [%s%s%s] at %#x,%#x irq %s%s%s\n", - i8042_pnp_kbd_name, (result_kbd > 0 && result_aux > 0) ? "," : "", + i8042_pnp_kbd_name, (i8042_pnp_kbd_devices && i8042_pnp_aux_devices) ? "," : "", i8042_pnp_aux_name, i8042_pnp_data_reg, i8042_pnp_command_reg, - kbd_irq_str, (result_kbd > 0 && result_aux > 0) ? "," : "", + kbd_irq_str, (i8042_pnp_kbd_devices && i8042_pnp_aux_devices) ? "," : "", aux_irq_str); #if defined(__ia64__) - if (result_kbd <= 0) + if (!i8042_pnp_kbd_devices) i8042_nokbd = 1; - if (result_aux <= 0) + if (!i8042_pnp_aux_devices) i8042_noaux = 1; #endif diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index d4c990f7c85e..79c97f94bcbd 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -84,7 +84,7 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) maxbytes = sizeof(ps2dev->cmdbuf); } - down(&ps2dev->cmd_sem); + mutex_lock(&ps2dev->cmd_mutex); serio_pause_rx(ps2dev->serio); ps2dev->flags = PS2_FLAG_CMD; @@ -94,7 +94,7 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) wait_event_timeout(ps2dev->wait, !(ps2dev->flags & PS2_FLAG_CMD), msecs_to_jiffies(timeout)); - up(&ps2dev->cmd_sem); + mutex_unlock(&ps2dev->cmd_mutex); } /* @@ -177,7 +177,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) return -1; } - down(&ps2dev->cmd_sem); + mutex_lock(&ps2dev->cmd_mutex); serio_pause_rx(ps2dev->serio); ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; @@ -229,7 +229,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) ps2dev->flags = 0; serio_continue_rx(ps2dev->serio); - up(&ps2dev->cmd_sem); + mutex_unlock(&ps2dev->cmd_mutex); return rc; } @@ -281,7 +281,7 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman void ps2_init(struct ps2dev *ps2dev, struct serio *serio) { - init_MUTEX(&ps2dev->cmd_sem); + mutex_init(&ps2dev->cmd_mutex); init_waitqueue_head(&ps2dev->wait); ps2dev->serio = serio; } diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 1d15c2819818..a5c1fb3a4a51 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -171,9 +171,8 @@ static struct serio * __init parkbd_allocate_serio(void) { struct serio *serio; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (serio) { - memset(serio, 0, sizeof(struct serio)); serio->id.type = parkbd_mode; serio->write = parkbd_write, strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name)); diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index a3bd11589bc3..513d37fc1acf 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -111,11 +111,10 @@ static int __devinit rpckbd_probe(struct platform_device *dev) { struct serio *serio; - serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); if (!serio) return -ENOMEM; - memset(serio, 0, sizeof(struct serio)); serio->id.type = SERIO_8042; serio->write = rpckbd_write; serio->open = rpckbd_open; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 2f76813c3a64..6521034bc933 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -34,6 +34,7 @@ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Serio abstraction core"); @@ -52,10 +53,10 @@ EXPORT_SYMBOL(serio_rescan); EXPORT_SYMBOL(serio_reconnect); /* - * serio_sem protects entire serio subsystem and is taken every time + * serio_mutex protects entire serio subsystem and is taken every time * serio port or driver registrered or unregistered. */ -static DECLARE_MUTEX(serio_sem); +static DEFINE_MUTEX(serio_mutex); static LIST_HEAD(serio_list); @@ -70,9 +71,9 @@ static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) { int retval; - down(&serio->drv_sem); + mutex_lock(&serio->drv_mutex); retval = drv->connect(serio, drv); - up(&serio->drv_sem); + mutex_unlock(&serio->drv_mutex); return retval; } @@ -81,20 +82,20 @@ static int serio_reconnect_driver(struct serio *serio) { int retval = -1; - down(&serio->drv_sem); + mutex_lock(&serio->drv_mutex); if (serio->drv && serio->drv->reconnect) retval = serio->drv->reconnect(serio); - up(&serio->drv_sem); + mutex_unlock(&serio->drv_mutex); return retval; } static void serio_disconnect_driver(struct serio *serio) { - down(&serio->drv_sem); + mutex_lock(&serio->drv_mutex); if (serio->drv) serio->drv->disconnect(serio); - up(&serio->drv_sem); + mutex_unlock(&serio->drv_mutex); } static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) @@ -195,6 +196,7 @@ static void serio_queue_event(void *object, struct module *owner, if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { if (!try_module_get(owner)) { printk(KERN_WARNING "serio: Can't get module reference, dropping event %d\n", event_type); + kfree(event); goto out; } @@ -272,7 +274,7 @@ static void serio_handle_event(void) struct serio_event *event; struct serio_driver *serio_drv; - down(&serio_sem); + mutex_lock(&serio_mutex); /* * Note that we handle only one event here to give swsusp @@ -314,7 +316,7 @@ static void serio_handle_event(void) serio_free_event(event); } - up(&serio_sem); + mutex_unlock(&serio_mutex); } /* @@ -449,7 +451,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * struct device_driver *drv; int retval; - retval = down_interruptible(&serio_sem); + retval = mutex_lock_interruptible(&serio_mutex); if (retval) return retval; @@ -469,7 +471,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * retval = -EINVAL; } - up(&serio_sem); + mutex_unlock(&serio_mutex); return retval; } @@ -524,7 +526,7 @@ static void serio_init_port(struct serio *serio) __module_get(THIS_MODULE); spin_lock_init(&serio->lock); - init_MUTEX(&serio->drv_sem); + mutex_init(&serio->drv_mutex); device_initialize(&serio->dev); snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), "serio%ld", (long)atomic_inc_return(&serio_no) - 1); @@ -661,10 +663,10 @@ void __serio_register_port(struct serio *serio, struct module *owner) */ void serio_unregister_port(struct serio *serio) { - down(&serio_sem); + mutex_lock(&serio_mutex); serio_disconnect_port(serio); serio_destroy_port(serio); - up(&serio_sem); + mutex_unlock(&serio_mutex); } /* @@ -672,17 +674,17 @@ void serio_unregister_port(struct serio *serio) */ void serio_unregister_child_port(struct serio *serio) { - down(&serio_sem); + mutex_lock(&serio_mutex); if (serio->child) { serio_disconnect_port(serio->child); serio_destroy_port(serio->child); } - up(&serio_sem); + mutex_unlock(&serio_mutex); } /* * Submits register request to kseriod for subsequent execution. - * Can be used when it is not obvious whether the serio_sem is + * Can be used when it is not obvious whether the serio_mutex is * taken or not and when delayed execution is feasible. */ void __serio_unregister_port_delayed(struct serio *serio, struct module *owner) @@ -765,7 +767,7 @@ void serio_unregister_driver(struct serio_driver *drv) { struct serio *serio; - down(&serio_sem); + mutex_lock(&serio_mutex); drv->manual_bind = 1; /* so serio_find_driver ignores it */ start_over: @@ -779,7 +781,7 @@ start_over: } driver_unregister(&drv->driver); - up(&serio_sem); + mutex_unlock(&serio_mutex); } static void serio_set_drv(struct serio *serio, struct serio_driver *drv) @@ -858,7 +860,7 @@ static int serio_resume(struct device *dev) return 0; } -/* called from serio_driver->connect/disconnect methods under serio_sem */ +/* called from serio_driver->connect/disconnect methods under serio_mutex */ int serio_open(struct serio *serio, struct serio_driver *drv) { serio_set_drv(serio, drv); @@ -870,7 +872,7 @@ int serio_open(struct serio *serio, struct serio_driver *drv) return 0; } -/* called from serio_driver->connect/disconnect methods under serio_sem */ +/* called from serio_driver->connect/disconnect methods under serio_mutex */ void serio_close(struct serio *serio) { if (serio->close) @@ -923,5 +925,5 @@ static void __exit serio_exit(void) kthread_stop(serio_task); } -module_init(serio_init); +subsys_initcall(serio_init); module_exit(serio_exit); diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 47e08de18d07..5a2703b536dc 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -19,6 +19,7 @@ #include #include #include +#include #define DRIVER_DESC "Raw serio driver" @@ -46,7 +47,7 @@ struct serio_raw_list { struct list_head node; }; -static DECLARE_MUTEX(serio_raw_sem); +static DEFINE_MUTEX(serio_raw_mutex); static LIST_HEAD(serio_raw_list); static unsigned int serio_raw_no; @@ -81,7 +82,7 @@ static int serio_raw_open(struct inode *inode, struct file *file) struct serio_raw_list *list; int retval = 0; - retval = down_interruptible(&serio_raw_sem); + retval = mutex_lock_interruptible(&serio_raw_mutex); if (retval) return retval; @@ -95,12 +96,11 @@ static int serio_raw_open(struct inode *inode, struct file *file) goto out; } - if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) { + if (!(list = kzalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) { retval = -ENOMEM; goto out; } - memset(list, 0, sizeof(struct serio_raw_list)); list->serio_raw = serio_raw; file->private_data = list; @@ -108,7 +108,7 @@ static int serio_raw_open(struct inode *inode, struct file *file) list_add_tail(&list->node, &serio_raw->list); out: - up(&serio_raw_sem); + mutex_unlock(&serio_raw_mutex); return retval; } @@ -130,12 +130,12 @@ static int serio_raw_release(struct inode *inode, struct file *file) struct serio_raw_list *list = file->private_data; struct serio_raw *serio_raw = list->serio_raw; - down(&serio_raw_sem); + mutex_lock(&serio_raw_mutex); serio_raw_fasync(-1, file, 0); serio_raw_cleanup(serio_raw); - up(&serio_raw_sem); + mutex_unlock(&serio_raw_mutex); return 0; } @@ -194,7 +194,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz int retval; unsigned char c; - retval = down_interruptible(&serio_raw_sem); + retval = mutex_lock_interruptible(&serio_raw_mutex); if (retval) return retval; @@ -219,7 +219,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer, siz }; out: - up(&serio_raw_sem); + mutex_unlock(&serio_raw_mutex); return written; } @@ -275,14 +275,13 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) struct serio_raw *serio_raw; int err; - if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) { + if (!(serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL))) { printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n"); return -ENOMEM; } - down(&serio_raw_sem); + mutex_lock(&serio_raw_mutex); - memset(serio_raw, 0, sizeof(struct serio_raw)); snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); serio_raw->refcnt = 1; serio_raw->serio = serio; @@ -325,7 +324,7 @@ out_free: serio_set_drvdata(serio, NULL); kfree(serio_raw); out: - up(&serio_raw_sem); + mutex_unlock(&serio_raw_mutex); return err; } @@ -350,7 +349,7 @@ static void serio_raw_disconnect(struct serio *serio) { struct serio_raw *serio_raw; - down(&serio_raw_sem); + mutex_lock(&serio_raw_mutex); serio_raw = serio_get_drvdata(serio); @@ -361,7 +360,7 @@ static void serio_raw_disconnect(struct serio *serio) if (!serio_raw_cleanup(serio_raw)) wake_up_interruptible(&serio_raw->wait); - up(&serio_raw_sem); + mutex_unlock(&serio_raw_mutex); } static struct serio_device_id serio_raw_serio_ids[] = { diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index ca1547929d62..d678d144bbf8 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -157,9 +157,8 @@ static int tsdev_open(struct inode *inode, struct file *file) if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) return -ENODEV; - if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL))) + if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL))) return -ENOMEM; - memset(list, 0, sizeof(struct tsdev_list)); list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0; @@ -379,9 +378,8 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, return NULL; } - if (!(tsdev = kmalloc(sizeof(struct tsdev), GFP_KERNEL))) + if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL))) return NULL; - memset(tsdev, 0, sizeof(struct tsdev)); INIT_LIST_HEAD(&tsdev->list); init_waitqueue_head(&tsdev->wait); diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig index 53c4fb62ed85..5b203fe21dcd 100644 --- a/drivers/isdn/gigaset/Kconfig +++ b/drivers/isdn/gigaset/Kconfig @@ -3,8 +3,8 @@ menu "Siemens Gigaset" config ISDN_DRV_GIGASET tristate "Siemens Gigaset support (isdn)" - depends on ISDN_I4L && m -# depends on ISDN_I4L && MODULES + depends on ISDN_I4L + select CRC_CCITT help Say m here if you have a Gigaset or Sinus isdn device. diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 171f8b703d61..ce3cd77094b3 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -3,7 +3,7 @@ * * Copyright (c) 2005 by Tilman Schmidt , * Hansjoerg Lipp , - * Stefan Eilers . + * Stefan Eilers. * * ===================================================================== * This program is free software; you can redistribute it and/or @@ -11,10 +11,6 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * ===================================================================== - * ToDo: ... - * ===================================================================== - * Version: $Id: asyncdata.c,v 1.2.2.7 2005/11/13 23:05:18 hjlipp Exp $ - * ===================================================================== */ #include "gigaset.h" @@ -45,7 +41,7 @@ static inline int muststuff(unsigned char c) * number of processed bytes */ static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes, - struct inbuf_t *inbuf) + struct inbuf_t *inbuf) { struct cardstate *cs = inbuf->cs; unsigned cbytes = cs->cbytes; @@ -55,10 +51,11 @@ static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes, for (;;) { cs->respdata[cbytes] = c; if (c == 10 || c == 13) { - dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", - __func__, cbytes); + gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", + __func__, cbytes); cs->cbytes = cbytes; - gigaset_handle_modem_response(cs); /* can change cs->dle */ + gigaset_handle_modem_response(cs); /* can change + cs->dle */ cbytes = 0; if (cs->dle && @@ -71,7 +68,7 @@ static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes, if (cbytes < MAX_RESP_SIZE - 1) cbytes++; else - warn("response too large"); + dev_warn(cs->dev, "response too large\n"); } if (!numbytes) @@ -96,11 +93,12 @@ static inline int cmd_loop(unsigned char c, unsigned char *src, int numbytes, * number of processed bytes */ static inline int lock_loop(unsigned char *src, int numbytes, - struct inbuf_t *inbuf) + struct inbuf_t *inbuf) { struct cardstate *cs = inbuf->cs; - gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src, 0); + gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", + numbytes, src); gigaset_if_receive(cs, src, numbytes); return numbytes; @@ -115,24 +113,18 @@ static inline int lock_loop(unsigned char *src, int numbytes, * numbytes (all bytes processed) on error --FIXME */ static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes, - struct inbuf_t *inbuf) + struct inbuf_t *inbuf) { struct cardstate *cs = inbuf->cs; struct bc_state *bcs = inbuf->bcs; - int inputstate; - __u16 fcs; - struct sk_buff *skb; + int inputstate = bcs->inputstate; + __u16 fcs = bcs->fcs; + struct sk_buff *skb = bcs->skb; unsigned char error; struct sk_buff *compskb; int startbytes = numbytes; int l; - IFNULLRETVAL(bcs, numbytes); - inputstate = bcs->inputstate; - fcs = bcs->fcs; - skb = bcs->skb; - IFNULLRETVAL(skb, numbytes); - if (unlikely(inputstate & INS_byte_stuff)) { inputstate &= ~INS_byte_stuff; goto byte_stuff; @@ -156,39 +148,37 @@ byte_stuff: c ^= PPP_TRANS; #ifdef CONFIG_GIGASET_DEBUG if (unlikely(!muststuff(c))) - dbg(DEBUG_HDLC, - "byte stuffed: 0x%02x", c); + gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c); #endif } else if (unlikely(c == PPP_FLAG)) { if (unlikely(inputstate & INS_skip_frame)) { if (!(inputstate & INS_have_data)) { /* 7E 7E */ - //dbg(DEBUG_HDLC, "(7e)7e------------------------"); #ifdef CONFIG_GIGASET_DEBUG ++bcs->emptycount; #endif } else - dbg(DEBUG_HDLC, + gig_dbg(DEBUG_HDLC, "7e----------------------------"); /* end of frame */ error = 1; gigaset_rcv_error(NULL, cs, bcs); } else if (!(inputstate & INS_have_data)) { /* 7E 7E */ - //dbg(DEBUG_HDLC, "(7e)7e------------------------"); #ifdef CONFIG_GIGASET_DEBUG ++bcs->emptycount; #endif break; } else { - dbg(DEBUG_HDLC, - "7e----------------------------"); + gig_dbg(DEBUG_HDLC, + "7e----------------------------"); /* end of frame */ error = 0; if (unlikely(fcs != PPP_GOODFCS)) { - err("Packet checksum at %lu failed, " - "packet is corrupted (%u bytes)!", + dev_err(cs->dev, + "Packet checksum at %lu failed, " + "packet is corrupted (%u bytes)!\n", bcs->rcvbytes, skb->len); compskb = NULL; gigaset_rcv_error(compskb, cs, bcs); @@ -202,9 +192,11 @@ byte_stuff: skb = NULL; inputstate |= INS_skip_frame; if (l == 1) { - err("invalid packet size (1)!"); + dev_err(cs->dev, + "invalid packet size (1)!\n"); error = 1; - gigaset_rcv_error(NULL, cs, bcs); + gigaset_rcv_error(NULL, + cs, bcs); } } if (likely(!(error || @@ -227,7 +219,8 @@ byte_stuff: } else if (likely((skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL)) { skb_reserve(skb, HW_HDR_LEN); } else { - warn("could not allocate new skb"); + dev_warn(cs->dev, + "could not allocate new skb\n"); inputstate |= INS_skip_frame; } @@ -235,7 +228,7 @@ byte_stuff: #ifdef CONFIG_GIGASET_DEBUG } else if (unlikely(muststuff(c))) { /* Should not happen. Possible after ZDLE=1. */ - dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); + gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); #endif } @@ -243,8 +236,8 @@ byte_stuff: #ifdef CONFIG_GIGASET_DEBUG if (unlikely(!(inputstate & INS_have_data))) { - dbg(DEBUG_HDLC, - "7e (%d x) ================", bcs->emptycount); + gig_dbg(DEBUG_HDLC, "7e (%d x) ================", + bcs->emptycount); bcs->emptycount = 0; } #endif @@ -253,14 +246,13 @@ byte_stuff: if (likely(!(inputstate & INS_skip_frame))) { if (unlikely(skb->len == SBUFSIZE)) { - warn("received packet too long"); + dev_warn(cs->dev, "received packet too long\n"); dev_kfree_skb_any(skb); skb = NULL; inputstate |= INS_skip_frame; break; } - *gigaset_skb_put_quick(skb, 1) = c; - /* *__skb_put (skb, 1) = c; */ + *__skb_put(skb, 1) = c; fcs = crc_ccitt_byte(fcs, c); } @@ -289,19 +281,14 @@ byte_stuff: * numbytes (all bytes processed) on error --FIXME */ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, - struct inbuf_t *inbuf) + struct inbuf_t *inbuf) { struct cardstate *cs = inbuf->cs; struct bc_state *bcs = inbuf->bcs; - int inputstate; - struct sk_buff *skb; + int inputstate = bcs->inputstate; + struct sk_buff *skb = bcs->skb; int startbytes = numbytes; - IFNULLRETVAL(bcs, numbytes); - inputstate = bcs->inputstate; - skb = bcs->skb; - IFNULLRETVAL(skb, numbytes); - for (;;) { /* add character */ inputstate |= INS_have_data; @@ -309,13 +296,13 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, if (likely(!(inputstate & INS_skip_frame))) { if (unlikely(skb->len == SBUFSIZE)) { //FIXME just pass skb up and allocate a new one - warn("received packet too long"); + dev_warn(cs->dev, "received packet too long\n"); dev_kfree_skb_any(skb); skb = NULL; inputstate |= INS_skip_frame; break; } - *gigaset_skb_put_quick(skb, 1) = gigaset_invtab[c]; + *__skb_put(skb, 1) = gigaset_invtab[c]; } if (unlikely(!numbytes)) @@ -343,7 +330,7 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes, != NULL)) { skb_reserve(skb, HW_HDR_LEN); } else { - warn("could not allocate new skb"); + dev_warn(cs->dev, "could not allocate new skb\n"); inputstate |= INS_skip_frame; } } @@ -364,13 +351,13 @@ void gigaset_m10x_input(struct inbuf_t *inbuf) head = atomic_read(&inbuf->head); tail = atomic_read(&inbuf->tail); - dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); + gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); if (head != tail) { cs = inbuf->cs; src = inbuf->data + head; numbytes = (head > tail ? RBUFSIZE : tail) - head; - dbg(DEBUG_INTR, "processing %u bytes", numbytes); + gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); while (numbytes) { if (atomic_read(&cs->mstate) == MS_LOCKED) { @@ -392,8 +379,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf) if (!(inbuf->inputstate & INS_DLE_char)) { - /* FIXME Einfach je nach Modus Funktionszeiger in cs setzen [hier+hdlc_loop]? */ - /* FIXME Spart folgendes "if" und ermoeglicht andere Protokolle */ + /* FIXME use function pointers? */ if (inbuf->inputstate & INS_command) procbytes = cmd_loop(c, src, numbytes, inbuf); else if (inbuf->bcs->proto2 == ISDN_PROTO_L2_HDLC) @@ -403,13 +389,14 @@ void gigaset_m10x_input(struct inbuf_t *inbuf) src += procbytes; numbytes -= procbytes; - } else { /* DLE-char */ + } else { /* DLE char */ inbuf->inputstate &= ~INS_DLE_char; switch (c) { case 'X': /*begin of command*/ #ifdef CONFIG_GIGASET_DEBUG if (inbuf->inputstate & INS_command) - err("received 'X' in command mode"); + dev_err(cs->dev, + "received 'X' in command mode\n"); #endif inbuf->inputstate |= INS_command | INS_DLE_command; @@ -417,7 +404,8 @@ void gigaset_m10x_input(struct inbuf_t *inbuf) case '.': /*end of command*/ #ifdef CONFIG_GIGASET_DEBUG if (!(inbuf->inputstate & INS_command)) - err("received '.' in hdlc mode"); + dev_err(cs->dev, + "received '.' in hdlc mode\n"); #endif inbuf->inputstate &= cs->dle ? ~(INS_DLE_command|INS_command) @@ -425,7 +413,9 @@ void gigaset_m10x_input(struct inbuf_t *inbuf) break; //case DLE_FLAG: /*DLE_FLAG in data stream*/ /* schon oben behandelt! */ default: - err("received 0x10 0x%02x!", (int) c); + dev_err(cs->dev, + "received 0x10 0x%02x!\n", + (int) c); /* FIXME: reset driver?? */ } } @@ -444,7 +434,7 @@ nextbyte: } } - dbg(DEBUG_INTR, "setting head to %u", head); + gig_dbg(DEBUG_INTR, "setting head to %u", head); atomic_set(&inbuf->head, head); } } @@ -479,14 +469,13 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail) stuf_cnt++; fcs = crc_ccitt_byte(fcs, *cp++); } - fcs ^= 0xffff; /* complement */ + fcs ^= 0xffff; /* complement */ /* size of new buffer: original size + number of stuffing bytes * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes */ hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + tail + head); if (!hdlc_skb) { - err("unable to allocate memory for HDLC encoding!"); dev_kfree_skb(skb); return NULL; } @@ -508,7 +497,7 @@ static struct sk_buff *HDLC_Encode(struct sk_buff *skb, int head, int tail) } /* Finally add FCS (byte stuffed) and flag sequence */ - c = (fcs & 0x00ff); /* least significant byte first */ + c = (fcs & 0x00ff); /* least significant byte first */ if (muststuff(c)) { *(skb_put(hdlc_skb, 1)) = PPP_ESCAPE; c ^= PPP_TRANS; @@ -546,7 +535,6 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) /* worst case: every byte must be stuffed */ iraw_skb = dev_alloc_skb(2*skb->len + tail + head); if (!iraw_skb) { - err("unable to allocate memory for HDLC encoding!"); dev_kfree_skb(skb); return NULL; } @@ -577,21 +565,23 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail) */ int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) { - unsigned len; - - IFNULLRETVAL(bcs, -EFAULT); - IFNULLRETVAL(skb, -EFAULT); - len = skb->len; + unsigned len = skb->len; + unsigned long flags; if (bcs->proto2 == ISDN_PROTO_L2_HDLC) skb = HDLC_Encode(skb, HW_HDR_LEN, 0); else skb = iraw_encode(skb, HW_HDR_LEN, 0); - if (!skb) + if (!skb) { + err("unable to allocate memory for encoding!\n"); return -ENOMEM; + } skb_queue_tail(&bcs->squeue, skb); - tasklet_schedule(&bcs->cs->write_tasklet); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->cs->connected) + tasklet_schedule(&bcs->cs->write_tasklet); + spin_unlock_irqrestore(&bcs->cs->lock, flags); return len; /* ok so far */ } diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 31f0f07832bc..f86ed6af3aa2 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -3,7 +3,7 @@ * * Copyright (c) 2001 by Hansjoerg Lipp , * Tilman Schmidt , - * Stefan Eilers . + * Stefan Eilers. * * Based on usb-gigaset.c. * @@ -13,10 +13,6 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * ===================================================================== - * ToDo: ... - * ===================================================================== - * Version: $Id: bas-gigaset.c,v 1.52.4.19 2006/02/04 18:28:16 hjlipp Exp $ - * ===================================================================== */ #include "gigaset.h" @@ -30,7 +26,7 @@ #include /* Version Information */ -#define DRIVER_AUTHOR "Tilman Schmidt , Hansjoerg Lipp , Stefan Eilers " +#define DRIVER_AUTHOR "Tilman Schmidt , Hansjoerg Lipp , Stefan Eilers" #define DRIVER_DESC "USB Driver for Gigaset 307x" @@ -70,9 +66,6 @@ static struct usb_device_id gigaset_table [] = { MODULE_DEVICE_TABLE(usb, gigaset_table); -/* Get a minor range for your devices from the usb maintainer */ -#define USB_SKEL_MINOR_BASE 200 - /*======================= local function prototypes =============================*/ /* This function is called if a new device is connected to the USB port. It @@ -88,25 +81,25 @@ static void gigaset_disconnect(struct usb_interface *interface); /*==============================================================================*/ struct bas_cardstate { - struct usb_device *udev; /* USB device pointer */ - struct usb_interface *interface; /* interface for this device */ + struct usb_device *udev; /* USB device pointer */ + struct usb_interface *interface; /* interface for this device */ unsigned char minor; /* starting minor number */ - struct urb *urb_ctrl; /* control pipe default URB */ + struct urb *urb_ctrl; /* control pipe default URB */ struct usb_ctrlrequest dr_ctrl; struct timer_list timer_ctrl; /* control request timeout */ struct timer_list timer_atrdy; /* AT command ready timeout */ - struct urb *urb_cmd_out; /* for sending AT commands */ + struct urb *urb_cmd_out; /* for sending AT commands */ struct usb_ctrlrequest dr_cmd_out; int retry_cmd_out; - struct urb *urb_cmd_in; /* for receiving AT replies */ + struct urb *urb_cmd_in; /* for receiving AT replies */ struct usb_ctrlrequest dr_cmd_in; struct timer_list timer_cmd_in; /* receive request timeout */ - unsigned char *rcvbuf; /* AT reply receive buffer */ + unsigned char *rcvbuf; /* AT reply receive buffer */ - struct urb *urb_int_in; /* URB for interrupt pipe */ + struct urb *urb_int_in; /* URB for interrupt pipe */ unsigned char int_in_buf[3]; spinlock_t lock; /* locks all following */ @@ -208,53 +201,54 @@ static inline char *usb_pipetype_str(int pipe) * write content of URB to syslog for debugging */ static inline void dump_urb(enum debuglevel level, const char *tag, - struct urb *urb) + struct urb *urb) { #ifdef CONFIG_GIGASET_DEBUG int i; - IFNULLRET(tag); - dbg(level, "%s urb(0x%08lx)->{", tag, (unsigned long) urb); + gig_dbg(level, "%s urb(0x%08lx)->{", tag, (unsigned long) urb); if (urb) { - dbg(level, - " dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, " - "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,", - (unsigned long) urb->dev, - usb_pipetype_str(urb->pipe), - usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", - urb->status, (unsigned long) urb->hcpriv, - urb->transfer_flags); - dbg(level, - " transfer_buffer=0x%08lx[%d], actual_length=%d, " - "bandwidth=%d, setup_packet=0x%08lx,", - (unsigned long) urb->transfer_buffer, - urb->transfer_buffer_length, urb->actual_length, - urb->bandwidth, (unsigned long) urb->setup_packet); - dbg(level, - " start_frame=%d, number_of_packets=%d, interval=%d, " - "error_count=%d,", - urb->start_frame, urb->number_of_packets, urb->interval, - urb->error_count); - dbg(level, - " context=0x%08lx, complete=0x%08lx, iso_frame_desc[]={", - (unsigned long) urb->context, - (unsigned long) urb->complete); + gig_dbg(level, + " dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, " + "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,", + (unsigned long) urb->dev, + usb_pipetype_str(urb->pipe), + usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + urb->status, (unsigned long) urb->hcpriv, + urb->transfer_flags); + gig_dbg(level, + " transfer_buffer=0x%08lx[%d], actual_length=%d, " + "bandwidth=%d, setup_packet=0x%08lx,", + (unsigned long) urb->transfer_buffer, + urb->transfer_buffer_length, urb->actual_length, + urb->bandwidth, (unsigned long) urb->setup_packet); + gig_dbg(level, + " start_frame=%d, number_of_packets=%d, interval=%d, " + "error_count=%d,", + urb->start_frame, urb->number_of_packets, urb->interval, + urb->error_count); + gig_dbg(level, + " context=0x%08lx, complete=0x%08lx, " + "iso_frame_desc[]={", + (unsigned long) urb->context, + (unsigned long) urb->complete); for (i = 0; i < urb->number_of_packets; i++) { - struct usb_iso_packet_descriptor *pifd = &urb->iso_frame_desc[i]; - dbg(level, - " {offset=%u, length=%u, actual_length=%u, " - "status=%u}", - pifd->offset, pifd->length, pifd->actual_length, - pifd->status); + struct usb_iso_packet_descriptor *pifd + = &urb->iso_frame_desc[i]; + gig_dbg(level, + " {offset=%u, length=%u, actual_length=%u, " + "status=%u}", + pifd->offset, pifd->length, pifd->actual_length, + pifd->status); } } - dbg(level, "}}"); + gig_dbg(level, "}}"); #endif } /* read/set modem control bits etc. (m10x only) */ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, - unsigned new_state) + unsigned new_state) { return -EINVAL; } @@ -280,8 +274,8 @@ static inline void error_hangup(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; - dbg(DEBUG_ANY, - "%s: scheduling HUP for channel %d", __func__, bcs->channel); + gig_dbg(DEBUG_ANY, "%s: scheduling HUP for channel %d", + __func__, bcs->channel); if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { //FIXME what should we do? @@ -301,22 +295,19 @@ static inline void error_hangup(struct bc_state *bcs) static inline void error_reset(struct cardstate *cs) { //FIXME try to recover without bothering the user - err("unrecoverable error - please disconnect the Gigaset base to reset"); + dev_err(cs->dev, + "unrecoverable error - please disconnect Gigaset base to reset\n"); } /* check_pending * check for completion of pending control request * parameter: - * urb USB request block of completed request - * urb->context = hardware specific controller state structure + * ucs hardware specific controller state structure */ static void check_pending(struct bas_cardstate *ucs) { unsigned long flags; - IFNULLRET(ucs); - IFNULLRET(cardstate); - spin_lock_irqsave(&ucs->lock, flags); switch (ucs->pending) { case 0: @@ -336,8 +327,6 @@ static void check_pending(struct bas_cardstate *ucs) case HD_CLOSE_ATCHANNEL: if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) ucs->pending = 0; - //wake_up_interruptible(cs->initwait); - //FIXME need own wait queue? break; case HD_CLOSE_B1CHANNEL: if (!(atomic_read(&ucs->basstate) & BS_B1OPEN)) @@ -354,7 +343,9 @@ static void check_pending(struct bas_cardstate *ucs) * are handled separately and should never end up here */ default: - warn("unknown pending request 0x%02x cleared", ucs->pending); + dev_warn(&ucs->interface->dev, + "unknown pending request 0x%02x cleared\n", + ucs->pending); ucs->pending = 0; } @@ -372,27 +363,23 @@ static void check_pending(struct bas_cardstate *ucs) static void cmd_in_timeout(unsigned long data) { struct cardstate *cs = (struct cardstate *) data; - struct bas_cardstate *ucs; + struct bas_cardstate *ucs = cs->hw.bas; unsigned long flags; - IFNULLRET(cs); - ucs = cs->hw.bas; - IFNULLRET(ucs); - spin_lock_irqsave(&cs->lock, flags); - if (!atomic_read(&cs->connected)) { - dbg(DEBUG_USBREQ, "%s: disconnected", __func__); + if (unlikely(!cs->connected)) { + gig_dbg(DEBUG_USBREQ, "%s: disconnected", __func__); spin_unlock_irqrestore(&cs->lock, flags); return; } if (!ucs->rcvbuf_size) { - dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); + gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); spin_unlock_irqrestore(&cs->lock, flags); return; } spin_unlock_irqrestore(&cs->lock, flags); - err("timeout reading AT response"); + dev_err(cs->dev, "timeout reading AT response\n"); error_reset(cs); //FIXME retry? } @@ -412,18 +399,15 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs); */ static int atread_submit(struct cardstate *cs, int timeout) { - struct bas_cardstate *ucs; + struct bas_cardstate *ucs = cs->hw.bas; int ret; - IFNULLRETVAL(cs, -EINVAL); - ucs = cs->hw.bas; - IFNULLRETVAL(ucs, -EINVAL); - IFNULLRETVAL(ucs->urb_cmd_in, -EINVAL); - - dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", ucs->rcvbuf_size); + gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", + ucs->rcvbuf_size); if (ucs->urb_cmd_in->status == -EINPROGRESS) { - err("could not submit HD_READ_ATMESSAGE: URB busy"); + dev_err(cs->dev, + "could not submit HD_READ_ATMESSAGE: URB busy\n"); return -EBUSY; } @@ -433,19 +417,19 @@ static int atread_submit(struct cardstate *cs, int timeout) ucs->dr_cmd_in.wIndex = 0; ucs->dr_cmd_in.wLength = cpu_to_le16(ucs->rcvbuf_size); usb_fill_control_urb(ucs->urb_cmd_in, ucs->udev, - usb_rcvctrlpipe(ucs->udev, 0), - (unsigned char*) & ucs->dr_cmd_in, - ucs->rcvbuf, ucs->rcvbuf_size, - read_ctrl_callback, cs->inbuf); + usb_rcvctrlpipe(ucs->udev, 0), + (unsigned char*) & ucs->dr_cmd_in, + ucs->rcvbuf, ucs->rcvbuf_size, + read_ctrl_callback, cs->inbuf); if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) { - err("could not submit HD_READ_ATMESSAGE: %s", - get_usb_statmsg(ret)); + dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", + get_usb_statmsg(ret)); return ret; } if (timeout > 0) { - dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); + gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); ucs->timer_cmd_in.expires = jiffies + timeout * HZ / 10; ucs->timer_cmd_in.data = (unsigned long) cs; ucs->timer_cmd_in.function = cmd_in_timeout; @@ -483,25 +467,14 @@ inline static void update_basstate(struct bas_cardstate *ucs, */ static void read_int_callback(struct urb *urb, struct pt_regs *regs) { - struct cardstate *cs; - struct bas_cardstate *ucs; + struct cardstate *cs = urb->context; + struct bas_cardstate *ucs = cs->hw.bas; struct bc_state *bcs; unsigned long flags; int status; unsigned l; int channel; - IFNULLRET(urb); - cs = (struct cardstate *) urb->context; - IFNULLRET(cs); - ucs = cs->hw.bas; - IFNULLRET(ucs); - - if (unlikely(!atomic_read(&cs->connected))) { - warn("%s: disconnected", __func__); - return; - } - switch (urb->status) { case 0: /* success */ break; @@ -509,11 +482,12 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) case -ECONNRESET: /* canceled (async) */ case -EINPROGRESS: /* pending */ /* ignore silently */ - dbg(DEBUG_USBREQ, - "%s: %s", __func__, get_usb_statmsg(urb->status)); + gig_dbg(DEBUG_USBREQ, "%s: %s", + __func__, get_usb_statmsg(urb->status)); return; default: /* severe trouble */ - warn("interrupt read: %s", get_usb_statmsg(urb->status)); + dev_warn(cs->dev, "interrupt read: %s\n", + get_usb_statmsg(urb->status)); //FIXME corrective action? resubmission always ok? goto resubmit; } @@ -521,10 +495,9 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) l = (unsigned) ucs->int_in_buf[1] + (((unsigned) ucs->int_in_buf[2]) << 8); - dbg(DEBUG_USBREQ, - "<-------%d: 0x%02x (%u [0x%02x 0x%02x])", urb->actual_length, - (int)ucs->int_in_buf[0], l, - (int)ucs->int_in_buf[1], (int)ucs->int_in_buf[2]); + gig_dbg(DEBUG_USBREQ, "<-------%d: 0x%02x (%u [0x%02x 0x%02x])", + urb->actual_length, (int)ucs->int_in_buf[0], l, + (int)ucs->int_in_buf[1], (int)ucs->int_in_buf[2]); channel = 0; @@ -570,28 +543,30 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) case HD_B1_FLOW_CONTROL: bcs = cs->bcs + channel; atomic_add((l - BAS_NORMFRAME) * BAS_CORRFRAMES, - &bcs->hw.bas->corrbytes); - dbg(DEBUG_ISO, - "Flow control (channel %d, sub %d): 0x%02x => %d", - channel, bcs->hw.bas->numsub, l, - atomic_read(&bcs->hw.bas->corrbytes)); + &bcs->hw.bas->corrbytes); + gig_dbg(DEBUG_ISO, + "Flow control (channel %d, sub %d): 0x%02x => %d", + channel, bcs->hw.bas->numsub, l, + atomic_read(&bcs->hw.bas->corrbytes)); break; case HD_RECEIVEATDATA_ACK: /* AT response ready to be received */ if (!l) { - warn("HD_RECEIVEATDATA_ACK with length 0 ignored"); + dev_warn(cs->dev, + "HD_RECEIVEATDATA_ACK with length 0 ignored\n"); break; } spin_lock_irqsave(&cs->lock, flags); if (ucs->rcvbuf_size) { spin_unlock_irqrestore(&cs->lock, flags); - err("receive AT data overrun, %d bytes lost", l); + dev_err(cs->dev, + "receive AT data overrun, %d bytes lost\n", l); error_reset(cs); //FIXME reschedule break; } if ((ucs->rcvbuf = kmalloc(l, GFP_ATOMIC)) == NULL) { spin_unlock_irqrestore(&cs->lock, flags); - err("%s: out of memory, %d bytes lost", __func__, l); + dev_err(cs->dev, "out of memory, %d bytes lost\n", l); error_reset(cs); //FIXME reschedule break; } @@ -607,25 +582,28 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs) break; case HD_RESET_INTERRUPT_PIPE_ACK: - dbg(DEBUG_USBREQ, "HD_RESET_INTERRUPT_PIPE_ACK"); + gig_dbg(DEBUG_USBREQ, "HD_RESET_INTERRUPT_PIPE_ACK"); break; case HD_SUSPEND_END: - dbg(DEBUG_USBREQ, "HD_SUSPEND_END"); + gig_dbg(DEBUG_USBREQ, "HD_SUSPEND_END"); break; default: - warn("unknown Gigaset signal 0x%02x (%u) ignored", - (int) ucs->int_in_buf[0], l); + dev_warn(cs->dev, + "unknown Gigaset signal 0x%02x (%u) ignored\n", + (int) ucs->int_in_buf[0], l); } check_pending(ucs); resubmit: - status = usb_submit_urb(urb, SLAB_ATOMIC); + spin_lock_irqsave(&cs->lock, flags); + status = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&cs->lock, flags); if (unlikely(status)) { - err("could not resubmit interrupt URB: %s", - get_usb_statmsg(status)); + dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", + get_usb_statmsg(status)); error_reset(cs); } } @@ -639,30 +617,22 @@ resubmit: */ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) { - struct cardstate *cs; - struct bas_cardstate *ucs; + struct inbuf_t *inbuf = urb->context; + struct cardstate *cs = inbuf->cs; + struct bas_cardstate *ucs = cs->hw.bas; + int have_data = 0; unsigned numbytes; unsigned long flags; - struct inbuf_t *inbuf; - int have_data = 0; - - IFNULLRET(urb); - inbuf = (struct inbuf_t *) urb->context; - IFNULLRET(inbuf); - cs = inbuf->cs; - IFNULLRET(cs); - ucs = cs->hw.bas; - IFNULLRET(ucs); spin_lock_irqsave(&cs->lock, flags); - if (!atomic_read(&cs->connected)) { + if (unlikely(!cs->connected)) { warn("%s: disconnected", __func__); spin_unlock_irqrestore(&cs->lock, flags); return; } if (!ucs->rcvbuf_size) { - warn("%s: no receive in progress", __func__); + dev_warn(cs->dev, "%s: no receive in progress\n", __func__); spin_unlock_irqrestore(&cs->lock, flags); return; } @@ -673,12 +643,14 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) case 0: /* normal completion */ numbytes = urb->actual_length; if (unlikely(numbytes == 0)) { - warn("control read: empty block received"); + dev_warn(cs->dev, + "control read: empty block received\n"); goto retry; } if (unlikely(numbytes != ucs->rcvbuf_size)) { - warn("control read: received %d chars, expected %d", - numbytes, ucs->rcvbuf_size); + dev_warn(cs->dev, + "control read: received %d chars, expected %d\n", + numbytes, ucs->rcvbuf_size); if (numbytes > ucs->rcvbuf_size) numbytes = ucs->rcvbuf_size; } @@ -698,23 +670,26 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) case -ECONNRESET: /* canceled (async) */ case -EINPROGRESS: /* pending */ /* no action necessary */ - dbg(DEBUG_USBREQ, - "%s: %s", __func__, get_usb_statmsg(urb->status)); + gig_dbg(DEBUG_USBREQ, "%s: %s", + __func__, get_usb_statmsg(urb->status)); break; default: /* severe trouble */ - warn("control read: %s", get_usb_statmsg(urb->status)); + dev_warn(cs->dev, "control read: %s\n", + get_usb_statmsg(urb->status)); retry: if (ucs->retry_cmd_in++ < BAS_RETRY) { - notice("control read: retry %d", ucs->retry_cmd_in); + dev_notice(cs->dev, "control read: retry %d\n", + ucs->retry_cmd_in); if (atread_submit(cs, BAS_TIMEOUT) >= 0) { /* resubmitted - bypass regular exit block */ spin_unlock_irqrestore(&cs->lock, flags); return; } } else { - err("control read: giving up after %d tries", - ucs->retry_cmd_in); + dev_err(cs->dev, + "control read: giving up after %d tries\n", + ucs->retry_cmd_in); } error_reset(cs); } @@ -724,7 +699,7 @@ static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs) ucs->rcvbuf_size = 0; spin_unlock_irqrestore(&cs->lock, flags); if (have_data) { - dbg(DEBUG_INTR, "%s-->BH", __func__); + gig_dbg(DEBUG_INTR, "%s-->BH", __func__); gigaset_schedule_event(cs); } } @@ -743,21 +718,16 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs) unsigned long flags; int i, rc; - IFNULLRET(urb); - IFNULLRET(urb->context); - IFNULLRET(cardstate); - /* status codes not worth bothering the tasklet with */ if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || - urb->status == -EINPROGRESS)) { - dbg(DEBUG_ISO, - "%s: %s", __func__, get_usb_statmsg(urb->status)); + urb->status == -EINPROGRESS)) { + gig_dbg(DEBUG_ISO, "%s: %s", + __func__, get_usb_statmsg(urb->status)); return; } - bcs = (struct bc_state *) urb->context; + bcs = urb->context; ubc = bcs->hw.bas; - IFNULLRET(ubc); spin_lock_irqsave(&ubc->isoinlock, flags); if (likely(ubc->isoindone == NULL)) { @@ -777,14 +747,17 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs) urb->iso_frame_desc[i].actual_length = 0; } if (likely(atomic_read(&ubc->running))) { - urb->dev = bcs->cs->hw.bas->udev; /* clobbered by USB subsystem */ + /* urb->dev is clobbered by USB subsystem */ + urb->dev = bcs->cs->hw.bas->udev; urb->transfer_flags = URB_ISO_ASAP; urb->number_of_packets = BAS_NUMFRAMES; - dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", __func__); + gig_dbg(DEBUG_ISO, "%s: isoc read overrun/resubmit", + __func__); rc = usb_submit_urb(urb, SLAB_ATOMIC); if (unlikely(rc != 0)) { - err("could not resubmit isochronous read URB: %s", - get_usb_statmsg(rc)); + dev_err(bcs->cs->dev, + "could not resubmit isochronous read " + "URB: %s\n", get_usb_statmsg(rc)); dump_urb(DEBUG_ISO, "isoc read", urb); error_hangup(bcs); } @@ -806,23 +779,17 @@ static void write_iso_callback(struct urb *urb, struct pt_regs *regs) struct bas_bc_state *ubc; unsigned long flags; - IFNULLRET(urb); - IFNULLRET(urb->context); - IFNULLRET(cardstate); - /* status codes not worth bothering the tasklet with */ if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || - urb->status == -EINPROGRESS)) { - dbg(DEBUG_ISO, - "%s: %s", __func__, get_usb_statmsg(urb->status)); + urb->status == -EINPROGRESS)) { + gig_dbg(DEBUG_ISO, "%s: %s", + __func__, get_usb_statmsg(urb->status)); return; } /* pass URB context to tasklet */ - ucx = (struct isow_urbctx_t *) urb->context; - IFNULLRET(ucx->bcs); + ucx = urb->context; ubc = ucx->bcs->hw.bas; - IFNULLRET(ubc); spin_lock_irqsave(&ubc->isooutlock, flags); ubc->isooutovfl = ubc->isooutdone; @@ -841,15 +808,11 @@ static void write_iso_callback(struct urb *urb, struct pt_regs *regs) */ static int starturbs(struct bc_state *bcs) { + struct bas_bc_state *ubc = bcs->hw.bas; struct urb *urb; - struct bas_bc_state *ubc; int j, k; int rc; - IFNULLRETVAL(bcs, -EFAULT); - ubc = bcs->hw.bas; - IFNULLRETVAL(ubc, -EFAULT); - /* initialize L2 reception */ if (bcs->proto2 == ISDN_PROTO_L2_HDLC) bcs->inputstate |= INS_flag_hunt; @@ -859,7 +822,7 @@ static int starturbs(struct bc_state *bcs) for (k = 0; k < BAS_INURBS; k++) { urb = ubc->isoinurbs[k]; if (!urb) { - err("isoinurbs[%d]==NULL", k); + dev_err(bcs->cs->dev, "isoinurbs[%d]==NULL\n", k); rc = -EFAULT; goto error; } @@ -882,8 +845,9 @@ static int starturbs(struct bc_state *bcs) dump_urb(DEBUG_ISO, "Initial isoc read", urb); if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { - err("could not submit isochronous read URB %d: %s", - k, get_usb_statmsg(rc)); + dev_err(bcs->cs->dev, + "could not submit isochronous read URB %d: %s\n", + k, get_usb_statmsg(rc)); goto error; } } @@ -895,7 +859,7 @@ static int starturbs(struct bc_state *bcs) for (k = 0; k < BAS_OUTURBS; ++k) { urb = ubc->isoouturbs[k].urb; if (!urb) { - err("isoouturbs[%d].urb==NULL", k); + dev_err(bcs->cs->dev, "isoouturbs[%d].urb==NULL\n", k); rc = -EFAULT; goto error; } @@ -922,8 +886,9 @@ static int starturbs(struct bc_state *bcs) dump_urb(DEBUG_ISO, "Initial isoc write", urb); rc = usb_submit_urb(ubc->isoouturbs[k].urb, SLAB_ATOMIC); if (rc != 0) { - err("could not submit isochronous write URB %d: %s", - k, get_usb_statmsg(rc)); + dev_err(bcs->cs->dev, + "could not submit isochronous write URB %d: %s\n", + k, get_usb_statmsg(rc)); goto error; } } @@ -946,20 +911,20 @@ static void stopurbs(struct bas_bc_state *ubc) { int k, rc; - IFNULLRET(ubc); - atomic_set(&ubc->running, 0); for (k = 0; k < BAS_INURBS; ++k) { rc = usb_unlink_urb(ubc->isoinurbs[k]); - dbg(DEBUG_ISO, "%s: isoc input URB %d unlinked, result = %d", - __func__, k, rc); + gig_dbg(DEBUG_ISO, + "%s: isoc input URB %d unlinked, result = %d", + __func__, k, rc); } for (k = 0; k < BAS_OUTURBS; ++k) { rc = usb_unlink_urb(ubc->isoouturbs[k].urb); - dbg(DEBUG_ISO, "%s: isoc output URB %d unlinked, result = %d", - __func__, k, rc); + gig_dbg(DEBUG_ISO, + "%s: isoc output URB %d unlinked, result = %d", + __func__, k, rc); } } @@ -977,19 +942,14 @@ static void stopurbs(struct bas_bc_state *ubc) */ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) { - struct urb *urb; - struct bas_bc_state *ubc; + struct urb *urb = ucx->urb; + struct bas_bc_state *ubc = ucx->bcs->hw.bas; struct usb_iso_packet_descriptor *ifd; int corrbytes, nframe, rc; + unsigned long flags; - IFNULLRETVAL(ucx, -EFAULT); - urb = ucx->urb; - IFNULLRETVAL(urb, -EFAULT); - IFNULLRETVAL(ucx->bcs, -EFAULT); - ubc = ucx->bcs->hw.bas; - IFNULLRETVAL(ubc, -EFAULT); - - urb->dev = ucx->bcs->cs->hw.bas->udev; /* clobbered by USB subsystem */ + /* urb->dev is clobbered by USB subsystem */ + urb->dev = ucx->bcs->cs->hw.bas->udev; urb->transfer_flags = URB_ISO_ASAP; urb->transfer_buffer = ubc->isooutbuf->data; urb->transfer_buffer_length = sizeof(ubc->isooutbuf->data); @@ -1000,7 +960,8 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) /* compute frame length according to flow control */ ifd->length = BAS_NORMFRAME; if ((corrbytes = atomic_read(&ubc->corrbytes)) != 0) { - dbg(DEBUG_ISO, "%s: corrbytes=%d", __func__, corrbytes); + gig_dbg(DEBUG_ISO, "%s: corrbytes=%d", + __func__, corrbytes); if (corrbytes > BAS_HIGHFRAME - BAS_NORMFRAME) corrbytes = BAS_HIGHFRAME - BAS_NORMFRAME; else if (corrbytes < BAS_LOWFRAME - BAS_NORMFRAME) @@ -1008,18 +969,21 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) ifd->length += corrbytes; atomic_add(-corrbytes, &ubc->corrbytes); } - //dbg(DEBUG_ISO, "%s: frame %d length=%d", __func__, nframe, ifd->length); /* retrieve block of data to send */ - ifd->offset = gigaset_isowbuf_getbytes(ubc->isooutbuf, ifd->length); + ifd->offset = gigaset_isowbuf_getbytes(ubc->isooutbuf, + ifd->length); if (ifd->offset < 0) { if (ifd->offset == -EBUSY) { - dbg(DEBUG_ISO, "%s: buffer busy at frame %d", - __func__, nframe); - /* tasklet will be restarted from gigaset_send_skb() */ + gig_dbg(DEBUG_ISO, + "%s: buffer busy at frame %d", + __func__, nframe); + /* tasklet will be restarted from + gigaset_send_skb() */ } else { - err("%s: buffer error %d at frame %d", - __func__, ifd->offset, nframe); + dev_err(ucx->bcs->cs->dev, + "%s: buffer error %d at frame %d\n", + __func__, ifd->offset, nframe); return ifd->offset; } break; @@ -1029,9 +993,14 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) ifd->actual_length = 0; } if ((urb->number_of_packets = nframe) > 0) { - if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { - err("could not submit isochronous write URB: %s", - get_usb_statmsg(rc)); + spin_lock_irqsave(&ucx->bcs->cs->lock, flags); + rc = ucx->bcs->cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&ucx->bcs->cs->lock, flags); + + if (rc) { + dev_err(ucx->bcs->cs->dev, + "could not submit isochronous write URB: %s\n", + get_usb_statmsg(rc)); dump_urb(DEBUG_ISO, "isoc write", urb); return rc; } @@ -1048,9 +1017,9 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) */ static void write_iso_tasklet(unsigned long data) { - struct bc_state *bcs; - struct bas_bc_state *ubc; - struct cardstate *cs; + struct bc_state *bcs = (struct bc_state *) data; + struct bas_bc_state *ubc = bcs->hw.bas; + struct cardstate *cs = bcs->cs; struct isow_urbctx_t *done, *next, *ovfl; struct urb *urb; struct usb_iso_packet_descriptor *ifd; @@ -1060,22 +1029,10 @@ static void write_iso_tasklet(unsigned long data) struct sk_buff *skb; int len; - bcs = (struct bc_state *) data; - IFNULLRET(bcs); - ubc = bcs->hw.bas; - IFNULLRET(ubc); - cs = bcs->cs; - IFNULLRET(cs); - /* loop while completed URBs arrive in time */ for (;;) { - if (unlikely(!atomic_read(&cs->connected))) { - warn("%s: disconnected", __func__); - return; - } - if (unlikely(!(atomic_read(&ubc->running)))) { - dbg(DEBUG_ISO, "%s: not running", __func__); + gig_dbg(DEBUG_ISO, "%s: not running", __func__); return; } @@ -1087,7 +1044,7 @@ static void write_iso_tasklet(unsigned long data) ubc->isooutovfl = NULL; spin_unlock_irqrestore(&ubc->isooutlock, flags); if (ovfl) { - err("isochronous write buffer underrun - buy a faster machine :-)"); + dev_err(cs->dev, "isochronous write buffer underrun\n"); error_hangup(bcs); break; } @@ -1110,7 +1067,8 @@ static void write_iso_tasklet(unsigned long data) spin_unlock_irqrestore(&ubc->isooutlock, flags); if (next) { /* couldn't put it back */ - err("losing isochronous write URB"); + dev_err(cs->dev, + "losing isochronous write URB\n"); error_hangup(bcs); } } @@ -1123,22 +1081,25 @@ static void write_iso_tasklet(unsigned long data) break; case -EXDEV: /* inspect individual frames */ /* assumptions (for lack of documentation): - * - actual_length bytes of the frame in error are successfully sent + * - actual_length bytes of the frame in error are + * successfully sent * - all following frames are not sent at all */ - dbg(DEBUG_ISO, "%s: URB partially completed", __func__); + gig_dbg(DEBUG_ISO, "%s: URB partially completed", + __func__); offset = done->limit; /* just in case */ for (i = 0; i < BAS_NUMFRAMES; i++) { ifd = &urb->iso_frame_desc[i]; if (ifd->status || ifd->actual_length != ifd->length) { - warn("isochronous write: frame %d: %s, " - "only %d of %d bytes sent", + dev_warn(cs->dev, + "isochronous write: frame %d: %s, " + "only %d of %d bytes sent\n", i, get_usb_statmsg(ifd->status), ifd->actual_length, ifd->length); offset = (ifd->offset + - ifd->actual_length) - % BAS_OUTBUFSIZE; + ifd->actual_length) + % BAS_OUTBUFSIZE; break; } } @@ -1148,25 +1109,26 @@ static void write_iso_tasklet(unsigned long data) ifd = &urb->iso_frame_desc[i]; if (ifd->status != -EINPROGRESS || ifd->actual_length != 0) { - warn("isochronous write: frame %d: %s, " - "%d of %d bytes sent", + dev_warn(cs->dev, + "isochronous write: frame %d: %s, " + "%d of %d bytes sent\n", i, get_usb_statmsg(ifd->status), ifd->actual_length, ifd->length); offset = (ifd->offset + - ifd->actual_length) - % BAS_OUTBUFSIZE; + ifd->actual_length) + % BAS_OUTBUFSIZE; break; } } #endif break; - case -EPIPE: //FIXME is this the code for "underrun"? - err("isochronous write stalled"); + case -EPIPE: //FIXME is this the code for "underrun"? + dev_err(cs->dev, "isochronous write stalled\n"); error_hangup(bcs); break; default: /* severe trouble */ - warn("isochronous write: %s", - get_usb_statmsg(urb->status)); + dev_warn(cs->dev, "isochronous write: %s\n", + get_usb_statmsg(urb->status)); } /* mark the write buffer area covered by this URB as free */ @@ -1194,8 +1156,8 @@ static void write_iso_tasklet(unsigned long data) if (gigaset_isoc_buildframe(bcs, skb->data, len) == -EAGAIN) { /* insufficient buffer space, push back onto queue */ skb_queue_head(&bcs->squeue, skb); - dbg(DEBUG_ISO, "%s: skb requeued, qlen=%d", - __func__, skb_queue_len(&bcs->squeue)); + gig_dbg(DEBUG_ISO, "%s: skb requeued, qlen=%d", + __func__, skb_queue_len(&bcs->squeue)); break; } skb_pull(skb, len); @@ -1215,28 +1177,16 @@ static void write_iso_tasklet(unsigned long data) */ static void read_iso_tasklet(unsigned long data) { - struct bc_state *bcs; - struct bas_bc_state *ubc; - struct cardstate *cs; + struct bc_state *bcs = (struct bc_state *) data; + struct bas_bc_state *ubc = bcs->hw.bas; + struct cardstate *cs = bcs->cs; struct urb *urb; char *rcvbuf; unsigned long flags; int totleft, numbytes, offset, frame, rc; - bcs = (struct bc_state *) data; - IFNULLRET(bcs); - ubc = bcs->hw.bas; - IFNULLRET(ubc); - cs = bcs->cs; - IFNULLRET(cs); - /* loop while more completed URBs arrive in the meantime */ for (;;) { - if (!atomic_read(&cs->connected)) { - warn("%s: disconnected", __func__); - return; - } - /* retrieve URB */ spin_lock_irqsave(&ubc->isoinlock, flags); if (!(urb = ubc->isoindone)) { @@ -1245,38 +1195,45 @@ static void read_iso_tasklet(unsigned long data) } ubc->isoindone = NULL; if (unlikely(ubc->loststatus != -EINPROGRESS)) { - warn("isochronous read overrun, dropped URB with status: %s, %d bytes lost", - get_usb_statmsg(ubc->loststatus), ubc->isoinlost); + dev_warn(cs->dev, + "isochronous read overrun, " + "dropped URB with status: %s, %d bytes lost\n", + get_usb_statmsg(ubc->loststatus), + ubc->isoinlost); ubc->loststatus = -EINPROGRESS; } spin_unlock_irqrestore(&ubc->isoinlock, flags); if (unlikely(!(atomic_read(&ubc->running)))) { - dbg(DEBUG_ISO, "%s: channel not running, dropped URB with status: %s", - __func__, get_usb_statmsg(urb->status)); + gig_dbg(DEBUG_ISO, + "%s: channel not running, " + "dropped URB with status: %s", + __func__, get_usb_statmsg(urb->status)); return; } switch (urb->status) { case 0: /* normal completion */ break; - case -EXDEV: /* inspect individual frames (we do that anyway) */ - dbg(DEBUG_ISO, "%s: URB partially completed", __func__); + case -EXDEV: /* inspect individual frames + (we do that anyway) */ + gig_dbg(DEBUG_ISO, "%s: URB partially completed", + __func__); break; case -ENOENT: case -ECONNRESET: - dbg(DEBUG_ISO, "%s: URB canceled", __func__); + gig_dbg(DEBUG_ISO, "%s: URB canceled", __func__); continue; /* -> skip */ case -EINPROGRESS: /* huh? */ - dbg(DEBUG_ISO, "%s: URB still pending", __func__); + gig_dbg(DEBUG_ISO, "%s: URB still pending", __func__); continue; /* -> skip */ case -EPIPE: - err("isochronous read stalled"); + dev_err(cs->dev, "isochronous read stalled\n"); error_hangup(bcs); continue; /* -> skip */ default: /* severe trouble */ - warn("isochronous read: %s", - get_usb_statmsg(urb->status)); + dev_warn(cs->dev, "isochronous read: %s\n", + get_usb_statmsg(urb->status)); goto error; } @@ -1284,33 +1241,44 @@ static void read_iso_tasklet(unsigned long data) totleft = urb->actual_length; for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) { if (unlikely(urb->iso_frame_desc[frame].status)) { - warn("isochronous read: frame %d: %s", - frame, get_usb_statmsg(urb->iso_frame_desc[frame].status)); + dev_warn(cs->dev, + "isochronous read: frame %d: %s\n", + frame, + get_usb_statmsg( + urb->iso_frame_desc[frame].status)); break; } numbytes = urb->iso_frame_desc[frame].actual_length; if (unlikely(numbytes > BAS_MAXFRAME)) { - warn("isochronous read: frame %d: numbytes (%d) > BAS_MAXFRAME", - frame, numbytes); + dev_warn(cs->dev, + "isochronous read: frame %d: " + "numbytes (%d) > BAS_MAXFRAME\n", + frame, numbytes); break; } if (unlikely(numbytes > totleft)) { - warn("isochronous read: frame %d: numbytes (%d) > totleft (%d)", - frame, numbytes, totleft); + dev_warn(cs->dev, + "isochronous read: frame %d: " + "numbytes (%d) > totleft (%d)\n", + frame, numbytes, totleft); break; } offset = urb->iso_frame_desc[frame].offset; if (unlikely(offset + numbytes > BAS_INBUFSIZE)) { - warn("isochronous read: frame %d: offset (%d) + numbytes (%d) > BAS_INBUFSIZE", - frame, offset, numbytes); + dev_warn(cs->dev, + "isochronous read: frame %d: " + "offset (%d) + numbytes (%d) " + "> BAS_INBUFSIZE\n", + frame, offset, numbytes); break; } gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs); totleft -= numbytes; } if (unlikely(totleft > 0)) - warn("isochronous read: %d data bytes missing", - totleft); + dev_warn(cs->dev, + "isochronous read: %d data bytes missing\n", + totleft); error: /* URB processed, resubmit */ @@ -1318,12 +1286,17 @@ static void read_iso_tasklet(unsigned long data) urb->iso_frame_desc[frame].status = 0; urb->iso_frame_desc[frame].actual_length = 0; } - urb->dev = bcs->cs->hw.bas->udev; /* clobbered by USB subsystem */ + /* urb->dev is clobbered by USB subsystem */ + urb->dev = bcs->cs->hw.bas->udev; urb->transfer_flags = URB_ISO_ASAP; urb->number_of_packets = BAS_NUMFRAMES; - if ((rc = usb_submit_urb(urb, SLAB_ATOMIC)) != 0) { - err("could not resubmit isochronous read URB: %s", - get_usb_statmsg(rc)); + spin_lock_irqsave(&cs->lock, flags); + rc = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&cs->lock, flags); + if (rc) { + dev_err(cs->dev, + "could not resubmit isochronous read URB: %s\n", + get_usb_statmsg(rc)); dump_urb(DEBUG_ISO, "resubmit iso read", urb); error_hangup(bcs); } @@ -1341,15 +1314,10 @@ static void read_iso_tasklet(unsigned long data) static void req_timeout(unsigned long data) { struct bc_state *bcs = (struct bc_state *) data; - struct bas_cardstate *ucs; + struct bas_cardstate *ucs = bcs->cs->hw.bas; int pending; unsigned long flags; - IFNULLRET(bcs); - IFNULLRET(bcs->cs); - ucs = bcs->cs->hw.bas; - IFNULLRET(ucs); - check_pending(ucs); spin_lock_irqsave(&ucs->lock, flags); @@ -1359,33 +1327,34 @@ static void req_timeout(unsigned long data) switch (pending) { case 0: /* no pending request */ - dbg(DEBUG_USBREQ, "%s: no request pending", __func__); + gig_dbg(DEBUG_USBREQ, "%s: no request pending", __func__); break; case HD_OPEN_ATCHANNEL: - err("timeout opening AT channel"); + dev_err(bcs->cs->dev, "timeout opening AT channel\n"); error_reset(bcs->cs); break; case HD_OPEN_B2CHANNEL: case HD_OPEN_B1CHANNEL: - err("timeout opening channel %d", bcs->channel + 1); + dev_err(bcs->cs->dev, "timeout opening channel %d\n", + bcs->channel + 1); error_hangup(bcs); break; case HD_CLOSE_ATCHANNEL: - err("timeout closing AT channel"); - //wake_up_interruptible(cs->initwait); - //FIXME need own wait queue? + dev_err(bcs->cs->dev, "timeout closing AT channel\n"); break; case HD_CLOSE_B2CHANNEL: case HD_CLOSE_B1CHANNEL: - err("timeout closing channel %d", bcs->channel + 1); + dev_err(bcs->cs->dev, "timeout closing channel %d\n", + bcs->channel + 1); break; default: - warn("request 0x%02x timed out, clearing", pending); + dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n", + pending); } } @@ -1398,18 +1367,14 @@ static void req_timeout(unsigned long data) */ static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) { - struct bas_cardstate *ucs; + struct bas_cardstate *ucs = urb->context; unsigned long flags; - IFNULLRET(urb); - IFNULLRET(urb->context); - IFNULLRET(cardstate); - - ucs = (struct bas_cardstate *) urb->context; spin_lock_irqsave(&ucs->lock, flags); if (urb->status && ucs->pending) { - err("control request 0x%02x failed: %s", - ucs->pending, get_usb_statmsg(urb->status)); + dev_err(&ucs->interface->dev, + "control request 0x%02x failed: %s\n", + ucs->pending, get_usb_statmsg(urb->status)); del_timer(&ucs->timer_ctrl); ucs->pending = 0; } @@ -1438,28 +1403,25 @@ static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs) */ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) { - struct bas_cardstate *ucs; + struct bas_cardstate *ucs = bcs->cs->hw.bas; int ret; unsigned long flags; - IFNULLRETVAL(bcs, -EINVAL); - IFNULLRETVAL(bcs->cs, -EINVAL); - ucs = bcs->cs->hw.bas; - IFNULLRETVAL(ucs, -EINVAL); - IFNULLRETVAL(ucs->urb_ctrl, -EINVAL); - - dbg(DEBUG_USBREQ, "-------> 0x%02x (%d)", req, val); + gig_dbg(DEBUG_USBREQ, "-------> 0x%02x (%d)", req, val); spin_lock_irqsave(&ucs->lock, flags); if (ucs->pending) { spin_unlock_irqrestore(&ucs->lock, flags); - err("submission of request 0x%02x failed: request 0x%02x still pending", - req, ucs->pending); + dev_err(bcs->cs->dev, + "submission of request 0x%02x failed: " + "request 0x%02x still pending\n", + req, ucs->pending); return -EBUSY; } if (ucs->urb_ctrl->status == -EINPROGRESS) { spin_unlock_irqrestore(&ucs->lock, flags); - err("could not submit request 0x%02x: URB busy", req); + dev_err(bcs->cs->dev, + "could not submit request 0x%02x: URB busy\n", req); return -EBUSY; } @@ -1469,19 +1431,19 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) ucs->dr_ctrl.wIndex = 0; ucs->dr_ctrl.wLength = 0; usb_fill_control_urb(ucs->urb_ctrl, ucs->udev, - usb_sndctrlpipe(ucs->udev, 0), - (unsigned char*) &ucs->dr_ctrl, NULL, 0, - write_ctrl_callback, ucs); + usb_sndctrlpipe(ucs->udev, 0), + (unsigned char*) &ucs->dr_ctrl, NULL, 0, + write_ctrl_callback, ucs); if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) { - err("could not submit request 0x%02x: %s", - req, get_usb_statmsg(ret)); + dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n", + req, get_usb_statmsg(ret)); spin_unlock_irqrestore(&ucs->lock, flags); return ret; } ucs->pending = req; if (timeout > 0) { - dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); + gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); ucs->timer_ctrl.expires = jiffies + timeout * HZ / 10; ucs->timer_ctrl.data = (unsigned long) bcs; ucs->timer_ctrl.function = req_timeout; @@ -1504,19 +1466,18 @@ static int gigaset_init_bchannel(struct bc_state *bcs) { int req, ret; - IFNULLRETVAL(bcs, -EINVAL); - if ((ret = starturbs(bcs)) < 0) { - err("could not start isochronous I/O for channel %d", - bcs->channel + 1); + dev_err(bcs->cs->dev, + "could not start isochronous I/O for channel %d\n", + bcs->channel + 1); error_hangup(bcs); return ret; } req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) { - err("could not open channel %d: %s", - bcs->channel + 1, get_usb_statmsg(ret)); + dev_err(bcs->cs->dev, "could not open channel %d: %s\n", + bcs->channel + 1, get_usb_statmsg(ret)); stopurbs(bcs->hw.bas); error_hangup(bcs); } @@ -1537,8 +1498,6 @@ static int gigaset_close_bchannel(struct bc_state *bcs) { int req, ret; - IFNULLRETVAL(bcs, -EINVAL); - if (!(atomic_read(&bcs->cs->hw.bas->basstate) & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) { /* channel not running: just signal common.c */ @@ -1548,8 +1507,9 @@ static int gigaset_close_bchannel(struct bc_state *bcs) req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) - err("could not submit HD_CLOSE_BxCHANNEL request: %s", - get_usb_statmsg(ret)); + dev_err(bcs->cs->dev, + "could not submit HD_CLOSE_BxCHANNEL request: %s\n", + get_usb_statmsg(ret)); return ret; } @@ -1564,17 +1524,13 @@ static int gigaset_close_bchannel(struct bc_state *bcs) */ static void complete_cb(struct cardstate *cs) { - struct cmdbuf_t *cb; - - IFNULLRET(cs); - cb = cs->cmdbuf; - IFNULLRET(cb); + struct cmdbuf_t *cb = cs->cmdbuf; /* unqueue completed buffer */ cs->cmdbytes -= cs->curlen; - dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD, - "write_command: sent %u bytes, %u left", - cs->curlen, cs->cmdbytes); + gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, + "write_command: sent %u bytes, %u left", + cs->curlen, cs->cmdbytes); if ((cs->cmdbuf = cb->next) != NULL) { cs->cmdbuf->prev = NULL; cs->curlen = cs->cmdbuf->len; @@ -1600,15 +1556,9 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len); */ static void write_command_callback(struct urb *urb, struct pt_regs *regs) { - struct cardstate *cs; + struct cardstate *cs = urb->context; + struct bas_cardstate *ucs = cs->hw.bas; unsigned long flags; - struct bas_cardstate *ucs; - - IFNULLRET(urb); - cs = (struct cardstate *) urb->context; - IFNULLRET(cs); - ucs = cs->hw.bas; - IFNULLRET(ucs); /* check status */ switch (urb->status) { @@ -1618,22 +1568,27 @@ static void write_command_callback(struct urb *urb, struct pt_regs *regs) case -ECONNRESET: /* canceled (async) */ case -EINPROGRESS: /* pending */ /* ignore silently */ - dbg(DEBUG_USBREQ, - "%s: %s", __func__, get_usb_statmsg(urb->status)); + gig_dbg(DEBUG_USBREQ, "%s: %s", + __func__, get_usb_statmsg(urb->status)); return; default: /* any failure */ if (++ucs->retry_cmd_out > BAS_RETRY) { - warn("command write: %s, giving up after %d retries", - get_usb_statmsg(urb->status), ucs->retry_cmd_out); + dev_warn(cs->dev, + "command write: %s, " + "giving up after %d retries\n", + get_usb_statmsg(urb->status), + ucs->retry_cmd_out); break; } if (cs->cmdbuf == NULL) { - warn("command write: %s, cannot retry - cmdbuf gone", - get_usb_statmsg(urb->status)); + dev_warn(cs->dev, + "command write: %s, " + "cannot retry - cmdbuf gone\n", + get_usb_statmsg(urb->status)); break; } - notice("command write: %s, retry %d", - get_usb_statmsg(urb->status), ucs->retry_cmd_out); + dev_notice(cs->dev, "command write: %s, retry %d\n", + get_usb_statmsg(urb->status), ucs->retry_cmd_out); if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0) /* resubmitted - bypass regular exit block */ return; @@ -1655,13 +1610,9 @@ static void write_command_callback(struct urb *urb, struct pt_regs *regs) static void atrdy_timeout(unsigned long data) { struct cardstate *cs = (struct cardstate *) data; - struct bas_cardstate *ucs; + struct bas_cardstate *ucs = cs->hw.bas; - IFNULLRET(cs); - ucs = cs->hw.bas; - IFNULLRET(ucs); - - warn("timeout waiting for HD_READY_SEND_ATDATA"); + dev_warn(cs->dev, "timeout waiting for HD_READY_SEND_ATDATA\n"); /* fake the missing signal - what else can I do? */ update_basstate(ucs, BS_ATREADY, BS_ATTIMER); @@ -1682,18 +1633,15 @@ static void atrdy_timeout(unsigned long data) */ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) { - struct bas_cardstate *ucs; + struct bas_cardstate *ucs = cs->hw.bas; + unsigned long flags; int ret; - IFNULLRETVAL(cs, -EFAULT); - ucs = cs->hw.bas; - IFNULLRETVAL(ucs, -EFAULT); - IFNULLRETVAL(ucs->urb_cmd_out, -EFAULT); - - dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len); + gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len); if (ucs->urb_cmd_out->status == -EINPROGRESS) { - err("could not submit HD_WRITE_ATMESSAGE: URB busy"); + dev_err(cs->dev, + "could not submit HD_WRITE_ATMESSAGE: URB busy\n"); return -EBUSY; } @@ -1707,9 +1655,13 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) (unsigned char*) &ucs->dr_cmd_out, buf, len, write_command_callback, cs); - if ((ret = usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC)) != 0) { - err("could not submit HD_WRITE_ATMESSAGE: %s", - get_usb_statmsg(ret)); + spin_lock_irqsave(&cs->lock, flags); + ret = cs->connected ? usb_submit_urb(ucs->urb_cmd_out, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&cs->lock, flags); + + if (ret) { + dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n", + get_usb_statmsg(ret)); return ret; } @@ -1718,8 +1670,8 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) /* start timeout if necessary */ if (!(atomic_read(&ucs->basstate) & BS_ATTIMER)) { - dbg(DEBUG_OUTPUT, - "setting ATREADY timeout of %d/10 secs", ATRDY_TIMEOUT); + gig_dbg(DEBUG_OUTPUT, "setting ATREADY timeout of %d/10 secs", + ATRDY_TIMEOUT); ucs->timer_atrdy.expires = jiffies + ATRDY_TIMEOUT * HZ / 10; ucs->timer_atrdy.data = (unsigned long) cs; ucs->timer_atrdy.function = atrdy_timeout; @@ -1740,21 +1692,17 @@ static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) static int start_cbsend(struct cardstate *cs) { struct cmdbuf_t *cb; - struct bas_cardstate *ucs; + struct bas_cardstate *ucs = cs->hw.bas; unsigned long flags; int rc; int retval = 0; - IFNULLRETVAL(cs, -EFAULT); - ucs = cs->hw.bas; - IFNULLRETVAL(ucs, -EFAULT); - /* check if AT channel is open */ if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) { - dbg(DEBUG_TRANSCMD | DEBUG_LOCKCMD, "AT channel not open"); + gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open"); rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT); if (rc < 0) { - err("could not open AT channel"); + dev_err(cs->dev, "could not open AT channel\n"); /* flush command queue */ spin_lock_irqsave(&cs->cmdlock, flags); while (cs->cmdbuf != NULL) @@ -1792,27 +1740,23 @@ static int start_cbsend(struct cardstate *cs) * cs controller state structure * buf command string to send * len number of bytes to send (max. IF_WRITEBUF) - * wake_tasklet tasklet to run when transmission is completed (NULL if none) + * wake_tasklet tasklet to run when transmission is completed + * (NULL if none) * return value: * number of bytes queued on success * error code < 0 on error */ static int gigaset_write_cmd(struct cardstate *cs, - const unsigned char *buf, int len, - struct tasklet_struct *wake_tasklet) + const unsigned char *buf, int len, + struct tasklet_struct *wake_tasklet) { struct cmdbuf_t *cb; unsigned long flags; int status; gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? - DEBUG_TRANSCMD : DEBUG_LOCKCMD, - "CMD Transmit", len, buf, 0); - - if (!atomic_read(&cs->connected)) { - err("%s: not connected", __func__); - return -ENODEV; - } + DEBUG_TRANSCMD : DEBUG_LOCKCMD, + "CMD Transmit", len, buf); if (len <= 0) return 0; /* nothing to do */ @@ -1820,7 +1764,7 @@ static int gigaset_write_cmd(struct cardstate *cs, if (len > IF_WRITEBUF) len = IF_WRITEBUF; if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { - err("%s: out of memory", __func__); + dev_err(cs->dev, "%s: out of memory\n", __func__); return -ENOMEM; } @@ -1849,7 +1793,8 @@ static int gigaset_write_cmd(struct cardstate *cs, /* gigaset_write_room * tty_driver.write_room interface routine - * return number of characters the driver will accept to be written via gigaset_write_cmd + * return number of characters the driver will accept to be written via + * gigaset_write_cmd * parameter: * controller state structure * return value: @@ -1947,7 +1892,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) return 0; } tasklet_init(&ubc->sent_tasklet, - &write_iso_tasklet, (unsigned long) bcs); + &write_iso_tasklet, (unsigned long) bcs); spin_lock_init(&ubc->isoinlock); for (i = 0; i < BAS_INURBS; ++i) @@ -1968,7 +1913,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) ubc->shared0s = 0; ubc->stolen0s = 0; tasklet_init(&ubc->rcvd_tasklet, - &read_iso_tasklet, (unsigned long) bcs); + &read_iso_tasklet, (unsigned long) bcs); return 1; } @@ -2027,57 +1972,56 @@ static int gigaset_initcshw(struct cardstate *cs) */ static void freeurbs(struct cardstate *cs) { - struct bas_cardstate *ucs; + struct bas_cardstate *ucs = cs->hw.bas; struct bas_bc_state *ubc; int i, j; - IFNULLRET(cs); - ucs = cs->hw.bas; - IFNULLRET(ucs); - for (j = 0; j < 2; ++j) { ubc = cs->bcs[j].hw.bas; - IFNULLCONT(ubc); for (i = 0; i < BAS_OUTURBS; ++i) if (ubc->isoouturbs[i].urb) { usb_kill_urb(ubc->isoouturbs[i].urb); - dbg(DEBUG_INIT, - "%s: isoc output URB %d/%d unlinked", - __func__, j, i); + gig_dbg(DEBUG_INIT, + "%s: isoc output URB %d/%d unlinked", + __func__, j, i); usb_free_urb(ubc->isoouturbs[i].urb); ubc->isoouturbs[i].urb = NULL; } for (i = 0; i < BAS_INURBS; ++i) if (ubc->isoinurbs[i]) { usb_kill_urb(ubc->isoinurbs[i]); - dbg(DEBUG_INIT, - "%s: isoc input URB %d/%d unlinked", - __func__, j, i); + gig_dbg(DEBUG_INIT, + "%s: isoc input URB %d/%d unlinked", + __func__, j, i); usb_free_urb(ubc->isoinurbs[i]); ubc->isoinurbs[i] = NULL; } } if (ucs->urb_int_in) { usb_kill_urb(ucs->urb_int_in); - dbg(DEBUG_INIT, "%s: interrupt input URB unlinked", __func__); + gig_dbg(DEBUG_INIT, "%s: interrupt input URB unlinked", + __func__); usb_free_urb(ucs->urb_int_in); ucs->urb_int_in = NULL; } if (ucs->urb_cmd_out) { usb_kill_urb(ucs->urb_cmd_out); - dbg(DEBUG_INIT, "%s: command output URB unlinked", __func__); + gig_dbg(DEBUG_INIT, "%s: command output URB unlinked", + __func__); usb_free_urb(ucs->urb_cmd_out); ucs->urb_cmd_out = NULL; } if (ucs->urb_cmd_in) { usb_kill_urb(ucs->urb_cmd_in); - dbg(DEBUG_INIT, "%s: command input URB unlinked", __func__); + gig_dbg(DEBUG_INIT, "%s: command input URB unlinked", + __func__); usb_free_urb(ucs->urb_cmd_in); ucs->urb_cmd_in = NULL; } if (ucs->urb_ctrl) { usb_kill_urb(ucs->urb_ctrl); - dbg(DEBUG_INIT, "%s: control output URB unlinked", __func__); + gig_dbg(DEBUG_INIT, "%s: control output URB unlinked", + __func__); usb_free_urb(ucs->urb_ctrl); ucs->urb_ctrl = NULL; } @@ -2099,12 +2043,10 @@ static int gigaset_probe(struct usb_interface *interface, int i, j; int ret; - IFNULLRETVAL(udev, -ENODEV); - - dbg(DEBUG_ANY, - "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", - __func__, le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); + gig_dbg(DEBUG_ANY, + "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", + __func__, le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); /* See if the device offered us matches what we can accept */ if ((le16_to_cpu(udev->descriptor.idVendor) != USB_GIGA_VENDOR_ID) || @@ -2112,20 +2054,21 @@ static int gigaset_probe(struct usb_interface *interface, le16_to_cpu(udev->descriptor.idProduct) != USB_4175_PRODUCT_ID && le16_to_cpu(udev->descriptor.idProduct) != USB_SX303_PRODUCT_ID && le16_to_cpu(udev->descriptor.idProduct) != USB_SX353_PRODUCT_ID)) { - dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__); + gig_dbg(DEBUG_ANY, "%s: unmatched ID - exiting", __func__); return -ENODEV; } /* set required alternate setting */ hostif = interface->cur_altsetting; if (hostif->desc.bAlternateSetting != 3) { - dbg(DEBUG_ANY, - "%s: wrong alternate setting %d - trying to switch", - __func__, hostif->desc.bAlternateSetting); + gig_dbg(DEBUG_ANY, + "%s: wrong alternate setting %d - trying to switch", + __func__, hostif->desc.bAlternateSetting); if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3) < 0) { - warn("usb_set_interface failed, device %d interface %d altsetting %d", - udev->devnum, hostif->desc.bInterfaceNumber, - hostif->desc.bAlternateSetting); + dev_warn(&udev->dev, "usb_set_interface failed, " + "device %d interface %d altsetting %d\n", + udev->devnum, hostif->desc.bInterfaceNumber, + hostif->desc.bAlternateSetting); return -ENODEV; } hostif = interface->cur_altsetting; @@ -2134,23 +2077,28 @@ static int gigaset_probe(struct usb_interface *interface, /* Reject application specific interfaces */ if (hostif->desc.bInterfaceClass != 255) { - warn("%s: bInterfaceClass == %d", - __func__, hostif->desc.bInterfaceClass); + dev_warn(&udev->dev, "%s: bInterfaceClass == %d\n", + __func__, hostif->desc.bInterfaceClass); return -ENODEV; } - info("%s: Device matched (Vendor: 0x%x, Product: 0x%x)", - __func__, le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); + dev_info(&udev->dev, + "%s: Device matched (Vendor: 0x%x, Product: 0x%x)\n", + __func__, le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); cs = gigaset_getunassignedcs(driver); if (!cs) { - err("%s: no free cardstate", __func__); + dev_err(&udev->dev, "no free cardstate\n"); return -ENODEV; } ucs = cs->hw.bas; + + /* save off device structure ptrs for later use */ + usb_get_dev(udev); ucs->udev = udev; ucs->interface = interface; + cs->dev = &interface->dev; /* allocate URBs: * - one for the interrupt pipe @@ -2159,22 +2107,22 @@ static int gigaset_probe(struct usb_interface *interface, */ ucs->urb_int_in = usb_alloc_urb(0, SLAB_KERNEL); if (!ucs->urb_int_in) { - err("No free urbs available"); + dev_err(cs->dev, "no free urbs available\n"); goto error; } ucs->urb_cmd_in = usb_alloc_urb(0, SLAB_KERNEL); if (!ucs->urb_cmd_in) { - err("No free urbs available"); + dev_err(cs->dev, "no free urbs available\n"); goto error; } ucs->urb_cmd_out = usb_alloc_urb(0, SLAB_KERNEL); if (!ucs->urb_cmd_out) { - err("No free urbs available"); + dev_err(cs->dev, "no free urbs available\n"); goto error; } ucs->urb_ctrl = usb_alloc_urb(0, SLAB_KERNEL); if (!ucs->urb_ctrl) { - err("No free urbs available"); + dev_err(cs->dev, "no free urbs available\n"); goto error; } @@ -2184,7 +2132,7 @@ static int gigaset_probe(struct usb_interface *interface, ubc->isoouturbs[i].urb = usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL); if (!ubc->isoouturbs[i].urb) { - err("No free urbs available"); + dev_err(cs->dev, "no free urbs available\n"); goto error; } } @@ -2192,7 +2140,7 @@ static int gigaset_probe(struct usb_interface *interface, ubc->isoinurbs[i] = usb_alloc_urb(BAS_NUMFRAMES, SLAB_KERNEL); if (!ubc->isoinurbs[i]) { - err("No free urbs available"); + dev_err(cs->dev, "no free urbs available\n"); goto error; } } @@ -2204,13 +2152,14 @@ static int gigaset_probe(struct usb_interface *interface, /* Fill the interrupt urb and send it to the core */ endpoint = &hostif->endpoint[0].desc; usb_fill_int_urb(ucs->urb_int_in, udev, - usb_rcvintpipe(udev, - (endpoint->bEndpointAddress) & 0x0f), - ucs->int_in_buf, 3, read_int_callback, cs, - endpoint->bInterval); + usb_rcvintpipe(udev, + (endpoint->bEndpointAddress) & 0x0f), + ucs->int_in_buf, 3, read_int_callback, cs, + endpoint->bInterval); ret = usb_submit_urb(ucs->urb_int_in, SLAB_KERNEL); if (ret) { - err("could not submit interrupt URB: %s", get_usb_statmsg(ret)); + dev_err(cs->dev, "could not submit interrupt URB: %s\n", + get_usb_statmsg(ret)); goto error; } @@ -2221,18 +2170,18 @@ static int gigaset_probe(struct usb_interface *interface, /* tell common part that the device is ready */ if (startmode == SM_LOCKED) atomic_set(&cs->mstate, MS_LOCKED); - if (!gigaset_start(cs)) - goto error; /* save address of controller structure */ usb_set_intfdata(interface, cs); - /* set up device sysfs */ - gigaset_init_dev_sysfs(interface); + if (!gigaset_start(cs)) + goto error; + return 0; error: freeurbs(cs); + usb_set_intfdata(interface, NULL); gigaset_unassign(cs); return -ENODEV; } @@ -2245,23 +2194,22 @@ static void gigaset_disconnect(struct usb_interface *interface) struct cardstate *cs; struct bas_cardstate *ucs; - /* clear device sysfs */ - gigaset_free_dev_sysfs(interface); - cs = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - IFNULLRET(cs); ucs = cs->hw.bas; - IFNULLRET(ucs); - info("disconnecting GigaSet base"); + dev_info(cs->dev, "disconnecting Gigaset base\n"); gigaset_stop(cs); freeurbs(cs); + usb_set_intfdata(interface, NULL); kfree(ucs->rcvbuf); ucs->rcvbuf = NULL; ucs->rcvbuf_size = 0; atomic_set(&ucs->basstate, 0); + usb_put_dev(ucs->udev); + ucs->interface = NULL; + ucs->udev = NULL; + cs->dev = NULL; gigaset_unassign(cs); } @@ -2293,13 +2241,14 @@ static int __init bas_gigaset_init(void) /* allocate memory for our driver state and intialize it */ if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, - GIGASET_MODULENAME, GIGASET_DEVNAME, - GIGASET_DEVFSNAME, &gigops, - THIS_MODULE)) == NULL) + GIGASET_MODULENAME, GIGASET_DEVNAME, + GIGASET_DEVFSNAME, &gigops, + THIS_MODULE)) == NULL) goto error; /* allocate memory for our device state and intialize it */ - cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode, GIGASET_MODULENAME); + cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode, + GIGASET_MODULENAME); if (!cardstate) goto error; @@ -2329,19 +2278,18 @@ error: if (cardstate) static void __exit bas_gigaset_exit(void) { gigaset_blockdriver(driver); /* => probe will fail - * => no gigaset_start any more - */ + * => no gigaset_start any more + */ gigaset_shutdown(cardstate); /* from now on, no isdn callback should be possible */ if (atomic_read(&cardstate->hw.bas->basstate) & BS_ATOPEN) { - dbg(DEBUG_ANY, "closing AT channel"); + gig_dbg(DEBUG_ANY, "closing AT channel"); if (req_submit(cardstate->bcs, - HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) { - /* successfully submitted - wait for completion */ - //wait_event_interruptible(cs->initwait, !cs->hw.bas->pending); - //FIXME need own wait queue? wakeup? + HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT) >= 0) { + /* successfully submitted */ + //FIXME wait for completion? } } diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 64371995c1a9..749b3da1236e 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -1,7 +1,7 @@ /* * Stuff used by all variants of the driver * - * Copyright (c) 2001 by Stefan Eilers , + * Copyright (c) 2001 by Stefan Eilers, * Hansjoerg Lipp , * Tilman Schmidt . * @@ -11,10 +11,6 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * ===================================================================== - * ToDo: ... - * ===================================================================== - * Version: $Id: common.c,v 1.104.4.22 2006/02/04 18:28:16 hjlipp Exp $ - * ===================================================================== */ #include "gigaset.h" @@ -23,7 +19,7 @@ #include /* Version Information */ -#define DRIVER_AUTHOR "Hansjoerg Lipp , Tilman Schmidt , Stefan Eilers " +#define DRIVER_AUTHOR "Hansjoerg Lipp , Tilman Schmidt , Stefan Eilers" #define DRIVER_DESC "Driver for Gigaset 307x" /* Module parameters */ @@ -32,21 +28,10 @@ EXPORT_SYMBOL_GPL(gigaset_debuglevel); module_param_named(debug, gigaset_debuglevel, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(debug, "debug level"); -/*====================================================================== - Prototypes of internal functions - */ - -//static void gigaset_process_response(int resp_code, int parameter, -// struct at_state_t *at_state, -// unsigned char ** pstring); -static struct cardstate *alloc_cs(struct gigaset_driver *drv); -static void free_cs(struct cardstate *cs); -static void make_valid(struct cardstate *cs, unsigned mask); -static void make_invalid(struct cardstate *cs, unsigned mask); - -#define VALID_MINOR 0x01 -#define VALID_ID 0x02 -#define ASSIGNED 0x04 +/* driver state flags */ +#define VALID_MINOR 0x01 +#define VALID_ID 0x02 +#define ASSIGNED 0x04 /* bitwise byte inversion table */ __u8 gigaset_invtab[256] = { @@ -86,42 +71,40 @@ __u8 gigaset_invtab[256] = { EXPORT_SYMBOL_GPL(gigaset_invtab); void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, - size_t len, const unsigned char *buf, int from_user) + size_t len, const unsigned char *buf) { unsigned char outbuf[80]; - unsigned char inbuf[80 - 1]; - size_t numin; - const unsigned char *in; + unsigned char c; size_t space = sizeof outbuf - 1; unsigned char *out = outbuf; + size_t numin = len; - if (!from_user) { - in = buf; - numin = len; - } else { - numin = len < sizeof inbuf ? len : sizeof inbuf; - in = inbuf; - if (copy_from_user(inbuf, (const unsigned char __user *) buf, numin)) { - strncpy(inbuf, "", sizeof inbuf); - numin = sizeof "" - 1; + while (numin--) { + c = *buf++; + if (c == '~' || c == '^' || c == '\\') { + if (!space--) + break; + *out++ = '\\'; } - } - - for (; numin && space; --numin, ++in) { - --space; - if (*in >= 32) - *out++ = *in; - else { + if (c & 0x80) { + if (!space--) + break; + *out++ = '~'; + c ^= 0x80; + } + if (c < 0x20 || c == 0x7f) { + if (!space--) + break; *out++ = '^'; - if (space) { - *out++ = '@' + *in; - --space; - } + c ^= 0x40; } + if (!space--) + break; + *out++ = c; } *out = 0; - dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf); + gig_dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf); } EXPORT_SYMBOL_GPL(gigaset_dbg_buffer); @@ -146,11 +129,6 @@ int gigaset_enterconfigmode(struct cardstate *cs) { int i, r; - if (!atomic_read(&cs->connected)) { - err("not connected!"); - return -1; - } - cs->control_state = TIOCM_RTS; //FIXME r = setflags(cs, TIOCM_DTR, 200); @@ -174,7 +152,7 @@ int gigaset_enterconfigmode(struct cardstate *cs) return 0; error: - err("error %d on setuartbits!\n", -r); + dev_err(cs->dev, "error %d on setuartbits\n", -r); cs->control_state = TIOCM_RTS|TIOCM_DTR; // FIXME is this a good value? cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS|TIOCM_DTR); @@ -187,13 +165,13 @@ static int test_timeout(struct at_state_t *at_state) return 0; if (--at_state->timer_expires) { - dbg(DEBUG_MCMD, "decreased timer of %p to %lu", - at_state, at_state->timer_expires); + gig_dbg(DEBUG_MCMD, "decreased timer of %p to %lu", + at_state, at_state->timer_expires); return 0; } if (!gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL, - atomic_read(&at_state->timer_index), NULL)) { + at_state->timer_index, NULL)) { //FIXME what should we do? } @@ -221,10 +199,10 @@ static void timer_tick(unsigned long data) if (test_timeout(at_state)) timeout = 1; - if (atomic_read(&cs->running)) { - mod_timer(&cs->timer, jiffies + GIG_TICK); + if (cs->running) { + mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK)); if (timeout) { - dbg(DEBUG_CMD, "scheduling timeout"); + gig_dbg(DEBUG_CMD, "scheduling timeout"); tasklet_schedule(&cs->event_tasklet); } } @@ -238,13 +216,14 @@ int gigaset_get_channel(struct bc_state *bcs) spin_lock_irqsave(&bcs->cs->lock, flags); if (bcs->use_count) { - dbg(DEBUG_ANY, "could not allocate channel %d", bcs->channel); + gig_dbg(DEBUG_ANY, "could not allocate channel %d", + bcs->channel); spin_unlock_irqrestore(&bcs->cs->lock, flags); return 0; } ++bcs->use_count; bcs->busy = 1; - dbg(DEBUG_ANY, "allocated channel %d", bcs->channel); + gig_dbg(DEBUG_ANY, "allocated channel %d", bcs->channel); spin_unlock_irqrestore(&bcs->cs->lock, flags); return 1; } @@ -255,13 +234,13 @@ void gigaset_free_channel(struct bc_state *bcs) spin_lock_irqsave(&bcs->cs->lock, flags); if (!bcs->busy) { - dbg(DEBUG_ANY, "could not free channel %d", bcs->channel); + gig_dbg(DEBUG_ANY, "could not free channel %d", bcs->channel); spin_unlock_irqrestore(&bcs->cs->lock, flags); return; } --bcs->use_count; bcs->busy = 0; - dbg(DEBUG_ANY, "freed channel %d", bcs->channel); + gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel); spin_unlock_irqrestore(&bcs->cs->lock, flags); } @@ -274,14 +253,14 @@ int gigaset_get_channels(struct cardstate *cs) for (i = 0; i < cs->channels; ++i) if (cs->bcs[i].use_count) { spin_unlock_irqrestore(&cs->lock, flags); - dbg(DEBUG_ANY, "could not allocated all channels"); + gig_dbg(DEBUG_ANY, "could not allocate all channels"); return 0; } for (i = 0; i < cs->channels; ++i) ++cs->bcs[i].use_count; spin_unlock_irqrestore(&cs->lock, flags); - dbg(DEBUG_ANY, "allocated all channels"); + gig_dbg(DEBUG_ANY, "allocated all channels"); return 1; } @@ -291,7 +270,7 @@ void gigaset_free_channels(struct cardstate *cs) unsigned long flags; int i; - dbg(DEBUG_ANY, "unblocking all channels"); + gig_dbg(DEBUG_ANY, "unblocking all channels"); spin_lock_irqsave(&cs->lock, flags); for (i = 0; i < cs->channels; ++i) --cs->bcs[i].use_count; @@ -303,7 +282,7 @@ void gigaset_block_channels(struct cardstate *cs) unsigned long flags; int i; - dbg(DEBUG_ANY, "blocking all channels"); + gig_dbg(DEBUG_ANY, "blocking all channels"); spin_lock_irqsave(&cs->lock, flags); for (i = 0; i < cs->channels; ++i) ++cs->bcs[i].use_count; @@ -314,25 +293,27 @@ static void clear_events(struct cardstate *cs) { struct event_t *ev; unsigned head, tail; + unsigned long flags; - /* no locking needed (no reader/writer allowed) */ + spin_lock_irqsave(&cs->ev_lock, flags); - head = atomic_read(&cs->ev_head); - tail = atomic_read(&cs->ev_tail); + head = cs->ev_head; + tail = cs->ev_tail; while (tail != head) { ev = cs->events + head; kfree(ev->ptr); - head = (head + 1) % MAX_EVENTS; } - atomic_set(&cs->ev_head, tail); + cs->ev_head = tail; + + spin_unlock_irqrestore(&cs->ev_lock, flags); } struct event_t *gigaset_add_event(struct cardstate *cs, - struct at_state_t *at_state, int type, - void *ptr, int parameter, void *arg) + struct at_state_t *at_state, int type, + void *ptr, int parameter, void *arg) { unsigned long flags; unsigned next, tail; @@ -340,9 +321,9 @@ struct event_t *gigaset_add_event(struct cardstate *cs, spin_lock_irqsave(&cs->ev_lock, flags); - tail = atomic_read(&cs->ev_tail); + tail = cs->ev_tail; next = (tail + 1) % MAX_EVENTS; - if (unlikely(next == atomic_read(&cs->ev_head))) + if (unlikely(next == cs->ev_head)) err("event queue full"); else { event = cs->events + tail; @@ -352,7 +333,7 @@ struct event_t *gigaset_add_event(struct cardstate *cs, event->ptr = ptr; event->arg = arg; event->parameter = parameter; - atomic_set(&cs->ev_tail, next); + cs->ev_tail = next; } spin_unlock_irqrestore(&cs->ev_lock, flags); @@ -391,14 +372,14 @@ static void gigaset_freebcs(struct bc_state *bcs) { int i; - dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel); + gig_dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel); if (!bcs->cs->ops->freebcshw(bcs)) { - dbg(DEBUG_INIT, "failed"); + gig_dbg(DEBUG_INIT, "failed"); } - dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel); + gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel); clear_at_state(&bcs->at_state); - dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel); + gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel); if (bcs->skb) dev_kfree_skb(bcs->skb); @@ -408,6 +389,52 @@ static void gigaset_freebcs(struct bc_state *bcs) } } +static struct cardstate *alloc_cs(struct gigaset_driver *drv) +{ + unsigned long flags; + unsigned i; + static struct cardstate *ret = NULL; + + spin_lock_irqsave(&drv->lock, flags); + for (i = 0; i < drv->minors; ++i) { + if (!(drv->flags[i] & VALID_MINOR)) { + drv->flags[i] = VALID_MINOR; + ret = drv->cs + i; + } + if (ret) + break; + } + spin_unlock_irqrestore(&drv->lock, flags); + return ret; +} + +static void free_cs(struct cardstate *cs) +{ + unsigned long flags; + struct gigaset_driver *drv = cs->driver; + spin_lock_irqsave(&drv->lock, flags); + drv->flags[cs->minor_index] = 0; + spin_unlock_irqrestore(&drv->lock, flags); +} + +static void make_valid(struct cardstate *cs, unsigned mask) +{ + unsigned long flags; + struct gigaset_driver *drv = cs->driver; + spin_lock_irqsave(&drv->lock, flags); + drv->flags[cs->minor_index] |= mask; + spin_unlock_irqrestore(&drv->lock, flags); +} + +static void make_invalid(struct cardstate *cs, unsigned mask) +{ + unsigned long flags; + struct gigaset_driver *drv = cs->driver; + spin_lock_irqsave(&drv->lock, flags); + drv->flags[cs->minor_index] &= ~mask; + spin_unlock_irqrestore(&drv->lock, flags); +} + void gigaset_freecs(struct cardstate *cs) { int i; @@ -416,7 +443,7 @@ void gigaset_freecs(struct cardstate *cs) if (!cs) return; - down(&cs->sem); + mutex_lock(&cs->mutex); if (!cs->bcs) goto f_cs; @@ -424,8 +451,9 @@ void gigaset_freecs(struct cardstate *cs) goto f_bcs; spin_lock_irqsave(&cs->lock, flags); - atomic_set(&cs->running, 0); - spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are not rescheduled below */ + cs->running = 0; + spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are + not rescheduled below */ tasklet_kill(&cs->event_tasklet); del_timer_sync(&cs->timer); @@ -434,7 +462,7 @@ void gigaset_freecs(struct cardstate *cs) default: gigaset_if_free(cs); - dbg(DEBUG_INIT, "clearing hw"); + gig_dbg(DEBUG_INIT, "clearing hw"); cs->ops->freecshw(cs); //FIXME cmdbuf @@ -443,36 +471,36 @@ void gigaset_freecs(struct cardstate *cs) case 2: /* error in initcshw */ /* Deregister from LL */ make_invalid(cs, VALID_ID); - dbg(DEBUG_INIT, "clearing iif"); + gig_dbg(DEBUG_INIT, "clearing iif"); gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD); /* fall through */ case 1: /* error when regestering to LL */ - dbg(DEBUG_INIT, "clearing at_state"); + gig_dbg(DEBUG_INIT, "clearing at_state"); clear_at_state(&cs->at_state); dealloc_at_states(cs); /* fall through */ case 0: /* error in one call to initbcs */ for (i = 0; i < cs->channels; ++i) { - dbg(DEBUG_INIT, "clearing bcs[%d]", i); + gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i); gigaset_freebcs(cs->bcs + i); } clear_events(cs); - dbg(DEBUG_INIT, "freeing inbuf"); + gig_dbg(DEBUG_INIT, "freeing inbuf"); kfree(cs->inbuf); } -f_bcs: dbg(DEBUG_INIT, "freeing bcs[]"); +f_bcs: gig_dbg(DEBUG_INIT, "freeing bcs[]"); kfree(cs->bcs); -f_cs: dbg(DEBUG_INIT, "freeing cs"); - up(&cs->sem); +f_cs: gig_dbg(DEBUG_INIT, "freeing cs"); + mutex_unlock(&cs->mutex); free_cs(cs); } EXPORT_SYMBOL_GPL(gigaset_freecs); void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, - struct cardstate *cs, int cid) + struct cardstate *cs, int cid) { int i; @@ -482,8 +510,8 @@ void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, at_state->pending_commands = 0; at_state->timer_expires = 0; at_state->timer_active = 0; - atomic_set(&at_state->timer_index, 0); - atomic_set(&at_state->seq_index, 0); + at_state->timer_index = 0; + at_state->seq_index = 0; at_state->ConState = 0; for (i = 0; i < STR_NUM; ++i) at_state->str_var[i] = NULL; @@ -501,7 +529,7 @@ void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs, - struct cardstate *cs, int inputstate) + struct cardstate *cs, int inputstate) /* inbuf->read must be allocated before! */ { atomic_set(&inbuf->head, 0); @@ -512,9 +540,50 @@ static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs, inbuf->inputstate = inputstate; } +/* append received bytes to inbuf */ +int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, + unsigned numbytes) +{ + unsigned n, head, tail, bytesleft; + + gig_dbg(DEBUG_INTR, "received %u bytes", numbytes); + + if (!numbytes) + return 0; + + bytesleft = numbytes; + tail = atomic_read(&inbuf->tail); + head = atomic_read(&inbuf->head); + gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); + + while (bytesleft) { + if (head > tail) + n = head - 1 - tail; + else if (head == 0) + n = (RBUFSIZE-1) - tail; + else + n = RBUFSIZE - tail; + if (!n) { + dev_err(inbuf->cs->dev, + "buffer overflow (%u bytes lost)", bytesleft); + break; + } + if (n > bytesleft) + n = bytesleft; + memcpy(inbuf->data + tail, src, n); + bytesleft -= n; + tail = (tail + n) % RBUFSIZE; + src += n; + } + gig_dbg(DEBUG_INTR, "setting tail to %u", tail); + atomic_set(&inbuf->tail, tail); + return numbytes != bytesleft; +} +EXPORT_SYMBOL_GPL(gigaset_fill_inbuf); + /* Initialize the b-channel structure */ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, - struct cardstate *cs, int channel) + struct cardstate *cs, int channel) { int i; @@ -526,7 +595,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, bcs->trans_down = 0; bcs->trans_up = 0; - dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel); + gig_dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel); gigaset_at_init(&bcs->at_state, bcs, cs, -1); bcs->rcvbytes = 0; @@ -535,7 +604,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, bcs->emptycount = 0; #endif - dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel); + gig_dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel); bcs->fcs = PPP_INITFCS; bcs->inputstate = 0; if (cs->ignoreframes) { @@ -544,7 +613,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) skb_reserve(bcs->skb, HW_HDR_LEN); else { - warn("could not allocate skb"); + dev_warn(cs->dev, "could not allocate skb\n"); bcs->inputstate |= INS_skip_frame; } @@ -559,14 +628,13 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, for (i = 0; i < AT_NUM; ++i) bcs->commands[i] = NULL; - dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); + gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); if (cs->ops->initbcshw(bcs)) return bcs; -//error: - dbg(DEBUG_INIT, " failed"); + gig_dbg(DEBUG_INIT, " failed"); - dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel); + gig_dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel); if (bcs->skb) dev_kfree_skb(bcs->skb); @@ -578,9 +646,10 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, * Calls hardware dependent gigaset_initcshw() function * Calls B channel initialization function gigaset_initbcs() for each B channel * parameters: - * drv hardware driver the device belongs to + * drv hardware driver the device belongs to * channels number of B channels supported by device - * onechannel !=0: B channel data and AT commands share one communication channel + * onechannel !=0: B channel data and AT commands share one + * communication channel * ==0: B channels have separate communication channels * ignoreframes number of frames to ignore after setting up B channel * cidmode !=0: start in CallID mode @@ -593,17 +662,18 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, int cidmode, const char *modulename) { struct cardstate *cs = NULL; + unsigned long flags; int i; - dbg(DEBUG_INIT, "allocating cs"); + gig_dbg(DEBUG_INIT, "allocating cs"); cs = alloc_cs(drv); if (!cs) goto error; - dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); + gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); if (!cs->bcs) goto error; - dbg(DEBUG_INIT, "allocating inbuf"); + gig_dbg(DEBUG_INIT, "allocating inbuf"); cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL); if (!cs->inbuf) goto error; @@ -613,19 +683,23 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, cs->onechannel = onechannel; cs->ignoreframes = ignoreframes; INIT_LIST_HEAD(&cs->temp_at_states); - atomic_set(&cs->running, 0); + cs->running = 0; init_timer(&cs->timer); /* clear next & prev */ spin_lock_init(&cs->ev_lock); - atomic_set(&cs->ev_tail, 0); - atomic_set(&cs->ev_head, 0); - init_MUTEX_LOCKED(&cs->sem); - tasklet_init(&cs->event_tasklet, &gigaset_handle_event, (unsigned long) cs); + cs->ev_tail = 0; + cs->ev_head = 0; + mutex_init(&cs->mutex); + mutex_lock(&cs->mutex); + + tasklet_init(&cs->event_tasklet, &gigaset_handle_event, + (unsigned long) cs); atomic_set(&cs->commands_pending, 0); cs->cur_at_seq = 0; cs->gotfwver = -1; cs->open_count = 0; + cs->dev = NULL; cs->tty = NULL; - atomic_set(&cs->cidmode, cidmode != 0); + cs->cidmode = cidmode != 0; //if(onechannel) { //FIXME cs->tabnocid = gigaset_tab_nocid_m10x; @@ -642,50 +716,43 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, atomic_set(&cs->mstate, MS_UNINITIALIZED); for (i = 0; i < channels; ++i) { - dbg(DEBUG_INIT, "setting up bcs[%d].read", i); + gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i); if (!gigaset_initbcs(cs->bcs + i, cs, i)) goto error; } ++cs->cs_init; - dbg(DEBUG_INIT, "setting up at_state"); + gig_dbg(DEBUG_INIT, "setting up at_state"); spin_lock_init(&cs->lock); gigaset_at_init(&cs->at_state, NULL, cs, 0); cs->dle = 0; cs->cbytes = 0; - dbg(DEBUG_INIT, "setting up inbuf"); + gig_dbg(DEBUG_INIT, "setting up inbuf"); if (onechannel) { //FIXME distinction necessary? gigaset_inbuf_init(cs->inbuf, cs->bcs, cs, INS_command); } else gigaset_inbuf_init(cs->inbuf, NULL, cs, INS_command); - atomic_set(&cs->connected, 0); + cs->connected = 0; + cs->isdn_up = 0; - dbg(DEBUG_INIT, "setting up cmdbuf"); + gig_dbg(DEBUG_INIT, "setting up cmdbuf"); cs->cmdbuf = cs->lastcmdbuf = NULL; spin_lock_init(&cs->cmdlock); cs->curlen = 0; cs->cmdbytes = 0; - /* - * Tell the ISDN4Linux subsystem (the LL) that - * a driver for a USB-Device is available ! - * If this is done, "isdnctrl" is able to bind a device for this driver even - * if no physical usb-device is currently connected. - * But this device will just be accessable if a physical USB device is connected - * (via "gigaset_probe") . - */ - dbg(DEBUG_INIT, "setting up iif"); + gig_dbg(DEBUG_INIT, "setting up iif"); if (!gigaset_register_to_LL(cs, modulename)) { - err("register_isdn=>error"); + err("register_isdn failed"); goto error; } make_valid(cs, VALID_ID); ++cs->cs_init; - dbg(DEBUG_INIT, "setting up hw"); + gig_dbg(DEBUG_INIT, "setting up hw"); if (!cs->ops->initcshw(cs)) goto error; @@ -693,27 +760,29 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, gigaset_if_init(cs); - atomic_set(&cs->running, 1); - cs->timer.data = (unsigned long) cs; - cs->timer.function = timer_tick; - cs->timer.expires = jiffies + GIG_TICK; + spin_lock_irqsave(&cs->lock, flags); + cs->running = 1; + spin_unlock_irqrestore(&cs->lock, flags); + setup_timer(&cs->timer, timer_tick, (unsigned long) cs); + cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK); /* FIXME: can jiffies increase too much until the timer is added? * Same problem(?) with mod_timer() in timer_tick(). */ add_timer(&cs->timer); - dbg(DEBUG_INIT, "cs initialized!"); - up(&cs->sem); + gig_dbg(DEBUG_INIT, "cs initialized"); + mutex_unlock(&cs->mutex); return cs; error: if (cs) - up(&cs->sem); - dbg(DEBUG_INIT, "failed"); + mutex_unlock(&cs->mutex); + gig_dbg(DEBUG_INIT, "failed"); gigaset_freecs(cs); return NULL; } EXPORT_SYMBOL_GPL(gigaset_initcs); -/* ReInitialize the b-channel structure */ /* e.g. called on hangup, disconnect */ +/* ReInitialize the b-channel structure */ +/* e.g. called on hangup, disconnect */ void gigaset_bcs_reinit(struct bc_state *bcs) { struct sk_buff *skb; @@ -723,12 +792,12 @@ void gigaset_bcs_reinit(struct bc_state *bcs) while ((skb = skb_dequeue(&bcs->squeue)) != NULL) dev_kfree_skb(skb); - spin_lock_irqsave(&cs->lock, flags); //FIXME + spin_lock_irqsave(&cs->lock, flags); clear_at_state(&bcs->at_state); bcs->at_state.ConState = 0; bcs->at_state.timer_active = 0; bcs->at_state.timer_expires = 0; - bcs->at_state.cid = -1; /* No CID defined */ + bcs->at_state.cid = -1; /* No CID defined */ spin_unlock_irqrestore(&cs->lock, flags); bcs->inputstate = 0; @@ -803,11 +872,14 @@ static void cleanup_cs(struct cardstate *cs) int gigaset_start(struct cardstate *cs) { - if (down_interruptible(&cs->sem)) - return 0; - //info("USB device for Gigaset 307x now attached to Dev %d", ucs->minor); + unsigned long flags; - atomic_set(&cs->connected, 1); + if (mutex_lock_interruptible(&cs->mutex)) + return 0; + + spin_lock_irqsave(&cs->lock, flags); + cs->connected = 1; + spin_unlock_irqrestore(&cs->lock, flags); if (atomic_read(&cs->mstate) != MS_LOCKED) { cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); @@ -826,23 +898,26 @@ int gigaset_start(struct cardstate *cs) goto error; } - dbg(DEBUG_CMD, "scheduling START"); + gig_dbg(DEBUG_CMD, "scheduling START"); gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); - up(&cs->sem); + /* set up device sysfs */ + gigaset_init_dev_sysfs(cs); + + mutex_unlock(&cs->mutex); return 1; error: - up(&cs->sem); + mutex_unlock(&cs->mutex); return 0; } EXPORT_SYMBOL_GPL(gigaset_start); void gigaset_shutdown(struct cardstate *cs) { - down(&cs->sem); + mutex_lock(&cs->mutex); cs->waiting = 1; @@ -851,11 +926,11 @@ void gigaset_shutdown(struct cardstate *cs) goto exit; } - dbg(DEBUG_CMD, "scheduling SHUTDOWN"); + gig_dbg(DEBUG_CMD, "scheduling SHUTDOWN"); gigaset_schedule_event(cs); if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) { - warn("aborted"); + warn("%s: aborted", __func__); //FIXME } @@ -872,15 +947,13 @@ void gigaset_shutdown(struct cardstate *cs) cleanup_cs(cs); exit: - up(&cs->sem); + mutex_unlock(&cs->mutex); } EXPORT_SYMBOL_GPL(gigaset_shutdown); void gigaset_stop(struct cardstate *cs) { - down(&cs->sem); - - atomic_set(&cs->connected, 0); + mutex_lock(&cs->mutex); cs->waiting = 1; @@ -889,21 +962,21 @@ void gigaset_stop(struct cardstate *cs) goto exit; } - dbg(DEBUG_CMD, "scheduling STOP"); + gig_dbg(DEBUG_CMD, "scheduling STOP"); gigaset_schedule_event(cs); if (wait_event_interruptible(cs->waitqueue, !cs->waiting)) { - warn("aborted"); + warn("%s: aborted", __func__); //FIXME } - /* Tell the LL that the device is not available .. */ - gigaset_i4l_cmd(cs, ISDN_STAT_STOP); // FIXME move to event layer? + /* clear device sysfs */ + gigaset_free_dev_sysfs(cs); cleanup_cs(cs); exit: - up(&cs->sem); + mutex_unlock(&cs->mutex); } EXPORT_SYMBOL_GPL(gigaset_stop); @@ -947,31 +1020,25 @@ void gigaset_debugdrivers(void) spin_lock_irqsave(&driver_lock, flags); list_for_each_entry(drv, &drivers, list) { - dbg(DEBUG_DRIVER, "driver %p", drv); + gig_dbg(DEBUG_DRIVER, "driver %p", drv); spin_lock(&drv->lock); for (i = 0; i < drv->minors; ++i) { - dbg(DEBUG_DRIVER, " index %u", i); - dbg(DEBUG_DRIVER, " flags 0x%02x", drv->flags[i]); + gig_dbg(DEBUG_DRIVER, " index %u", i); + gig_dbg(DEBUG_DRIVER, " flags 0x%02x", + drv->flags[i]); cs = drv->cs + i; - dbg(DEBUG_DRIVER, " cardstate %p", cs); - dbg(DEBUG_DRIVER, " minor_index %u", cs->minor_index); - dbg(DEBUG_DRIVER, " driver %p", cs->driver); - dbg(DEBUG_DRIVER, " i4l id %d", cs->myid); + gig_dbg(DEBUG_DRIVER, " cardstate %p", cs); + gig_dbg(DEBUG_DRIVER, " minor_index %u", + cs->minor_index); + gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver); + gig_dbg(DEBUG_DRIVER, " i4l id %d", cs->myid); } spin_unlock(&drv->lock); } spin_unlock_irqrestore(&driver_lock, flags); } -EXPORT_SYMBOL_GPL(gigaset_debugdrivers); -struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty) -{ - if (tty->index < 0 || tty->index >= tty->driver->num) - return NULL; - return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start); -} - -struct cardstate *gigaset_get_cs_by_minor(unsigned minor) +static struct cardstate *gigaset_get_cs_by_minor(unsigned minor) { unsigned long flags; static struct cardstate *ret = NULL; @@ -994,6 +1061,13 @@ struct cardstate *gigaset_get_cs_by_minor(unsigned minor) return ret; } +struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty) +{ + if (tty->index < 0 || tty->index >= tty->driver->num) + return NULL; + return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start); +} + void gigaset_freedriver(struct gigaset_driver *drv) { unsigned long flags; @@ -1014,20 +1088,20 @@ EXPORT_SYMBOL_GPL(gigaset_freedriver); /* gigaset_initdriver * Allocate and initialize gigaset_driver structure. Initialize interface. * parameters: - * minor First minor number - * minors Number of minors this driver can handle - * procname Name of the driver (e.g. for /proc/tty/drivers, path in /proc/driver) - * devname Name of the device files (prefix without minor number) - * devfsname Devfs name of the device files without %d + * minor First minor number + * minors Number of minors this driver can handle + * procname Name of the driver + * devname Name of the device files (prefix without minor number) + * devfsname Devfs name of the device files without %d * return value: - * Pointer to the gigaset_driver structure on success, NULL on failure. + * Pointer to the gigaset_driver structure on success, NULL on failure. */ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, - const char *procname, - const char *devname, - const char *devfsname, - const struct gigaset_ops *ops, - struct module *owner) + const char *procname, + const char *devname, + const char *devfsname, + const struct gigaset_ops *ops, + struct module *owner) { struct gigaset_driver *drv; unsigned long flags; @@ -1036,8 +1110,9 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, drv = kmalloc(sizeof *drv, GFP_KERNEL); if (!drv) return NULL; + if (!try_module_get(owner)) - return NULL; + goto out1; drv->cs = NULL; drv->have_tty = 0; @@ -1051,10 +1126,11 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL); if (!drv->cs) - goto out1; + goto out2; + drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL); if (!drv->flags) - goto out2; + goto out3; for (i = 0; i < minors; ++i) { drv->flags[i] = 0; @@ -1071,61 +1147,16 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, return drv; -out2: +out3: kfree(drv->cs); +out2: + module_put(owner); out1: kfree(drv); - module_put(owner); return NULL; } EXPORT_SYMBOL_GPL(gigaset_initdriver); -static struct cardstate *alloc_cs(struct gigaset_driver *drv) -{ - unsigned long flags; - unsigned i; - static struct cardstate *ret = NULL; - - spin_lock_irqsave(&drv->lock, flags); - for (i = 0; i < drv->minors; ++i) { - if (!(drv->flags[i] & VALID_MINOR)) { - drv->flags[i] = VALID_MINOR; - ret = drv->cs + i; - } - if (ret) - break; - } - spin_unlock_irqrestore(&drv->lock, flags); - return ret; -} - -static void free_cs(struct cardstate *cs) -{ - unsigned long flags; - struct gigaset_driver *drv = cs->driver; - spin_lock_irqsave(&drv->lock, flags); - drv->flags[cs->minor_index] = 0; - spin_unlock_irqrestore(&drv->lock, flags); -} - -static void make_valid(struct cardstate *cs, unsigned mask) -{ - unsigned long flags; - struct gigaset_driver *drv = cs->driver; - spin_lock_irqsave(&drv->lock, flags); - drv->flags[cs->minor_index] |= mask; - spin_unlock_irqrestore(&drv->lock, flags); -} - -static void make_invalid(struct cardstate *cs, unsigned mask) -{ - unsigned long flags; - struct gigaset_driver *drv = cs->driver; - spin_lock_irqsave(&drv->lock, flags); - drv->flags[cs->minor_index] &= ~mask; - spin_unlock_irqrestore(&drv->lock, flags); -} - /* For drivers without fixed assignment device<->cardstate (usb) */ struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv) { diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index fdcb80bb21c7..1ba3424a286b 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -1,7 +1,7 @@ /* * Stuff used by all variants of the driver * - * Copyright (c) 2001 by Stefan Eilers , + * Copyright (c) 2001 by Stefan Eilers, * Hansjoerg Lipp , * Tilman Schmidt . * @@ -11,82 +11,78 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * ===================================================================== - * ToDo: ... - * ===================================================================== - * Version: $Id: ev-layer.c,v 1.4.2.18 2006/02/04 18:28:16 hjlipp Exp $ - * ===================================================================== */ #include "gigaset.h" /* ========================================================== */ /* bit masks for pending commands */ -#define PC_INIT 0x004 -#define PC_DLE0 0x008 -#define PC_DLE1 0x010 -#define PC_CID 0x080 -#define PC_NOCID 0x100 -#define PC_HUP 0x002 -#define PC_DIAL 0x001 -#define PC_ACCEPT 0x040 -#define PC_SHUTDOWN 0x020 -#define PC_CIDMODE 0x200 -#define PC_UMMODE 0x400 +#define PC_DIAL 0x001 +#define PC_HUP 0x002 +#define PC_INIT 0x004 +#define PC_DLE0 0x008 +#define PC_DLE1 0x010 +#define PC_SHUTDOWN 0x020 +#define PC_ACCEPT 0x040 +#define PC_CID 0x080 +#define PC_NOCID 0x100 +#define PC_CIDMODE 0x200 +#define PC_UMMODE 0x400 /* types of modem responses */ -#define RT_NOTHING 0 -#define RT_ZSAU 1 -#define RT_RING 2 -#define RT_NUMBER 3 -#define RT_STRING 4 -#define RT_HEX 5 -#define RT_ZCAU 6 +#define RT_NOTHING 0 +#define RT_ZSAU 1 +#define RT_RING 2 +#define RT_NUMBER 3 +#define RT_STRING 4 +#define RT_HEX 5 +#define RT_ZCAU 6 /* Possible ASCII responses */ -#define RSP_OK 0 -//#define RSP_BUSY 1 -//#define RSP_CONNECT 2 -#define RSP_ZGCI 3 -#define RSP_RING 4 -#define RSP_ZAOC 5 -#define RSP_ZCSTR 6 -#define RSP_ZCFGT 7 -#define RSP_ZCFG 8 -#define RSP_ZCCR 9 -#define RSP_EMPTY 10 -#define RSP_ZLOG 11 -#define RSP_ZCAU 12 -#define RSP_ZMWI 13 -#define RSP_ZABINFO 14 -#define RSP_ZSMLSTCHG 15 -#define RSP_VAR 100 -#define RSP_ZSAU (RSP_VAR + VAR_ZSAU) -#define RSP_ZDLE (RSP_VAR + VAR_ZDLE) -#define RSP_ZVLS (RSP_VAR + VAR_ZVLS) -#define RSP_ZCTP (RSP_VAR + VAR_ZCTP) -#define RSP_STR (RSP_VAR + VAR_NUM) -#define RSP_NMBR (RSP_STR + STR_NMBR) -#define RSP_ZCPN (RSP_STR + STR_ZCPN) -#define RSP_ZCON (RSP_STR + STR_ZCON) -#define RSP_ZBC (RSP_STR + STR_ZBC) -#define RSP_ZHLC (RSP_STR + STR_ZHLC) -#define RSP_ERROR -1 /* ERROR */ -#define RSP_WRONG_CID -2 /* unknown cid in cmd */ -//#define RSP_EMPTY -3 -#define RSP_UNKNOWN -4 /* unknown response */ -#define RSP_FAIL -5 /* internal error */ -#define RSP_INVAL -6 /* invalid response */ +#define RSP_OK 0 +//#define RSP_BUSY 1 +//#define RSP_CONNECT 2 +#define RSP_ZGCI 3 +#define RSP_RING 4 +#define RSP_ZAOC 5 +#define RSP_ZCSTR 6 +#define RSP_ZCFGT 7 +#define RSP_ZCFG 8 +#define RSP_ZCCR 9 +#define RSP_EMPTY 10 +#define RSP_ZLOG 11 +#define RSP_ZCAU 12 +#define RSP_ZMWI 13 +#define RSP_ZABINFO 14 +#define RSP_ZSMLSTCHG 15 +#define RSP_VAR 100 +#define RSP_ZSAU (RSP_VAR + VAR_ZSAU) +#define RSP_ZDLE (RSP_VAR + VAR_ZDLE) +#define RSP_ZVLS (RSP_VAR + VAR_ZVLS) +#define RSP_ZCTP (RSP_VAR + VAR_ZCTP) +#define RSP_STR (RSP_VAR + VAR_NUM) +#define RSP_NMBR (RSP_STR + STR_NMBR) +#define RSP_ZCPN (RSP_STR + STR_ZCPN) +#define RSP_ZCON (RSP_STR + STR_ZCON) +#define RSP_ZBC (RSP_STR + STR_ZBC) +#define RSP_ZHLC (RSP_STR + STR_ZHLC) +#define RSP_ERROR -1 /* ERROR */ +#define RSP_WRONG_CID -2 /* unknown cid in cmd */ +//#define RSP_EMPTY -3 +#define RSP_UNKNOWN -4 /* unknown response */ +#define RSP_FAIL -5 /* internal error */ +#define RSP_INVAL -6 /* invalid response */ -#define RSP_NONE -19 -#define RSP_STRING -20 -#define RSP_NULL -21 -//#define RSP_RETRYFAIL -22 -//#define RSP_RETRY -23 -//#define RSP_SKIP -24 -#define RSP_INIT -27 -#define RSP_ANY -26 -#define RSP_LAST -28 -#define RSP_NODEV -9 +#define RSP_NONE -19 +#define RSP_STRING -20 +#define RSP_NULL -21 +//#define RSP_RETRYFAIL -22 +//#define RSP_RETRY -23 +//#define RSP_SKIP -24 +#define RSP_INIT -27 +#define RSP_ANY -26 +#define RSP_LAST -28 +#define RSP_NODEV -9 /* actions for process_response */ #define ACT_NOTHING 0 @@ -112,7 +108,7 @@ #define ACT_DISCONNECT 20 #define ACT_CONNECT 21 #define ACT_REMOTEREJECT 22 -#define ACT_CONNTIMEOUT 23 +#define ACT_CONNTIMEOUT 23 #define ACT_REMOTEHUP 24 #define ACT_ABORTHUP 25 #define ACT_ICALL 26 @@ -127,40 +123,40 @@ #define ACT_ERROR 35 #define ACT_ABORTCID 36 #define ACT_ZCAU 37 -#define ACT_NOTIFY_BC_DOWN 38 -#define ACT_NOTIFY_BC_UP 39 -#define ACT_DIAL 40 -#define ACT_ACCEPT 41 -#define ACT_PROTO_L2 42 -#define ACT_HUP 43 -#define ACT_IF_LOCK 44 -#define ACT_START 45 -#define ACT_STOP 46 -#define ACT_FAKEDLE0 47 -#define ACT_FAKEHUP 48 -#define ACT_FAKESDOWN 49 -#define ACT_SHUTDOWN 50 -#define ACT_PROC_CIDMODE 51 -#define ACT_UMODESET 52 -#define ACT_FAILUMODE 53 -#define ACT_CMODESET 54 -#define ACT_FAILCMODE 55 -#define ACT_IF_VER 56 +#define ACT_NOTIFY_BC_DOWN 38 +#define ACT_NOTIFY_BC_UP 39 +#define ACT_DIAL 40 +#define ACT_ACCEPT 41 +#define ACT_PROTO_L2 42 +#define ACT_HUP 43 +#define ACT_IF_LOCK 44 +#define ACT_START 45 +#define ACT_STOP 46 +#define ACT_FAKEDLE0 47 +#define ACT_FAKEHUP 48 +#define ACT_FAKESDOWN 49 +#define ACT_SHUTDOWN 50 +#define ACT_PROC_CIDMODE 51 +#define ACT_UMODESET 52 +#define ACT_FAILUMODE 53 +#define ACT_CMODESET 54 +#define ACT_FAILCMODE 55 +#define ACT_IF_VER 56 #define ACT_CMD 100 /* at command sequences */ -#define SEQ_NONE 0 -#define SEQ_INIT 100 -#define SEQ_DLE0 200 -#define SEQ_DLE1 250 -#define SEQ_CID 300 -#define SEQ_NOCID 350 -#define SEQ_HUP 400 -#define SEQ_DIAL 600 -#define SEQ_ACCEPT 720 -#define SEQ_SHUTDOWN 500 -#define SEQ_CIDMODE 10 -#define SEQ_UMMODE 11 +#define SEQ_NONE 0 +#define SEQ_INIT 100 +#define SEQ_DLE0 200 +#define SEQ_DLE1 250 +#define SEQ_CID 300 +#define SEQ_NOCID 350 +#define SEQ_HUP 400 +#define SEQ_DIAL 600 +#define SEQ_ACCEPT 720 +#define SEQ_SHUTDOWN 500 +#define SEQ_CIDMODE 10 +#define SEQ_UMMODE 11 // 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), 400: hup, 500: reset, 600: dial, 700: ring @@ -175,7 +171,7 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ // {ACT_TIMEOUT}}, {RSP_INIT, -1, -1,SEQ_INIT, 100, INIT_TIMEOUT, - {ACT_TIMEOUT}}, /* wait until device is ready */ + {ACT_TIMEOUT}}, /* wait until device is ready */ {EV_TIMEOUT, 100,100, -1, 101, 3, {0}, "Z\r"}, /* device in transparent mode? try to initialize it. */ {RSP_OK, 101,103, -1, 120, 5, {ACT_GETSTRING}, "+GMR\r"}, /* get version */ @@ -190,8 +186,8 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ {RSP_ERROR, 108,108, -1, 0, 0, {ACT_FAILINIT}}, {EV_TIMEOUT, 108,108, -1, 105, 2, {ACT_SETDLE0, - ACT_HUPMODEM, - ACT_TIMEOUT}}, /* still timeout => connection in unimodem mode? */ + ACT_HUPMODEM, + ACT_TIMEOUT}}, /* still timeout => connection in unimodem mode? */ {EV_TIMEOUT, 105,105, -1, 103, 5, {0}, "Z\r"}, {RSP_ERROR, 102,102, -1, 107, 5, {0}, "^GETPRE\r"}, /* ERROR on ATZ => maybe in config mode? */ @@ -393,7 +389,7 @@ struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */ #if 0 -static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME aenderungen uebernehmen +static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME { /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ @@ -401,7 +397,7 @@ static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME aenderungen ueberne {RSP_LAST,0,0,0,0,0,0} }; -static struct reply_t tab_cid[] = /* no dle mode */ //FIXME aenderungen uebernehmen +static struct reply_t tab_cid[] = /* no dle mode */ //FIXME { /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ @@ -412,30 +408,30 @@ static struct reply_t tab_cid[] = /* no dle mode */ //FIXME aenderungen ueberneh static struct resp_type_t resp_type[]= { - /*{"", RSP_EMPTY, RT_NOTHING},*/ - {"OK", RSP_OK, RT_NOTHING}, - {"ERROR", RSP_ERROR, RT_NOTHING}, - {"ZSAU", RSP_ZSAU, RT_ZSAU}, - {"ZCAU", RSP_ZCAU, RT_ZCAU}, - {"RING", RSP_RING, RT_RING}, - {"ZGCI", RSP_ZGCI, RT_NUMBER}, - {"ZVLS", RSP_ZVLS, RT_NUMBER}, - {"ZCTP", RSP_ZCTP, RT_NUMBER}, - {"ZDLE", RSP_ZDLE, RT_NUMBER}, - {"ZCFGT", RSP_ZCFGT, RT_NUMBER}, - {"ZCCR", RSP_ZCCR, RT_NUMBER}, - {"ZMWI", RSP_ZMWI, RT_NUMBER}, - {"ZHLC", RSP_ZHLC, RT_STRING}, - {"ZBC", RSP_ZBC, RT_STRING}, - {"NMBR", RSP_NMBR, RT_STRING}, - {"ZCPN", RSP_ZCPN, RT_STRING}, - {"ZCON", RSP_ZCON, RT_STRING}, - {"ZAOC", RSP_ZAOC, RT_STRING}, - {"ZCSTR", RSP_ZCSTR, RT_STRING}, - {"ZCFG", RSP_ZCFG, RT_HEX}, - {"ZLOG", RSP_ZLOG, RT_NOTHING}, - {"ZABINFO", RSP_ZABINFO, RT_NOTHING}, - {"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING}, + /*{"", RSP_EMPTY, RT_NOTHING},*/ + {"OK", RSP_OK, RT_NOTHING}, + {"ERROR", RSP_ERROR, RT_NOTHING}, + {"ZSAU", RSP_ZSAU, RT_ZSAU}, + {"ZCAU", RSP_ZCAU, RT_ZCAU}, + {"RING", RSP_RING, RT_RING}, + {"ZGCI", RSP_ZGCI, RT_NUMBER}, + {"ZVLS", RSP_ZVLS, RT_NUMBER}, + {"ZCTP", RSP_ZCTP, RT_NUMBER}, + {"ZDLE", RSP_ZDLE, RT_NUMBER}, + {"ZCFGT", RSP_ZCFGT, RT_NUMBER}, + {"ZCCR", RSP_ZCCR, RT_NUMBER}, + {"ZMWI", RSP_ZMWI, RT_NUMBER}, + {"ZHLC", RSP_ZHLC, RT_STRING}, + {"ZBC", RSP_ZBC, RT_STRING}, + {"NMBR", RSP_NMBR, RT_STRING}, + {"ZCPN", RSP_ZCPN, RT_STRING}, + {"ZCON", RSP_ZCON, RT_STRING}, + {"ZAOC", RSP_ZAOC, RT_STRING}, + {"ZCSTR", RSP_ZCSTR, RT_STRING}, + {"ZCFG", RSP_ZCFG, RT_HEX}, + {"ZLOG", RSP_ZLOG, RT_NOTHING}, + {"ZABINFO", RSP_ZABINFO, RT_NOTHING}, + {"ZSMLSTCHG", RSP_ZSMLSTCHG, RT_NOTHING}, {NULL,0,0} }; @@ -446,9 +442,7 @@ static int isdn_getnum(char *p) { int v = -1; - IFNULLRETVAL(p, -1); - - dbg(DEBUG_TRANSCMD, "string: %s", p); + gig_dbg(DEBUG_TRANSCMD, "string: %s", p); while (*p >= '0' && *p <= '9') v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p++) - '0'); @@ -465,9 +459,7 @@ static int isdn_gethex(char *p) int v = 0; int c; - IFNULLRETVAL(p, -1); - - dbg(DEBUG_TRANSCMD, "string: %s", p); + gig_dbg(DEBUG_TRANSCMD, "string: %s", p); if (!*p) return -1; @@ -490,14 +482,6 @@ static int isdn_gethex(char *p) return v; } -static inline void new_index(atomic_t *index, int max) -{ - if (atomic_read(index) == max) //FIXME race? - atomic_set(index, 0); - else - atomic_inc(index); -} - /* retrieve CID from parsed response * returns 0 if no CID, -1 if invalid CID, or CID value 1..65535 */ @@ -536,16 +520,14 @@ void gigaset_handle_modem_response(struct cardstate *cs) int cid; int rawstring; - IFNULLRET(cs); - len = cs->cbytes; if (!len) { /* ignore additional LFs/CRs (M10x config mode or cx100) */ - dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]); + gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[len]); return; } cs->respdata[len] = 0; - dbg(DEBUG_TRANSCMD, "raw string: '%s'", cs->respdata); + gig_dbg(DEBUG_TRANSCMD, "raw string: '%s'", cs->respdata); argv[0] = cs->respdata; params = 1; if (cs->at_state.getstring) { @@ -561,7 +543,8 @@ void gigaset_handle_modem_response(struct cardstate *cs) case ',': case '=': if (params > MAX_REC_PARAMS) { - warn("too many parameters in response"); + dev_warn(cs->dev, + "too many parameters in response\n"); /* need last parameter (might be CID) */ params--; } @@ -572,33 +555,33 @@ void gigaset_handle_modem_response(struct cardstate *cs) cid = params > 1 ? cid_of_response(argv[params-1]) : 0; if (cid < 0) { gigaset_add_event(cs, &cs->at_state, RSP_INVAL, - NULL, 0, NULL); + NULL, 0, NULL); return; } for (j = 1; j < params; ++j) argv[j][-1] = 0; - dbg(DEBUG_TRANSCMD, "CMD received: %s", argv[0]); + gig_dbg(DEBUG_TRANSCMD, "CMD received: %s", argv[0]); if (cid) { --params; - dbg(DEBUG_TRANSCMD, "CID: %s", argv[params]); + gig_dbg(DEBUG_TRANSCMD, "CID: %s", argv[params]); } - dbg(DEBUG_TRANSCMD, "available params: %d", params - 1); + gig_dbg(DEBUG_TRANSCMD, "available params: %d", params - 1); for (j = 1; j < params; j++) - dbg(DEBUG_TRANSCMD, "param %d: %s", j, argv[j]); + gig_dbg(DEBUG_TRANSCMD, "param %d: %s", j, argv[j]); } spin_lock_irqsave(&cs->ev_lock, flags); - head = atomic_read(&cs->ev_head); - tail = atomic_read(&cs->ev_tail); + head = cs->ev_head; + tail = cs->ev_tail; abort = 1; curarg = 0; while (curarg < params) { next = (tail + 1) % MAX_EVENTS; if (unlikely(next == head)) { - err("event queue full"); + dev_err(cs->dev, "event queue full\n"); break; } @@ -619,8 +602,9 @@ void gigaset_handle_modem_response(struct cardstate *cs) if (!rt->response) { event->type = RSP_UNKNOWN; - warn("unknown modem response: %s", - argv[curarg]); + dev_warn(cs->dev, + "unknown modem response: %s\n", + argv[curarg]); break; } @@ -636,7 +620,8 @@ void gigaset_handle_modem_response(struct cardstate *cs) break; case RT_RING: if (!cid) { - err("received RING without CID!"); + dev_err(cs->dev, + "received RING without CID!\n"); event->type = RSP_INVAL; abort = 1; } else { @@ -664,27 +649,25 @@ void gigaset_handle_modem_response(struct cardstate *cs) event->parameter = ZSAU_DISCONNECT_REQ; else { event->parameter = ZSAU_UNKNOWN; - warn("%s: unknown parameter %s after ZSAU", - __func__, argv[curarg]); + dev_warn(cs->dev, + "%s: unknown parameter %s after ZSAU\n", + __func__, argv[curarg]); } ++curarg; break; case RT_STRING: if (curarg < params) { - len = strlen(argv[curarg]) + 1; - event->ptr = kmalloc(len, GFP_ATOMIC); - if (event->ptr) - memcpy(event->ptr, argv[curarg], len); - else - err("no memory for string!"); + event->ptr = kstrdup(argv[curarg], GFP_ATOMIC); + if (!event->ptr) + dev_err(cs->dev, "out of memory\n"); ++curarg; } #ifdef CONFIG_GIGASET_DEBUG if (!event->ptr) - dbg(DEBUG_CMD, "string==NULL"); + gig_dbg(DEBUG_CMD, "string==NULL"); else - dbg(DEBUG_CMD, - "string==%s", (char *) event->ptr); + gig_dbg(DEBUG_CMD, "string==%s", + (char *) event->ptr); #endif break; case RT_ZCAU: @@ -694,7 +677,7 @@ void gigaset_handle_modem_response(struct cardstate *cs) j = isdn_gethex(argv[curarg + 1]); if (i >= 0 && i < 256 && j >= 0 && j < 256) event->parameter = (unsigned) i << 8 - | j; + | j; curarg += 2; } else curarg = params - 1; @@ -712,7 +695,7 @@ void gigaset_handle_modem_response(struct cardstate *cs) } else event->parameter = -1; #ifdef CONFIG_GIGASET_DEBUG - dbg(DEBUG_CMD, "parameter==%d", event->parameter); + gig_dbg(DEBUG_CMD, "parameter==%d", event->parameter); #endif break; } @@ -724,12 +707,13 @@ void gigaset_handle_modem_response(struct cardstate *cs) break; } - atomic_set(&cs->ev_tail, tail); + cs->ev_tail = tail; spin_unlock_irqrestore(&cs->ev_lock, flags); if (curarg != params) - dbg(DEBUG_ANY, "invalid number of processed parameters: %d/%d", - curarg, params); + gig_dbg(DEBUG_ANY, + "invalid number of processed parameters: %d/%d", + curarg, params); } EXPORT_SYMBOL_GPL(gigaset_handle_modem_response); @@ -739,23 +723,19 @@ EXPORT_SYMBOL_GPL(gigaset_handle_modem_response); static void disconnect(struct at_state_t **at_state_p) { unsigned long flags; - struct bc_state *bcs; - struct cardstate *cs; + struct bc_state *bcs = (*at_state_p)->bcs; + struct cardstate *cs = (*at_state_p)->cs; - IFNULLRET(at_state_p); - IFNULLRET(*at_state_p); - bcs = (*at_state_p)->bcs; - cs = (*at_state_p)->cs; - IFNULLRET(cs); - - new_index(&(*at_state_p)->seq_index, MAX_SEQ_INDEX); + spin_lock_irqsave(&cs->lock, flags); + ++(*at_state_p)->seq_index; /* revert to selected idle mode */ - if (!atomic_read(&cs->cidmode)) { + if (!cs->cidmode) { cs->at_state.pending_commands |= PC_UMMODE; atomic_set(&cs->commands_pending, 1); //FIXME - dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); + gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); } + spin_unlock_irqrestore(&cs->lock, flags); if (bcs) { /* B channel assigned: invoke hardware specific handler */ @@ -777,7 +757,7 @@ static void disconnect(struct at_state_t **at_state_p) * The structure should be freed by calling disconnect() after use. */ static inline struct at_state_t *get_free_channel(struct cardstate *cs, - int cid) + int cid) /* cids: >0: siemens-cid 0: without cid -1: no cid assigned yet @@ -826,7 +806,7 @@ static void init_failed(struct cardstate *cs, int mode) static void schedule_init(struct cardstate *cs, int state) { if (cs->at_state.pending_commands & PC_INIT) { - dbg(DEBUG_CMD, "not scheduling PC_INIT again"); + gig_dbg(DEBUG_CMD, "not scheduling PC_INIT again"); return; } atomic_set(&cs->mstate, state); @@ -834,52 +814,56 @@ static void schedule_init(struct cardstate *cs, int state) gigaset_block_channels(cs); cs->at_state.pending_commands |= PC_INIT; atomic_set(&cs->commands_pending, 1); - dbg(DEBUG_CMD, "Scheduling PC_INIT"); + gig_dbg(DEBUG_CMD, "Scheduling PC_INIT"); } -/* Add "AT" to a command, add the cid, dle encode it, send the result to the hardware. */ +/* Add "AT" to a command, add the cid, dle encode it, send the result to the + hardware. */ static void send_command(struct cardstate *cs, const char *cmd, int cid, - int dle, gfp_t kmallocflags) + int dle, gfp_t kmallocflags) { size_t cmdlen, buflen; char *cmdpos, *cmdbuf, *cmdtail; cmdlen = strlen(cmd); buflen = 11 + cmdlen; + if (unlikely(buflen <= cmdlen)) { + dev_err(cs->dev, "integer overflow in buflen\n"); + return; + } - if (likely(buflen > cmdlen)) { - cmdbuf = kmalloc(buflen, kmallocflags); - if (likely(cmdbuf != NULL)) { - cmdpos = cmdbuf + 9; - cmdtail = cmdpos + cmdlen; - memcpy(cmdpos, cmd, cmdlen); + cmdbuf = kmalloc(buflen, kmallocflags); + if (unlikely(!cmdbuf)) { + dev_err(cs->dev, "out of memory\n"); + return; + } - if (cid > 0 && cid <= 65535) { - do { - *--cmdpos = '0' + cid % 10; - cid /= 10; - ++cmdlen; - } while (cid); - } + cmdpos = cmdbuf + 9; + cmdtail = cmdpos + cmdlen; + memcpy(cmdpos, cmd, cmdlen); - cmdlen += 2; - *--cmdpos = 'T'; - *--cmdpos = 'A'; + if (cid > 0 && cid <= 65535) { + do { + *--cmdpos = '0' + cid % 10; + cid /= 10; + ++cmdlen; + } while (cid); + } - if (dle) { - cmdlen += 4; - *--cmdpos = '('; - *--cmdpos = 0x10; - *cmdtail++ = 0x10; - *cmdtail++ = ')'; - } + cmdlen += 2; + *--cmdpos = 'T'; + *--cmdpos = 'A'; - cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL); - kfree(cmdbuf); - } else - err("no memory for command buffer"); - } else - err("overflow in buflen"); + if (dle) { + cmdlen += 4; + *--cmdpos = '('; + *--cmdpos = 0x10; + *cmdtail++ = 0x10; + *cmdtail++ = ')'; + } + + cs->ops->write_cmd(cs, cmdpos, cmdlen, NULL); + kfree(cmdbuf); } static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid) @@ -910,9 +894,6 @@ static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid) static void bchannel_down(struct bc_state *bcs) { - IFNULLRET(bcs); - IFNULLRET(bcs->cs); - if (bcs->chstate & CHS_B_UP) { bcs->chstate &= ~CHS_B_UP; gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP); @@ -930,16 +911,15 @@ static void bchannel_down(struct bc_state *bcs) static void bchannel_up(struct bc_state *bcs) { - IFNULLRET(bcs); - if (!(bcs->chstate & CHS_D_UP)) { - notice("%s: D channel not up", __func__); + dev_notice(bcs->cs->dev, "%s: D channel not up\n", __func__); bcs->chstate |= CHS_D_UP; gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); } if (bcs->chstate & CHS_B_UP) { - notice("%s: B channel already up", __func__); + dev_notice(bcs->cs->dev, "%s: B channel already up\n", + __func__); return; } @@ -947,17 +927,21 @@ static void bchannel_up(struct bc_state *bcs) gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN); } -static void start_dial(struct at_state_t *at_state, void *data, int seq_index) +static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_index) { struct bc_state *bcs = at_state->bcs; struct cardstate *cs = at_state->cs; int retval; + unsigned long flags; bcs->chstate |= CHS_NOTIFY_LL; - //atomic_set(&bcs->status, BCS_INIT); - if (atomic_read(&at_state->seq_index) != seq_index) + spin_lock_irqsave(&cs->lock, flags); + if (at_state->seq_index != seq_index) { + spin_unlock_irqrestore(&cs->lock, flags); goto error; + } + spin_unlock_irqrestore(&cs->lock, flags); retval = gigaset_isdn_setup_dial(at_state, data); if (retval != 0) @@ -965,20 +949,14 @@ static void start_dial(struct at_state_t *at_state, void *data, int seq_index) at_state->pending_commands |= PC_CID; - dbg(DEBUG_CMD, "Scheduling PC_CID"); -//#ifdef GIG_MAYINITONDIAL -// if (atomic_read(&cs->MState) == MS_UNKNOWN) { -// cs->at_state.pending_commands |= PC_INIT; -// dbg(DEBUG_CMD, "Scheduling PC_INIT"); -// } -//#endif - atomic_set(&cs->commands_pending, 1); //FIXME + gig_dbg(DEBUG_CMD, "Scheduling PC_CID"); + atomic_set(&cs->commands_pending, 1); return; error: at_state->pending_commands |= PC_NOCID; - dbg(DEBUG_CMD, "Scheduling PC_NOCID"); - atomic_set(&cs->commands_pending, 1); //FIXME + gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID"); + atomic_set(&cs->commands_pending, 1); return; } @@ -991,13 +969,13 @@ static void start_accept(struct at_state_t *at_state) if (retval == 0) { at_state->pending_commands |= PC_ACCEPT; - dbg(DEBUG_CMD, "Scheduling PC_ACCEPT"); - atomic_set(&cs->commands_pending, 1); //FIXME + gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT"); + atomic_set(&cs->commands_pending, 1); } else { //FIXME at_state->pending_commands |= PC_HUP; - dbg(DEBUG_CMD, "Scheduling PC_HUP"); - atomic_set(&cs->commands_pending, 1); //FIXME + gig_dbg(DEBUG_CMD, "Scheduling PC_HUP"); + atomic_set(&cs->commands_pending, 1); } } @@ -1008,9 +986,10 @@ static void do_start(struct cardstate *cs) if (atomic_read(&cs->mstate) != MS_LOCKED) schedule_init(cs, MS_INIT); + cs->isdn_up = 1; gigaset_i4l_cmd(cs, ISDN_STAT_RUN); - // FIXME: not in locked mode - // FIXME 2: only after init sequence + // FIXME: not in locked mode + // FIXME 2: only after init sequence cs->waiting = 0; wake_up(&cs->waitqueue); @@ -1023,6 +1002,12 @@ static void finish_shutdown(struct cardstate *cs) atomic_set(&cs->mode, M_UNKNOWN); } + /* Tell the LL that the device is not available .. */ + if (cs->isdn_up) { + cs->isdn_up = 0; + gigaset_i4l_cmd(cs, ISDN_STAT_STOP); + } + /* The rest is done by cleanup_cs () in user mode. */ cs->cmd_result = -ENODEV; @@ -1037,15 +1022,20 @@ static void do_shutdown(struct cardstate *cs) if (atomic_read(&cs->mstate) == MS_READY) { atomic_set(&cs->mstate, MS_SHUTDOWN); cs->at_state.pending_commands |= PC_SHUTDOWN; - atomic_set(&cs->commands_pending, 1); //FIXME - dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN"); //FIXME - //gigaset_schedule_event(cs); //FIXME + atomic_set(&cs->commands_pending, 1); + gig_dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN"); } else finish_shutdown(cs); } static void do_stop(struct cardstate *cs) { + unsigned long flags; + + spin_lock_irqsave(&cs->lock, flags); + cs->connected = 0; + spin_unlock_irqrestore(&cs->lock, flags); + do_shutdown(cs); } @@ -1069,9 +1059,11 @@ static int reinit_and_retry(struct cardstate *cs, int channel) return 0; if (channel < 0) - warn("Could not enter cid mode. Reinit device and try again."); + dev_warn(cs->dev, + "Could not enter cid mode. Reinit device and try again.\n"); else { - warn("Could not get a call id. Reinit device and try again."); + dev_warn(cs->dev, + "Could not get a call id. Reinit device and try again.\n"); cs->bcs[channel].at_state.pending_commands |= PC_CID; } schedule_init(cs, MS_INIT); @@ -1079,7 +1071,7 @@ static int reinit_and_retry(struct cardstate *cs, int channel) } static int at_state_invalid(struct cardstate *cs, - struct at_state_t *test_ptr) + struct at_state_t *test_ptr) { unsigned long flags; unsigned channel; @@ -1116,7 +1108,7 @@ static void handle_icall(struct cardstate *cs, struct bc_state *bcs, case ICALL_ACCEPT: break; default: - err("internal error: disposition=%d", retval); + dev_err(cs->dev, "internal error: disposition=%d\n", retval); /* --v-- fall through --v-- */ case ICALL_IGNORE: case ICALL_REJECT: @@ -1160,7 +1152,6 @@ static int do_lock(struct cardstate *cs) mode = atomic_read(&cs->mode); atomic_set(&cs->mstate, MS_LOCKED); atomic_set(&cs->mode, M_UNKNOWN); - //FIXME reset card state / at states / bcs states return mode; } @@ -1173,8 +1164,7 @@ static int do_unlock(struct cardstate *cs) atomic_set(&cs->mstate, MS_UNINITIALIZED); atomic_set(&cs->mode, M_UNKNOWN); gigaset_free_channels(cs); - //FIXME reset card state / at states / bcs states - if (atomic_read(&cs->connected)) + if (cs->connected) schedule_init(cs, MS_INIT); return 0; @@ -1203,21 +1193,23 @@ static void do_action(int action, struct cardstate *cs, at_state->waiting = 1; break; case ACT_INIT: - //FIXME setup everything cs->at_state.pending_commands &= ~PC_INIT; cs->cur_at_seq = SEQ_NONE; atomic_set(&cs->mode, M_UNIMODEM); - if (!atomic_read(&cs->cidmode)) { + spin_lock_irqsave(&cs->lock, flags); + if (!cs->cidmode) { + spin_unlock_irqrestore(&cs->lock, flags); gigaset_free_channels(cs); atomic_set(&cs->mstate, MS_READY); break; } + spin_unlock_irqrestore(&cs->lock, flags); cs->at_state.pending_commands |= PC_CIDMODE; - atomic_set(&cs->commands_pending, 1); //FIXME - dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); + atomic_set(&cs->commands_pending, 1); + gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); break; case ACT_FAILINIT: - warn("Could not initialize the device."); + dev_warn(cs->dev, "Could not initialize the device.\n"); cs->dle = 0; init_failed(cs, M_UNKNOWN); cs->cur_at_seq = SEQ_NONE; @@ -1273,8 +1265,8 @@ static void do_action(int action, struct cardstate *cs, /* get fresh AT state structure for new CID */ at_state2 = get_free_channel(cs, ev->parameter); if (!at_state2) { - warn("RING ignored: " - "could not allocate channel structure"); + dev_warn(cs->dev, + "RING ignored: could not allocate channel structure\n"); break; } @@ -1302,7 +1294,7 @@ static void do_action(int action, struct cardstate *cs, at_state = *p_at_state; break; case ACT_FAILSDOWN: - warn("Could not shut down the device."); + dev_warn(cs->dev, "Could not shut down the device.\n"); /* fall through */ case ACT_FAKESDOWN: case ACT_SDOWN: @@ -1355,7 +1347,7 @@ static void do_action(int action, struct cardstate *cs, break; case ACT_ABORTHUP: cs->cur_at_seq = SEQ_NONE; - warn("Could not hang up."); + dev_warn(cs->dev, "Could not hang up.\n"); at_state->cid = -1; if (bcs && cs->onechannel) at_state->pending_commands |= PC_DLE0; @@ -1367,14 +1359,15 @@ static void do_action(int action, struct cardstate *cs, break; case ACT_FAILDLE0: cs->cur_at_seq = SEQ_NONE; - warn("Could not leave DLE mode."); + dev_warn(cs->dev, "Could not leave DLE mode.\n"); at_state2 = &cs->bcs[cs->curchannel].at_state; disconnect(&at_state2); schedule_init(cs, MS_RECOVER); break; case ACT_FAILDLE1: cs->cur_at_seq = SEQ_NONE; - warn("Could not enter DLE mode. Try to hang up."); + dev_warn(cs->dev, + "Could not enter DLE mode. Trying to hang up.\n"); channel = cs->curchannel; cs->bcs[channel].at_state.pending_commands |= PC_HUP; atomic_set(&cs->commands_pending, 1); @@ -1395,7 +1388,8 @@ static void do_action(int action, struct cardstate *cs, cs->cur_at_seq = SEQ_NONE; channel = cs->curchannel; if (!reinit_and_retry(cs, channel)) { - warn("Could not get a call id. Dialing not possible"); + dev_warn(cs->dev, + "Could not get a call ID. Cannot dial.\n"); at_state2 = &cs->bcs[channel].at_state; disconnect(&at_state2); } @@ -1428,7 +1422,8 @@ static void do_action(int action, struct cardstate *cs, at_state->pending_commands |= PC_HUP; atomic_set(&cs->commands_pending, 1); break; - case ACT_GETSTRING: /* warning: RING, ZDLE, ... are not handled properly any more */ + case ACT_GETSTRING: /* warning: RING, ZDLE, ... + are not handled properly anymore */ at_state->getstring = 1; break; case ACT_SETVER: @@ -1469,16 +1464,16 @@ static void do_action(int action, struct cardstate *cs, case ACT_GOTVER: if (cs->gotfwver == 0) { cs->gotfwver = 1; - dbg(DEBUG_ANY, - "firmware version %02d.%03d.%02d.%02d", - cs->fwver[0], cs->fwver[1], - cs->fwver[2], cs->fwver[3]); + gig_dbg(DEBUG_ANY, + "firmware version %02d.%03d.%02d.%02d", + cs->fwver[0], cs->fwver[1], + cs->fwver[2], cs->fwver[3]); break; } /* fall through */ case ACT_FAILVER: cs->gotfwver = -1; - err("could not read firmware version."); + dev_err(cs->dev, "could not read firmware version.\n"); break; #ifdef CONFIG_GIGASET_DEBUG case ACT_ERROR: @@ -1496,16 +1491,16 @@ static void do_action(int action, struct cardstate *cs, break; #endif case ACT_DEBUG: - dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d", + gig_dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d", __func__, ev->type, at_state->ConState); break; case ACT_WARN: - warn("%s: resp_code %d in ConState %d!", - __func__, ev->type, at_state->ConState); + dev_warn(cs->dev, "%s: resp_code %d in ConState %d!\n", + __func__, ev->type, at_state->ConState); break; case ACT_ZCAU: - warn("cause code %04x in connection state %d.", - ev->parameter, at_state->ConState); + dev_warn(cs->dev, "cause code %04x in connection state %d.\n", + ev->parameter, at_state->ConState); break; /* events from the LL */ @@ -1516,14 +1511,14 @@ static void do_action(int action, struct cardstate *cs, start_accept(at_state); break; case ACT_PROTO_L2: - dbg(DEBUG_CMD, - "set protocol to %u", (unsigned) ev->parameter); + gig_dbg(DEBUG_CMD, "set protocol to %u", + (unsigned) ev->parameter); at_state->bcs->proto2 = ev->parameter; break; case ACT_HUP: at_state->pending_commands |= PC_HUP; - atomic_set(&cs->commands_pending, 1); //FIXME - dbg(DEBUG_CMD, "Scheduling PC_HUP"); + atomic_set(&cs->commands_pending, 1); + gig_dbg(DEBUG_CMD, "Scheduling PC_HUP"); break; /* hotplug events */ @@ -1555,17 +1550,19 @@ static void do_action(int action, struct cardstate *cs, /* events from the proc file system */ // FIXME without ACT_xxxx? case ACT_PROC_CIDMODE: - if (ev->parameter != atomic_read(&cs->cidmode)) { - atomic_set(&cs->cidmode, ev->parameter); + spin_lock_irqsave(&cs->lock, flags); + if (ev->parameter != cs->cidmode) { + cs->cidmode = ev->parameter; if (ev->parameter) { cs->at_state.pending_commands |= PC_CIDMODE; - dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); + gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); } else { cs->at_state.pending_commands |= PC_UMMODE; - dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); + gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); } atomic_set(&cs->commands_pending, 1); } + spin_unlock_irqrestore(&cs->lock, flags); cs->waiting = 0; wake_up(&cs->waitqueue); break; @@ -1590,7 +1587,7 @@ static void do_action(int action, struct cardstate *cs, *p_resp_code = RSP_NULL; } } else - err("%s: action==%d!", __func__, action); + dev_err(cs->dev, "%s: action==%d!\n", __func__, action); } } @@ -1609,47 +1606,46 @@ static void process_event(struct cardstate *cs, struct event_t *ev) int curact; unsigned long flags; - IFNULLRET(cs); - IFNULLRET(ev); - if (ev->cid >= 0) { at_state = at_state_from_cid(cs, ev->cid); if (!at_state) { gigaset_add_event(cs, &cs->at_state, RSP_WRONG_CID, - NULL, 0, NULL); + NULL, 0, NULL); return; } } else { at_state = ev->at_state; if (at_state_invalid(cs, at_state)) { - dbg(DEBUG_ANY, - "event for invalid at_state %p", at_state); + gig_dbg(DEBUG_ANY, "event for invalid at_state %p", + at_state); return; } } - dbg(DEBUG_CMD, - "connection state %d, event %d", at_state->ConState, ev->type); + gig_dbg(DEBUG_CMD, "connection state %d, event %d", + at_state->ConState, ev->type); bcs = at_state->bcs; sendcid = at_state->cid; /* Setting the pointer to the dial array */ rep = at_state->replystruct; - IFNULLRET(rep); + spin_lock_irqsave(&cs->lock, flags); if (ev->type == EV_TIMEOUT) { - if (ev->parameter != atomic_read(&at_state->timer_index) + if (ev->parameter != at_state->timer_index || !at_state->timer_active) { ev->type = RSP_NONE; /* old timeout */ - dbg(DEBUG_ANY, "old timeout"); + gig_dbg(DEBUG_ANY, "old timeout"); } else if (!at_state->waiting) - dbg(DEBUG_ANY, "timeout occured"); + gig_dbg(DEBUG_ANY, "timeout occurred"); else - dbg(DEBUG_ANY, "stopped waiting"); + gig_dbg(DEBUG_ANY, "stopped waiting"); } + spin_unlock_irqrestore(&cs->lock, flags); - /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] or at_state->str_var[STR_XXXX], set it */ + /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] + or at_state->str_var[STR_XXXX], set it */ if (ev->type >= RSP_VAR && ev->type < RSP_VAR + VAR_NUM) { index = ev->type - RSP_VAR; at_state->int_var[index] = ev->parameter; @@ -1657,20 +1653,22 @@ static void process_event(struct cardstate *cs, struct event_t *ev) index = ev->type - RSP_STR; kfree(at_state->str_var[index]); at_state->str_var[index] = ev->ptr; - ev->ptr = NULL; /* prevent process_events() from deallocating ptr */ + ev->ptr = NULL; /* prevent process_events() from + deallocating ptr */ } if (ev->type == EV_TIMEOUT || ev->type == RSP_STRING) at_state->getstring = 0; - /* Search row in dial array which matches modem response and current constate */ + /* Search row in dial array which matches modem response and current + constate */ for (;; rep++) { rcode = rep->resp_code; - /* dbg (DEBUG_ANY, "rcode %d", rcode); */ if (rcode == RSP_LAST) { /* found nothing...*/ - warn("%s: rcode=RSP_LAST: resp_code %d in ConState %d!", - __func__, ev->type, at_state->ConState); + dev_warn(cs->dev, "%s: rcode=RSP_LAST: " + "resp_code %d in ConState %d!\n", + __func__, ev->type, at_state->ConState); return; } if ((rcode == RSP_ANY || rcode == ev->type) @@ -1706,14 +1704,14 @@ static void process_event(struct cardstate *cs, struct event_t *ev) } else { /* Send command to modem if not NULL... */ if (p_command/*rep->command*/) { - if (atomic_read(&cs->connected)) + if (cs->connected) send_command(cs, p_command, - sendcid, cs->dle, - GFP_ATOMIC); + sendcid, cs->dle, + GFP_ATOMIC); else gigaset_add_event(cs, at_state, - RSP_NODEV, - NULL, 0, NULL); + RSP_NODEV, + NULL, 0, NULL); } spin_lock_irqsave(&cs->lock, flags); @@ -1723,8 +1721,7 @@ static void process_event(struct cardstate *cs, struct event_t *ev) } else if (rep->timeout > 0) { /* new timeout */ at_state->timer_expires = rep->timeout * 10; at_state->timer_active = 1; - new_index(&at_state->timer_index, - MAX_TIMER_INDEX); + ++at_state->timer_index; } spin_unlock_irqrestore(&cs->lock, flags); } @@ -1744,17 +1741,16 @@ static void process_command_flags(struct cardstate *cs) struct bc_state *bcs; int i; int sequence; - - IFNULLRET(cs); + unsigned long flags; atomic_set(&cs->commands_pending, 0); if (cs->cur_at_seq) { - dbg(DEBUG_CMD, "not searching scheduled commands: busy"); + gig_dbg(DEBUG_CMD, "not searching scheduled commands: busy"); return; } - dbg(DEBUG_CMD, "searching scheduled commands"); + gig_dbg(DEBUG_CMD, "searching scheduled commands"); sequence = SEQ_NONE; @@ -1795,8 +1791,9 @@ static void process_command_flags(struct cardstate *cs) } /* only switch back to unimodem mode, if no commands are pending and no channels are up */ + spin_lock_irqsave(&cs->lock, flags); if (cs->at_state.pending_commands == PC_UMMODE - && !atomic_read(&cs->cidmode) + && !cs->cidmode && list_empty(&cs->temp_at_states) && atomic_read(&cs->mode) == M_CID) { sequence = SEQ_UMMODE; @@ -1810,6 +1807,7 @@ static void process_command_flags(struct cardstate *cs) } } } + spin_unlock_irqrestore(&cs->lock, flags); cs->at_state.pending_commands &= ~PC_UMMODE; if (sequence != SEQ_NONE) { schedule_sequence(cs, at_state, sequence); @@ -1865,11 +1863,7 @@ static void process_command_flags(struct cardstate *cs) if (cs->at_state.pending_commands & PC_CIDMODE) { cs->at_state.pending_commands &= ~PC_CIDMODE; if (atomic_read(&cs->mode) == M_UNIMODEM) { -#if 0 - cs->retry_count = 2; -#else cs->retry_count = 1; -#endif schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE); return; } @@ -1897,7 +1891,7 @@ static void process_command_flags(struct cardstate *cs) switch (atomic_read(&cs->mode)) { case M_UNIMODEM: cs->at_state.pending_commands |= PC_CIDMODE; - dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); + gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); atomic_set(&cs->commands_pending, 1); return; #ifdef GIG_MAYINITONDIAL @@ -1926,18 +1920,21 @@ static void process_events(struct cardstate *cs) int i; int check_flags = 0; int was_busy; + unsigned long flags; - /* no locking needed (only one reader) */ - head = atomic_read(&cs->ev_head); + spin_lock_irqsave(&cs->ev_lock, flags); + head = cs->ev_head; for (i = 0; i < 2 * MAX_EVENTS; ++i) { - tail = atomic_read(&cs->ev_tail); + tail = cs->ev_tail; if (tail == head) { if (!check_flags && !atomic_read(&cs->commands_pending)) break; check_flags = 0; + spin_unlock_irqrestore(&cs->ev_lock, flags); process_command_flags(cs); - tail = atomic_read(&cs->ev_tail); + spin_lock_irqsave(&cs->ev_lock, flags); + tail = cs->ev_tail; if (tail == head) { if (!atomic_read(&cs->commands_pending)) break; @@ -1947,18 +1944,23 @@ static void process_events(struct cardstate *cs) ev = cs->events + head; was_busy = cs->cur_at_seq != SEQ_NONE; + spin_unlock_irqrestore(&cs->ev_lock, flags); process_event(cs, ev); + spin_lock_irqsave(&cs->ev_lock, flags); kfree(ev->ptr); ev->ptr = NULL; if (was_busy && cs->cur_at_seq == SEQ_NONE) check_flags = 1; head = (head + 1) % MAX_EVENTS; - atomic_set(&cs->ev_head, head); + cs->ev_head = head; } + spin_unlock_irqrestore(&cs->ev_lock, flags); + if (i == 2 * MAX_EVENTS) { - err("infinite loop in process_events; aborting."); + dev_err(cs->dev, + "infinite loop in process_events; aborting.\n"); } } @@ -1970,12 +1972,9 @@ void gigaset_handle_event(unsigned long data) { struct cardstate *cs = (struct cardstate *) data; - IFNULLRET(cs); - IFNULLRET(cs->inbuf); - /* handle incoming data on control/common channel */ if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) { - dbg(DEBUG_INTR, "processing new data"); + gig_dbg(DEBUG_INTR, "processing new data"); cs->ops->handle_input(cs->inbuf); } diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 729edcdb6dac..9d21ba8757b0 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -1,11 +1,16 @@ -/* Siemens Gigaset 307x driver +/* + * Siemens Gigaset 307x driver * Common header file for all connection variants * - * Written by Stefan Eilers + * Written by Stefan Eilers * and Hansjoerg Lipp * - * Version: $Id: gigaset.h,v 1.97.4.26 2006/02/04 18:28:16 hjlipp Exp $ - * =========================================================================== + * ===================================================================== + * 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. + * ===================================================================== */ #ifndef GIGASET_H @@ -15,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -27,21 +31,22 @@ #include #include #include +#include #define GIG_VERSION {0,5,0,0} #define GIG_COMPAT {0,4,0,0} -#define MAX_REC_PARAMS 10 /* Max. number of params in response string */ -#define MAX_RESP_SIZE 512 /* Max. size of a response string */ -#define HW_HDR_LEN 2 /* Header size used to store ack info */ +#define MAX_REC_PARAMS 10 /* Max. number of params in response string */ +#define MAX_RESP_SIZE 512 /* Max. size of a response string */ +#define HW_HDR_LEN 2 /* Header size used to store ack info */ -#define MAX_EVENTS 64 /* size of event queue */ +#define MAX_EVENTS 64 /* size of event queue */ #define RBUFSIZE 8192 -#define SBUFSIZE 4096 /* sk_buff payload size */ +#define SBUFSIZE 4096 /* sk_buff payload size */ -#define MAX_BUF_SIZE (SBUFSIZE - 2) /* Max. size of a data packet from LL */ -#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ +#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ +#define MAX_BUF_SIZE (SBUFSIZE - 2) /* Max. size of a data packet from LL */ /* compile time options */ #define GIG_MAJOR 0 @@ -50,10 +55,7 @@ #define GIG_RETRYCID #define GIG_X75 -#define MAX_TIMER_INDEX 1000 -#define MAX_SEQ_INDEX 1000 - -#define GIG_TICK (HZ / 10) +#define GIG_TICK 100 /* in milliseconds */ /* timeout values (unit: 1 sec) */ #define INIT_TIMEOUT 1 @@ -67,74 +69,89 @@ #define MAXACT 3 -#define IFNULL(a) if (unlikely(!(a))) -#define IFNULLRET(a) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return; } -#define IFNULLRETVAL(a,b) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); return (b); } -#define IFNULLCONT(a) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); continue; } -#define IFNULLGOTO(a,b) if (unlikely(!(a))) {err("%s==NULL at %s:%d!", #a, __FILE__, __LINE__); goto b; } - extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */ -/* any combination of these can be given with the 'debug=' parameter to insmod, e.g. - * 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and DEBUG_INTR. */ +/* any combination of these can be given with the 'debug=' parameter to insmod, + * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and + * DEBUG_INTR. + */ enum debuglevel { /* up to 24 bits (atomic_t) */ DEBUG_REG = 0x0002, /* serial port I/O register operations */ DEBUG_OPEN = 0x0004, /* open/close serial port */ DEBUG_INTR = 0x0008, /* interrupt processing */ - DEBUG_INTR_DUMP = 0x0010, /* Activating hexdump debug output on interrupt - requests, not available as run-time option */ + DEBUG_INTR_DUMP = 0x0010, /* Activating hexdump debug output on + interrupt requests, not available as + run-time option */ DEBUG_CMD = 0x00020, /* sent/received LL commands */ DEBUG_STREAM = 0x00040, /* application data stream I/O events */ DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */ DEBUG_LLDATA = 0x00100, /* sent/received LL data */ - DEBUG_INTR_0 = 0x00200, /* serial port output interrupt processing */ + DEBUG_INTR_0 = 0x00200, /* serial port interrupt processing */ DEBUG_DRIVER = 0x00400, /* driver structure */ DEBUG_HDLC = 0x00800, /* M10x HDLC processing */ DEBUG_WRITE = 0x01000, /* M105 data write */ - DEBUG_TRANSCMD = 0x02000, /*AT-COMMANDS+RESPONSES*/ - DEBUG_MCMD = 0x04000, /*COMMANDS THAT ARE SENT VERY OFTEN*/ - DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data structures */ + DEBUG_TRANSCMD = 0x02000, /* AT-COMMANDS+RESPONSES */ + DEBUG_MCMD = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */ + DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data + structures */ DEBUG_LOCK = 0x10000, /* semaphore operations */ DEBUG_OUTPUT = 0x20000, /* output to device */ - DEBUG_ISO = 0x40000, /* isochronous transfers */ + DEBUG_ISO = 0x40000, /* isochronous transfers */ DEBUG_IF = 0x80000, /* character device operations */ - DEBUG_USBREQ = 0x100000, /* USB communication (except payload data) */ - DEBUG_LOCKCMD = 0x200000, /* AT commands and responses when MS_LOCKED */ + DEBUG_USBREQ = 0x100000, /* USB communication (except payload + data) */ + DEBUG_LOCKCMD = 0x200000, /* AT commands and responses when + MS_LOCKED */ - DEBUG_ANY = 0x3fffff, /* print message if any of the others is activated */ + DEBUG_ANY = 0x3fffff, /* print message if any of the others is + activated */ }; -#ifdef CONFIG_GIGASET_DEBUG -#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ) -//#define DEBUG_DEFAULT (DEBUG_LOCK | DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUF_IF | DEBUG_DRIVER | DEBUG_OUTPUT | DEBUG_INTR) -#else -#define DEBUG_DEFAULT 0 +/* missing from linux/device.h ... */ +#ifndef dev_notice +#define dev_notice(dev, format, arg...) \ + dev_printk(KERN_NOTICE , dev , format , ## arg) #endif -/* redefine syslog macros to prepend module name instead of entire source path */ -/* The space before the comma in ", ##" is needed by gcc 2.95 */ -#undef info -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg) - -#undef notice -#define notice(format, arg...) printk(KERN_NOTICE "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg) - -#undef warn -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg) - +/* Kernel message macros for situations where dev_printk and friends cannot be + * used for lack of reliable access to a device structure. + * linux/usb.h already contains these but in an obsolete form which clutters + * the log needlessly, and according to the USB maintainer those should be + * removed rather than fixed anyway. + */ #undef err -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg) +#undef info +#undef warn +#undef notice + +#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \ + format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \ + format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING KBUILD_MODNAME ": " \ + format "\n" , ## arg) +#define notice(format, arg...) printk(KERN_NOTICE KBUILD_MODNAME ": " \ + format "\n" , ## arg) -#undef dbg #ifdef CONFIG_GIGASET_DEBUG -#define dbg(level, format, arg...) do { if (unlikely(((enum debuglevel)gigaset_debuglevel) & (level))) \ - printk(KERN_DEBUG "%s: " format "\n", THIS_MODULE ? THIS_MODULE->name : "gigaset_hw" , ## arg); } while (0) + +#define gig_dbg(level, format, arg...) \ + do { \ + if (unlikely(((enum debuglevel)gigaset_debuglevel) & (level))) \ + printk(KERN_DEBUG KBUILD_MODNAME ": " format "\n", \ + ## arg); \ + } while (0) +#define DEBUG_DEFAULT (DEBUG_INIT | DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ) + #else -#define dbg(level, format, arg...) do {} while (0) + +#define gig_dbg(level, format, arg...) do {} while (0) +#define DEBUG_DEFAULT 0 + #endif void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, - size_t len, const unsigned char *buf, int from_user); + size_t len, const unsigned char *buf); /* connection state */ #define ZSAU_NONE 0 @@ -148,13 +165,14 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, #define ZSAU_UNKNOWN -1 /* USB control transfer requests */ -#define OUT_VENDOR_REQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) -#define IN_VENDOR_REQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) +#define OUT_VENDOR_REQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) +#define IN_VENDOR_REQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) /* int-in-events 3070 */ #define HD_B1_FLOW_CONTROL 0x80 #define HD_B2_FLOW_CONTROL 0x81 -#define HD_RECEIVEATDATA_ACK (0x35) // 3070 // att: HD_RECEIVE>>AT<>AT< ignore */ - int max_ConState; /* <0 => ignore */ - int parameter; /* e.g. ZSAU_XXXX <0: ignore*/ - int new_ConState; /* <0 => ignore */ - int timeout; /* >0 => *HZ; <=0 => TOUT_XXXX*/ - int action[MAXACT]; /* ACT_XXXX */ - char *command; /* NULL==none */ + int resp_code; /* RSP_XXXX */ + int min_ConState; /* <0 => ignore */ + int max_ConState; /* <0 => ignore */ + int parameter; /* e.g. ZSAU_XXXX <0: ignore*/ + int new_ConState; /* <0 => ignore */ + int timeout; /* >0 => *HZ; <=0 => TOUT_XXXX*/ + int action[MAXACT]; /* ACT_XXXX */ + char *command; /* NULL==none */ }; extern struct reply_t gigaset_tab_cid_m10x[]; extern struct reply_t gigaset_tab_nocid_m10x[]; struct inbuf_t { - unsigned char *rcvbuf; /* usb-gigaset receive buffer */ + unsigned char *rcvbuf; /* usb-gigaset receive buffer */ struct bc_state *bcs; - struct cardstate *cs; - int inputstate; - - atomic_t head, tail; - unsigned char data[RBUFSIZE]; + struct cardstate *cs; + int inputstate; + atomic_t head, tail; + unsigned char data[RBUFSIZE]; }; /* isochronous write buffer structure @@ -319,16 +337,9 @@ struct inbuf_t { * if writesem <= 0, data[write..read-1] is currently being written to * - idle contains the byte value to repeat when the end of valid data is * reached; if nextread==write (buffer contains no data to send), either the - * BAS_OUTBUFPAD bytes immediately before data[write] (if write>=BAS_OUTBUFPAD) - * or those of the pad area (if write=BAS_OUTBUFPAD) or those of the pad area (if write for modem reponses (and incomming data for M10x) - * -> on timeout - * -> after setting bits in xxx.at_state.pending_command - * (e.g. command from LL) */ - struct tasklet_struct write_tasklet; /* tasklet for serial output - * (not used in base driver) */ + int dle; /* !=0 if modem commands/responses are + dle encoded */ + int cur_at_seq; /* sequence of AT commands being + processed */ + int curchannel; /* channel those commands are meant + for */ + atomic_t commands_pending; /* flag(s) in xxx.commands_pending have + been set */ + struct tasklet_struct event_tasklet; + /* tasklet for serializing AT commands. + * Scheduled + * -> for modem reponses (and + * incoming data for M10x) + * -> on timeout + * -> after setting bits in + * xxx.at_state.pending_command + * (e.g. command from LL) */ + struct tasklet_struct write_tasklet; + /* tasklet for serial output + * (not used in base driver) */ /* event queue */ struct event_t events[MAX_EVENTS]; - atomic_t ev_tail, ev_head; + unsigned ev_tail, ev_head; spinlock_t ev_lock; /* current modem response */ unsigned char respdata[MAX_RESP_SIZE]; unsigned cbytes; - /* hardware drivers */ + /* private data of hardware drivers */ union { - struct usb_cardstate *usb; /* private data of USB hardware driver */ - struct ser_cardstate *ser; /* private data of serial hardware driver */ - struct bas_cardstate *bas; /* private data of base hardware driver */ + struct usb_cardstate *usb; /* USB hardware driver (m105) */ + struct ser_cardstate *ser; /* serial hardware driver */ + struct bas_cardstate *bas; /* USB hardware driver (base) */ } hw; }; struct gigaset_driver { struct list_head list; - spinlock_t lock; /* locks minor tables and blocked */ - //struct semaphore sem; /* locks this structure */ + spinlock_t lock; /* locks minor tables and blocked */ struct tty_driver *tty; unsigned have_tty; unsigned minor; @@ -553,37 +571,42 @@ struct bas_bc_state { struct isow_urbctx_t isoouturbs[BAS_OUTURBS]; struct isow_urbctx_t *isooutdone, *isooutfree, *isooutovfl; struct isowbuf_t *isooutbuf; - unsigned numsub; /* submitted URB counter (for diagnostic messages only) */ + unsigned numsub; /* submitted URB counter + (for diagnostic messages only) */ struct tasklet_struct sent_tasklet; /* isochronous input state */ spinlock_t isoinlock; struct urb *isoinurbs[BAS_INURBS]; unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS]; - struct urb *isoindone; /* completed isoc read URB */ - int loststatus; /* status of dropped URB */ - unsigned isoinlost; /* number of bytes lost */ - /* state of bit unstuffing algorithm (in addition to BC_state.inputstate) */ - unsigned seqlen; /* number of '1' bits not yet unstuffed */ - unsigned inbyte, inbits; /* collected bits for next byte */ + struct urb *isoindone; /* completed isoc read URB */ + int loststatus; /* status of dropped URB */ + unsigned isoinlost; /* number of bytes lost */ + /* state of bit unstuffing algorithm + (in addition to BC_state.inputstate) */ + unsigned seqlen; /* number of '1' bits not yet + unstuffed */ + unsigned inbyte, inbits; /* collected bits for next byte */ /* statistics */ - unsigned goodbytes; /* bytes correctly received */ - unsigned alignerrs; /* frames with incomplete byte at end */ - unsigned fcserrs; /* FCS errors */ - unsigned frameerrs; /* framing errors */ - unsigned giants; /* long frames */ - unsigned runts; /* short frames */ - unsigned aborts; /* HDLC aborts */ - unsigned shared0s; /* '0' bits shared between flags */ - unsigned stolen0s; /* '0' stuff bits also serving as leading flag bits */ + unsigned goodbytes; /* bytes correctly received */ + unsigned alignerrs; /* frames with incomplete byte at end */ + unsigned fcserrs; /* FCS errors */ + unsigned frameerrs; /* framing errors */ + unsigned giants; /* long frames */ + unsigned runts; /* short frames */ + unsigned aborts; /* HDLC aborts */ + unsigned shared0s; /* '0' bits shared between flags */ + unsigned stolen0s; /* '0' stuff bits also serving as + leading flag bits */ struct tasklet_struct rcvd_tasklet; }; struct gigaset_ops { - /* Called from ev-layer.c/interface.c for sending AT commands to the device */ + /* Called from ev-layer.c/interface.c for sending AT commands to the + device */ int (*write_cmd)(struct cardstate *cs, - const unsigned char *buf, int len, - struct tasklet_struct *wake_tasklet); + const unsigned char *buf, int len, + struct tasklet_struct *wake_tasklet); /* Called from interface.c for additional device control */ int (*write_room)(struct cardstate *cs); @@ -604,7 +627,8 @@ struct gigaset_ops { /* Called by gigaset_freecs() for freeing bcs->hw.xxx */ int (*freebcshw)(struct bc_state *bcs); - /* Called by gigaset_stop() or gigaset_bchannel_down() for resetting bcs->hw.xxx */ + /* Called by gigaset_stop() or gigaset_bchannel_down() for resetting + bcs->hw.xxx */ void (*reinitbcshw)(struct bc_state *bcs); /* Called by gigaset_initcs() for setting up cs->hw.xxx */ @@ -613,13 +637,10 @@ struct gigaset_ops { /* Called by gigaset_freecs() for freeing cs->hw.xxx */ void (*freecshw)(struct cardstate *cs); - ///* Called by gigaset_stop() for killing URBs, shutting down the device, ... - // hardwareup: ==0: don't try to shut down the device, hardware is really not accessible - // !=0: hardware still up */ - //void (*stophw)(struct cardstate *cs, int hardwareup); - - /* Called from common.c/interface.c for additional serial port control */ - int (*set_modem_ctrl)(struct cardstate *cs, unsigned old_state, unsigned new_state); + /* Called from common.c/interface.c for additional serial port + control */ + int (*set_modem_ctrl)(struct cardstate *cs, unsigned old_state, + unsigned new_state); int (*baud_rate)(struct cardstate *cs, unsigned cflag); int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag); @@ -639,7 +660,7 @@ struct gigaset_ops { * : 0x10 * : ((a-z)* | (A-Z)* | (0-10)*)+ */ -#define DLE_FLAG 0x10 +#define DLE_FLAG 0x10 /* =========================================================================== * Functions implemented in asyncdata.c @@ -667,7 +688,8 @@ void gigaset_isoc_input(struct inbuf_t *inbuf); /* Called from bas-gigaset.c to process a block of data * received through the isochronous channel */ -void gigaset_isoc_receive(unsigned char *src, unsigned count, struct bc_state *bcs); +void gigaset_isoc_receive(unsigned char *src, unsigned count, + struct bc_state *bcs); /* Called from bas-gigaset.c to put a block of data * into the isochronous output buffer */ @@ -703,7 +725,7 @@ static inline void gigaset_isdn_rcv_err(struct bc_state *bcs) isdn_ctrl response; /* error -> LL */ - dbg(DEBUG_CMD, "sending L1ERR"); + gig_dbg(DEBUG_CMD, "sending L1ERR"); response.driver = bcs->cs->myid; response.command = ISDN_STAT_L1ERR; response.arg = bcs->channel; @@ -727,8 +749,8 @@ void gigaset_handle_modem_response(struct cardstate *cs); */ /* initialize sysfs for device */ -void gigaset_init_dev_sysfs(struct usb_interface *interface); -void gigaset_free_dev_sysfs(struct usb_interface *interface); +void gigaset_init_dev_sysfs(struct cardstate *cs); +void gigaset_free_dev_sysfs(struct cardstate *cs); /* =========================================================================== * Functions implemented in common.c/gigaset.h @@ -736,7 +758,7 @@ void gigaset_free_dev_sysfs(struct usb_interface *interface); void gigaset_bcs_reinit(struct bc_state *bcs); void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, - struct cardstate *cs, int cid); + struct cardstate *cs, int cid); int gigaset_get_channel(struct bc_state *bcs); void gigaset_free_channel(struct bc_state *bcs); int gigaset_get_channels(struct cardstate *cs); @@ -745,16 +767,15 @@ void gigaset_block_channels(struct cardstate *cs); /* Allocate and initialize driver structure. */ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, - const char *procname, - const char *devname, - const char *devfsname, - const struct gigaset_ops *ops, - struct module *owner); + const char *procname, + const char *devname, + const char *devfsname, + const struct gigaset_ops *ops, + struct module *owner); /* Deallocate driver structure. */ void gigaset_freedriver(struct gigaset_driver *drv); void gigaset_debugdrivers(void); -struct cardstate *gigaset_get_cs_by_minor(unsigned minor); struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty); struct cardstate *gigaset_get_cs_by_id(int id); @@ -763,7 +784,8 @@ struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv); void gigaset_unassign(struct cardstate *cs); void gigaset_blockdriver(struct gigaset_driver *drv); -/* Allocate and initialize card state. Calls hardware dependent gigaset_init[b]cs(). */ +/* Allocate and initialize card state. Calls hardware dependent + gigaset_init[b]cs(). */ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, int onechannel, int ignoreframes, int cidmode, const char *modulename); @@ -788,8 +810,8 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); * ptr must be kmalloc()ed (and not be freed by the caller). */ struct event_t *gigaset_add_event(struct cardstate *cs, - struct at_state_t *at_state, int type, - void *ptr, int parameter, void *arg); + struct at_state_t *at_state, int type, + void *ptr, int parameter, void *arg); /* Called on CONFIG1 command from frontend. */ int gigaset_enterconfigmode(struct cardstate *cs); //0: success <0: errorcode @@ -799,7 +821,7 @@ static inline void gigaset_schedule_event(struct cardstate *cs) { unsigned long flags; spin_lock_irqsave(&cs->lock, flags); - if (atomic_read(&cs->running)) + if (cs->running) tasklet_schedule(&cs->event_tasklet); spin_unlock_irqrestore(&cs->lock, flags); } @@ -810,7 +832,7 @@ static inline void gigaset_bchannel_down(struct bc_state *bcs) { gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_CLOSED, NULL, 0, NULL); - dbg(DEBUG_CMD, "scheduling BC_CLOSED"); + gig_dbg(DEBUG_CMD, "scheduling BC_CLOSED"); gigaset_schedule_event(bcs->cs); } @@ -820,36 +842,19 @@ static inline void gigaset_bchannel_up(struct bc_state *bcs) { gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_OPEN, NULL, 0, NULL); - dbg(DEBUG_CMD, "scheduling BC_OPEN"); + gig_dbg(DEBUG_CMD, "scheduling BC_OPEN"); gigaset_schedule_event(bcs->cs); } /* handling routines for sk_buff */ /* ============================= */ -/* private version of __skb_put() - * append 'len' bytes to the content of 'skb', already knowing that the - * existing buffer can accomodate them - * returns a pointer to the location where the new bytes should be copied to - * This function does not take any locks so it must be called with the - * appropriate locks held only. - */ -static inline unsigned char *gigaset_skb_put_quick(struct sk_buff *skb, - unsigned int len) -{ - unsigned char *tmp = skb->tail; - /*SKB_LINEAR_ASSERT(skb);*/ /* not needed here */ - skb->tail += len; - skb->len += len; - return tmp; -} - /* pass received skb to LL * Warning: skb must not be accessed anymore! */ static inline void gigaset_rcv_skb(struct sk_buff *skb, - struct cardstate *cs, - struct bc_state *bcs) + struct cardstate *cs, + struct bc_state *bcs) { cs->iif.rcvcallb_skb(cs->myid, bcs->channel, skb); bcs->trans_down++; @@ -859,8 +864,8 @@ static inline void gigaset_rcv_skb(struct sk_buff *skb, * Warning: skb must not be accessed anymore! */ static inline void gigaset_rcv_error(struct sk_buff *procskb, - struct cardstate *cs, - struct bc_state *bcs) + struct cardstate *cs, + struct bc_state *bcs) { if (procskb) dev_kfree_skb(procskb); @@ -877,46 +882,9 @@ static inline void gigaset_rcv_error(struct sk_buff *procskb, /* bitwise byte inversion table */ extern __u8 gigaset_invtab[]; /* in common.c */ - /* append received bytes to inbuf */ -static inline int gigaset_fill_inbuf(struct inbuf_t *inbuf, - const unsigned char *src, - unsigned numbytes) -{ - unsigned n, head, tail, bytesleft; - - dbg(DEBUG_INTR, "received %u bytes", numbytes); - - if (!numbytes) - return 0; - - bytesleft = numbytes; - tail = atomic_read(&inbuf->tail); - head = atomic_read(&inbuf->head); - dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); - - while (bytesleft) { - if (head > tail) - n = head - 1 - tail; - else if (head == 0) - n = (RBUFSIZE-1) - tail; - else - n = RBUFSIZE - tail; - if (!n) { - err("buffer overflow (%u bytes lost)", bytesleft); - break; - } - if (n > bytesleft) - n = bytesleft; - memcpy(inbuf->data + tail, src, n); - bytesleft -= n; - tail = (tail + n) % RBUFSIZE; - src += n; - } - dbg(DEBUG_INTR, "setting tail to %u", tail); - atomic_set(&inbuf->tail, tail); - return numbytes != bytesleft; -} +int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, + unsigned numbytes); /* =========================================================================== * Functions implemented in interface.c @@ -924,7 +892,7 @@ static inline int gigaset_fill_inbuf(struct inbuf_t *inbuf, /* initialize interface */ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, - const char *devname, const char *devfsname); + const char *devname, const char *devfsname); /* release interface */ void gigaset_if_freedriver(struct gigaset_driver *drv); /* add minor */ @@ -933,6 +901,6 @@ void gigaset_if_init(struct cardstate *cs); void gigaset_if_free(struct cardstate *cs); /* device received data */ void gigaset_if_receive(struct cardstate *cs, - unsigned char *buffer, size_t len); + unsigned char *buffer, size_t len); #endif diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 731a675f21b0..0815dbfb8291 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -1,9 +1,9 @@ /* * Stuff used by all variants of the driver * - * Copyright (c) 2001 by Stefan Eilers (Eilers.Stefan@epost.de), - * Hansjoerg Lipp (hjlipp@web.de), - * Tilman Schmidt (tilman@imap.cc). + * Copyright (c) 2001 by Stefan Eilers, + * Hansjoerg Lipp , + * Tilman Schmidt . * * ===================================================================== * This program is free software; you can redistribute it and/or @@ -11,15 +11,11 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * ===================================================================== - * ToDo: ... - * ===================================================================== - * Version: $Id: i4l.c,v 1.3.2.9 2006/02/04 18:28:16 hjlipp Exp $ - * ===================================================================== */ #include "gigaset.h" -/* == Handling of I4L IO ============================================================================*/ +/* == Handling of I4L IO =====================================================*/ /* writebuf_from_LL * called by LL to transmit data on an open channel @@ -29,14 +25,16 @@ * parameters: * driverID driver ID as assigned by LL * channel channel number - * ack if != 0 LL wants to be notified on completion via statcallb(ISDN_STAT_BSENT) + * ack if != 0 LL wants to be notified on completion via + * statcallb(ISDN_STAT_BSENT) * skb skb containing data to send * return value: * number of accepted bytes * 0 if temporarily unable to accept data (out of buffer space) * <0 on error (eg. -EINVAL) */ -static int writebuf_from_LL(int driverID, int channel, int ack, struct sk_buff *skb) +static int writebuf_from_LL(int driverID, int channel, int ack, + struct sk_buff *skb) { struct cardstate *cs; struct bc_state *bcs; @@ -54,31 +52,28 @@ static int writebuf_from_LL(int driverID, int channel, int ack, struct sk_buff * bcs = &cs->bcs[channel]; len = skb->len; - dbg(DEBUG_LLDATA, - "Receiving data from LL (id: %d, channel: %d, ack: %d, size: %d)", - driverID, channel, ack, len); + gig_dbg(DEBUG_LLDATA, + "Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)", + driverID, channel, ack, len); if (!len) { if (ack) - warn("not ACKing empty packet from LL"); + notice("%s: not ACKing empty packet", __func__); return 0; } if (len > MAX_BUF_SIZE) { - err("%s: packet too large (%d bytes)", __func__, channel); + err("%s: packet too large (%d bytes)", __func__, len); return -EINVAL; } - if (!atomic_read(&cs->connected)) - return -ENODEV; - skblen = ack ? len : 0; skb->head[0] = skblen & 0xff; skb->head[1] = skblen >> 8; - dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x", len, skblen, - (unsigned) skb->head[0], (unsigned) skb->head[1]); + gig_dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x", + len, skblen, (unsigned) skb->head[0], (unsigned) skb->head[1]); /* pass to device-specific module */ - return cs->ops->send_skb(bcs, skb); + return cs->ops->send_skb(bcs, skb); //FIXME cs->ops->send_skb() must handle !cs->connected correctly } void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) @@ -89,14 +84,14 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) ++bcs->trans_up; if (skb->len) - warn("%s: skb->len==%d", __func__, skb->len); + dev_warn(bcs->cs->dev, "%s: skb->len==%d\n", + __func__, skb->len); len = (unsigned char) skb->head[0] | (unsigned) (unsigned char) skb->head[1] << 8; if (len) { - dbg(DEBUG_MCMD, - "Acknowledge sending to LL (id: %d, channel: %d size: %u)", - bcs->cs->myid, bcs->channel, len); + gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)", + bcs->cs->myid, bcs->channel, len); response.driver = bcs->cs->myid; response.command = ISDN_STAT_BSENT; @@ -119,15 +114,12 @@ static int command_from_LL(isdn_ctrl *cntrl) struct bc_state *bcs; int retval = 0; struct setup_parm *sp; + unsigned param; + unsigned long flags; - //dbg(DEBUG_ANY, "Gigaset_HW: Receiving command"); gigaset_debugdrivers(); - /* Terminate this call if no device is present. Bt if the command is "ISDN_CMD_LOCK" or - * "ISDN_CMD_UNLOCK" then execute it due to the fact that they are device independent ! - */ - //FIXME "remove test for &connected" - if ((!cs || !atomic_read(&cs->connected))) { + if (!cs) { warn("LL tried to access unknown device with nr. %d", cntrl->driver); return -ENODEV; @@ -135,29 +127,30 @@ static int command_from_LL(isdn_ctrl *cntrl) switch (cntrl->command) { case ISDN_CMD_IOCTL: - - dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver:%d,arg: %ld)", - cntrl->driver, cntrl->arg); + gig_dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver: %d, arg: %ld)", + cntrl->driver, cntrl->arg); warn("ISDN_CMD_IOCTL is not supported."); return -EINVAL; case ISDN_CMD_DIAL: - dbg(DEBUG_ANY, "ISDN_CMD_DIAL (driver: %d, channel: %ld, " - "phone: %s,ownmsn: %s, si1: %d, si2: %d)", - cntrl->driver, cntrl->arg, - cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn, - cntrl->parm.setup.si1, cntrl->parm.setup.si2); + gig_dbg(DEBUG_ANY, + "ISDN_CMD_DIAL (driver: %d, ch: %ld, " + "phone: %s, ownmsn: %s, si1: %d, si2: %d)", + cntrl->driver, cntrl->arg, + cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn, + cntrl->parm.setup.si1, cntrl->parm.setup.si2); if (cntrl->arg >= cs->channels) { - err("invalid channel (%d)", (int) cntrl->arg); + err("ISDN_CMD_DIAL: invalid channel (%d)", + (int) cntrl->arg); return -EINVAL; } bcs = cs->bcs + cntrl->arg; if (!gigaset_get_channel(bcs)) { - err("channel not free"); + err("ISDN_CMD_DIAL: channel not free"); return -EBUSY; } @@ -169,42 +162,46 @@ static int command_from_LL(isdn_ctrl *cntrl) } *sp = cntrl->parm.setup; - if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, - atomic_read(&bcs->at_state.seq_index), - NULL)) { + spin_lock_irqsave(&cs->lock, flags); + param = bcs->at_state.seq_index; + spin_unlock_irqrestore(&cs->lock, flags); + + if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp, param, + NULL)) { //FIXME what should we do? kfree(sp); gigaset_free_channel(bcs); return -ENOMEM; } - dbg(DEBUG_CMD, "scheduling DIAL"); + gig_dbg(DEBUG_CMD, "scheduling DIAL"); gigaset_schedule_event(cs); break; case ISDN_CMD_ACCEPTD: //FIXME - dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD"); + gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD"); if (cntrl->arg >= cs->channels) { - err("invalid channel (%d)", (int) cntrl->arg); + err("ISDN_CMD_ACCEPTD: invalid channel (%d)", + (int) cntrl->arg); return -EINVAL; } if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state, - EV_ACCEPT, NULL, 0, NULL)) { + EV_ACCEPT, NULL, 0, NULL)) { //FIXME what should we do? return -ENOMEM; } - dbg(DEBUG_CMD, "scheduling ACCEPT"); + gig_dbg(DEBUG_CMD, "scheduling ACCEPT"); gigaset_schedule_event(cs); break; case ISDN_CMD_ACCEPTB: - dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB"); + gig_dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB"); break; case ISDN_CMD_HANGUP: - dbg(DEBUG_ANY, - "ISDN_CMD_HANGUP (channel: %d)", (int) cntrl->arg); + gig_dbg(DEBUG_ANY, "ISDN_CMD_HANGUP (ch: %d)", + (int) cntrl->arg); if (cntrl->arg >= cs->channels) { err("ISDN_CMD_HANGUP: invalid channel (%u)", @@ -213,66 +210,68 @@ static int command_from_LL(isdn_ctrl *cntrl) } if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state, - EV_HUP, NULL, 0, NULL)) { + EV_HUP, NULL, 0, NULL)) { //FIXME what should we do? return -ENOMEM; } - dbg(DEBUG_CMD, "scheduling HUP"); + gig_dbg(DEBUG_CMD, "scheduling HUP"); gigaset_schedule_event(cs); break; - case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ //FIXME - dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ"); + case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ //FIXME + gig_dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ"); break; - case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ //FIXME - dbg(DEBUG_ANY, - "ISDN_CMD_SETEAZ (id:%d, channel: %ld, number: %s)", - cntrl->driver, cntrl->arg, cntrl->parm.num); + case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ //FIXME + gig_dbg(DEBUG_ANY, + "ISDN_CMD_SETEAZ (id: %d, ch: %ld, number: %s)", + cntrl->driver, cntrl->arg, cntrl->parm.num); break; - case ISDN_CMD_SETL2: /* Set L2 to given protocol */ - dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (Channel: %ld, Proto: %lx)", - cntrl->arg & 0xff, (cntrl->arg >> 8)); + case ISDN_CMD_SETL2: /* Set L2 to given protocol */ + gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (ch: %ld, proto: %lx)", + cntrl->arg & 0xff, (cntrl->arg >> 8)); if ((cntrl->arg & 0xff) >= cs->channels) { - err("invalid channel (%u)", + err("ISDN_CMD_SETL2: invalid channel (%u)", (unsigned) cntrl->arg & 0xff); return -EINVAL; } if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg & 0xff].at_state, - EV_PROTO_L2, NULL, cntrl->arg >> 8, - NULL)) { + EV_PROTO_L2, NULL, cntrl->arg >> 8, + NULL)) { //FIXME what should we do? return -ENOMEM; } - dbg(DEBUG_CMD, "scheduling PROTO_L2"); + gig_dbg(DEBUG_CMD, "scheduling PROTO_L2"); gigaset_schedule_event(cs); break; - case ISDN_CMD_SETL3: /* Set L3 to given protocol */ - dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (Channel: %ld, Proto: %lx)", - cntrl->arg & 0xff, (cntrl->arg >> 8)); + case ISDN_CMD_SETL3: /* Set L3 to given protocol */ + gig_dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (ch: %ld, proto: %lx)", + cntrl->arg & 0xff, (cntrl->arg >> 8)); if ((cntrl->arg & 0xff) >= cs->channels) { - err("invalid channel (%u)", + err("ISDN_CMD_SETL3: invalid channel (%u)", (unsigned) cntrl->arg & 0xff); return -EINVAL; } if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) { - err("invalid protocol %lu", cntrl->arg >> 8); + err("ISDN_CMD_SETL3: invalid protocol %lu", + cntrl->arg >> 8); return -EINVAL; } break; case ISDN_CMD_PROCEED: - dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME + gig_dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME break; case ISDN_CMD_ALERT: - dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME + gig_dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME if (cntrl->arg >= cs->channels) { - err("invalid channel (%d)", (int) cntrl->arg); + err("ISDN_CMD_ALERT: invalid channel (%d)", + (int) cntrl->arg); return -EINVAL; } //bcs = cs->bcs + cntrl->arg; @@ -280,32 +279,31 @@ static int command_from_LL(isdn_ctrl *cntrl) // FIXME break; case ISDN_CMD_REDIR: - dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME + gig_dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME break; case ISDN_CMD_PROT_IO: - dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO"); + gig_dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO"); break; case ISDN_CMD_FAXCMD: - dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD"); + gig_dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD"); break; case ISDN_CMD_GETL2: - dbg(DEBUG_ANY, "ISDN_CMD_GETL2"); + gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL2"); break; case ISDN_CMD_GETL3: - dbg(DEBUG_ANY, "ISDN_CMD_GETL3"); + gig_dbg(DEBUG_ANY, "ISDN_CMD_GETL3"); break; case ISDN_CMD_GETEAZ: - dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ"); + gig_dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ"); break; case ISDN_CMD_SETSIL: - dbg(DEBUG_ANY, "ISDN_CMD_SETSIL"); + gig_dbg(DEBUG_ANY, "ISDN_CMD_SETSIL"); break; case ISDN_CMD_GETSIL: - dbg(DEBUG_ANY, "ISDN_CMD_GETSIL"); + gig_dbg(DEBUG_ANY, "ISDN_CMD_GETSIL"); break; default: - err("unknown command %d from LL", - cntrl->command); + err("unknown command %d from LL", cntrl->command); return -EINVAL; } @@ -350,7 +348,8 @@ int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data) proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */ break; default: - err("invalid protocol: %u", bcs->proto2); + dev_err(bcs->cs->dev, "%s: invalid L2 protocol: %u\n", + __func__, bcs->proto2); return -EINVAL; } @@ -378,7 +377,7 @@ int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data) bcs->commands[i] = NULL; if (length[i] && !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) { - err("out of memory"); + dev_err(bcs->cs->dev, "out of memory\n"); return -ENOMEM; } } @@ -396,10 +395,14 @@ int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data) } if (bcs->commands[AT_MSN]) - snprintf(bcs->commands[AT_MSN], length[AT_MSN], "^SMSN=%s\r", sp->eazmsn); - snprintf(bcs->commands[AT_BC ], length[AT_BC ], "^SBC=%s\r", bc); - snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto); - snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], "^SISO=%u\r", (unsigned)bcs->channel + 1); + snprintf(bcs->commands[AT_MSN], length[AT_MSN], + "^SMSN=%s\r", sp->eazmsn); + snprintf(bcs->commands[AT_BC ], length[AT_BC ], + "^SBC=%s\r", bc); + snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], + "^SBPR=%u\r", proto); + snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], + "^SISO=%u\r", (unsigned)bcs->channel + 1); return 0; } @@ -419,7 +422,8 @@ int gigaset_isdn_setup_accept(struct at_state_t *at_state) proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */ break; default: - err("invalid protocol: %u", bcs->proto2); + dev_err(at_state->cs->dev, "%s: invalid protocol: %u\n", + __func__, bcs->proto2); return -EINVAL; } @@ -436,13 +440,15 @@ int gigaset_isdn_setup_accept(struct at_state_t *at_state) bcs->commands[i] = NULL; if (length[i] && !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) { - err("out of memory"); + dev_err(at_state->cs->dev, "out of memory\n"); return -ENOMEM; } } - snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto); - snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], "^SISO=%u\r", (unsigned) bcs->channel + 1); + snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], + "^SBPR=%u\r", proto); + snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], + "^SISO=%u\r", (unsigned) bcs->channel + 1); return 0; } @@ -473,7 +479,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state) response.parm.setup.si1 = 1; response.parm.setup.si2 = 2; } else { - warn("RING ignored - unsupported BC %s", + dev_warn(cs->dev, "RING ignored - unsupported BC %s\n", at_state->str_var[STR_ZBC]); return ICALL_IGNORE; } @@ -491,18 +497,17 @@ int gigaset_isdn_icall(struct at_state_t *at_state) response.parm.setup.eazmsn[0] = 0; if (!bcs) { - notice("no channel for incoming call"); - dbg(DEBUG_CMD, "Sending ICALLW"); + dev_notice(cs->dev, "no channel for incoming call\n"); response.command = ISDN_STAT_ICALLW; response.arg = 0; //FIXME } else { - dbg(DEBUG_CMD, "Sending ICALL"); + gig_dbg(DEBUG_CMD, "Sending ICALL"); response.command = ISDN_STAT_ICALL; response.arg = bcs->channel; //FIXME } response.driver = cs->myid; retval = cs->iif.statcallb(&response); - dbg(DEBUG_CMD, "Response: %d", retval); + gig_dbg(DEBUG_CMD, "Response: %d", retval); switch (retval) { case 0: /* no takers */ return ICALL_IGNORE; @@ -512,7 +517,8 @@ int gigaset_isdn_icall(struct at_state_t *at_state) case 2: /* reject */ return ICALL_REJECT; case 3: /* incomplete */ - warn("LL requested unsupported feature: Incomplete Number"); + dev_warn(cs->dev, + "LL requested unsupported feature: Incomplete Number\n"); return ICALL_IGNORE; case 4: /* proceeding */ /* Gigaset will send ALERTING anyway. @@ -520,10 +526,11 @@ int gigaset_isdn_icall(struct at_state_t *at_state) */ return ICALL_ACCEPT; case 5: /* deflect */ - warn("LL requested unsupported feature: Call Deflection"); + dev_warn(cs->dev, + "LL requested unsupported feature: Call Deflection\n"); return ICALL_IGNORE; default: - err("LL error %d on ICALL", retval); + dev_err(cs->dev, "LL error %d on ICALL\n", retval); return ICALL_IGNORE; } } @@ -533,7 +540,7 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid) { isdn_if *iif = &cs->iif; - dbg(DEBUG_ANY, "Register driver capabilities to LL"); + gig_dbg(DEBUG_ANY, "Register driver capabilities to LL"); //iif->id[sizeof(iif->id) - 1]=0; //strncpy(iif->id, isdnid, sizeof(iif->id) - 1); @@ -542,26 +549,26 @@ int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid) return -ENOMEM; //FIXME EINVAL/...?? iif->owner = THIS_MODULE; - iif->channels = cs->channels; /* I am supporting just one channel *//* I was supporting...*/ + iif->channels = cs->channels; iif->maxbufsize = MAX_BUF_SIZE; - iif->features = ISDN_FEATURE_L2_TRANS | /* Our device is very advanced, therefore */ + iif->features = ISDN_FEATURE_L2_TRANS | ISDN_FEATURE_L2_HDLC | #ifdef GIG_X75 ISDN_FEATURE_L2_X75I | #endif ISDN_FEATURE_L3_TRANS | ISDN_FEATURE_P_EURO; - iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */ + iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */ iif->command = command_from_LL; iif->writebuf_skb = writebuf_from_LL; - iif->writecmd = NULL; /* Don't support isdnctrl */ - iif->readstat = NULL; /* Don't support isdnctrl */ - iif->rcvcallb_skb = NULL; /* Will be set by LL */ - iif->statcallb = NULL; /* Will be set by LL */ + iif->writecmd = NULL; /* Don't support isdnctrl */ + iif->readstat = NULL; /* Don't support isdnctrl */ + iif->rcvcallb_skb = NULL; /* Will be set by LL */ + iif->statcallb = NULL; /* Will be set by LL */ if (!register_isdn(iif)) return 0; - cs->myid = iif->channels; /* Set my device id */ + cs->myid = iif->channels; /* Set my device id */ return 1; } diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 3a81d9c65141..08e4c4eea14d 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -9,8 +9,6 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * ===================================================================== - * Version: $Id: interface.c,v 1.14.4.15 2006/02/04 18:28:16 hjlipp Exp $ - * ===================================================================== */ #include "gigaset.h" @@ -24,7 +22,7 @@ static int if_lock(struct cardstate *cs, int *arg) { int cmd = *arg; - dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd); + gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd); if (cmd > 1) return -EINVAL; @@ -35,7 +33,7 @@ static int if_lock(struct cardstate *cs, int *arg) } if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED - && atomic_read(&cs->connected)) { + && cs->connected) { cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); cs->ops->baud_rate(cs, B115200); cs->ops->set_line_ctrl(cs, CS8); @@ -44,12 +42,12 @@ static int if_lock(struct cardstate *cs, int *arg) cs->waiting = 1; if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK, - NULL, cmd, NULL)) { + NULL, cmd, NULL)) { cs->waiting = 0; return -ENOMEM; } - dbg(DEBUG_CMD, "scheduling IF_LOCK"); + gig_dbg(DEBUG_CMD, "scheduling IF_LOCK"); gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); @@ -68,7 +66,7 @@ static int if_version(struct cardstate *cs, unsigned arg[4]) static const unsigned compat[4] = GIG_COMPAT; unsigned cmd = arg[0]; - dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd); + gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd); switch (cmd) { case GIGVER_DRIVER: @@ -80,12 +78,12 @@ static int if_version(struct cardstate *cs, unsigned arg[4]) case GIGVER_FWBASE: cs->waiting = 1; if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER, - NULL, 0, arg)) { + NULL, 0, arg)) { cs->waiting = 0; return -ENOMEM; } - dbg(DEBUG_CMD, "scheduling IF_VER"); + gig_dbg(DEBUG_CMD, "scheduling IF_VER"); gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); @@ -101,7 +99,7 @@ static int if_version(struct cardstate *cs, unsigned arg[4]) static int if_config(struct cardstate *cs, int *arg) { - dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg); + gig_dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg); if (*arg != 1) return -EINVAL; @@ -109,6 +107,11 @@ static int if_config(struct cardstate *cs, int *arg) if (atomic_read(&cs->mstate) != MS_LOCKED) return -EBUSY; + if (!cs->connected) { + err("not connected!"); + return -ENODEV; + } + *arg = 0; return gigaset_enterconfigmode(cs); } @@ -119,7 +122,7 @@ static int if_config(struct cardstate *cs, int *arg) static int if_open(struct tty_struct *tty, struct file *filp); static void if_close(struct tty_struct *tty, struct file *filp); static int if_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); + unsigned int cmd, unsigned long arg); static int if_write_room(struct tty_struct *tty); static int if_chars_in_buffer(struct tty_struct *tty); static void if_throttle(struct tty_struct *tty); @@ -127,9 +130,9 @@ static void if_unthrottle(struct tty_struct *tty); static void if_set_termios(struct tty_struct *tty, struct termios *old); static int if_tiocmget(struct tty_struct *tty, struct file *file); static int if_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear); + unsigned int set, unsigned int clear); static int if_write(struct tty_struct *tty, - const unsigned char *buf, int count); + const unsigned char *buf, int count); static struct tty_operations if_ops = { .open = if_open, @@ -153,8 +156,8 @@ static int if_open(struct tty_struct *tty, struct file *filp) struct cardstate *cs; unsigned long flags; - dbg(DEBUG_IF, "%d+%d: %s()", tty->driver->minor_start, tty->index, - __FUNCTION__); + gig_dbg(DEBUG_IF, "%d+%d: %s()", + tty->driver->minor_start, tty->index, __func__); tty->driver_data = NULL; @@ -162,7 +165,7 @@ static int if_open(struct tty_struct *tty, struct file *filp) if (!cs) return -ENODEV; - if (down_interruptible(&cs->sem)) + if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? tty->driver_data = cs; @@ -173,10 +176,9 @@ static int if_open(struct tty_struct *tty, struct file *filp) cs->tty = tty; spin_unlock_irqrestore(&cs->lock, flags); tty->low_latency = 1; //FIXME test - //FIXME } - up(&cs->sem); + mutex_unlock(&cs->mutex); return 0; } @@ -187,30 +189,29 @@ static void if_close(struct tty_struct *tty, struct file *filp) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return; } - dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); + gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - down(&cs->sem); + mutex_lock(&cs->mutex); if (!cs->open_count) - warn("%s: device not opened", __FUNCTION__); + warn("%s: device not opened", __func__); else { if (!--cs->open_count) { spin_lock_irqsave(&cs->lock, flags); cs->tty = NULL; spin_unlock_irqrestore(&cs->lock, flags); - //FIXME } } - up(&cs->sem); + mutex_unlock(&cs->mutex); } static int if_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { struct cardstate *cs; int retval = -ENODEV; @@ -220,17 +221,17 @@ static int if_ioctl(struct tty_struct *tty, struct file *file, cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return -ENODEV; } - dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __FUNCTION__, cmd); + gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd); - if (down_interruptible(&cs->sem)) + if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->open_count) - warn("%s: device not opened", __FUNCTION__); + warn("%s: device not opened", __func__); else { retval = 0; switch (cmd) { @@ -250,37 +251,40 @@ static int if_ioctl(struct tty_struct *tty, struct file *file, break; case GIGASET_BRKCHARS: //FIXME test if MS_LOCKED - gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS", - 6, (const unsigned char *) arg, 1); - if (!atomic_read(&cs->connected)) { - dbg(DEBUG_ANY, "can't communicate with unplugged device"); + if (!cs->connected) { + gig_dbg(DEBUG_ANY, + "can't communicate with unplugged device"); retval = -ENODEV; break; } retval = copy_from_user(&buf, - (const unsigned char __user *) arg, 6) - ? -EFAULT : 0; - if (retval >= 0) + (const unsigned char __user *) arg, 6) + ? -EFAULT : 0; + if (retval >= 0) { + gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS", + 6, (const unsigned char *) arg); retval = cs->ops->brkchars(cs, buf); + } break; case GIGASET_VERSION: - retval = copy_from_user(version, (unsigned __user *) arg, - sizeof version) ? -EFAULT : 0; + retval = copy_from_user(version, + (unsigned __user *) arg, sizeof version) + ? -EFAULT : 0; if (retval >= 0) retval = if_version(cs, version); if (retval >= 0) - retval = copy_to_user((unsigned __user *) arg, version, - sizeof version) - ? -EFAULT : 0; + retval = copy_to_user((unsigned __user *) arg, + version, sizeof version) + ? -EFAULT : 0; break; - default: - dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x", - __FUNCTION__, cmd); + default: + gig_dbg(DEBUG_ANY, "%s: arg not supported - 0x%04x", + __func__, cmd); retval = -ENOIOCTLCMD; } } - up(&cs->sem); + mutex_unlock(&cs->mutex); return retval; } @@ -292,25 +296,25 @@ static int if_tiocmget(struct tty_struct *tty, struct file *file) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return -ENODEV; } - dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); + gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - if (down_interruptible(&cs->sem)) + if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? // FIXME read from device? retval = cs->control_state & (TIOCM_RTS|TIOCM_DTR); - up(&cs->sem); + mutex_unlock(&cs->mutex); return retval; } static int if_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) + unsigned int set, unsigned int clear) { struct cardstate *cs; int retval; @@ -318,18 +322,18 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file, cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return -ENODEV; } - dbg(DEBUG_IF, - "%u: %s(0x%x, 0x%x)", cs->minor_index, __FUNCTION__, set, clear); + gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)", + cs->minor_index, __func__, set, clear); - if (down_interruptible(&cs->sem)) + if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? - if (!atomic_read(&cs->connected)) { - dbg(DEBUG_ANY, "can't communicate with unplugged device"); + if (!cs->connected) { + gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); retval = -ENODEV; } else { mc = (cs->control_state | set) & ~clear & (TIOCM_RTS|TIOCM_DTR); @@ -337,7 +341,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file, cs->control_state = mc; } - up(&cs->sem); + mutex_unlock(&cs->mutex); return retval; } @@ -349,29 +353,29 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return -ENODEV; } - dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); + gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - if (down_interruptible(&cs->sem)) + if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->open_count) - warn("%s: device not opened", __FUNCTION__); + warn("%s: device not opened", __func__); else if (atomic_read(&cs->mstate) != MS_LOCKED) { warn("can't write to unlocked device"); retval = -EBUSY; - } else if (!atomic_read(&cs->connected)) { - dbg(DEBUG_ANY, "can't write to unplugged device"); + } else if (!cs->connected) { + gig_dbg(DEBUG_ANY, "can't write to unplugged device"); retval = -EBUSY; //FIXME } else { retval = cs->ops->write_cmd(cs, buf, count, - &cs->if_wake_tasklet); + &cs->if_wake_tasklet); } - up(&cs->sem); + mutex_unlock(&cs->mutex); return retval; } @@ -383,27 +387,27 @@ static int if_write_room(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return -ENODEV; } - dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); + gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - if (down_interruptible(&cs->sem)) + if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->open_count) - warn("%s: device not opened", __FUNCTION__); + warn("%s: device not opened", __func__); else if (atomic_read(&cs->mstate) != MS_LOCKED) { warn("can't write to unlocked device"); retval = -EBUSY; //FIXME - } else if (!atomic_read(&cs->connected)) { - dbg(DEBUG_ANY, "can't write to unplugged device"); + } else if (!cs->connected) { + gig_dbg(DEBUG_ANY, "can't write to unplugged device"); retval = -EBUSY; //FIXME } else retval = cs->ops->write_room(cs); - up(&cs->sem); + mutex_unlock(&cs->mutex); return retval; } @@ -415,27 +419,27 @@ static int if_chars_in_buffer(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return -ENODEV; } - dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); + gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - if (down_interruptible(&cs->sem)) + if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? if (!cs->open_count) - warn("%s: device not opened", __FUNCTION__); + warn("%s: device not opened", __func__); else if (atomic_read(&cs->mstate) != MS_LOCKED) { warn("can't write to unlocked device"); retval = -EBUSY; - } else if (!atomic_read(&cs->connected)) { - dbg(DEBUG_ANY, "can't write to unplugged device"); + } else if (!cs->connected) { + gig_dbg(DEBUG_ANY, "can't write to unplugged device"); retval = -EBUSY; //FIXME } else retval = cs->ops->chars_in_buffer(cs); - up(&cs->sem); + mutex_unlock(&cs->mutex); return retval; } @@ -446,21 +450,21 @@ static void if_throttle(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return; } - dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); + gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - down(&cs->sem); + mutex_lock(&cs->mutex); if (!cs->open_count) - warn("%s: device not opened", __FUNCTION__); + warn("%s: device not opened", __func__); else { //FIXME } - up(&cs->sem); + mutex_unlock(&cs->mutex); } static void if_unthrottle(struct tty_struct *tty) @@ -469,21 +473,21 @@ static void if_unthrottle(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return; } - dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); + gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - down(&cs->sem); + mutex_lock(&cs->mutex); if (!cs->open_count) - warn("%s: device not opened", __FUNCTION__); + warn("%s: device not opened", __func__); else { //FIXME } - up(&cs->sem); + mutex_unlock(&cs->mutex); } static void if_set_termios(struct tty_struct *tty, struct termios *old) @@ -496,21 +500,21 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __FUNCTION__); + err("cs==NULL in %s", __func__); return; } - dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __FUNCTION__); + gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - down(&cs->sem); + mutex_lock(&cs->mutex); if (!cs->open_count) { - warn("%s: device not opened", __FUNCTION__); + warn("%s: device not opened", __func__); goto out; } - if (!atomic_read(&cs->connected)) { - dbg(DEBUG_ANY, "can't communicate with unplugged device"); + if (!cs->connected) { + gig_dbg(DEBUG_ANY, "can't communicate with unplugged device"); goto out; } @@ -518,8 +522,8 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old) iflag = tty->termios->c_iflag; cflag = tty->termios->c_cflag; old_cflag = old ? old->c_cflag : cflag; //FIXME? - dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", cs->minor_index, - iflag, cflag, old_cflag); + gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", + cs->minor_index, iflag, cflag, old_cflag); /* get a local copy of the current port settings */ control_state = cs->control_state; @@ -531,14 +535,15 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old) * Premature optimization is the root of all evil. */ - /* reassert DTR and (maybe) RTS on transition from B0 */ + /* reassert DTR and (maybe) RTS on transition from B0 */ if ((old_cflag & CBAUD) == B0) { new_state = control_state | TIOCM_DTR; /* don't set RTS if using hardware flow control */ if (!(old_cflag & CRTSCTS)) new_state |= TIOCM_RTS; - dbg(DEBUG_IF, "%u: from B0 - set DTR%s", cs->minor_index, - (new_state & TIOCM_RTS) ? " only" : "/RTS"); + gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s", + cs->minor_index, + (new_state & TIOCM_RTS) ? " only" : "/RTS"); cs->ops->set_modem_ctrl(cs, control_state, new_state); control_state = new_state; } @@ -547,7 +552,7 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old) if ((cflag & CBAUD) == B0) { /* Drop RTS and DTR */ - dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index); + gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index); new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS); cs->ops->set_modem_ctrl(cs, control_state, new_state); control_state = new_state; @@ -567,15 +572,17 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old) * Just do what we have seen with SniffUSB on Win98. */ /* Drop DTR/RTS if no flow control otherwise assert */ - dbg(DEBUG_IF, "%u: control_state %x", cs->minor_index, control_state); + gig_dbg(DEBUG_IF, "%u: control_state %x", + cs->minor_index, control_state); new_state = control_state; if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) new_state |= TIOCM_DTR | TIOCM_RTS; else new_state &= ~(TIOCM_DTR | TIOCM_RTS); if (new_state != control_state) { - dbg(DEBUG_IF, "%u: new_state %x", cs->minor_index, new_state); - gigaset_set_modem_ctrl(cs, control_state, new_state); // FIXME: mct_u232.c sets the old state here. is this a bug? + gig_dbg(DEBUG_IF, "%u: new_state %x", + cs->minor_index, new_state); + gigaset_set_modem_ctrl(cs, control_state, new_state); control_state = new_state; } #endif @@ -584,7 +591,7 @@ static void if_set_termios(struct tty_struct *tty, struct termios *old) cs->control_state = control_state; out: - up(&cs->sem); + mutex_unlock(&cs->mutex); } @@ -600,7 +607,7 @@ static void if_wake(unsigned long data) if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { - dbg(DEBUG_IF, "write wakeup call"); + gig_dbg(DEBUG_IF, "write wakeup call"); tty->ldisc.write_wakeup(tty); } @@ -635,14 +642,14 @@ void gigaset_if_free(struct cardstate *cs) } void gigaset_if_receive(struct cardstate *cs, - unsigned char *buffer, size_t len) + unsigned char *buffer, size_t len) { unsigned long flags; struct tty_struct *tty; spin_lock_irqsave(&cs->lock, flags); if ((tty = cs->tty) == NULL) - dbg(DEBUG_ANY, "receive on closed device"); + gig_dbg(DEBUG_ANY, "receive on closed device"); else { tty_buffer_request_room(tty, len); tty_insert_flip_string(tty, buffer, len); @@ -655,13 +662,13 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive); /* gigaset_if_initdriver * Initialize tty interface. * parameters: - * drv Driver - * procname Name of the driver (e.g. for /proc/tty/drivers) - * devname Name of the device files (prefix without minor number) - * devfsname Devfs name of the device files without %d + * drv Driver + * procname Name of the driver (e.g. for /proc/tty/drivers) + * devname Name of the device files (prefix without minor number) + * devfsname Devfs name of the device files without %d */ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, - const char *devname, const char *devfsname) + const char *devname, const char *devfsname) { unsigned minors = drv->minors; int ret; @@ -696,7 +703,7 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, warn("failed to register tty driver (error %d)", ret); goto error; } - dbg(DEBUG_IF, "tty driver initialized"); + gig_dbg(DEBUG_IF, "tty driver initialized"); drv->have_tty = 1; return; diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 5744eb91b315..45f017ed6e8c 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -10,10 +10,6 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * ===================================================================== - * ToDo: ... - * ===================================================================== - * Version: $Id: isocdata.c,v 1.2.2.5 2005/11/13 23:05:19 hjlipp Exp $ - * ===================================================================== */ #include "gigaset.h" @@ -87,14 +83,14 @@ static inline int isowbuf_startwrite(struct isowbuf_t *iwb) { if (!atomic_dec_and_test(&iwb->writesem)) { atomic_inc(&iwb->writesem); - dbg(DEBUG_ISO, - "%s: couldn't acquire iso write semaphore", __func__); + gig_dbg(DEBUG_ISO, "%s: couldn't acquire iso write semaphore", + __func__); return 0; } #ifdef CONFIG_GIGASET_DEBUG - dbg(DEBUG_ISO, - "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d", - __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits); + gig_dbg(DEBUG_ISO, + "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d", + __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits); #endif return 1; } @@ -147,7 +143,7 @@ static inline void isowbuf_putflag(struct isowbuf_t *iwb) /* recover the idle flag byte */ write = atomic_read(&iwb->write); iwb->idle = iwb->data[write]; - dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle); + gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle); /* mask extraneous bits in buffer */ iwb->data[write] &= (1 << iwb->wbits) - 1; } @@ -166,15 +162,14 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) read = atomic_read(&iwb->nextread); write = atomic_read(&iwb->write); if (likely(read == write)) { - //dbg(DEBUG_STREAM, "%s: send buffer empty", __func__); /* return idle frame */ return read < BAS_OUTBUFPAD ? - BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD; + BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD; } limit = read + size; - dbg(DEBUG_STREAM, - "%s: read=%d write=%d limit=%d", __func__, read, write, limit); + gig_dbg(DEBUG_STREAM, "%s: read=%d write=%d limit=%d", + __func__, read, write, limit); #ifdef CONFIG_GIGASET_DEBUG if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) { err("invalid size %d", size); @@ -196,11 +191,12 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) return -EBUSY; /* write position could have changed */ if (limit >= (write = atomic_read(&iwb->write))) { - pbyte = iwb->data[write]; /* save partial byte */ + pbyte = iwb->data[write]; /* save + partial byte */ limit = write + BAS_OUTBUFPAD; - dbg(DEBUG_STREAM, - "%s: filling %d->%d with %02x", - __func__, write, limit, iwb->idle); + gig_dbg(DEBUG_STREAM, + "%s: filling %d->%d with %02x", + __func__, write, limit, iwb->idle); if (write + BAS_OUTBUFPAD < BAS_OUTBUFSIZE) memset(iwb->data + write, iwb->idle, BAS_OUTBUFPAD); @@ -211,9 +207,11 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) - write); limit = 0; } - dbg(DEBUG_STREAM, "%s: restoring %02x at %d", - __func__, pbyte, limit); - iwb->data[limit] = pbyte; /* restore partial byte */ + gig_dbg(DEBUG_STREAM, + "%s: restoring %02x at %d", + __func__, pbyte, limit); + iwb->data[limit] = pbyte; /* restore + partial byte */ atomic_set(&iwb->write, limit); } isowbuf_donewrite(iwb); @@ -242,19 +240,17 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) * write hex bytes to syslog for debugging */ static inline void dump_bytes(enum debuglevel level, const char *tag, - unsigned char *bytes, int count) + unsigned char *bytes, int count) { #ifdef CONFIG_GIGASET_DEBUG unsigned char c; static char dbgline[3 * 32 + 1]; static const char hexdigit[] = "0123456789abcdef"; int i = 0; - IFNULLRET(tag); - IFNULLRET(bytes); while (count-- > 0) { if (i > sizeof(dbgline) - 4) { dbgline[i] = '\0'; - dbg(level, "%s:%s", tag, dbgline); + gig_dbg(level, "%s:%s", tag, dbgline); i = 0; } c = *bytes++; @@ -264,7 +260,7 @@ static inline void dump_bytes(enum debuglevel level, const char *tag, dbgline[i++] = hexdigit[c & 0x0f]; } dbgline[i] = '\0'; - dbg(level, "%s:%s", tag, dbgline); + gig_dbg(level, "%s:%s", tag, dbgline); #endif } @@ -380,7 +376,7 @@ static u16 stufftab[5 * 256] = { */ static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin, - int ones) + int ones) { u16 stuff; int shiftinc, newones; @@ -422,7 +418,7 @@ static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin, */ static inline int hdlc_buildframe(struct isowbuf_t *iwb, - unsigned char *in, int count) + unsigned char *in, int count) { int ones; u16 fcs; @@ -431,8 +427,8 @@ static inline int hdlc_buildframe(struct isowbuf_t *iwb, if (isowbuf_freebytes(iwb) < count + count / 5 + 6 || !isowbuf_startwrite(iwb)) { - dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN", - __func__, isowbuf_freebytes(iwb)); + gig_dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN", + __func__, isowbuf_freebytes(iwb)); return -EAGAIN; } @@ -484,11 +480,11 @@ static inline int trans_buildframe(struct isowbuf_t *iwb, if (isowbuf_freebytes(iwb) < count || !isowbuf_startwrite(iwb)) { - dbg(DEBUG_ISO, "can't put %d bytes", count); + gig_dbg(DEBUG_ISO, "can't put %d bytes", count); return -EAGAIN; } - dbg(DEBUG_STREAM, "put %d bytes", count); + gig_dbg(DEBUG_STREAM, "put %d bytes", count); write = atomic_read(&iwb->write); do { c = gigaset_invtab[*in++]; @@ -508,11 +504,13 @@ int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len) switch (bcs->proto2) { case ISDN_PROTO_L2_HDLC: result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len); - dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d", __func__, len, result); + gig_dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d", + __func__, len, result); break; default: /* assume transparent */ result = trans_buildframe(bcs->hw.bas->isooutbuf, in, len); - dbg(DEBUG_ISO, "%s: %d bytes trans -> %d", __func__, len, result); + gig_dbg(DEBUG_ISO, "%s: %d bytes trans -> %d", + __func__, len, result); } return result; } @@ -528,13 +526,13 @@ static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) return; } if (unlikely(bcs->skb->len == SBUFSIZE)) { - warn("received oversized packet discarded"); + dev_warn(bcs->cs->dev, "received oversized packet discarded\n"); bcs->hw.bas->giants++; dev_kfree_skb_any(bcs->skb); bcs->skb = NULL; return; } - *gigaset_skb_put_quick(bcs->skb, 1) = c; + *__skb_put(bcs->skb, 1) = c; } /* hdlc_flush @@ -549,7 +547,7 @@ static inline void hdlc_flush(struct bc_state *bcs) if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) skb_reserve(bcs->skb, HW_HDR_LEN); else - err("could not allocate skb"); + dev_err(bcs->cs->dev, "could not allocate skb\n"); } /* reset packet state */ @@ -571,23 +569,25 @@ static inline void hdlc_done(struct bc_state *bcs) if ((procskb = bcs->skb) == NULL) { /* previous error */ - dbg(DEBUG_ISO, "%s: skb=NULL", __func__); + gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__); gigaset_rcv_error(NULL, bcs->cs, bcs); } else if (procskb->len < 2) { - notice("received short frame (%d octets)", procskb->len); + dev_notice(bcs->cs->dev, "received short frame (%d octets)\n", + procskb->len); bcs->hw.bas->runts++; gigaset_rcv_error(procskb, bcs->cs, bcs); } else if (bcs->fcs != PPP_GOODFCS) { - notice("frame check error (0x%04x)", bcs->fcs); + dev_notice(bcs->cs->dev, "frame check error (0x%04x)\n", + bcs->fcs); bcs->hw.bas->fcserrs++; gigaset_rcv_error(procskb, bcs->cs, bcs); } else { procskb->len -= 2; /* subtract FCS */ procskb->tail -= 2; - dbg(DEBUG_ISO, - "%s: good frame (%d octets)", __func__, procskb->len); + gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)", + __func__, procskb->len); dump_bytes(DEBUG_STREAM, - "rcv data", procskb->data, procskb->len); + "rcv data", procskb->data, procskb->len); bcs->hw.bas->goodbytes += procskb->len; gigaset_rcv_skb(procskb, bcs->cs, bcs); } @@ -595,7 +595,7 @@ static inline void hdlc_done(struct bc_state *bcs) if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) skb_reserve(bcs->skb, HW_HDR_LEN); else - err("could not allocate skb"); + dev_err(bcs->cs->dev, "could not allocate skb\n"); bcs->fcs = PPP_INITFCS; } @@ -610,14 +610,14 @@ static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits) return; } - notice("received partial byte (%d bits)", inbits); + dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits); bcs->hw.bas->alignerrs++; gigaset_rcv_error(bcs->skb, bcs->cs, bcs); if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) skb_reserve(bcs->skb, HW_HDR_LEN); else - err("could not allocate skb"); + dev_err(bcs->cs->dev, "could not allocate skb\n"); bcs->fcs = PPP_INITFCS; } @@ -659,16 +659,12 @@ static unsigned char bitcounts[256] = { * bcs receiving B channel structure */ static inline void hdlc_unpack(unsigned char *src, unsigned count, - struct bc_state *bcs) + struct bc_state *bcs) { - struct bas_bc_state *ubc; + struct bas_bc_state *ubc = bcs->hw.bas; int inputstate; unsigned seqlen, inbyte, inbits; - IFNULLRET(bcs); - ubc = bcs->hw.bas; - IFNULLRET(ubc); - /* load previous state: * inputstate = set of flag bits: * - INS_flag_hunt: no complete opening flag received since connection setup or last abort @@ -856,7 +852,7 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count, * bcs receiving B channel structure */ static inline void trans_receive(unsigned char *src, unsigned count, - struct bc_state *bcs) + struct bc_state *bcs) { struct sk_buff *skb; int dobytes; @@ -870,7 +866,7 @@ static inline void trans_receive(unsigned char *src, unsigned count, if (unlikely((skb = bcs->skb) == NULL)) { bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN); if (!skb) { - err("could not allocate skb"); + dev_err(bcs->cs->dev, "could not allocate skb\n"); return; } skb_reserve(skb, HW_HDR_LEN); @@ -888,7 +884,8 @@ static inline void trans_receive(unsigned char *src, unsigned count, gigaset_rcv_skb(skb, bcs->cs, bcs); bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN); if (!skb) { - err("could not allocate skb"); + dev_err(bcs->cs->dev, + "could not allocate skb\n"); return; } skb_reserve(bcs->skb, HW_HDR_LEN); @@ -921,8 +918,8 @@ static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf) case '\r': case '\n': /* end of line */ - dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", - __func__, cbytes); + gig_dbg(DEBUG_TRANSCMD, "%s: End of Command (%d Bytes)", + __func__, cbytes); cs->cbytes = cbytes; gigaset_handle_modem_response(cs); cbytes = 0; @@ -932,7 +929,7 @@ static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf) if (cbytes < MAX_RESP_SIZE - 1) cbytes++; else - warn("response too large"); + dev_warn(cs->dev, "response too large\n"); } } @@ -951,27 +948,27 @@ void gigaset_isoc_input(struct inbuf_t *inbuf) head = atomic_read(&inbuf->head); while (head != (tail = atomic_read(&inbuf->tail))) { - dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); + gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); if (head > tail) tail = RBUFSIZE; src = inbuf->data + head; numbytes = tail - head; - dbg(DEBUG_INTR, "processing %u bytes", numbytes); + gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); if (atomic_read(&cs->mstate) == MS_LOCKED) { gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", - numbytes, src, 0); + numbytes, src); gigaset_if_receive(inbuf->cs, src, numbytes); } else { gigaset_dbg_buffer(DEBUG_CMD, "received response", - numbytes, src, 0); + numbytes, src); cmd_loop(src, numbytes, inbuf); } head += numbytes; if (head == RBUFSIZE) head = 0; - dbg(DEBUG_INTR, "setting head to %u", head); + gig_dbg(DEBUG_INTR, "setting head to %u", head); atomic_set(&inbuf->head, head); } } @@ -992,18 +989,18 @@ void gigaset_isoc_input(struct inbuf_t *inbuf) */ int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb) { - int len; - - IFNULLRETVAL(bcs, -EFAULT); - IFNULLRETVAL(skb, -EFAULT); - len = skb->len; + int len = skb->len; + unsigned long flags; skb_queue_tail(&bcs->squeue, skb); - dbg(DEBUG_ISO, - "%s: skb queued, qlen=%d", __func__, skb_queue_len(&bcs->squeue)); + gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d", + __func__, skb_queue_len(&bcs->squeue)); /* tasklet submits URB if necessary */ - tasklet_schedule(&bcs->hw.bas->sent_tasklet); + spin_lock_irqsave(&bcs->cs->lock, flags); + if (bcs->cs->connected) + tasklet_schedule(&bcs->hw.bas->sent_tasklet); + spin_unlock_irqrestore(&bcs->cs->lock, flags); return len; /* ok so far */ } diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c index c6915fa2be6c..d267a636b53c 100644 --- a/drivers/isdn/gigaset/proc.c +++ b/drivers/isdn/gigaset/proc.c @@ -1,7 +1,7 @@ /* * Stuff used by all variants of the driver * - * Copyright (c) 2001 by Stefan Eilers , + * Copyright (c) 2001 by Stefan Eilers, * Hansjoerg Lipp , * Tilman Schmidt . * @@ -11,26 +11,29 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * ===================================================================== - * ToDo: ... - * ===================================================================== - * Version: $Id: proc.c,v 1.5.2.13 2006/02/04 18:28:16 hjlipp Exp $ - * ===================================================================== */ #include "gigaset.h" #include -static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_cidmode(struct device *dev, struct device_attribute *attr, + char *buf) { - struct usb_interface *intf = to_usb_interface(dev); - struct cardstate *cs = usb_get_intfdata(intf); - return sprintf(buf, "%d\n", atomic_read(&cs->cidmode)); // FIXME use scnprintf for 13607 bit architectures (if PAGE_SIZE==4096) + int ret; + unsigned long flags; + struct cardstate *cs = dev_get_drvdata(dev); + + spin_lock_irqsave(&cs->lock, flags); + ret = sprintf(buf, "%u\n", cs->cidmode); + spin_unlock_irqrestore(&cs->lock, flags); + + return ret; } -static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct usb_interface *intf = to_usb_interface(dev); - struct cardstate *cs = usb_get_intfdata(intf); + struct cardstate *cs = dev_get_drvdata(dev); long int value; char *end; @@ -41,23 +44,23 @@ static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, co if (value < 0 || value > 1) return -EINVAL; - if (down_interruptible(&cs->sem)) + if (mutex_lock_interruptible(&cs->mutex)) return -ERESTARTSYS; // FIXME -EINTR? cs->waiting = 1; if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE, - NULL, value, NULL)) { + NULL, value, NULL)) { cs->waiting = 0; - up(&cs->sem); + mutex_unlock(&cs->mutex); return -ENOMEM; } - dbg(DEBUG_CMD, "scheduling PROC_CIDMODE"); + gig_dbg(DEBUG_CMD, "scheduling PROC_CIDMODE"); gigaset_schedule_event(cs); wait_event(cs->waitqueue, !cs->waiting); - up(&cs->sem); + mutex_unlock(&cs->mutex); return count; } @@ -65,17 +68,15 @@ static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, co static DEVICE_ATTR(cidmode, S_IRUGO|S_IWUSR, show_cidmode, set_cidmode); /* free sysfs for device */ -void gigaset_free_dev_sysfs(struct usb_interface *interface) +void gigaset_free_dev_sysfs(struct cardstate *cs) { - dbg(DEBUG_INIT, "removing sysfs entries"); - device_remove_file(&interface->dev, &dev_attr_cidmode); + gig_dbg(DEBUG_INIT, "removing sysfs entries"); + device_remove_file(cs->dev, &dev_attr_cidmode); } -EXPORT_SYMBOL_GPL(gigaset_free_dev_sysfs); /* initialize sysfs for device */ -void gigaset_init_dev_sysfs(struct usb_interface *interface) +void gigaset_init_dev_sysfs(struct cardstate *cs) { - dbg(DEBUG_INIT, "setting up sysfs"); - device_create_file(&interface->dev, &dev_attr_cidmode); + gig_dbg(DEBUG_INIT, "setting up sysfs"); + device_create_file(cs->dev, &dev_attr_cidmode); } -EXPORT_SYMBOL_GPL(gigaset_init_dev_sysfs); diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 323fc7349dec..bfb73fd5077e 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -1,7 +1,7 @@ /* * USB driver for Gigaset 307x directly or using M105 Data. * - * Copyright (c) 2001 by Stefan Eilers + * Copyright (c) 2001 by Stefan Eilers * and Hansjoerg Lipp . * * This driver was derived from the USB skeleton driver by @@ -13,10 +13,6 @@ * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * ===================================================================== - * ToDo: ... - * ===================================================================== - * Version: $Id: usb-gigaset.c,v 1.85.4.18 2006/02/04 18:28:16 hjlipp Exp $ - * ===================================================================== */ #include "gigaset.h" @@ -29,7 +25,7 @@ #include /* Version Information */ -#define DRIVER_AUTHOR "Hansjoerg Lipp , Stefan Eilers " +#define DRIVER_AUTHOR "Hansjoerg Lipp , Stefan Eilers" #define DRIVER_DESC "USB Driver for Gigaset 307x using M105" /* Module parameters */ @@ -62,10 +58,6 @@ static struct usb_device_id gigaset_table [] = { MODULE_DEVICE_TABLE(usb, gigaset_table); -/* Get a minor range for your devices from the usb maintainer */ -#define USB_SKEL_MINOR_BASE 200 - - /* * Control requests (empty fields: 00) * @@ -114,7 +106,7 @@ MODULE_DEVICE_TABLE(usb, gigaset_table); */ static int gigaset_probe(struct usb_interface *interface, - const struct usb_device_id *id); + const struct usb_device_id *id); static void gigaset_disconnect(struct usb_interface *interface); static struct gigaset_driver *driver = NULL; @@ -122,29 +114,29 @@ static struct cardstate *cardstate = NULL; /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver gigaset_usb_driver = { - .name = GIGASET_MODULENAME, - .probe = gigaset_probe, - .disconnect = gigaset_disconnect, - .id_table = gigaset_table, + .name = GIGASET_MODULENAME, + .probe = gigaset_probe, + .disconnect = gigaset_disconnect, + .id_table = gigaset_table, }; struct usb_cardstate { - struct usb_device *udev; /* save off the usb device pointer */ - struct usb_interface *interface; /* the interface for this device */ - atomic_t busy; /* bulk output in progress */ + struct usb_device *udev; /* usb device pointer */ + struct usb_interface *interface; /* interface for this device */ + atomic_t busy; /* bulk output in progress */ - /* Output buffer for commands (M105: and data)*/ - unsigned char *bulk_out_buffer; /* the buffer to send data */ - int bulk_out_size; /* the size of the send buffer */ - __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ - struct urb *bulk_out_urb; /* the urb used to transmit data */ + /* Output buffer */ + unsigned char *bulk_out_buffer; + int bulk_out_size; + __u8 bulk_out_endpointAddr; + struct urb *bulk_out_urb; - /* Input buffer for command responses (M105: and data)*/ - int rcvbuf_size; /* the size of the receive buffer */ - struct urb *read_urb; /* the urb used to receive data */ - __u8 int_in_endpointAddr; /* the address of the bulk in endpoint */ + /* Input buffer */ + int rcvbuf_size; + struct urb *read_urb; + __u8 int_in_endpointAddr; - char bchars[6]; /* req. 0x19 */ + char bchars[6]; /* for request 0x19 */ }; struct usb_bc_state {}; @@ -157,19 +149,20 @@ static inline unsigned tiocm_to_gigaset(unsigned state) #ifdef CONFIG_GIGASET_UNDOCREQ /* WARNING: EXPERIMENTAL! */ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, - unsigned new_state) + unsigned new_state) { + struct usb_device *udev = cs->hw.usb->udev; unsigned mask, val; int r; mask = tiocm_to_gigaset(old_state ^ new_state); val = tiocm_to_gigaset(new_state); - dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask); - r = usb_control_msg(cs->hw.usb->udev, - usb_sndctrlpipe(cs->hw.usb->udev, 0), 7, 0x41, - (val & 0xff) | ((mask & 0xff) << 8), 0, - NULL, 0, 2000 /*timeout??*/); // don't use this in an interrupt/BH + gig_dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask); + // don't use this in an interrupt/BH + r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 7, 0x41, + (val & 0xff) | ((mask & 0xff) << 8), 0, + NULL, 0, 2000 /* timeout? */); if (r < 0) return r; //.. @@ -178,30 +171,29 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, static int set_value(struct cardstate *cs, u8 req, u16 val) { + struct usb_device *udev = cs->hw.usb->udev; int r, r2; - dbg(DEBUG_USBREQ, "request %02x (%04x)", (unsigned)req, (unsigned)val); - r = usb_control_msg(cs->hw.usb->udev, - usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x12, 0x41, - 0xf /*?*/, 0, - NULL, 0, 2000 /*?*/); /* no idea, what this does */ + gig_dbg(DEBUG_USBREQ, "request %02x (%04x)", + (unsigned)req, (unsigned)val); + r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x12, 0x41, + 0xf /*?*/, 0, NULL, 0, 2000 /*?*/); + /* no idea what this does */ if (r < 0) { - err("error %d on request 0x12", -r); + dev_err(&udev->dev, "error %d on request 0x12\n", -r); return r; } - r = usb_control_msg(cs->hw.usb->udev, - usb_sndctrlpipe(cs->hw.usb->udev, 0), req, 0x41, - val, 0, - NULL, 0, 2000 /*?*/); + r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), req, 0x41, + val, 0, NULL, 0, 2000 /*?*/); if (r < 0) - err("error %d on request 0x%02x", -r, (unsigned)req); + dev_err(&udev->dev, "error %d on request 0x%02x\n", + -r, (unsigned)req); - r2 = usb_control_msg(cs->hw.usb->udev, - usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41, - 0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/); + r2 = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, + 0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/); if (r2 < 0) - err("error %d on request 0x19", -r2); + dev_err(&udev->dev, "error %d on request 0x19\n", -r2); return r < 0 ? r : (r2 < 0 ? r2 : 0); } @@ -229,8 +221,8 @@ static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) case B115200: rate = 115200; break; default: rate = 9600; - err("unsupported baudrate request 0x%x," - " using default of B9600", cflag); + dev_err(cs->dev, "unsupported baudrate request 0x%x," + " using default of B9600\n", cflag); } val = 0x383fff / rate + 1; @@ -259,7 +251,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) case CS8: val |= 8 << 8; break; default: - err("CSIZE was not CS5-CS8, using default of 8"); + dev_err(cs->dev, "CSIZE was not CS5-CS8, using default of 8\n"); val |= 8 << 8; break; } @@ -277,7 +269,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) #else static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, - unsigned new_state) + unsigned new_state) { return -EINVAL; } @@ -309,15 +301,12 @@ static int gigaset_close_bchannel(struct bc_state *bcs) return 0; } -//void send_ack_to_LL(void *data); static int write_modem(struct cardstate *cs); static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb); -/* Handling of send queue. If there is already a skb opened, put data to - * the transfer buffer by calling "write_modem". Otherwise take a new skb out of the queue. - * This function will be called by the ISR via "transmit_chars" (USB: B-Channel Bulk callback handler - * via immediate task queue) or by writebuf_from_LL if the LL wants to transmit data. +/* Write tasklet handler: Continue sending current skb, or send command, or + * start sending an skb from the send queue. */ static void gigaset_modem_fill(unsigned long data) { @@ -327,10 +316,10 @@ static void gigaset_modem_fill(unsigned long data) unsigned long flags; int again; - dbg(DEBUG_OUTPUT, "modem_fill"); + gig_dbg(DEBUG_OUTPUT, "modem_fill"); if (atomic_read(&cs->hw.usb->busy)) { - dbg(DEBUG_OUTPUT, "modem_fill: busy"); + gig_dbg(DEBUG_OUTPUT, "modem_fill: busy"); return; } @@ -341,26 +330,27 @@ static void gigaset_modem_fill(unsigned long data) cb = cs->cmdbuf; spin_unlock_irqrestore(&cs->cmdlock, flags); if (cb) { /* commands to send? */ - dbg(DEBUG_OUTPUT, "modem_fill: cb"); + gig_dbg(DEBUG_OUTPUT, "modem_fill: cb"); if (send_cb(cs, cb) < 0) { - dbg(DEBUG_OUTPUT, - "modem_fill: send_cb failed"); - again = 1; /* no callback will be called! */ + gig_dbg(DEBUG_OUTPUT, + "modem_fill: send_cb failed"); + again = 1; /* no callback will be + called! */ } } else { /* skbs to send? */ bcs->tx_skb = skb_dequeue(&bcs->squeue); if (bcs->tx_skb) - dbg(DEBUG_INTR, - "Dequeued skb (Adr: %lx)!", - (unsigned long) bcs->tx_skb); + gig_dbg(DEBUG_INTR, + "Dequeued skb (Adr: %lx)!", + (unsigned long) bcs->tx_skb); } } if (bcs->tx_skb) { - dbg(DEBUG_OUTPUT, "modem_fill: tx_skb"); + gig_dbg(DEBUG_OUTPUT, "modem_fill: tx_skb"); if (write_modem(cs) < 0) { - dbg(DEBUG_OUTPUT, - "modem_fill: write_modem failed"); + gig_dbg(DEBUG_OUTPUT, + "modem_fill: write_modem failed"); // FIXME should we tell the LL? again = 1; /* no callback will be called! */ } @@ -371,88 +361,85 @@ static void gigaset_modem_fill(unsigned long data) /** * gigaset_read_int_callback * - * It is called if the data was received from the device. This is almost similiar to - * the interrupt service routine in the serial device. + * It is called if the data was received from the device. */ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs) { + struct inbuf_t *inbuf = urb->context; + struct cardstate *cs = inbuf->cs; int resubmit = 0; int r; - struct cardstate *cs; unsigned numbytes; unsigned char *src; - //unsigned long flags; - struct inbuf_t *inbuf; - - IFNULLRET(urb); - inbuf = (struct inbuf_t *) urb->context; - IFNULLRET(inbuf); - //spin_lock_irqsave(&inbuf->lock, flags); - cs = inbuf->cs; - IFNULLGOTO(cs, exit); - IFNULLGOTO(cardstate, exit); - - if (!atomic_read(&cs->connected)) { - err("%s: disconnected", __func__); - goto exit; - } + unsigned long flags; if (!urb->status) { + if (!cs->connected) { + err("%s: disconnected", __func__); /* should never happen */ + return; + } + numbytes = urb->actual_length; if (numbytes) { src = inbuf->rcvbuf; if (unlikely(*src)) - warn("%s: There was no leading 0, but 0x%02x!", - __func__, (unsigned) *src); + dev_warn(cs->dev, + "%s: There was no leading 0, but 0x%02x!\n", + __func__, (unsigned) *src); ++src; /* skip leading 0x00 */ --numbytes; if (gigaset_fill_inbuf(inbuf, src, numbytes)) { - dbg(DEBUG_INTR, "%s-->BH", __func__); + gig_dbg(DEBUG_INTR, "%s-->BH", __func__); gigaset_schedule_event(inbuf->cs); } } else - dbg(DEBUG_INTR, "Received zero block length"); + gig_dbg(DEBUG_INTR, "Received zero block length"); resubmit = 1; } else { /* The urb might have been killed. */ - dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d", - __func__, urb->status); - if (urb->status != -ENOENT) /* not killed */ + gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d", + __func__, urb->status); + if (urb->status != -ENOENT) { /* not killed */ + if (!cs->connected) { + err("%s: disconnected", __func__); /* should never happen */ + return; + } resubmit = 1; + } } -exit: - //spin_unlock_irqrestore(&inbuf->lock, flags); + if (resubmit) { - r = usb_submit_urb(urb, SLAB_ATOMIC); + spin_lock_irqsave(&cs->lock, flags); + r = cs->connected ? usb_submit_urb(urb, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&cs->lock, flags); if (r) - err("error %d when resubmitting urb.", -r); + dev_err(cs->dev, "error %d when resubmitting urb.\n", + -r); } } -/* This callback routine is called when data was transmitted to a B-Channel. - * Therefore it has to check if there is still data to transmit. This - * happens by calling modem_fill via task queue. - * - */ +/* This callback routine is called when data was transmitted to the device. */ static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs) { - struct cardstate *cs = (struct cardstate *) urb->context; + struct cardstate *cs = urb->context; + unsigned long flags; - IFNULLRET(cs); -#ifdef CONFIG_GIGASET_DEBUG - if (!atomic_read(&cs->connected)) { - err("%s:not connected", __func__); - return; - } -#endif if (urb->status) - err("bulk transfer failed (status %d)", -urb->status); /* That's all we can do. Communication problems - are handeled by timeouts or network protocols */ + dev_err(cs->dev, "bulk transfer failed (status %d)\n", + -urb->status); + /* That's all we can do. Communication problems + are handled by timeouts or network protocols. */ - atomic_set(&cs->hw.usb->busy, 0); - tasklet_schedule(&cs->write_tasklet); + spin_lock_irqsave(&cs->lock, flags); + if (!cs->connected) { + err("%s: not connected", __func__); + } else { + atomic_set(&cs->hw.usb->busy, 0); + tasklet_schedule(&cs->write_tasklet); + } + spin_unlock_irqrestore(&cs->lock, flags); } static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) @@ -469,8 +456,8 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) spin_lock_irqsave(&cs->cmdlock, flags); cs->cmdbytes -= cs->curlen; - dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left", - cs->curlen, cs->cmdbytes); + gig_dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left", + cs->curlen, cs->cmdbytes); cs->cmdbuf = cb = cb->next; if (cb) { cb->prev = NULL; @@ -487,52 +474,51 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) } if (cb) { count = min(cb->len, ucs->bulk_out_size); + gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count); + usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, - usb_sndbulkpipe(ucs->udev, - ucs->bulk_out_endpointAddr & 0x0f), - cb->buf + cb->offset, count, - gigaset_write_bulk_callback, cs); + usb_sndbulkpipe(ucs->udev, + ucs->bulk_out_endpointAddr & 0x0f), + cb->buf + cb->offset, count, + gigaset_write_bulk_callback, cs); cb->offset += count; cb->len -= count; atomic_set(&ucs->busy, 1); - dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count); - status = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); + spin_lock_irqsave(&cs->lock, flags); + status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC) : -ENODEV; + spin_unlock_irqrestore(&cs->lock, flags); + if (status) { atomic_set(&ucs->busy, 0); - err("could not submit urb (error %d).", + err("could not submit urb (error %d)\n", -status); - cb->len = 0; /* skip urb => remove cb+wakeup in next loop cycle */ + cb->len = 0; /* skip urb => remove cb+wakeup + in next loop cycle */ } } - } while (cb && status); /* bei Fehler naechster Befehl //FIXME: ist das OK? */ + } while (cb && status); /* next command on error */ return status; } -/* Write string into transbuf and send it to modem. - */ +/* Send command to device. */ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, - int len, struct tasklet_struct *wake_tasklet) + int len, struct tasklet_struct *wake_tasklet) { struct cmdbuf_t *cb; unsigned long flags; gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? - DEBUG_TRANSCMD : DEBUG_LOCKCMD, - "CMD Transmit", len, buf, 0); - - if (!atomic_read(&cs->connected)) { - err("%s: not connected", __func__); - return -ENODEV; - } + DEBUG_TRANSCMD : DEBUG_LOCKCMD, + "CMD Transmit", len, buf); if (len <= 0) return 0; if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) { - err("%s: out of memory", __func__); + dev_err(cs->dev, "%s: out of memory\n", __func__); return -ENOMEM; } @@ -554,7 +540,10 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, cs->lastcmdbuf = cb; spin_unlock_irqrestore(&cs->cmdlock, flags); - tasklet_schedule(&cs->write_tasklet); + spin_lock_irqsave(&cs->lock, flags); + if (cs->connected) + tasklet_schedule(&cs->write_tasklet); + spin_unlock_irqrestore(&cs->lock, flags); return len; } @@ -578,11 +567,12 @@ static int gigaset_chars_in_buffer(struct cardstate *cs) static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) { #ifdef CONFIG_GIGASET_UNDOCREQ - gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf, 0); + struct usb_device *udev = cs->hw.usb->udev; + + gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf); memcpy(cs->hw.usb->bchars, buf, 6); - return usb_control_msg(cs->hw.usb->udev, - usb_sndctrlpipe(cs->hw.usb->udev, 0), 0x19, 0x41, - 0, 0, &buf, 6, 2000); + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, + 0, 0, &buf, 6, 2000); #else return -EINVAL; #endif @@ -604,7 +594,6 @@ static int gigaset_initbcshw(struct bc_state *bcs) if (!bcs->hw.usb) return 0; - //bcs->hw.usb->trans_flg = READY_TO_TRNSMIT; /* B-Channel ready to transmit */ return 1; } @@ -614,7 +603,6 @@ static void gigaset_reinitbcshw(struct bc_state *bcs) static void gigaset_freecshw(struct cardstate *cs) { - //FIXME tasklet_kill(&cs->write_tasklet); kfree(cs->hw.usb); } @@ -639,33 +627,21 @@ static int gigaset_initcshw(struct cardstate *cs) //ucs->urb_cmd_out = NULL; ucs->read_urb = NULL; tasklet_init(&cs->write_tasklet, - &gigaset_modem_fill, (unsigned long) cs); + &gigaset_modem_fill, (unsigned long) cs); return 1; } -/* Writes the data of the current open skb into the modem. - * We have to protect against multiple calls until the - * callback handler () is called , due to the fact that we - * are just allowed to send data once to an endpoint. Therefore - * we using "trans_flg" to synchonize ... - */ +/* Send data from current skb to the device. */ static int write_modem(struct cardstate *cs) { - int ret; + int ret = 0; int count; struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ struct usb_cardstate *ucs = cs->hw.usb; - //unsigned long flags; + unsigned long flags; - IFNULLRETVAL(bcs->tx_skb, -EINVAL); - - dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len); - - ret = -ENODEV; - IFNULLGOTO(ucs->bulk_out_buffer, error); - IFNULLGOTO(ucs->bulk_out_urb, error); - ret = 0; + gig_dbg(DEBUG_WRITE, "len: %d...", bcs->tx_skb->len); if (!bcs->tx_skb->len) { dev_kfree_skb_any(bcs->tx_skb); @@ -679,40 +655,42 @@ static int write_modem(struct cardstate *cs) count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); memcpy(ucs->bulk_out_buffer, bcs->tx_skb->data, count); skb_pull(bcs->tx_skb, count); - - usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, - usb_sndbulkpipe(ucs->udev, - ucs->bulk_out_endpointAddr & 0x0f), - ucs->bulk_out_buffer, count, - gigaset_write_bulk_callback, cs); atomic_set(&ucs->busy, 1); - dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); + gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); + + spin_lock_irqsave(&cs->lock, flags); + if (cs->connected) { + usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, + usb_sndbulkpipe(ucs->udev, + ucs->bulk_out_endpointAddr & 0x0f), + ucs->bulk_out_buffer, count, + gigaset_write_bulk_callback, cs); + ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); + } else { + ret = -ENODEV; + } + spin_unlock_irqrestore(&cs->lock, flags); - ret = usb_submit_urb(ucs->bulk_out_urb, SLAB_ATOMIC); if (ret) { - err("could not submit urb (error %d).", -ret); + err("could not submit urb (error %d)\n", -ret); atomic_set(&ucs->busy, 0); } + if (!bcs->tx_skb->len) { /* skb sent completely */ gigaset_skb_sent(bcs, bcs->tx_skb); //FIXME also, when ret<0? - dbg(DEBUG_INTR, - "kfree skb (Adr: %lx)!", (unsigned long) bcs->tx_skb); + gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!", + (unsigned long) bcs->tx_skb); dev_kfree_skb_any(bcs->tx_skb); bcs->tx_skb = NULL; } return ret; -error: - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - return ret; - } static int gigaset_probe(struct usb_interface *interface, - const struct usb_device_id *id) + const struct usb_device_id *id) { int retval; struct usb_device *udev = interface_to_usbdev(interface); @@ -720,16 +698,14 @@ static int gigaset_probe(struct usb_interface *interface, struct usb_host_interface *hostif; struct cardstate *cs = NULL; struct usb_cardstate *ucs = NULL; - //struct usb_interface_descriptor *iface_desc; struct usb_endpoint_descriptor *endpoint; - //isdn_ctrl command; int buffer_size; int alt; - //unsigned long flags; - info("%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", - __func__, le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); + gig_dbg(DEBUG_ANY, + "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", + __func__, le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); retval = -ENODEV; //FIXME @@ -744,7 +720,7 @@ static int gigaset_probe(struct usb_interface *interface, ifnum = hostif->desc.bInterfaceNumber; // FIXME ? if (alt != 0 || ifnum != 0) { - warn("ifnum %d, alt %d", ifnum, alt); + dev_warn(&udev->dev, "ifnum %d, alt %d\n", ifnum, alt); return -ENODEV; } @@ -752,42 +728,29 @@ static int gigaset_probe(struct usb_interface *interface, * */ if (hostif->desc.bInterfaceClass != 255) { - info("%s: Device matched, but iface_desc[%d]->bInterfaceClass==%d !", - __func__, ifnum, hostif->desc.bInterfaceClass); + dev_info(&udev->dev, + "%s: Device matched but iface_desc[%d]->bInterfaceClass==%d!\n", + __func__, ifnum, hostif->desc.bInterfaceClass); return -ENODEV; } - info("%s: Device matched ... !", __func__); + dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); cs = gigaset_getunassignedcs(driver); if (!cs) { - warn("No free cardstate!"); + dev_warn(&udev->dev, "no free cardstate\n"); return -ENODEV; } ucs = cs->hw.usb; -#if 0 - if (usb_set_configuration(udev, udev->config[0].desc.bConfigurationValue) < 0) { - warn("set_configuration failed"); - goto error; - } + /* save off device structure ptrs for later use */ + usb_get_dev(udev); + ucs->udev = udev; + ucs->interface = interface; + cs->dev = &interface->dev; - - if (usb_set_interface(udev, ifnum/*==0*/, alt/*==0*/) < 0) { - warn("usb_set_interface failed, device %d interface %d altsetting %d", - udev->devnum, ifnum, alt); - goto error; - } -#endif - - /* set up the endpoint information */ - /* check out the endpoints */ - /* We will get 2 endpoints: One for sending commands to the device (bulk out) and one to - * poll messages from the device(int in). - * Therefore we will have an almost similiar situation as with our serial port handler. - * If an connection will be established, we will have to create data in/out pipes - * dynamically... - */ + /* save address of controller structure */ + usb_set_intfdata(interface, cs); // dev_set_drvdata(&interface->dev, cs); endpoint = &hostif->endpoint[0].desc; @@ -796,14 +759,14 @@ static int gigaset_probe(struct usb_interface *interface, ucs->bulk_out_endpointAddr = endpoint->bEndpointAddress; ucs->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!ucs->bulk_out_buffer) { - err("Couldn't allocate bulk_out_buffer"); + dev_err(cs->dev, "Couldn't allocate bulk_out_buffer\n"); retval = -ENOMEM; goto error; } ucs->bulk_out_urb = usb_alloc_urb(0, SLAB_KERNEL); if (!ucs->bulk_out_urb) { - err("Couldn't allocate bulk_out_buffer"); + dev_err(cs->dev, "Couldn't allocate bulk_out_urb\n"); retval = -ENOMEM; goto error; } @@ -811,12 +774,10 @@ static int gigaset_probe(struct usb_interface *interface, endpoint = &hostif->endpoint[1].desc; atomic_set(&ucs->busy, 0); - ucs->udev = udev; - ucs->interface = interface; ucs->read_urb = usb_alloc_urb(0, SLAB_KERNEL); if (!ucs->read_urb) { - err("No free urbs available"); + dev_err(cs->dev, "No free urbs available\n"); retval = -ENOMEM; goto error; } @@ -825,38 +786,33 @@ static int gigaset_probe(struct usb_interface *interface, ucs->int_in_endpointAddr = endpoint->bEndpointAddress; cs->inbuf[0].rcvbuf = kmalloc(buffer_size, GFP_KERNEL); if (!cs->inbuf[0].rcvbuf) { - err("Couldn't allocate rcvbuf"); + dev_err(cs->dev, "Couldn't allocate rcvbuf\n"); retval = -ENOMEM; goto error; } /* Fill the interrupt urb and send it to the core */ usb_fill_int_urb(ucs->read_urb, udev, - usb_rcvintpipe(udev, - endpoint->bEndpointAddress & 0x0f), - cs->inbuf[0].rcvbuf, buffer_size, - gigaset_read_int_callback, - cs->inbuf + 0, endpoint->bInterval); + usb_rcvintpipe(udev, + endpoint->bEndpointAddress & 0x0f), + cs->inbuf[0].rcvbuf, buffer_size, + gigaset_read_int_callback, + cs->inbuf + 0, endpoint->bInterval); retval = usb_submit_urb(ucs->read_urb, SLAB_KERNEL); if (retval) { - err("Could not submit URB!"); + dev_err(cs->dev, "Could not submit URB (error %d)\n", -retval); goto error; } /* tell common part that the device is ready */ if (startmode == SM_LOCKED) atomic_set(&cs->mstate, MS_LOCKED); + if (!gigaset_start(cs)) { tasklet_kill(&cs->write_tasklet); retval = -ENODEV; //FIXME goto error; } - - /* save address of controller structure */ - usb_set_intfdata(interface, cs); - - /* set up device sysfs */ - gigaset_init_dev_sysfs(interface); return 0; error: @@ -868,48 +824,45 @@ error: kfree(cs->inbuf[0].rcvbuf); if (ucs->read_urb != NULL) usb_free_urb(ucs->read_urb); + usb_set_intfdata(interface, NULL); ucs->read_urb = ucs->bulk_out_urb = NULL; cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; + usb_put_dev(ucs->udev); + ucs->udev = NULL; + ucs->interface = NULL; gigaset_unassign(cs); return retval; } -/** - * skel_disconnect - */ static void gigaset_disconnect(struct usb_interface *interface) { struct cardstate *cs; struct usb_cardstate *ucs; cs = usb_get_intfdata(interface); - - /* clear device sysfs */ - gigaset_free_dev_sysfs(interface); - - usb_set_intfdata(interface, NULL); ucs = cs->hw.usb; usb_kill_urb(ucs->read_urb); - //info("GigaSet USB device #%d will be disconnected", minor); gigaset_stop(cs); + usb_set_intfdata(interface, NULL); tasklet_kill(&cs->write_tasklet); - usb_kill_urb(ucs->bulk_out_urb); /* FIXME: nur, wenn noetig */ - //usb_kill_urb(ucs->urb_cmd_out); /* FIXME: nur, wenn noetig */ + usb_kill_urb(ucs->bulk_out_urb); /* FIXME: only if active? */ kfree(ucs->bulk_out_buffer); if (ucs->bulk_out_urb != NULL) usb_free_urb(ucs->bulk_out_urb); - //if(ucs->urb_cmd_out != NULL) - // usb_free_urb(ucs->urb_cmd_out); kfree(cs->inbuf[0].rcvbuf); if (ucs->read_urb != NULL) usb_free_urb(ucs->read_urb); - ucs->read_urb = ucs->bulk_out_urb/*=ucs->urb_cmd_out*/=NULL; + ucs->read_urb = ucs->bulk_out_urb = NULL; cs->inbuf[0].rcvbuf = ucs->bulk_out_buffer = NULL; + usb_put_dev(ucs->udev); + ucs->interface = NULL; + ucs->udev = NULL; + cs->dev = NULL; gigaset_unassign(cs); } @@ -942,9 +895,9 @@ static int __init usb_gigaset_init(void) /* allocate memory for our driver state and intialize it */ if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, - GIGASET_MODULENAME, GIGASET_DEVNAME, - GIGASET_DEVFSNAME, &ops, - THIS_MODULE)) == NULL) + GIGASET_MODULENAME, GIGASET_DEVNAME, + GIGASET_DEVFSNAME, &ops, + THIS_MODULE)) == NULL) goto error; /* allocate memory for our device state and intialize it */ @@ -981,8 +934,8 @@ error: if (cardstate) static void __exit usb_gigaset_exit(void) { gigaset_blockdriver(driver); /* => probe will fail - * => no gigaset_start any more - */ + * => no gigaset_start any more + */ gigaset_shutdown(cardstate); /* from now on, no isdn callback should be possible */ diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index 2a2b03ff096b..7bbfd85ab793 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c @@ -51,8 +51,8 @@ MODULE_LICENSE("GPL"); handler. */ -static void avmcs_config(dev_link_t *link); -static void avmcs_release(dev_link_t *link); +static int avmcs_config(struct pcmcia_device *link); +static void avmcs_release(struct pcmcia_device *link); /* The attach() and detach() entry points are used to create and destroy @@ -65,10 +65,10 @@ static void avmcs_detach(struct pcmcia_device *p_dev); /* A linked list of "instances" of the skeleton device. Each actual PCMCIA card corresponds to one device instance, and is described - by one dev_link_t structure (defined in ds.h). + by one struct pcmcia_device structure (defined in ds.h). You may not want to use a linked list for this -- for example, the - memory card driver uses an array of dev_link_t pointers, where minor + memory card driver uses an array of struct pcmcia_device pointers, where minor device numbers are used to derive the corresponding array index. */ @@ -78,7 +78,7 @@ static void avmcs_detach(struct pcmcia_device *p_dev); example, ethernet cards, modems). In other cases, there may be many actual or logical devices (SCSI adapters, memory cards with multiple partitions). The dev_node_t structures need to be kept - in a linked list starting at the 'dev' field of a dev_link_t + in a linked list starting at the 'dev' field of a struct pcmcia_device structure. We allocate them in the card's private data structure, because they generally can't be allocated dynamically. */ @@ -99,54 +99,38 @@ typedef struct local_info_t { ======================================================================*/ -static int avmcs_attach(struct pcmcia_device *p_dev) +static int avmcs_probe(struct pcmcia_device *p_dev) { - dev_link_t *link; local_info_t *local; - /* Initialize the dev_link_t structure */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) - goto err; - memset(link, 0, sizeof(struct dev_link_t)); - /* The io structure describes IO port mapping */ - link->io.NumPorts1 = 16; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.NumPorts2 = 0; + p_dev->io.NumPorts1 = 16; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.NumPorts2 = 0; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + + p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - /* General socket configuration */ - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; + p_dev->conf.Attributes = CONF_ENABLE_IRQ; + p_dev->conf.IntType = INT_MEMORY_AND_IO; + p_dev->conf.ConfigIndex = 1; + p_dev->conf.Present = PRESENT_OPTION; /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) - goto err_kfree; + goto err; memset(local, 0, sizeof(local_info_t)); - link->priv = local; + p_dev->priv = local; - link->handle = p_dev; - p_dev->instance = link; + return avmcs_config(p_dev); - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - avmcs_config(link); - - return 0; - - err_kfree: - kfree(link); err: - return -EINVAL; + return -ENOMEM; } /* avmcs_attach */ /*====================================================================== @@ -158,15 +142,10 @@ static int avmcs_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void avmcs_detach(struct pcmcia_device *p_dev) +static void avmcs_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - - if (link->state & DEV_CONFIG) avmcs_release(link); - - kfree(link->priv); - kfree(link); + kfree(link->priv); } /* avmcs_detach */ /*====================================================================== @@ -177,7 +156,7 @@ static void avmcs_detach(struct pcmcia_device *p_dev) ======================================================================*/ -static int get_tuple(client_handle_t handle, tuple_t *tuple, +static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_tuple_data(handle, tuple); @@ -185,7 +164,7 @@ static int get_tuple(client_handle_t handle, tuple_t *tuple, return pcmcia_parse_tuple(handle, tuple, parse); } -static int first_tuple(client_handle_t handle, tuple_t *tuple, +static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_first_tuple(handle, tuple); @@ -193,7 +172,7 @@ static int first_tuple(client_handle_t handle, tuple_t *tuple, return get_tuple(handle, tuple, parse); } -static int next_tuple(client_handle_t handle, tuple_t *tuple, +static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_next_tuple(handle, tuple); @@ -201,9 +180,8 @@ static int next_tuple(client_handle_t handle, tuple_t *tuple, return get_tuple(handle, tuple, parse); } -static void avmcs_config(dev_link_t *link) +static int avmcs_config(struct pcmcia_device *link) { - client_handle_t handle; tuple_t tuple; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; @@ -213,8 +191,7 @@ static void avmcs_config(dev_link_t *link) char devname[128]; int cardtype; int (*addcard)(unsigned int port, unsigned irq); - - handle = link->handle; + dev = link->priv; /* @@ -223,25 +200,21 @@ static void avmcs_config(dev_link_t *link) */ do { tuple.DesiredTuple = CISTPL_CONFIG; - i = pcmcia_get_first_tuple(handle, &tuple); + i = pcmcia_get_first_tuple(link, &tuple); if (i != CS_SUCCESS) break; tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - i = pcmcia_get_tuple_data(handle, &tuple); + i = pcmcia_get_tuple_data(link, &tuple); if (i != CS_SUCCESS) break; - i = pcmcia_parse_tuple(handle, &tuple, &parse); + i = pcmcia_parse_tuple(link, &tuple, &parse); if (i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; } while (0); if (i != CS_SUCCESS) { - cs_error(link->handle, ParseTuple, i); - link->state &= ~DEV_CONFIG_PENDING; - return; + cs_error(link, ParseTuple, i); + return -ENODEV; } - - /* Configure card */ - link->state |= DEV_CONFIG; do { @@ -252,7 +225,7 @@ static void avmcs_config(dev_link_t *link) tuple.DesiredTuple = CISTPL_VERS_1; devname[0] = 0; - if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { + if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) { strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], sizeof(devname)); } @@ -263,7 +236,7 @@ static void avmcs_config(dev_link_t *link) tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); while (i == CS_SUCCESS) { if (cf->io.nwin > 0) { link->conf.ConfigIndex = cf->index; @@ -273,36 +246,36 @@ static void avmcs_config(dev_link_t *link) printk(KERN_INFO "avm_cs: testing i/o %#x-%#x\n", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(link, &tuple, &parse); } found_port: if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); break; } - + /* * allocate an interrupt line */ - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); - pcmcia_release_io(link->handle, &link->io); + cs_error(link, RequestIRQ, i); + /* undo */ + pcmcia_disable_device(link); break; } - + /* * configure the PCMCIA socket */ - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); + cs_error(link, RequestConfiguration, i); + pcmcia_disable_device(link); break; } @@ -331,13 +304,12 @@ found_port: dev->node.major = 64; dev->node.minor = 0; - link->dev = &dev->node; - - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &dev->node; + /* If any step failed, release any partially configured state */ if (i != 0) { avmcs_release(link); - return; + return -ENODEV; } @@ -351,9 +323,10 @@ found_port: printk(KERN_ERR "avm_cs: failed to add AVM-%s-Controller at i/o %#x, irq %d\n", dev->node.dev_name, link->io.BasePort1, link->irq.AssignedIRQ); avmcs_release(link); - return; + return -ENODEV; } dev->node.minor = i; + return 0; } /* avmcs_config */ @@ -365,56 +338,12 @@ found_port: ======================================================================*/ -static void avmcs_release(dev_link_t *link) +static void avmcs_release(struct pcmcia_device *link) { - b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); - - /* Unlink the device chain */ - link->dev = NULL; - - /* Don't bother checking to see if these succeed or not */ - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + b1pcmcia_delcard(link->io.BasePort1, link->irq.AssignedIRQ); + pcmcia_disable_device(link); } /* avmcs_release */ -static int avmcs_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int avmcs_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; -} - -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. A CARD_REMOVAL event - also sets some flags to discourage the net drivers from trying - to talk to the card any more. - - When a CARD_REMOVAL event is received, we immediately set a flag - to block future accesses to this device. All the functions that - actually access the device should check this flag to make sure - the card is still present. - -======================================================================*/ - static struct pcmcia_device_id avmcs_ids[] = { PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335), @@ -429,11 +358,9 @@ static struct pcmcia_driver avmcs_driver = { .drv = { .name = "avm_cs", }, - .probe = avmcs_attach, + .probe = avmcs_probe, .remove = avmcs_detach, .id_table = avmcs_ids, - .suspend= avmcs_suspend, - .resume = avmcs_resume, }; static int __init avmcs_init(void) diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 969da40c4248..ac28e3278ad9 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c @@ -67,8 +67,8 @@ module_param(isdnprot, int, 0); handler. */ -static void avma1cs_config(dev_link_t *link); -static void avma1cs_release(dev_link_t *link); +static int avma1cs_config(struct pcmcia_device *link); +static void avma1cs_release(struct pcmcia_device *link); /* The attach() and detach() entry points are used to create and destroy @@ -82,10 +82,10 @@ static void avma1cs_detach(struct pcmcia_device *p_dev); /* A linked list of "instances" of the skeleton device. Each actual PCMCIA card corresponds to one device instance, and is described - by one dev_link_t structure (defined in ds.h). + by one struct pcmcia_device structure (defined in ds.h). You may not want to use a linked list for this -- for example, the - memory card driver uses an array of dev_link_t pointers, where minor + memory card driver uses an array of struct pcmcia_device pointers, where minor device numbers are used to derive the corresponding array index. */ @@ -95,7 +95,7 @@ static void avma1cs_detach(struct pcmcia_device *p_dev); example, ethernet cards, modems). In other cases, there may be many actual or logical devices (SCSI adapters, memory cards with multiple partitions). The dev_node_t structures need to be kept - in a linked list starting at the 'dev' field of a dev_link_t + in a linked list starting at the 'dev' field of a struct pcmcia_device structure. We allocate them in the card's private data structure, because they generally can't be allocated dynamically. */ @@ -116,55 +116,40 @@ typedef struct local_info_t { ======================================================================*/ -static int avma1cs_attach(struct pcmcia_device *p_dev) +static int avma1cs_probe(struct pcmcia_device *p_dev) { - dev_link_t *link; local_info_t *local; DEBUG(0, "avma1cs_attach()\n"); - /* Initialize the dev_link_t structure */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) - return -ENOMEM; - memset(link, 0, sizeof(struct dev_link_t)); - /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); - if (!local) { - kfree(link); + if (!local) return -ENOMEM; - } + memset(local, 0, sizeof(local_info_t)); - link->priv = local; + p_dev->priv = local; /* The io structure describes IO port mapping */ - link->io.NumPorts1 = 16; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.NumPorts2 = 16; - link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; - link->io.IOAddrLines = 5; + p_dev->io.NumPorts1 = 16; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.NumPorts2 = 16; + p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_16; + p_dev->io.IOAddrLines = 5; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; /* General socket configuration */ - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; + p_dev->conf.Attributes = CONF_ENABLE_IRQ; + p_dev->conf.IntType = INT_MEMORY_AND_IO; + p_dev->conf.ConfigIndex = 1; + p_dev->conf.Present = PRESENT_OPTION; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - avma1cs_config(link); - - return 0; + return avma1cs_config(p_dev); } /* avma1cs_attach */ /*====================================================================== @@ -176,17 +161,11 @@ static int avma1cs_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void avma1cs_detach(struct pcmcia_device *p_dev) +static void avma1cs_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - - DEBUG(0, "avma1cs_detach(0x%p)\n", link); - - if (link->state & DEV_CONFIG) - avma1cs_release(link); - - kfree(link->priv); - kfree(link); + DEBUG(0, "avma1cs_detach(0x%p)\n", link); + avma1cs_release(link); + kfree(link->priv); } /* avma1cs_detach */ /*====================================================================== @@ -197,7 +176,7 @@ static void avma1cs_detach(struct pcmcia_device *p_dev) ======================================================================*/ -static int get_tuple(client_handle_t handle, tuple_t *tuple, +static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_tuple_data(handle, tuple); @@ -205,7 +184,7 @@ static int get_tuple(client_handle_t handle, tuple_t *tuple, return pcmcia_parse_tuple(handle, tuple, parse); } -static int first_tuple(client_handle_t handle, tuple_t *tuple, +static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_first_tuple(handle, tuple); @@ -213,7 +192,7 @@ static int first_tuple(client_handle_t handle, tuple_t *tuple, return get_tuple(handle, tuple, parse); } -static int next_tuple(client_handle_t handle, tuple_t *tuple, +static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_next_tuple(handle, tuple); @@ -221,9 +200,8 @@ static int next_tuple(client_handle_t handle, tuple_t *tuple, return get_tuple(handle, tuple, parse); } -static void avma1cs_config(dev_link_t *link) +static int avma1cs_config(struct pcmcia_device *link) { - client_handle_t handle; tuple_t tuple; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; @@ -233,8 +211,7 @@ static void avma1cs_config(dev_link_t *link) char devname[128]; IsdnCard_t icard; int busy = 0; - - handle = link->handle; + dev = link->priv; DEBUG(0, "avma1cs_config(0x%p)\n", link); @@ -245,25 +222,21 @@ static void avma1cs_config(dev_link_t *link) */ do { tuple.DesiredTuple = CISTPL_CONFIG; - i = pcmcia_get_first_tuple(handle, &tuple); + i = pcmcia_get_first_tuple(link, &tuple); if (i != CS_SUCCESS) break; tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - i = pcmcia_get_tuple_data(handle, &tuple); + i = pcmcia_get_tuple_data(link, &tuple); if (i != CS_SUCCESS) break; - i = pcmcia_parse_tuple(handle, &tuple, &parse); + i = pcmcia_parse_tuple(link, &tuple, &parse); if (i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; } while (0); if (i != CS_SUCCESS) { - cs_error(link->handle, ParseTuple, i); - link->state &= ~DEV_CONFIG_PENDING; - return; + cs_error(link, ParseTuple, i); + return -ENODEV; } - - /* Configure card */ - link->state |= DEV_CONFIG; do { @@ -274,7 +247,7 @@ static void avma1cs_config(dev_link_t *link) tuple.DesiredTuple = CISTPL_VERS_1; devname[0] = 0; - if( !first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 1 ) { + if( !first_tuple(link, &tuple, &parse) && parse.version_1.ns > 1 ) { strlcpy(devname,parse.version_1.str + parse.version_1.ofs[1], sizeof(devname)); } @@ -285,7 +258,7 @@ static void avma1cs_config(dev_link_t *link) tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); while (i == CS_SUCCESS) { if (cf->io.nwin > 0) { link->conf.ConfigIndex = cf->index; @@ -295,36 +268,36 @@ static void avma1cs_config(dev_link_t *link) printk(KERN_INFO "avma1_cs: testing i/o %#x-%#x\n", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1 - 1); - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(link, &tuple, &parse); } found_port: if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); break; } /* * allocate an interrupt line */ - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); - pcmcia_release_io(link->handle, &link->io); + cs_error(link, RequestIRQ, i); + /* undo */ + pcmcia_disable_device(link); break; } - + /* * configure the PCMCIA socket */ - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); + cs_error(link, RequestConfiguration, i); + pcmcia_disable_device(link); break; } @@ -336,13 +309,12 @@ found_port: strcpy(dev->node.dev_name, "A1"); dev->node.major = 45; dev->node.minor = 0; - link->dev = &dev->node; - - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &dev->node; + /* If any step failed, release any partially configured state */ if (i != 0) { avma1cs_release(link); - return; + return -ENODEV; } printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n", @@ -357,10 +329,11 @@ found_port: if (i < 0) { printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 PCMCIA %d at i/o %#x\n", i, link->io.BasePort1); avma1cs_release(link); - return; + return -ENODEV; } dev->node.minor = i; + return 0; } /* avma1cs_config */ /*====================================================================== @@ -371,47 +344,18 @@ found_port: ======================================================================*/ -static void avma1cs_release(dev_link_t *link) +static void avma1cs_release(struct pcmcia_device *link) { - local_info_t *local = link->priv; + local_info_t *local = link->priv; - DEBUG(0, "avma1cs_release(0x%p)\n", link); + DEBUG(0, "avma1cs_release(0x%p)\n", link); - /* no unregister function with hisax */ - HiSax_closecard(local->node.minor); + /* now unregister function with hisax */ + HiSax_closecard(local->node.minor); - /* Unlink the device chain */ - link->dev = NULL; - - /* Don't bother checking to see if these succeed or not */ - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } /* avma1cs_release */ -static int avma1cs_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int avma1cs_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; -} - static struct pcmcia_device_id avma1cs_ids[] = { PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), @@ -425,13 +369,11 @@ static struct pcmcia_driver avma1cs_driver = { .drv = { .name = "avma1_cs", }, - .probe = avma1cs_attach, + .probe = avma1cs_probe, .remove = avma1cs_detach, .id_table = avma1cs_ids, - .suspend = avma1cs_suspend, - .resume = avma1cs_resume, }; - + /*====================================================================*/ static int __init init_avma1_cs(void) diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 062fb8f0739f..e18e75be8ed3 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c @@ -94,8 +94,8 @@ module_param(protocol, int, 0); handler. */ -static void elsa_cs_config(dev_link_t *link); -static void elsa_cs_release(dev_link_t *link); +static int elsa_cs_config(struct pcmcia_device *link); +static void elsa_cs_release(struct pcmcia_device *link); /* The attach() and detach() entry points are used to create and destroy @@ -111,7 +111,7 @@ static void elsa_cs_detach(struct pcmcia_device *p_dev); example, ethernet cards, modems). In other cases, there may be many actual or logical devices (SCSI adapters, memory cards with multiple partitions). The dev_node_t structures need to be kept - in a linked list starting at the 'dev' field of a dev_link_t + in a linked list starting at the 'dev' field of a struct pcmcia_device structure. We allocate them in the card's private data structure, because they generally shouldn't be allocated dynamically. In this case, we also provide a flag to indicate if a device is @@ -121,7 +121,7 @@ static void elsa_cs_detach(struct pcmcia_device *p_dev); */ typedef struct local_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; int busy; int cardnr; @@ -139,9 +139,8 @@ typedef struct local_info_t { ======================================================================*/ -static int elsa_cs_attach(struct pcmcia_device *p_dev) +static int elsa_cs_probe(struct pcmcia_device *link) { - dev_link_t *link; local_info_t *local; DEBUG(0, "elsa_cs_attach()\n"); @@ -150,8 +149,11 @@ static int elsa_cs_attach(struct pcmcia_device *p_dev) local = kmalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) return -ENOMEM; memset(local, 0, sizeof(local_info_t)); + + local->p_dev = link; + link->priv = local; + local->cardnr = -1; - link = &local->link; link->priv = local; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; @@ -170,16 +172,9 @@ static int elsa_cs_attach(struct pcmcia_device *p_dev) link->io.IOAddrLines = 3; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - elsa_cs_config(link); - - return 0; + return elsa_cs_config(link); } /* elsa_cs_attach */ /*====================================================================== @@ -191,20 +186,16 @@ static int elsa_cs_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void elsa_cs_detach(struct pcmcia_device *p_dev) +static void elsa_cs_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - local_info_t *info = link->priv; + local_info_t *info = link->priv; - DEBUG(0, "elsa_cs_detach(0x%p)\n", link); + DEBUG(0, "elsa_cs_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) { - info->busy = 1; - elsa_cs_release(link); - } - - kfree(info); + info->busy = 1; + elsa_cs_release(link); + kfree(info); } /* elsa_cs_detach */ /*====================================================================== @@ -214,7 +205,7 @@ static void elsa_cs_detach(struct pcmcia_device *p_dev) device available to the system. ======================================================================*/ -static int get_tuple(client_handle_t handle, tuple_t *tuple, +static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_tuple_data(handle, tuple); @@ -222,7 +213,7 @@ static int get_tuple(client_handle_t handle, tuple_t *tuple, return pcmcia_parse_tuple(handle, tuple, parse); } -static int first_tuple(client_handle_t handle, tuple_t *tuple, +static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_first_tuple(handle, tuple); @@ -230,7 +221,7 @@ static int first_tuple(client_handle_t handle, tuple_t *tuple, return get_tuple(handle, tuple, parse); } -static int next_tuple(client_handle_t handle, tuple_t *tuple, +static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_next_tuple(handle, tuple); @@ -238,9 +229,8 @@ static int next_tuple(client_handle_t handle, tuple_t *tuple, return get_tuple(handle, tuple, parse); } -static void elsa_cs_config(dev_link_t *link) +static int elsa_cs_config(struct pcmcia_device *link) { - client_handle_t handle; tuple_t tuple; cisparse_t parse; local_info_t *dev; @@ -250,7 +240,6 @@ static void elsa_cs_config(dev_link_t *link) IsdnCard_t icard; DEBUG(0, "elsa_config(0x%p)\n", link); - handle = link->handle; dev = link->priv; /* @@ -262,7 +251,7 @@ static void elsa_cs_config(dev_link_t *link) tuple.TupleDataMax = 255; tuple.TupleOffset = 0; tuple.Attributes = 0; - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); if (i != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; @@ -270,32 +259,29 @@ static void elsa_cs_config(dev_link_t *link) link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); while (i == CS_SUCCESS) { if ( (cf->io.nwin > 0) && cf->io.win[0].base) { printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n"); link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } else { printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n"); link->conf.ConfigIndex = cf->index; for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) { link->io.BasePort1 = j; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } break; } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(link, &tuple, &parse); } if (i != CS_SUCCESS) { @@ -303,14 +289,14 @@ static void elsa_cs_config(dev_link_t *link) goto cs_failed; } - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { link->irq.AssignedIRQ = 0; last_fn = RequestIRQ; goto cs_failed; } - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { last_fn = RequestConfiguration; goto cs_failed; @@ -321,14 +307,11 @@ static void elsa_cs_config(dev_link_t *link) sprintf(dev->node.dev_name, "elsa"); dev->node.major = dev->node.minor = 0x0; - link->dev = &dev->node; + link->dev_node = &dev->node; /* Finally, report what we've done */ - printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", - dev->node.dev_name, link->conf.ConfigIndex, - link->conf.Vcc/10, link->conf.Vcc%10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + printk(KERN_INFO "%s: index 0x%02x: ", + dev->node.dev_name, link->conf.ConfigIndex); if (link->conf.Attributes & CONF_ENABLE_IRQ) printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) @@ -339,8 +322,6 @@ static void elsa_cs_config(dev_link_t *link) link->io.BasePort2+link->io.NumPorts2-1); printk("\n"); - link->state &= ~DEV_CONFIG_PENDING; - icard.para[0] = link->irq.AssignedIRQ; icard.para[1] = link->io.BasePort1; icard.protocol = protocol; @@ -354,10 +335,11 @@ static void elsa_cs_config(dev_link_t *link) } else ((local_info_t*)link->priv)->cardnr = i; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, i); + cs_error(link, last_fn, i); elsa_cs_release(link); + return -ENODEV; } /* elsa_cs_config */ /*====================================================================== @@ -368,7 +350,7 @@ cs_failed: ======================================================================*/ -static void elsa_cs_release(dev_link_t *link) +static void elsa_cs_release(struct pcmcia_device *link) { local_info_t *local = link->priv; @@ -380,39 +362,23 @@ static void elsa_cs_release(dev_link_t *link) HiSax_closecard(local->cardnr); } } - /* Unlink the device chain */ - link->dev = NULL; - /* Don't bother checking to see if these succeed or not */ - if (link->win) - pcmcia_release_window(link->win); - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } /* elsa_cs_release */ -static int elsa_suspend(struct pcmcia_device *p_dev) +static int elsa_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); local_info_t *dev = link->priv; - link->state |= DEV_SUSPEND; dev->busy = 1; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); return 0; } -static int elsa_resume(struct pcmcia_device *p_dev) +static int elsa_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); local_info_t *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); dev->busy = 0; return 0; @@ -430,7 +396,7 @@ static struct pcmcia_driver elsa_cs_driver = { .drv = { .name = "elsa_cs", }, - .probe = elsa_cs_attach, + .probe = elsa_cs_probe, .remove = elsa_cs_detach, .id_table = elsa_ids, .suspend = elsa_suspend, diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index 6f5213a18a8d..9bb18f3f7829 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -95,8 +95,8 @@ module_param(protocol, int, 0); event handler. */ -static void sedlbauer_config(dev_link_t *link); -static void sedlbauer_release(dev_link_t *link); +static int sedlbauer_config(struct pcmcia_device *link); +static void sedlbauer_release(struct pcmcia_device *link); /* The attach() and detach() entry points are used to create and destroy @@ -119,7 +119,7 @@ static void sedlbauer_detach(struct pcmcia_device *p_dev); example, ethernet cards, modems). In other cases, there may be many actual or logical devices (SCSI adapters, memory cards with multiple partitions). The dev_node_t structures need to be kept - in a linked list starting at the 'dev' field of a dev_link_t + in a linked list starting at the 'dev' field of a struct pcmcia_device structure. We allocate them in the card's private data structure, because they generally shouldn't be allocated dynamically. @@ -130,7 +130,7 @@ static void sedlbauer_detach(struct pcmcia_device *p_dev); */ typedef struct local_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; int stop; int cardnr; @@ -148,11 +148,10 @@ typedef struct local_info_t { ======================================================================*/ -static int sedlbauer_attach(struct pcmcia_device *p_dev) +static int sedlbauer_probe(struct pcmcia_device *link) { local_info_t *local; - dev_link_t *link; - + DEBUG(0, "sedlbauer_attach()\n"); /* Allocate space for private device-specific data */ @@ -160,8 +159,10 @@ static int sedlbauer_attach(struct pcmcia_device *p_dev) if (!local) return -ENOMEM; memset(local, 0, sizeof(local_info_t)); local->cardnr = -1; - link = &local->link; link->priv = local; - + + local->p_dev = link; + link->priv = local; + /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; @@ -182,18 +183,10 @@ static int sedlbauer_attach(struct pcmcia_device *p_dev) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.IOAddrLines = 3; - link->conf.Attributes = 0; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - sedlbauer_config(link); - - return 0; + return sedlbauer_config(link); } /* sedlbauer_attach */ /*====================================================================== @@ -205,19 +198,15 @@ static int sedlbauer_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void sedlbauer_detach(struct pcmcia_device *p_dev) +static void sedlbauer_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); + DEBUG(0, "sedlbauer_detach(0x%p)\n", link); - DEBUG(0, "sedlbauer_detach(0x%p)\n", link); + ((local_info_t *)link->priv)->stop = 1; + sedlbauer_release(link); - if (link->state & DEV_CONFIG) { - ((local_info_t *)link->priv)->stop = 1; - sedlbauer_release(link); - } - - /* This points to the parent local_info_t struct */ - kfree(link->priv); + /* This points to the parent local_info_t struct */ + kfree(link->priv); } /* sedlbauer_detach */ /*====================================================================== @@ -230,9 +219,8 @@ static void sedlbauer_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void sedlbauer_config(dev_link_t *link) +static int sedlbauer_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; local_info_t *dev = link->priv; tuple_t tuple; cisparse_t parse; @@ -254,18 +242,13 @@ static void sedlbauer_config(dev_link_t *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - - /* Configure card */ - link->state |= DEV_CONFIG; - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); /* In this loop, we scan the CIS for configuration table entries, @@ -280,12 +263,12 @@ static void sedlbauer_config(dev_link_t *link) will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; @@ -309,10 +292,10 @@ static void sedlbauer_config(dev_link_t *link) } if (cfg->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; /* Do we need to allocate an interrupt? */ @@ -339,13 +322,13 @@ static void sedlbauer_config(dev_link_t *link) link->io.NumPorts2 = io->win[1].len; } /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; } /* Now set up a common memory window, if needed. There is room - in the dev_link_t structure for one memory window handle, + in the struct pcmcia_device structure for one memory window handle, but if the base addresses need to be saved, or if multiple windows are needed, the info should go in the private data structure for this device. @@ -366,7 +349,7 @@ static void sedlbauer_config(dev_link_t *link) req.Size = 0x1000; */ req.AccessSpeed = 0; - if (pcmcia_request_window(&link->handle, &req, &link->win) != 0) + if (pcmcia_request_window(&link, &req, &link->win) != 0) goto next_entry; map.Page = 0; map.CardOffset = mem->win[0].card_addr; if (pcmcia_map_mem_page(link->win, &map) != 0) @@ -374,29 +357,25 @@ static void sedlbauer_config(dev_link_t *link) } /* If we got this far, we're cool! */ break; - + next_entry: -/* new in dummy.cs 2001/01/28 MN - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); -*/ - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } - + /* Allocate an interrupt line. Note that this does not assign a handler to the interrupt, unless the 'Handler' member of the irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); /* At this point, the dev_node_t structure(s) need to be @@ -404,14 +383,13 @@ static void sedlbauer_config(dev_link_t *link) */ sprintf(dev->node.dev_name, "sedlbauer"); dev->node.major = dev->node.minor = 0; - link->dev = &dev->node; + link->dev_node = &dev->node; /* Finally, report what we've done */ - printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", - dev->node.dev_name, link->conf.ConfigIndex, - link->conf.Vcc/10, link->conf.Vcc%10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + printk(KERN_INFO "%s: index 0x%02x:", + dev->node.dev_name, link->conf.ConfigIndex); + if (link->conf.Vpp) + printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); if (link->conf.Attributes & CONF_ENABLE_IRQ) printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) @@ -424,8 +402,6 @@ static void sedlbauer_config(dev_link_t *link) printk(", mem 0x%06lx-0x%06lx", req.Base, req.Base+req.Size-1); printk("\n"); - - link->state &= ~DEV_CONFIG_PENDING; icard.para[0] = link->irq.AssignedIRQ; icard.para[1] = link->io.BasePort1; @@ -437,14 +413,16 @@ static void sedlbauer_config(dev_link_t *link) printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d at i/o %#x\n", last_ret, link->io.BasePort1); sedlbauer_release(link); + return -ENODEV; } else ((local_info_t*)link->priv)->cardnr = last_ret; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); sedlbauer_release(link); + return -ENODEV; } /* sedlbauer_config */ @@ -456,7 +434,7 @@ cs_failed: ======================================================================*/ -static void sedlbauer_release(dev_link_t *link) +static void sedlbauer_release(struct pcmcia_device *link) { local_info_t *local = link->priv; DEBUG(0, "sedlbauer_release(0x%p)\n", link); @@ -467,46 +445,23 @@ static void sedlbauer_release(dev_link_t *link) HiSax_closecard(local->cardnr); } } - /* Unlink the device chain */ - link->dev = NULL; - /* - In a normal driver, additional code may be needed to release - other kernel data structures associated with this device. - */ - - /* Don't bother checking to see if these succeed or not */ - if (link->win) - pcmcia_release_window(link->win); - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - if (link->irq.AssignedIRQ) - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } /* sedlbauer_release */ -static int sedlbauer_suspend(struct pcmcia_device *p_dev) +static int sedlbauer_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); local_info_t *dev = link->priv; - link->state |= DEV_SUSPEND; dev->stop = 1; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); return 0; } -static int sedlbauer_resume(struct pcmcia_device *p_dev) +static int sedlbauer_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); local_info_t *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); dev->stop = 0; return 0; @@ -530,7 +485,7 @@ static struct pcmcia_driver sedlbauer_driver = { .drv = { .name = "sedlbauer_cs", }, - .probe = sedlbauer_attach, + .probe = sedlbauer_probe, .remove = sedlbauer_detach, .id_table = sedlbauer_ids, .suspend = sedlbauer_suspend, diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 4e5c14c7240e..afcc2aeadb34 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -75,8 +75,8 @@ module_param(protocol, int, 0); handler. */ -static void teles_cs_config(dev_link_t *link); -static void teles_cs_release(dev_link_t *link); +static int teles_cs_config(struct pcmcia_device *link); +static void teles_cs_release(struct pcmcia_device *link); /* The attach() and detach() entry points are used to create and destroy @@ -89,10 +89,10 @@ static void teles_detach(struct pcmcia_device *p_dev); /* A linked list of "instances" of the teles_cs device. Each actual PCMCIA card corresponds to one device instance, and is described - by one dev_link_t structure (defined in ds.h). + by one struct pcmcia_device structure (defined in ds.h). You may not want to use a linked list for this -- for example, the - memory card driver uses an array of dev_link_t pointers, where minor + memory card driver uses an array of struct pcmcia_device pointers, where minor device numbers are used to derive the corresponding array index. */ @@ -102,7 +102,7 @@ static void teles_detach(struct pcmcia_device *p_dev); example, ethernet cards, modems). In other cases, there may be many actual or logical devices (SCSI adapters, memory cards with multiple partitions). The dev_node_t structures need to be kept - in a linked list starting at the 'dev' field of a dev_link_t + in a linked list starting at the 'dev' field of a struct pcmcia_device structure. We allocate them in the card's private data structure, because they generally shouldn't be allocated dynamically. In this case, we also provide a flag to indicate if a device is @@ -112,7 +112,7 @@ static void teles_detach(struct pcmcia_device *p_dev); */ typedef struct local_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; int busy; int cardnr; @@ -130,9 +130,8 @@ typedef struct local_info_t { ======================================================================*/ -static int teles_attach(struct pcmcia_device *p_dev) +static int teles_probe(struct pcmcia_device *link) { - dev_link_t *link; local_info_t *local; DEBUG(0, "teles_attach()\n"); @@ -142,7 +141,9 @@ static int teles_attach(struct pcmcia_device *p_dev) if (!local) return -ENOMEM; memset(local, 0, sizeof(local_info_t)); local->cardnr = -1; - link = &local->link; link->priv = local; + + local->p_dev = link; + link->priv = local; /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; @@ -161,16 +162,9 @@ static int teles_attach(struct pcmcia_device *p_dev) link->io.IOAddrLines = 5; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - teles_cs_config(link); - - return 0; + return teles_cs_config(link); } /* teles_attach */ /*====================================================================== @@ -182,20 +176,16 @@ static int teles_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void teles_detach(struct pcmcia_device *p_dev) +static void teles_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - local_info_t *info = link->priv; + local_info_t *info = link->priv; - DEBUG(0, "teles_detach(0x%p)\n", link); + DEBUG(0, "teles_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) { - info->busy = 1; - teles_cs_release(link); - } - - kfree(info); + info->busy = 1; + teles_cs_release(link); + kfree(info); } /* teles_detach */ /*====================================================================== @@ -205,7 +195,7 @@ static void teles_detach(struct pcmcia_device *p_dev) device available to the system. ======================================================================*/ -static int get_tuple(client_handle_t handle, tuple_t *tuple, +static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_tuple_data(handle, tuple); @@ -213,7 +203,7 @@ static int get_tuple(client_handle_t handle, tuple_t *tuple, return pcmcia_parse_tuple(handle, tuple, parse); } -static int first_tuple(client_handle_t handle, tuple_t *tuple, +static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_first_tuple(handle, tuple); @@ -221,7 +211,7 @@ static int first_tuple(client_handle_t handle, tuple_t *tuple, return get_tuple(handle, tuple, parse); } -static int next_tuple(client_handle_t handle, tuple_t *tuple, +static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i = pcmcia_get_next_tuple(handle, tuple); @@ -229,9 +219,8 @@ static int next_tuple(client_handle_t handle, tuple_t *tuple, return get_tuple(handle, tuple, parse); } -static void teles_cs_config(dev_link_t *link) +static int teles_cs_config(struct pcmcia_device *link) { - client_handle_t handle; tuple_t tuple; cisparse_t parse; local_info_t *dev; @@ -241,7 +230,6 @@ static void teles_cs_config(dev_link_t *link) IsdnCard_t icard; DEBUG(0, "teles_config(0x%p)\n", link); - handle = link->handle; dev = link->priv; /* @@ -253,7 +241,7 @@ static void teles_cs_config(dev_link_t *link) tuple.TupleDataMax = 255; tuple.TupleOffset = 0; tuple.Attributes = 0; - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); if (i != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; @@ -261,32 +249,29 @@ static void teles_cs_config(dev_link_t *link) link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - i = first_tuple(handle, &tuple, &parse); + i = first_tuple(link, &tuple, &parse); while (i == CS_SUCCESS) { if ( (cf->io.nwin > 0) && cf->io.win[0].base) { printk(KERN_INFO "(teles_cs: looks like the 96 model)\n"); link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } else { printk(KERN_INFO "(teles_cs: looks like the 97 model)\n"); link->conf.ConfigIndex = cf->index; for (i = 0, j = 0x2f0; j > 0x100; j -= 0x10) { link->io.BasePort1 = j; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } break; } - i = next_tuple(handle, &tuple, &parse); + i = next_tuple(link, &tuple, &parse); } if (i != CS_SUCCESS) { @@ -294,14 +279,14 @@ static void teles_cs_config(dev_link_t *link) goto cs_failed; } - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { link->irq.AssignedIRQ = 0; last_fn = RequestIRQ; goto cs_failed; } - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { last_fn = RequestConfiguration; goto cs_failed; @@ -312,14 +297,11 @@ static void teles_cs_config(dev_link_t *link) sprintf(dev->node.dev_name, "teles"); dev->node.major = dev->node.minor = 0x0; - link->dev = &dev->node; + link->dev_node = &dev->node; /* Finally, report what we've done */ - printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", - dev->node.dev_name, link->conf.ConfigIndex, - link->conf.Vcc/10, link->conf.Vcc%10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + printk(KERN_INFO "%s: index 0x%02x:", + dev->node.dev_name, link->conf.ConfigIndex); if (link->conf.Attributes & CONF_ENABLE_IRQ) printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) @@ -330,8 +312,6 @@ static void teles_cs_config(dev_link_t *link) link->io.BasePort2+link->io.NumPorts2-1); printk("\n"); - link->state &= ~DEV_CONFIG_PENDING; - icard.para[0] = link->irq.AssignedIRQ; icard.para[1] = link->io.BasePort1; icard.protocol = protocol; @@ -342,13 +322,16 @@ static void teles_cs_config(dev_link_t *link) printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n", i, link->io.BasePort1); teles_cs_release(link); - } else - ((local_info_t*)link->priv)->cardnr = i; + return -ENODEV; + } + + ((local_info_t*)link->priv)->cardnr = i; + return 0; - return; cs_failed: - cs_error(link->handle, last_fn, i); + cs_error(link, last_fn, i); teles_cs_release(link); + return -ENODEV; } /* teles_cs_config */ /*====================================================================== @@ -359,7 +342,7 @@ cs_failed: ======================================================================*/ -static void teles_cs_release(dev_link_t *link) +static void teles_cs_release(struct pcmcia_device *link) { local_info_t *local = link->priv; @@ -371,39 +354,23 @@ static void teles_cs_release(dev_link_t *link) HiSax_closecard(local->cardnr); } } - /* Unlink the device chain */ - link->dev = NULL; - /* Don't bother checking to see if these succeed or not */ - if (link->win) - pcmcia_release_window(link->win); - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } /* teles_cs_release */ -static int teles_suspend(struct pcmcia_device *p_dev) +static int teles_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); local_info_t *dev = link->priv; - link->state |= DEV_SUSPEND; dev->busy = 1; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); return 0; } -static int teles_resume(struct pcmcia_device *p_dev) +static int teles_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); local_info_t *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); dev->busy = 0; return 0; @@ -421,7 +388,7 @@ static struct pcmcia_driver teles_cs_driver = { .drv = { .name = "teles_cs", }, - .probe = teles_attach, + .probe = teles_probe, .remove = teles_detach, .id_table = teles_ids, .suspend = teles_suspend, diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index a0927d1b7a0c..918742271c79 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -109,7 +109,7 @@ isdn_ppp_free(isdn_net_local * lp) { struct ippp_struct *is; - if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) { + if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", __FUNCTION__, lp->ppp_slot); return 0; @@ -126,7 +126,7 @@ isdn_ppp_free(isdn_net_local * lp) lp->netdev->pb->ref_ct--; spin_unlock(&lp->netdev->pb->lock); #endif /* CONFIG_ISDN_MPP */ - if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) { + if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n", __FUNCTION__, lp->ppp_slot); return 0; @@ -279,7 +279,7 @@ isdn_ppp_open(int min, struct file *file) int slot; struct ippp_struct *is; - if (min < 0 || min > ISDN_MAX_CHANNELS) + if (min < 0 || min >= ISDN_MAX_CHANNELS) return -ENODEV; slot = isdn_ppp_get_slot(); @@ -1042,7 +1042,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff if (lp->master) { // FIXME? mlp = (isdn_net_local *) lp->master->priv; slot = mlp->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n", lp->ppp_slot); goto drop_packet; @@ -1264,7 +1264,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) /* we have our lp locked from now on */ slot = lp->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", lp->ppp_slot); kfree_skb(skb); @@ -1603,7 +1603,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, mp = net_dev->pb; stats = &mp->stats; slot = lp->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d)\n", __FUNCTION__, lp->ppp_slot); stats->frame_drops++; @@ -1640,7 +1640,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, is->last_link_seqno = minseq = newseq; for (lpq = net_dev->queue;;) { slot = lpq->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n", __FUNCTION__, lpq->ppp_slot); } else { @@ -2648,7 +2648,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n", lp->ppp_slot); - if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) { + if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", __FUNCTION__, lp->ppp_slot); return; @@ -2658,7 +2658,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, if(lp->master) { int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", __FUNCTION__, slot); return; @@ -2845,7 +2845,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct if (lp->master) { slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; - if (slot < 0 || slot > ISDN_MAX_CHANNELS) { + if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", __FUNCTION__, slot); return; diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c index 94c9afb7017c..f4f71226a078 100644 --- a/drivers/isdn/sc/ioctl.c +++ b/drivers/isdn/sc/ioctl.c @@ -46,7 +46,8 @@ int sc_ioctl(int card, scs_ioctl *data) pr_debug("%s: SCIOCRESET: ioctl received\n", sc_adapter[card]->devicename); sc_adapter[card]->StartOnReset = 0; - return (reset(card)); + kfree(rcvmsg); + return reset(card); } case SCIOCLOAD: @@ -183,7 +184,7 @@ int sc_ioctl(int card, scs_ioctl *data) sc_adapter[card]->devicename); spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL); - if(!spid) { + if (!spid) { kfree(rcvmsg); return -ENOMEM; } @@ -195,10 +196,10 @@ int sc_ioctl(int card, scs_ioctl *data) if (!status) { pr_debug("%s: SCIOCGETSPID: command successful\n", sc_adapter[card]->devicename); - } - else { + } else { pr_debug("%s: SCIOCGETSPID: command failed (status = %d)\n", sc_adapter[card]->devicename, status); + kfree(spid); kfree(rcvmsg); return status; } diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig new file mode 100644 index 000000000000..3f5b64794542 --- /dev/null +++ b/drivers/leds/Kconfig @@ -0,0 +1,88 @@ + +menu "LED devices" + +config NEW_LEDS + bool "LED Support" + help + Say Y to enable Linux LED support. This is not related to standard + keyboard LEDs which are controlled via the input system. + +config LEDS_CLASS + tristate "LED Class Support" + depends NEW_LEDS + help + This option enables the led sysfs class in /sys/class/leds. You'll + need this to do anything useful with LEDs. If unsure, say N. + +comment "LED drivers" + +config LEDS_CORGI + tristate "LED Support for the Sharp SL-C7x0 series" + depends LEDS_CLASS && PXA_SHARP_C7xx + help + This option enables support for the LEDs on Sharp Zaurus + SL-C7x0 series (C700, C750, C760, C860). + +config LEDS_LOCOMO + tristate "LED Support for Locomo device" + depends LEDS_CLASS && SHARP_LOCOMO + help + This option enables support for the LEDs on Sharp Locomo. + Zaurus models SL-5500 and SL-5600. + +config LEDS_SPITZ + tristate "LED Support for the Sharp SL-Cxx00 series" + depends LEDS_CLASS && PXA_SHARP_Cxx00 + help + This option enables support for the LEDs on Sharp Zaurus + SL-Cxx00 series (C1000, C3000, C3100). + +config LEDS_IXP4XX + tristate "LED Support for GPIO connected LEDs on IXP4XX processors" + depends LEDS_CLASS && ARCH_IXP4XX + help + This option enables support for the LEDs connected to GPIO + outputs of the Intel IXP4XX processors. To be useful the + particular board must have LEDs and they must be connected + to the GPIO lines. If unsure, say Y. + +config LEDS_TOSA + tristate "LED Support for the Sharp SL-6000 series" + depends LEDS_CLASS && PXA_SHARPSL + help + This option enables support for the LEDs on Sharp Zaurus + SL-6000 series. + +config LEDS_S3C24XX + tristate "LED Support for Samsung S3C24XX GPIO LEDs" + depends on LEDS_CLASS && ARCH_S3C2410 + help + This option enables support for LEDs connected to GPIO lines + on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440. + +comment "LED Triggers" + +config LEDS_TRIGGERS + bool "LED Trigger support" + depends NEW_LEDS + help + This option enables trigger support for the leds class. + These triggers allow kernel events to drive the LEDs and can + be configured via sysfs. If unsure, say Y. + +config LEDS_TRIGGER_TIMER + tristate "LED Timer Trigger" + depends LEDS_TRIGGERS + help + This allows LEDs to be controlled by a programmable timer + via sysfs. If unsure, say Y. + +config LEDS_TRIGGER_IDE_DISK + bool "LED IDE Disk Trigger" + depends LEDS_TRIGGERS && BLK_DEV_IDEDISK + help + This allows LEDs to be controlled by IDE disk activity. + If unsure, say Y. + +endmenu + diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile new file mode 100644 index 000000000000..40f042633bf5 --- /dev/null +++ b/drivers/leds/Makefile @@ -0,0 +1,17 @@ + +# LED Core +obj-$(CONFIG_NEW_LEDS) += led-core.o +obj-$(CONFIG_LEDS_CLASS) += led-class.o +obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o + +# LED Platform Drivers +obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o +obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o +obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o +obj-$(CONFIG_LEDS_IXP4XX) += leds-ixp4xx-gpio.o +obj-$(CONFIG_LEDS_TOSA) += leds-tosa.o +obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o + +# LED Triggers +obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o +obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c new file mode 100644 index 000000000000..b0b5d05fadd6 --- /dev/null +++ b/drivers/leds/led-class.c @@ -0,0 +1,167 @@ +/* + * LED Class Core + * + * Copyright (C) 2005 John Lenz + * Copyright (C) 2005-2006 Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "leds.h" + +static struct class *leds_class; + +static ssize_t led_brightness_show(struct class_device *dev, char *buf) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + ssize_t ret = 0; + + /* no lock needed for this */ + sprintf(buf, "%u\n", led_cdev->brightness); + ret = strlen(buf) + 1; + + return ret; +} + +static ssize_t led_brightness_store(struct class_device *dev, + const char *buf, size_t size) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + ssize_t ret = -EINVAL; + char *after; + unsigned long state = simple_strtoul(buf, &after, 10); + + if (after - buf > 0) { + ret = after - buf; + led_set_brightness(led_cdev, state); + } + + return ret; +} + +static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show, + led_brightness_store); +#ifdef CONFIG_LEDS_TRIGGERS +static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store); +#endif + +/** + * led_classdev_suspend - suspend an led_classdev. + * @led_cdev: the led_classdev to suspend. + */ +void led_classdev_suspend(struct led_classdev *led_cdev) +{ + led_cdev->flags |= LED_SUSPENDED; + led_cdev->brightness_set(led_cdev, 0); +} +EXPORT_SYMBOL_GPL(led_classdev_suspend); + +/** + * led_classdev_resume - resume an led_classdev. + * @led_cdev: the led_classdev to resume. + */ +void led_classdev_resume(struct led_classdev *led_cdev) +{ + led_cdev->brightness_set(led_cdev, led_cdev->brightness); + led_cdev->flags &= ~LED_SUSPENDED; +} +EXPORT_SYMBOL_GPL(led_classdev_resume); + +/** + * led_classdev_register - register a new object of led_classdev class. + * @dev: The device to register. + * @led_cdev: the led_classdev structure for this device. + */ +int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) +{ + led_cdev->class_dev = class_device_create(leds_class, NULL, 0, + parent, "%s", led_cdev->name); + if (unlikely(IS_ERR(led_cdev->class_dev))) + return PTR_ERR(led_cdev->class_dev); + + class_set_devdata(led_cdev->class_dev, led_cdev); + + /* register the attributes */ + class_device_create_file(led_cdev->class_dev, + &class_device_attr_brightness); + + /* add to the list of leds */ + write_lock(&leds_list_lock); + list_add_tail(&led_cdev->node, &leds_list); + write_unlock(&leds_list_lock); + +#ifdef CONFIG_LEDS_TRIGGERS + rwlock_init(&led_cdev->trigger_lock); + + led_trigger_set_default(led_cdev); + + class_device_create_file(led_cdev->class_dev, + &class_device_attr_trigger); +#endif + + printk(KERN_INFO "Registered led device: %s\n", + led_cdev->class_dev->class_id); + + return 0; +} +EXPORT_SYMBOL_GPL(led_classdev_register); + +/** + * led_classdev_unregister - unregisters a object of led_properties class. + * @led_cdev: the led device to unreigister + * + * Unregisters a previously registered via led_classdev_register object. + */ +void led_classdev_unregister(struct led_classdev *led_cdev) +{ + class_device_remove_file(led_cdev->class_dev, + &class_device_attr_brightness); +#ifdef CONFIG_LEDS_TRIGGERS + class_device_remove_file(led_cdev->class_dev, + &class_device_attr_trigger); + write_lock(&led_cdev->trigger_lock); + if (led_cdev->trigger) + led_trigger_set(led_cdev, NULL); + write_unlock(&led_cdev->trigger_lock); +#endif + + class_device_unregister(led_cdev->class_dev); + + write_lock(&leds_list_lock); + list_del(&led_cdev->node); + write_unlock(&leds_list_lock); +} +EXPORT_SYMBOL_GPL(led_classdev_unregister); + +static int __init leds_init(void) +{ + leds_class = class_create(THIS_MODULE, "leds"); + if (IS_ERR(leds_class)) + return PTR_ERR(leds_class); + return 0; +} + +static void __exit leds_exit(void) +{ + class_destroy(leds_class); +} + +subsys_initcall(leds_init); +module_exit(leds_exit); + +MODULE_AUTHOR("John Lenz, Richard Purdie"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LED Class Interface"); diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c new file mode 100644 index 000000000000..fe6541326c71 --- /dev/null +++ b/drivers/leds/led-core.c @@ -0,0 +1,25 @@ +/* + * LED Class Core + * + * Copyright 2005-2006 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include "leds.h" + +rwlock_t leds_list_lock = RW_LOCK_UNLOCKED; +LIST_HEAD(leds_list); + +EXPORT_SYMBOL_GPL(leds_list); +EXPORT_SYMBOL_GPL(leds_list_lock); diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c new file mode 100644 index 000000000000..5e2cd8be1191 --- /dev/null +++ b/drivers/leds/led-triggers.c @@ -0,0 +1,239 @@ +/* + * LED Triggers Core + * + * Copyright 2005-2006 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "leds.h" + +/* + * Nests outside led_cdev->trigger_lock + */ +static rwlock_t triggers_list_lock = RW_LOCK_UNLOCKED; +static LIST_HEAD(trigger_list); + +ssize_t led_trigger_store(struct class_device *dev, const char *buf, + size_t count) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + char trigger_name[TRIG_NAME_MAX]; + struct led_trigger *trig; + size_t len; + + trigger_name[sizeof(trigger_name) - 1] = '\0'; + strncpy(trigger_name, buf, sizeof(trigger_name) - 1); + len = strlen(trigger_name); + + if (len && trigger_name[len - 1] == '\n') + trigger_name[len - 1] = '\0'; + + if (!strcmp(trigger_name, "none")) { + write_lock(&led_cdev->trigger_lock); + led_trigger_set(led_cdev, NULL); + write_unlock(&led_cdev->trigger_lock); + return count; + } + + read_lock(&triggers_list_lock); + list_for_each_entry(trig, &trigger_list, next_trig) { + if (!strcmp(trigger_name, trig->name)) { + write_lock(&led_cdev->trigger_lock); + led_trigger_set(led_cdev, trig); + write_unlock(&led_cdev->trigger_lock); + + read_unlock(&triggers_list_lock); + return count; + } + } + read_unlock(&triggers_list_lock); + + return -EINVAL; +} + + +ssize_t led_trigger_show(struct class_device *dev, char *buf) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + struct led_trigger *trig; + int len = 0; + + read_lock(&triggers_list_lock); + read_lock(&led_cdev->trigger_lock); + + if (!led_cdev->trigger) + len += sprintf(buf+len, "[none] "); + else + len += sprintf(buf+len, "none "); + + list_for_each_entry(trig, &trigger_list, next_trig) { + if (led_cdev->trigger && !strcmp(led_cdev->trigger->name, + trig->name)) + len += sprintf(buf+len, "[%s] ", trig->name); + else + len += sprintf(buf+len, "%s ", trig->name); + } + read_unlock(&led_cdev->trigger_lock); + read_unlock(&triggers_list_lock); + + len += sprintf(len+buf, "\n"); + return len; +} + +void led_trigger_event(struct led_trigger *trigger, + enum led_brightness brightness) +{ + struct list_head *entry; + + if (!trigger) + return; + + read_lock(&trigger->leddev_list_lock); + list_for_each(entry, &trigger->led_cdevs) { + struct led_classdev *led_cdev; + + led_cdev = list_entry(entry, struct led_classdev, trig_list); + led_set_brightness(led_cdev, brightness); + } + read_unlock(&trigger->leddev_list_lock); +} + +/* Caller must ensure led_cdev->trigger_lock held */ +void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) +{ + unsigned long flags; + + /* Remove any existing trigger */ + if (led_cdev->trigger) { + write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags); + list_del(&led_cdev->trig_list); + write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags); + if (led_cdev->trigger->deactivate) + led_cdev->trigger->deactivate(led_cdev); + } + if (trigger) { + write_lock_irqsave(&trigger->leddev_list_lock, flags); + list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs); + write_unlock_irqrestore(&trigger->leddev_list_lock, flags); + if (trigger->activate) + trigger->activate(led_cdev); + } + led_cdev->trigger = trigger; +} + +void led_trigger_set_default(struct led_classdev *led_cdev) +{ + struct led_trigger *trig; + + if (!led_cdev->default_trigger) + return; + + read_lock(&triggers_list_lock); + write_lock(&led_cdev->trigger_lock); + list_for_each_entry(trig, &trigger_list, next_trig) { + if (!strcmp(led_cdev->default_trigger, trig->name)) + led_trigger_set(led_cdev, trig); + } + write_unlock(&led_cdev->trigger_lock); + read_unlock(&triggers_list_lock); +} + +int led_trigger_register(struct led_trigger *trigger) +{ + struct led_classdev *led_cdev; + + rwlock_init(&trigger->leddev_list_lock); + INIT_LIST_HEAD(&trigger->led_cdevs); + + /* Add to the list of led triggers */ + write_lock(&triggers_list_lock); + list_add_tail(&trigger->next_trig, &trigger_list); + write_unlock(&triggers_list_lock); + + /* Register with any LEDs that have this as a default trigger */ + read_lock(&leds_list_lock); + list_for_each_entry(led_cdev, &leds_list, node) { + write_lock(&led_cdev->trigger_lock); + if (!led_cdev->trigger && led_cdev->default_trigger && + !strcmp(led_cdev->default_trigger, trigger->name)) + led_trigger_set(led_cdev, trigger); + write_unlock(&led_cdev->trigger_lock); + } + read_unlock(&leds_list_lock); + + return 0; +} + +void led_trigger_register_simple(const char *name, struct led_trigger **tp) +{ + struct led_trigger *trigger; + + trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + + if (trigger) { + trigger->name = name; + led_trigger_register(trigger); + } + *tp = trigger; +} + +void led_trigger_unregister(struct led_trigger *trigger) +{ + struct led_classdev *led_cdev; + + /* Remove from the list of led triggers */ + write_lock(&triggers_list_lock); + list_del(&trigger->next_trig); + write_unlock(&triggers_list_lock); + + /* Remove anyone actively using this trigger */ + read_lock(&leds_list_lock); + list_for_each_entry(led_cdev, &leds_list, node) { + write_lock(&led_cdev->trigger_lock); + if (led_cdev->trigger == trigger) + led_trigger_set(led_cdev, NULL); + write_unlock(&led_cdev->trigger_lock); + } + read_unlock(&leds_list_lock); +} + +void led_trigger_unregister_simple(struct led_trigger *trigger) +{ + led_trigger_unregister(trigger); + kfree(trigger); +} + +/* Used by LED Class */ +EXPORT_SYMBOL_GPL(led_trigger_set); +EXPORT_SYMBOL_GPL(led_trigger_set_default); +EXPORT_SYMBOL_GPL(led_trigger_show); +EXPORT_SYMBOL_GPL(led_trigger_store); + +/* LED Trigger Interface */ +EXPORT_SYMBOL_GPL(led_trigger_register); +EXPORT_SYMBOL_GPL(led_trigger_unregister); + +/* Simple LED Tigger Interface */ +EXPORT_SYMBOL_GPL(led_trigger_register_simple); +EXPORT_SYMBOL_GPL(led_trigger_unregister_simple); +EXPORT_SYMBOL_GPL(led_trigger_event); + +MODULE_AUTHOR("Richard Purdie"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("LED Triggers Core"); diff --git a/drivers/leds/leds-corgi.c b/drivers/leds/leds-corgi.c new file mode 100644 index 000000000000..bb7d84df0121 --- /dev/null +++ b/drivers/leds/leds-corgi.c @@ -0,0 +1,121 @@ +/* + * LED Triggers Core + * + * Copyright 2005-2006 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void corgiled_amber_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + if (value) + GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); + else + GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); +} + +static void corgiled_green_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + if (value) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN); +} + +static struct led_classdev corgi_amber_led = { + .name = "corgi:amber", + .default_trigger = "sharpsl-charge", + .brightness_set = corgiled_amber_set, +}; + +static struct led_classdev corgi_green_led = { + .name = "corgi:green", + .default_trigger = "nand-disk", + .brightness_set = corgiled_green_set, +}; + +#ifdef CONFIG_PM +static int corgiled_suspend(struct platform_device *dev, pm_message_t state) +{ +#ifdef CONFIG_LEDS_TRIGGERS + if (corgi_amber_led.trigger && strcmp(corgi_amber_led.trigger->name, "sharpsl-charge")) +#endif + led_classdev_suspend(&corgi_amber_led); + led_classdev_suspend(&corgi_green_led); + return 0; +} + +static int corgiled_resume(struct platform_device *dev) +{ + led_classdev_resume(&corgi_amber_led); + led_classdev_resume(&corgi_green_led); + return 0; +} +#endif + +static int corgiled_probe(struct platform_device *pdev) +{ + int ret; + + ret = led_classdev_register(&pdev->dev, &corgi_amber_led); + if (ret < 0) + return ret; + + ret = led_classdev_register(&pdev->dev, &corgi_green_led); + if (ret < 0) + led_classdev_unregister(&corgi_amber_led); + + return ret; +} + +static int corgiled_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&corgi_amber_led); + led_classdev_unregister(&corgi_green_led); + return 0; +} + +static struct platform_driver corgiled_driver = { + .probe = corgiled_probe, + .remove = corgiled_remove, +#ifdef CONFIG_PM + .suspend = corgiled_suspend, + .resume = corgiled_resume, +#endif + .driver = { + .name = "corgi-led", + }, +}; + +static int __init corgiled_init(void) +{ + return platform_driver_register(&corgiled_driver); +} + +static void __exit corgiled_exit(void) +{ + platform_driver_unregister(&corgiled_driver); +} + +module_init(corgiled_init); +module_exit(corgiled_exit); + +MODULE_AUTHOR("Richard Purdie "); +MODULE_DESCRIPTION("Corgi LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-ixp4xx-gpio.c b/drivers/leds/leds-ixp4xx-gpio.c new file mode 100644 index 000000000000..30ced150e4cf --- /dev/null +++ b/drivers/leds/leds-ixp4xx-gpio.c @@ -0,0 +1,215 @@ +/* + * IXP4XX GPIO driver LED driver + * + * Author: John Bowler + * + * Copyright (c) 2006 John Bowler + * + * Permission is hereby granted, free of charge, to any + * person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the + * Software without restriction, including without + * limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice + * shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF + * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +extern spinlock_t gpio_lock; + +/* Up to 16 gpio lines are possible. */ +#define GPIO_MAX 16 +static struct ixp4xxgpioled_device { + struct led_classdev ancestor; + int flags; +} ixp4xxgpioled_devices[GPIO_MAX]; + +void ixp4xxgpioled_brightness_set(struct led_classdev *pled, + enum led_brightness value) +{ + const struct ixp4xxgpioled_device *const ixp4xx_dev = + container_of(pled, struct ixp4xxgpioled_device, ancestor); + const u32 gpio_pin = ixp4xx_dev - ixp4xxgpioled_devices; + + if (gpio_pin < GPIO_MAX && ixp4xx_dev->ancestor.name != 0) { + /* Set or clear the 'gpio_pin' bit according to the style + * and the required setting (value > 0 == on) + */ + const int gpio_value = + (value > 0) == (ixp4xx_dev->flags != IXP4XX_GPIO_LOW) ? + IXP4XX_GPIO_HIGH : IXP4XX_GPIO_LOW; + + { + unsigned long flags; + spin_lock_irqsave(&gpio_lock, flags); + gpio_line_set(gpio_pin, gpio_value); + spin_unlock_irqrestore(&gpio_lock, flags); + } + } +} + +/* LEDs are described in resources, the following iterates over the valid + * LED resources. + */ +#define for_all_leds(i, pdev) \ + for (i=0; inum_resources; ++i) \ + if (pdev->resource[i].start < GPIO_MAX && \ + pdev->resource[i].name != 0) + +/* The following applies 'operation' to each LED from the given platform, + * the function always returns 0 to allow tail call elimination. + */ +static int apply_to_all_leds(struct platform_device *pdev, + void (*operation)(struct led_classdev *pled)) +{ + int i; + + for_all_leds(i, pdev) + operation(&ixp4xxgpioled_devices[pdev->resource[i].start].ancestor); + return 0; +} + +#ifdef CONFIG_PM +static int ixp4xxgpioled_suspend(struct platform_device *pdev, + pm_message_t state) +{ + return apply_to_all_leds(pdev, led_classdev_suspend); +} + +static int ixp4xxgpioled_resume(struct platform_device *pdev) +{ + return apply_to_all_leds(pdev, led_classdev_resume); +} +#endif + +static void ixp4xxgpioled_remove_one_led(struct led_classdev *pled) +{ + led_classdev_unregister(pled); + pled->name = 0; +} + +static int ixp4xxgpioled_remove(struct platform_device *pdev) +{ + return apply_to_all_leds(pdev, ixp4xxgpioled_remove_one_led); +} + +static int ixp4xxgpioled_probe(struct platform_device *pdev) +{ + /* The board level has to tell the driver where the + * LEDs are connected - there is no way to find out + * electrically. It must also say whether the GPIO + * lines are active high or active low. + * + * To do this read the num_resources (the number of + * LEDs) and the struct resource (the data for each + * LED). The name comes from the resource, and it + * isn't copied. + */ + int i; + + for_all_leds(i, pdev) { + const u8 gpio_pin = pdev->resource[i].start; + int rc; + + if (ixp4xxgpioled_devices[gpio_pin].ancestor.name == 0) { + unsigned long flags; + + spin_lock_irqsave(&gpio_lock, flags); + gpio_line_config(gpio_pin, IXP4XX_GPIO_OUT); + /* The config can, apparently, reset the state, + * I suspect the gpio line may be an input and + * the config may cause the line to be latched, + * so the setting depends on how the LED is + * connected to the line (which affects how it + * floats if not driven). + */ + gpio_line_set(gpio_pin, IXP4XX_GPIO_HIGH); + spin_unlock_irqrestore(&gpio_lock, flags); + + ixp4xxgpioled_devices[gpio_pin].flags = + pdev->resource[i].flags & IORESOURCE_BITS; + + ixp4xxgpioled_devices[gpio_pin].ancestor.name = + pdev->resource[i].name; + + /* This is how a board manufacturer makes the LED + * come on on reset - the GPIO line will be high, so + * make the LED light when the line is low... + */ + if (ixp4xxgpioled_devices[gpio_pin].flags != IXP4XX_GPIO_LOW) + ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 100; + else + ixp4xxgpioled_devices[gpio_pin].ancestor.brightness = 0; + + ixp4xxgpioled_devices[gpio_pin].ancestor.flags = 0; + + ixp4xxgpioled_devices[gpio_pin].ancestor.brightness_set = + ixp4xxgpioled_brightness_set; + + ixp4xxgpioled_devices[gpio_pin].ancestor.default_trigger = 0; + } + + rc = led_classdev_register(&pdev->dev, + &ixp4xxgpioled_devices[gpio_pin].ancestor); + if (rc < 0) { + ixp4xxgpioled_devices[gpio_pin].ancestor.name = 0; + ixp4xxgpioled_remove(pdev); + return rc; + } + } + + return 0; +} + +static struct platform_driver ixp4xxgpioled_driver = { + .probe = ixp4xxgpioled_probe, + .remove = ixp4xxgpioled_remove, +#ifdef CONFIG_PM + .suspend = ixp4xxgpioled_suspend, + .resume = ixp4xxgpioled_resume, +#endif + .driver = { + .name = "IXP4XX-GPIO-LED", + }, +}; + +static int __init ixp4xxgpioled_init(void) +{ + return platform_driver_register(&ixp4xxgpioled_driver); +} + +static void __exit ixp4xxgpioled_exit(void) +{ + platform_driver_unregister(&ixp4xxgpioled_driver); +} + +module_init(ixp4xxgpioled_init); +module_exit(ixp4xxgpioled_exit); + +MODULE_AUTHOR("John Bowler "); +MODULE_DESCRIPTION("IXP4XX GPIO LED driver"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c new file mode 100644 index 000000000000..749a86c2adb6 --- /dev/null +++ b/drivers/leds/leds-locomo.c @@ -0,0 +1,95 @@ +/* + * linux/drivers/leds/locomo.c + * + * Copyright (C) 2005 John Lenz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include + +static void locomoled_brightness_set(struct led_classdev *led_cdev, + enum led_brightness value, int offset) +{ + struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev); + unsigned long flags; + + local_irq_save(flags); + if (value) + locomo_writel(LOCOMO_LPT_TOFH, locomo_dev->mapbase + offset); + else + locomo_writel(LOCOMO_LPT_TOFL, locomo_dev->mapbase + offset); + local_irq_restore(flags); +} + +static void locomoled_brightness_set0(struct led_classdev *led_cdev, + enum led_brightness value) +{ + locomoled_brightness_set(led_cdev, value, LOCOMO_LPT0); +} + +static void locomoled_brightness_set1(struct led_classdev *led_cdev, + enum led_brightness value) +{ + locomoled_brightness_set(led_cdev, value, LOCOMO_LPT1); +} + +static struct led_classdev locomo_led0 = { + .name = "locomo:amber", + .brightness_set = locomoled_brightness_set0, +}; + +static struct led_classdev locomo_led1 = { + .name = "locomo:green", + .brightness_set = locomoled_brightness_set1, +}; + +static int locomoled_probe(struct locomo_dev *ldev) +{ + int ret; + + ret = led_classdev_register(&ldev->dev, &locomo_led0); + if (ret < 0) + return ret; + + ret = led_classdev_register(&ldev->dev, &locomo_led1); + if (ret < 0) + led_classdev_unregister(&locomo_led0); + + return ret; +} + +static int locomoled_remove(struct locomo_dev *dev) +{ + led_classdev_unregister(&locomo_led0); + led_classdev_unregister(&locomo_led1); + return 0; +} + +static struct locomo_driver locomoled_driver = { + .drv = { + .name = "locomoled" + }, + .devid = LOCOMO_DEVID_LED, + .probe = locomoled_probe, + .remove = locomoled_remove, +}; + +static int __init locomoled_init(void) +{ + return locomo_driver_register(&locomoled_driver); +} +module_init(locomoled_init); + +MODULE_AUTHOR("John Lenz "); +MODULE_DESCRIPTION("Locomo LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c new file mode 100644 index 000000000000..650cf72dc675 --- /dev/null +++ b/drivers/leds/leds-s3c24xx.c @@ -0,0 +1,163 @@ +/* drivers/leds/leds-s3c24xx.c + * + * (c) 2006 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * S3C24XX - LEDs GPIO driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* our context */ + +struct s3c24xx_gpio_led { + struct led_classdev cdev; + struct s3c24xx_led_platdata *pdata; +}; + +static inline struct s3c24xx_gpio_led *pdev_to_gpio(struct platform_device *dev) +{ + return platform_get_drvdata(dev); +} + +static inline struct s3c24xx_gpio_led *to_gpio(struct led_classdev *led_cdev) +{ + return container_of(led_cdev, struct s3c24xx_gpio_led, cdev); +} + +static void s3c24xx_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct s3c24xx_gpio_led *led = to_gpio(led_cdev); + struct s3c24xx_led_platdata *pd = led->pdata; + + /* there will be a sort delay between setting the output and + * going from output to input when using tristate. */ + + s3c2410_gpio_setpin(pd->gpio, (value ? 1 : 0) ^ + (pd->flags & S3C24XX_LEDF_ACTLOW)); + + if (pd->flags & S3C24XX_LEDF_TRISTATE) + s3c2410_gpio_cfgpin(pd->gpio, + value ? S3C2410_GPIO_OUTPUT : S3C2410_GPIO_INPUT); + +} + +static int s3c24xx_led_remove(struct platform_device *dev) +{ + struct s3c24xx_gpio_led *led = pdev_to_gpio(dev); + + led_classdev_unregister(&led->cdev); + kfree(led); + + return 0; +} + +static int s3c24xx_led_probe(struct platform_device *dev) +{ + struct s3c24xx_led_platdata *pdata = dev->dev.platform_data; + struct s3c24xx_gpio_led *led; + int ret; + + led = kzalloc(sizeof(struct s3c24xx_gpio_led), GFP_KERNEL); + if (led == NULL) { + dev_err(&dev->dev, "No memory for device\n"); + return -ENOMEM; + } + + platform_set_drvdata(dev, led); + + led->cdev.brightness_set = s3c24xx_led_set; + led->cdev.default_trigger = pdata->def_trigger; + led->cdev.name = pdata->name; + + led->pdata = pdata; + + /* no point in having a pull-up if we are always driving */ + + if (pdata->flags & S3C24XX_LEDF_TRISTATE) { + s3c2410_gpio_setpin(pdata->gpio, 0); + s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_INPUT); + } else { + s3c2410_gpio_pullup(pdata->gpio, 0); + s3c2410_gpio_setpin(pdata->gpio, 0); + s3c2410_gpio_cfgpin(pdata->gpio, S3C2410_GPIO_OUTPUT); + } + + /* register our new led device */ + + ret = led_classdev_register(&dev->dev, &led->cdev); + if (ret < 0) { + dev_err(&dev->dev, "led_classdev_register failed\n"); + goto exit_err1; + } + + return 0; + + exit_err1: + kfree(led); + return ret; +} + + +#ifdef CONFIG_PM +static int s3c24xx_led_suspend(struct platform_device *dev, pm_message_t state) +{ + struct s3c24xx_gpio_led *led = pdev_to_gpio(dev); + + led_classdev_suspend(&led->cdev); + return 0; +} + +static int s3c24xx_led_resume(struct platform_device *dev) +{ + struct s3c24xx_gpio_led *led = pdev_to_gpio(dev); + + led_classdev_resume(&led->cdev); + return 0; +} +#else +#define s3c24xx_led_suspend NULL +#define s3c24xx_led_resume NULL +#endif + +static struct platform_driver s3c24xx_led_driver = { + .probe = s3c24xx_led_probe, + .remove = s3c24xx_led_remove, + .suspend = s3c24xx_led_suspend, + .resume = s3c24xx_led_resume, + .driver = { + .name = "s3c24xx_led", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c24xx_led_init(void) +{ + return platform_driver_register(&s3c24xx_led_driver); +} + +static void __exit s3c24xx_led_exit(void) +{ + platform_driver_unregister(&s3c24xx_led_driver); +} + +module_init(s3c24xx_led_init); +module_exit(s3c24xx_led_exit); + +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("S3C24XX LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-spitz.c b/drivers/leds/leds-spitz.c new file mode 100644 index 000000000000..65bbef4a5e09 --- /dev/null +++ b/drivers/leds/leds-spitz.c @@ -0,0 +1,125 @@ +/* + * LED Triggers Core + * + * Copyright 2005-2006 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void spitzled_amber_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + if (value) + set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); + else + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); +} + +static void spitzled_green_set(struct led_classdev *led_cdev, enum led_brightness value) +{ + if (value) + set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN); + else + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN); +} + +static struct led_classdev spitz_amber_led = { + .name = "spitz:amber", + .default_trigger = "sharpsl-charge", + .brightness_set = spitzled_amber_set, +}; + +static struct led_classdev spitz_green_led = { + .name = "spitz:green", + .default_trigger = "ide-disk", + .brightness_set = spitzled_green_set, +}; + +#ifdef CONFIG_PM +static int spitzled_suspend(struct platform_device *dev, pm_message_t state) +{ +#ifdef CONFIG_LEDS_TRIGGERS + if (spitz_amber_led.trigger && strcmp(spitz_amber_led.trigger->name, "sharpsl-charge")) +#endif + led_classdev_suspend(&spitz_amber_led); + led_classdev_suspend(&spitz_green_led); + return 0; +} + +static int spitzled_resume(struct platform_device *dev) +{ + led_classdev_resume(&spitz_amber_led); + led_classdev_resume(&spitz_green_led); + return 0; +} +#endif + +static int spitzled_probe(struct platform_device *pdev) +{ + int ret; + + if (machine_is_akita()) + spitz_green_led.default_trigger = "nand-disk"; + + ret = led_classdev_register(&pdev->dev, &spitz_amber_led); + if (ret < 0) + return ret; + + ret = led_classdev_register(&pdev->dev, &spitz_green_led); + if (ret < 0) + led_classdev_unregister(&spitz_amber_led); + + return ret; +} + +static int spitzled_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&spitz_amber_led); + led_classdev_unregister(&spitz_green_led); + + return 0; +} + +static struct platform_driver spitzled_driver = { + .probe = spitzled_probe, + .remove = spitzled_remove, +#ifdef CONFIG_PM + .suspend = spitzled_suspend, + .resume = spitzled_resume, +#endif + .driver = { + .name = "spitz-led", + }, +}; + +static int __init spitzled_init(void) +{ + return platform_driver_register(&spitzled_driver); +} + +static void __exit spitzled_exit(void) +{ + platform_driver_unregister(&spitzled_driver); +} + +module_init(spitzled_init); +module_exit(spitzled_exit); + +MODULE_AUTHOR("Richard Purdie "); +MODULE_DESCRIPTION("Spitz LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-tosa.c b/drivers/leds/leds-tosa.c new file mode 100644 index 000000000000..c9e8cc1ec481 --- /dev/null +++ b/drivers/leds/leds-tosa.c @@ -0,0 +1,131 @@ +/* + * LED Triggers Core + * + * Copyright 2005 Dirk Opfer + * + * Author: Dirk Opfer + * based on spitz.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void tosaled_amber_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + if (value) + set_scoop_gpio(&tosascoop_jc_device.dev, + TOSA_SCOOP_JC_CHRG_ERR_LED); + else + reset_scoop_gpio(&tosascoop_jc_device.dev, + TOSA_SCOOP_JC_CHRG_ERR_LED); +} + +static void tosaled_green_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + if (value) + set_scoop_gpio(&tosascoop_jc_device.dev, + TOSA_SCOOP_JC_NOTE_LED); + else + reset_scoop_gpio(&tosascoop_jc_device.dev, + TOSA_SCOOP_JC_NOTE_LED); +} + +static struct led_classdev tosa_amber_led = { + .name = "tosa:amber", + .default_trigger = "sharpsl-charge", + .brightness_set = tosaled_amber_set, +}; + +static struct led_classdev tosa_green_led = { + .name = "tosa:green", + .default_trigger = "nand-disk", + .brightness_set = tosaled_green_set, +}; + +#ifdef CONFIG_PM +static int tosaled_suspend(struct platform_device *dev, pm_message_t state) +{ +#ifdef CONFIG_LEDS_TRIGGERS + if (tosa_amber_led.trigger && strcmp(tosa_amber_led.trigger->name, + "sharpsl-charge")) +#endif + led_classdev_suspend(&tosa_amber_led); + led_classdev_suspend(&tosa_green_led); + return 0; +} + +static int tosaled_resume(struct platform_device *dev) +{ + led_classdev_resume(&tosa_amber_led); + led_classdev_resume(&tosa_green_led); + return 0; +} +#else +#define tosaled_suspend NULL +#define tosaled_resume NULL +#endif + +static int tosaled_probe(struct platform_device *pdev) +{ + int ret; + + ret = led_classdev_register(&pdev->dev, &tosa_amber_led); + if (ret < 0) + return ret; + + ret = led_classdev_register(&pdev->dev, &tosa_green_led); + if (ret < 0) + led_classdev_unregister(&tosa_amber_led); + + return ret; +} + +static int tosaled_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&tosa_amber_led); + led_classdev_unregister(&tosa_green_led); + + return 0; +} + +static struct platform_driver tosaled_driver = { + .probe = tosaled_probe, + .remove = tosaled_remove, + .suspend = tosaled_suspend, + .resume = tosaled_resume, + .driver = { + .name = "tosa-led", + }, +}; + +static int __init tosaled_init(void) +{ + return platform_driver_register(&tosaled_driver); +} + +static void __exit tosaled_exit(void) +{ + platform_driver_unregister(&tosaled_driver); +} + +module_init(tosaled_init); +module_exit(tosaled_exit); + +MODULE_AUTHOR("Dirk Opfer "); +MODULE_DESCRIPTION("Tosa LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h new file mode 100644 index 000000000000..a715c4ed93ff --- /dev/null +++ b/drivers/leds/leds.h @@ -0,0 +1,44 @@ +/* + * LED Core + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef __LEDS_H_INCLUDED +#define __LEDS_H_INCLUDED + +#include + +static inline void led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + if (value > LED_FULL) + value = LED_FULL; + led_cdev->brightness = value; + if (!(led_cdev->flags & LED_SUSPENDED)) + led_cdev->brightness_set(led_cdev, value); +} + +extern rwlock_t leds_list_lock; +extern struct list_head leds_list; + +#ifdef CONFIG_LEDS_TRIGGERS +void led_trigger_set_default(struct led_classdev *led_cdev); +void led_trigger_set(struct led_classdev *led_cdev, + struct led_trigger *trigger); +#else +#define led_trigger_set_default(x) do {} while(0) +#define led_trigger_set(x, y) do {} while(0) +#endif + +ssize_t led_trigger_store(struct class_device *dev, const char *buf, + size_t count); +ssize_t led_trigger_show(struct class_device *dev, char *buf); + +#endif /* __LEDS_H_INCLUDED */ diff --git a/drivers/leds/ledtrig-ide-disk.c b/drivers/leds/ledtrig-ide-disk.c new file mode 100644 index 000000000000..fa651886ab4f --- /dev/null +++ b/drivers/leds/ledtrig-ide-disk.c @@ -0,0 +1,62 @@ +/* + * LED IDE-Disk Activity Trigger + * + * Copyright 2006 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include + +static void ledtrig_ide_timerfunc(unsigned long data); + +DEFINE_LED_TRIGGER(ledtrig_ide); +static DEFINE_TIMER(ledtrig_ide_timer, ledtrig_ide_timerfunc, 0, 0); +static int ide_activity; +static int ide_lastactivity; + +void ledtrig_ide_activity(void) +{ + ide_activity++; + if (!timer_pending(&ledtrig_ide_timer)) + mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10)); +} +EXPORT_SYMBOL(ledtrig_ide_activity); + +static void ledtrig_ide_timerfunc(unsigned long data) +{ + if (ide_lastactivity != ide_activity) { + ide_lastactivity = ide_activity; + led_trigger_event(ledtrig_ide, LED_FULL); + mod_timer(&ledtrig_ide_timer, jiffies + msecs_to_jiffies(10)); + } else { + led_trigger_event(ledtrig_ide, LED_OFF); + } +} + +static int __init ledtrig_ide_init(void) +{ + led_trigger_register_simple("ide-disk", &ledtrig_ide); + return 0; +} + +static void __exit ledtrig_ide_exit(void) +{ + led_trigger_unregister_simple(ledtrig_ide); +} + +module_init(ledtrig_ide_init); +module_exit(ledtrig_ide_exit); + +MODULE_AUTHOR("Richard Purdie "); +MODULE_DESCRIPTION("LED IDE Disk Activity Trigger"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c new file mode 100644 index 000000000000..f484b5d6dbf8 --- /dev/null +++ b/drivers/leds/ledtrig-timer.c @@ -0,0 +1,170 @@ +/* + * LED Kernel Timer Trigger + * + * Copyright 2005-2006 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "leds.h" + +struct timer_trig_data { + unsigned long delay_on; /* milliseconds on */ + unsigned long delay_off; /* milliseconds off */ + struct timer_list timer; +}; + +static void led_timer_function(unsigned long data) +{ + struct led_classdev *led_cdev = (struct led_classdev *) data; + struct timer_trig_data *timer_data = led_cdev->trigger_data; + unsigned long brightness = LED_OFF; + unsigned long delay = timer_data->delay_off; + + if (!timer_data->delay_on || !timer_data->delay_off) { + led_set_brightness(led_cdev, LED_OFF); + return; + } + + if (!led_cdev->brightness) { + brightness = LED_FULL; + delay = timer_data->delay_on; + } + + led_set_brightness(led_cdev, brightness); + + mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay)); +} + +static ssize_t led_delay_on_show(struct class_device *dev, char *buf) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + struct timer_trig_data *timer_data = led_cdev->trigger_data; + + sprintf(buf, "%lu\n", timer_data->delay_on); + + return strlen(buf) + 1; +} + +static ssize_t led_delay_on_store(struct class_device *dev, const char *buf, + size_t size) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + struct timer_trig_data *timer_data = led_cdev->trigger_data; + int ret = -EINVAL; + char *after; + unsigned long state = simple_strtoul(buf, &after, 10); + + if (after - buf > 0) { + timer_data->delay_on = state; + mod_timer(&timer_data->timer, jiffies + 1); + ret = after - buf; + } + + return ret; +} + +static ssize_t led_delay_off_show(struct class_device *dev, char *buf) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + struct timer_trig_data *timer_data = led_cdev->trigger_data; + + sprintf(buf, "%lu\n", timer_data->delay_off); + + return strlen(buf) + 1; +} + +static ssize_t led_delay_off_store(struct class_device *dev, const char *buf, + size_t size) +{ + struct led_classdev *led_cdev = class_get_devdata(dev); + struct timer_trig_data *timer_data = led_cdev->trigger_data; + int ret = -EINVAL; + char *after; + unsigned long state = simple_strtoul(buf, &after, 10); + + if (after - buf > 0) { + timer_data->delay_off = state; + mod_timer(&timer_data->timer, jiffies + 1); + ret = after - buf; + } + + return ret; +} + +static CLASS_DEVICE_ATTR(delay_on, 0644, led_delay_on_show, + led_delay_on_store); +static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show, + led_delay_off_store); + +static void timer_trig_activate(struct led_classdev *led_cdev) +{ + struct timer_trig_data *timer_data; + + timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL); + if (!timer_data) + return; + + led_cdev->trigger_data = timer_data; + + init_timer(&timer_data->timer); + timer_data->timer.function = led_timer_function; + timer_data->timer.data = (unsigned long) led_cdev; + + class_device_create_file(led_cdev->class_dev, + &class_device_attr_delay_on); + class_device_create_file(led_cdev->class_dev, + &class_device_attr_delay_off); +} + +static void timer_trig_deactivate(struct led_classdev *led_cdev) +{ + struct timer_trig_data *timer_data = led_cdev->trigger_data; + + if (timer_data) { + class_device_remove_file(led_cdev->class_dev, + &class_device_attr_delay_on); + class_device_remove_file(led_cdev->class_dev, + &class_device_attr_delay_off); + del_timer_sync(&timer_data->timer); + kfree(timer_data); + } +} + +static struct led_trigger timer_led_trigger = { + .name = "timer", + .activate = timer_trig_activate, + .deactivate = timer_trig_deactivate, +}; + +static int __init timer_trig_init(void) +{ + return led_trigger_register(&timer_led_trigger); +} + +static void __exit timer_trig_exit(void) +{ + led_trigger_unregister(&timer_led_trigger); +} + +module_init(timer_trig_init); +module_exit(timer_trig_exit); + +MODULE_AUTHOR("Richard Purdie "); +MODULE_DESCRIPTION("Timer LED trigger"); +MODULE_LICENSE("GPL"); diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 34fcabac5fdb..259fd8973ce9 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -42,6 +42,7 @@ #include #ifdef CONFIG_PPC #include +#include #endif @@ -294,7 +295,7 @@ int __init adb_init(void) int i; #ifdef CONFIG_PPC32 - if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + if (!machine_is(chrp) && !machine_is(powermac)) return 0; #endif #ifdef CONFIG_MAC diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index f5779a73184d..394334ec5765 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -1206,8 +1206,8 @@ init_ms_a3(int id) static int __init adbhid_init(void) { #ifndef CONFIG_MAC - if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return 0; + if (!machine_is(chrp) && !machine_is(powermac)) + return 0; #endif led_request.complete = 1; diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 8dbf2852bae0..53c1c7909413 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -839,8 +839,8 @@ static int __init media_bay_init(void) media_bays[i].cd_index = -1; #endif } - if (_machine != _MACH_Pmac) - return -ENODEV; + if (!machine_is(powermac)) + return 0; macio_register_driver(&media_bay_driver); diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index fd2aae150ccc..ac25a48362ac 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -139,11 +139,12 @@ config MD_RAID5_RESHAPE is online. However it is still EXPERIMENTAL code. It should work, but please be sure that you have backups. - You will need a version of mdadm newer than 2.3.1. During the - early stage of reshape there is a critical section where live data - is being over-written. A crash during this time needs extra care - for recovery. The newer mdadm takes a copy of the data in the - critical section and will restore it, if necessary, after a crash. + You will need mdadm verion 2.4.1 or later to use this + feature safely. During the early stage of reshape there is + a critical section where live data is being over-written. A + crash during this time needs extra care for recovery. The + newer mdadm takes a copy of the data in the critical section + and will restore it, if necessary, after a crash. The mdadm usage is e.g. mdadm --grow /dev/md1 --raid-disks=6 diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c index aecd9e0c2616..64fd8e79ea4c 100644 --- a/drivers/md/dm-target.c +++ b/drivers/md/dm-target.c @@ -78,8 +78,7 @@ void dm_put_target_type(struct target_type *t) if (--ti->use == 0) module_put(ti->tt.module); - if (ti->use < 0) - BUG(); + BUG_ON(ti->use < 0); up_read(&_lock); return; diff --git a/drivers/md/md.c b/drivers/md/md.c index 039e071c1007..434ca39d19c1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -163,6 +163,7 @@ void md_new_event(mddev_t *mddev) { atomic_inc(&md_event_count); wake_up(&md_event_waiters); + sysfs_notify(&mddev->kobj, NULL, "sync_action"); } EXPORT_SYMBOL_GPL(md_new_event); @@ -215,13 +216,11 @@ static void mddev_put(mddev_t *mddev) return; if (!mddev->raid_disks && list_empty(&mddev->disks)) { list_del(&mddev->all_mddevs); - /* that blocks */ + spin_unlock(&all_mddevs_lock); blk_cleanup_queue(mddev->queue); - /* that also blocks */ kobject_unregister(&mddev->kobj); - /* result blows... */ - } - spin_unlock(&all_mddevs_lock); + } else + spin_unlock(&all_mddevs_lock); } static mddev_t * mddev_find(dev_t unit) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 3cb0872a845d..6081941de1b3 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1135,8 +1135,19 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error) mirror = i; break; } - if (!uptodate) + if (!uptodate) { + int sync_blocks = 0; + sector_t s = r1_bio->sector; + long sectors_to_go = r1_bio->sectors; + /* make sure these bits doesn't get cleared. */ + do { + bitmap_end_sync(mddev->bitmap, r1_bio->sector, + &sync_blocks, 1); + s += sync_blocks; + sectors_to_go -= sync_blocks; + } while (sectors_to_go > 0); md_error(mddev, conf->mirrors[mirror].rdev); + } update_head_pos(mirror, r1_bio); @@ -1547,8 +1558,7 @@ static int init_resync(conf_t *conf) int buffs; buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE; - if (conf->r1buf_pool) - BUG(); + BUG_ON(conf->r1buf_pool); conf->r1buf_pool = mempool_create(buffs, r1buf_pool_alloc, r1buf_pool_free, conf->poolinfo); if (!conf->r1buf_pool) @@ -1721,8 +1731,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) break; - if (sync_blocks < (PAGE_SIZE>>9)) - BUG(); + BUG_ON(sync_blocks < (PAGE_SIZE>>9)); if (len > (sync_blocks<<9)) len = sync_blocks<<9; } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index ab90a6d12020..617012bc107a 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1117,8 +1117,7 @@ static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) for (i=0; icopies; i++) if (r10_bio->devs[i].bio == bio) break; - if (i == conf->copies) - BUG(); + BUG_ON(i == conf->copies); update_head_pos(i, r10_bio); d = r10_bio->devs[i].devnum; @@ -1518,8 +1517,7 @@ static int init_resync(conf_t *conf) int buffs; buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE; - if (conf->r10buf_pool) - BUG(); + BUG_ON(conf->r10buf_pool); conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf); if (!conf->r10buf_pool) return -ENOMEM; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index dae740adaf65..31843604049c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -73,10 +73,8 @@ static void print_raid5_conf (raid5_conf_t *conf); static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) { if (atomic_dec_and_test(&sh->count)) { - if (!list_empty(&sh->lru)) - BUG(); - if (atomic_read(&conf->active_stripes)==0) - BUG(); + BUG_ON(!list_empty(&sh->lru)); + BUG_ON(atomic_read(&conf->active_stripes)==0); if (test_bit(STRIPE_HANDLE, &sh->state)) { if (test_bit(STRIPE_DELAYED, &sh->state)) list_add_tail(&sh->lru, &conf->delayed_list); @@ -184,10 +182,8 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int raid5_conf_t *conf = sh->raid_conf; int i; - if (atomic_read(&sh->count) != 0) - BUG(); - if (test_bit(STRIPE_HANDLE, &sh->state)) - BUG(); + BUG_ON(atomic_read(&sh->count) != 0); + BUG_ON(test_bit(STRIPE_HANDLE, &sh->state)); CHECK_DEVLOCK(); PRINTK("init_stripe called, stripe %llu\n", @@ -269,8 +265,7 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector init_stripe(sh, sector, pd_idx, disks); } else { if (atomic_read(&sh->count)) { - if (!list_empty(&sh->lru)) - BUG(); + BUG_ON(!list_empty(&sh->lru)); } else { if (!test_bit(STRIPE_HANDLE, &sh->state)) atomic_inc(&conf->active_stripes); @@ -465,8 +460,7 @@ static int drop_one_stripe(raid5_conf_t *conf) spin_unlock_irq(&conf->device_lock); if (!sh) return 0; - if (atomic_read(&sh->count)) - BUG(); + BUG_ON(atomic_read(&sh->count)); shrink_buffers(sh, conf->pool_size); kmem_cache_free(conf->slab_cache, sh); atomic_dec(&conf->active_stripes); @@ -882,8 +876,7 @@ static void compute_parity(struct stripe_head *sh, int method) ptr[0] = page_address(sh->dev[pd_idx].page); switch(method) { case READ_MODIFY_WRITE: - if (!test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags)) - BUG(); + BUG_ON(!test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags)); for (i=disks ; i-- ;) { if (i==pd_idx) continue; @@ -896,7 +889,7 @@ static void compute_parity(struct stripe_head *sh, int method) if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) wake_up(&conf->wait_for_overlap); - if (sh->dev[i].written) BUG(); + BUG_ON(sh->dev[i].written); sh->dev[i].written = chosen; check_xor(); } @@ -912,7 +905,7 @@ static void compute_parity(struct stripe_head *sh, int method) if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) wake_up(&conf->wait_for_overlap); - if (sh->dev[i].written) BUG(); + BUG_ON(sh->dev[i].written); sh->dev[i].written = chosen; } break; @@ -995,8 +988,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9)) goto overlap; - if (*bip && bi->bi_next && (*bip) != bi->bi_next) - BUG(); + BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next); if (*bip) bi->bi_next = *bip; *bip = bi; @@ -1430,8 +1422,7 @@ static void handle_stripe(struct stripe_head *sh) set_bit(STRIPE_HANDLE, &sh->state); if (failed == 0) { char *pagea; - if (uptodate != disks) - BUG(); + BUG_ON(uptodate != disks); compute_parity(sh, CHECK_PARITY); uptodate--; pagea = page_address(sh->dev[sh->pd_idx].page); @@ -2096,8 +2087,7 @@ static void raid5d (mddev_t *mddev) list_del_init(first); atomic_inc(&sh->count); - if (atomic_read(&sh->count)!= 1) - BUG(); + BUG_ON(atomic_read(&sh->count)!= 1); spin_unlock_irq(&conf->device_lock); handled++; diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c index 6df4930fddec..bc69355e0100 100644 --- a/drivers/md/raid6main.c +++ b/drivers/md/raid6main.c @@ -91,10 +91,8 @@ static void print_raid6_conf (raid6_conf_t *conf); static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh) { if (atomic_dec_and_test(&sh->count)) { - if (!list_empty(&sh->lru)) - BUG(); - if (atomic_read(&conf->active_stripes)==0) - BUG(); + BUG_ON(!list_empty(&sh->lru)); + BUG_ON(atomic_read(&conf->active_stripes)==0); if (test_bit(STRIPE_HANDLE, &sh->state)) { if (test_bit(STRIPE_DELAYED, &sh->state)) list_add_tail(&sh->lru, &conf->delayed_list); @@ -202,10 +200,8 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx) raid6_conf_t *conf = sh->raid_conf; int disks = conf->raid_disks, i; - if (atomic_read(&sh->count) != 0) - BUG(); - if (test_bit(STRIPE_HANDLE, &sh->state)) - BUG(); + BUG_ON(atomic_read(&sh->count) != 0); + BUG_ON(test_bit(STRIPE_HANDLE, &sh->state)); CHECK_DEVLOCK(); PRINTK("init_stripe called, stripe %llu\n", @@ -284,13 +280,11 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector init_stripe(sh, sector, pd_idx); } else { if (atomic_read(&sh->count)) { - if (!list_empty(&sh->lru)) - BUG(); + BUG_ON(!list_empty(&sh->lru)); } else { if (!test_bit(STRIPE_HANDLE, &sh->state)) atomic_inc(&conf->active_stripes); - if (list_empty(&sh->lru)) - BUG(); + BUG_ON(list_empty(&sh->lru)); list_del_init(&sh->lru); } } @@ -353,8 +347,7 @@ static int drop_one_stripe(raid6_conf_t *conf) spin_unlock_irq(&conf->device_lock); if (!sh) return 0; - if (atomic_read(&sh->count)) - BUG(); + BUG_ON(atomic_read(&sh->count)); shrink_buffers(sh, conf->raid_disks); kmem_cache_free(conf->slab_cache, sh); atomic_dec(&conf->active_stripes); @@ -780,7 +773,7 @@ static void compute_parity(struct stripe_head *sh, int method) if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) wake_up(&conf->wait_for_overlap); - if (sh->dev[i].written) BUG(); + BUG_ON(sh->dev[i].written); sh->dev[i].written = chosen; } break; @@ -970,8 +963,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9)) goto overlap; - if (*bip && bi->bi_next && (*bip) != bi->bi_next) - BUG(); + BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next); if (*bip) bi->bi_next = *bip; *bip = bi; @@ -1906,8 +1898,7 @@ static void raid6d (mddev_t *mddev) list_del_init(first); atomic_inc(&sh->count); - if (atomic_read(&sh->count)!= 1) - BUG(); + BUG_ON(atomic_read(&sh->count)!= 1); spin_unlock_irq(&conf->device_lock); handled++; @@ -2151,6 +2142,8 @@ static int run(mddev_t *mddev) } /* Ok, everything is just fine now */ + sysfs_create_group(&mddev->kobj, &raid6_attrs_group); + mddev->array_size = mddev->size * (mddev->raid_disks - 2); mddev->queue->unplug_fn = raid6_unplug_device; diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index baa9f58beffc..fffc711c260c 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -51,18 +51,18 @@ config VIDEO_TVEEPROM tristate config USB_DABUSB - tristate "DABUSB driver" - depends on USB - ---help--- - A Digital Audio Broadcasting (DAB) Receiver for USB and Linux - brought to you by the DAB-Team - . This driver can be taken - as an example for URB-based bulk, control, and isochronous - transactions. URB's are explained in - . + tristate "DABUSB driver" + depends on USB + ---help--- + A Digital Audio Broadcasting (DAB) Receiver for USB and Linux + brought to you by the DAB-Team + . This driver can be taken + as an example for URB-based bulk, control, and isochronous + transactions. URB's are explained in + . - To compile this driver as a module, choose M here: the - module will be called dabusb. + To compile this driver as a module, choose M here: the + module will be called dabusb. endmenu diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index 2337b41714e0..376ca48f1d1d 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -7,6 +7,7 @@ config DVB_BT8XX select DVB_CX24110 select DVB_OR51211 select DVB_LGDT330X + select FW_LOADER help Support for PCI cards based on the Bt8xx PCI bridge. Examples are the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 09e96e9ddbdf..04578df3f249 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -141,12 +141,18 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) } if ((file->f_flags & O_ACCMODE) == O_RDONLY) { - void *mem = vmalloc(DVR_BUFFER_SIZE); + void *mem; + if (!dvbdev->readers) { + mutex_unlock(&dmxdev->mutex); + return -EBUSY; + } + mem = vmalloc(DVR_BUFFER_SIZE); if (!mem) { mutex_unlock(&dmxdev->mutex); return -ENOMEM; } dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); + dvbdev->readers--; } if ((file->f_flags & O_ACCMODE) == O_WRONLY) { @@ -184,6 +190,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) dmxdev->dvr_orig_fe); } if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + dvbdev->readers++; if (dmxdev->dvr_buffer.data) { void *mem = dmxdev->dvr_buffer.data; mb(); @@ -1029,8 +1036,7 @@ static struct file_operations dvb_dvr_fops = { static struct dvb_device dvbdev_dvr = { .priv = NULL, - .users = 1, - .writers = 1, + .readers = 1, .fops = &dvb_dvr_fops }; diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 2c3ea8f95dcd..4f8f257e6795 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -105,6 +105,7 @@ struct dvb_frontend_private { fe_status_t status; unsigned long tune_mode_flags; unsigned int delay; + unsigned int reinitialise; /* swzigzag values */ unsigned int state; @@ -121,6 +122,7 @@ struct dvb_frontend_private { unsigned int check_wrapped; }; +static void dvb_frontend_wakeup(struct dvb_frontend *fe); static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) { @@ -213,6 +215,15 @@ static void dvb_frontend_init(struct dvb_frontend *fe) fe->ops->init(fe); } +void dvb_frontend_reinitialise(struct dvb_frontend *fe) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + fepriv->reinitialise = 1; + dvb_frontend_wakeup(fe); +} +EXPORT_SYMBOL(dvb_frontend_reinitialise); + static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked) { int q2; @@ -505,8 +516,8 @@ static int dvb_frontend_thread(void *data) fepriv->quality = 0; fepriv->delay = 3*HZ; fepriv->status = 0; - dvb_frontend_init(fe); fepriv->wakeup = 0; + fepriv->reinitialise = 1; while (1) { up(&fepriv->sem); /* is locked when we enter the thread... */ @@ -524,6 +535,11 @@ static int dvb_frontend_thread(void *data) if (down_interruptible(&fepriv->sem)) break; + if (fepriv->reinitialise) { + dvb_frontend_init(fe); + fepriv->reinitialise = 0; + } + /* do an iteration of the tuning loop */ if (fe->ops->tune) { /* have we been asked to retune? */ diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index d5aee5ad67a0..5926a3b745c9 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -112,6 +112,8 @@ extern int dvb_register_frontend(struct dvb_adapter* dvb, extern int dvb_unregister_frontend(struct dvb_frontend* fe); +extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); + extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec); extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime); diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index a14e737ec848..7edd6362b9cc 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -233,6 +233,45 @@ static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { { 0xfe, 0x4e, KEY_POWER }, }; +static struct dvb_usb_rc_key dvico_portable_rc_keys[] = { + { 0xfc, 0x02, KEY_SETUP }, /* Profile */ + { 0xfc, 0x43, KEY_POWER2 }, + { 0xfc, 0x06, KEY_EPG }, + { 0xfc, 0x5a, KEY_BACK }, + { 0xfc, 0x05, KEY_MENU }, + { 0xfc, 0x47, KEY_INFO }, + { 0xfc, 0x01, KEY_TAB }, + { 0xfc, 0x42, KEY_PREVIOUSSONG },/* Replay */ + { 0xfc, 0x49, KEY_VOLUMEUP }, + { 0xfc, 0x09, KEY_VOLUMEDOWN }, + { 0xfc, 0x54, KEY_CHANNELUP }, + { 0xfc, 0x0b, KEY_CHANNELDOWN }, + { 0xfc, 0x16, KEY_CAMERA }, + { 0xfc, 0x40, KEY_TUNER }, /* ATV/DTV */ + { 0xfc, 0x45, KEY_OPEN }, + { 0xfc, 0x19, KEY_1 }, + { 0xfc, 0x18, KEY_2 }, + { 0xfc, 0x1b, KEY_3 }, + { 0xfc, 0x1a, KEY_4 }, + { 0xfc, 0x58, KEY_5 }, + { 0xfc, 0x59, KEY_6 }, + { 0xfc, 0x15, KEY_7 }, + { 0xfc, 0x14, KEY_8 }, + { 0xfc, 0x17, KEY_9 }, + { 0xfc, 0x44, KEY_ANGLE }, /* Aspect */ + { 0xfc, 0x55, KEY_0 }, + { 0xfc, 0x07, KEY_ZOOM }, + { 0xfc, 0x0a, KEY_REWIND }, + { 0xfc, 0x08, KEY_PLAYPAUSE }, + { 0xfc, 0x4b, KEY_FASTFORWARD }, + { 0xfc, 0x5b, KEY_MUTE }, + { 0xfc, 0x04, KEY_STOP }, + { 0xfc, 0x56, KEY_RECORD }, + { 0xfc, 0x57, KEY_POWER }, + { 0xfc, 0x41, KEY_UNKNOWN }, /* INPUT */ + { 0xfc, 0x00, KEY_UNKNOWN }, /* HD */ +}; + static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; @@ -511,6 +550,11 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { .i2c_algo = &cxusb_i2c_algo, + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_rc_query, + .generic_bulk_ctrl_endpoint = 0x01, /* parameter for the MPEG2-data transfer */ .urb = { @@ -600,6 +644,11 @@ static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = { .i2c_algo = &cxusb_i2c_algo, + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_rc_query, + .generic_bulk_ctrl_endpoint = 0x01, /* parameter for the MPEG2-data transfer */ .urb = { @@ -640,6 +689,11 @@ static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = { .i2c_algo = &cxusb_i2c_algo, + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_rc_query, + .generic_bulk_ctrl_endpoint = 0x01, /* parameter for the MPEG2-data transfer */ .urb = { diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index 12ebaf8bddca..70afcfd141ca 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -94,12 +94,14 @@ static int dtt200u_frontend_attach(struct dvb_usb_device *d) static struct dvb_usb_properties dtt200u_properties; static struct dvb_usb_properties wt220u_properties; +static struct dvb_usb_properties wt220u_zl0353_properties; static int dtt200u_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0) + dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0) return 0; return -ENODEV; @@ -110,6 +112,8 @@ static struct usb_device_id dtt200u_usb_table [] = { { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) }, + { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) }, { 0 }, }; MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); @@ -196,6 +200,47 @@ static struct dvb_usb_properties wt220u_properties = { } }; +static struct dvb_usb_properties wt220u_zl0353_properties = { + .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING, + .pid_filter_count = 15, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-wt220u-zl0353-01.fw", + + .power_ctrl = dtt200u_power_ctrl, + .streaming_ctrl = dtt200u_streaming_ctrl, + .pid_filter = dtt200u_pid_filter, + .frontend_attach = dtt200u_frontend_attach, + + .rc_interval = 300, + .rc_key_map = dtt200u_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys), + .rc_query = dtt200u_rc_query, + + .generic_bulk_ctrl_endpoint = 0x01, + + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + + .num_device_descs = 1, + .devices = { + { .name = "WideView WT-220U PenType Receiver (based on ZL353)", + .cold_ids = { &dtt200u_usb_table[4], NULL }, + .warm_ids = { &dtt200u_usb_table[5], NULL }, + }, + { NULL }, + } +}; + /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver dtt200u_usb_driver = { .name = "dvb_usb_dtt200u", diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 4a1b9e77e339..cb239049b098 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -83,6 +83,8 @@ #define USB_PID_DTT200U_WARM 0x0301 #define USB_PID_WT220U_COLD 0x0222 #define USB_PID_WT220U_WARM 0x0221 +#define USB_PID_WT220U_ZL0353_COLD 0x022a +#define USB_PID_WT220U_ZL0353_WARM 0x022b #define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300 #define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 #define USB_PID_NEBULA_DIGITV 0x0201 diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c index b6d95e1c9c52..2a89f8c5da99 100644 --- a/drivers/media/dvb/dvb-usb/vp702x-fe.c +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -147,8 +147,9 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe, cmd[4] = (sr >> 4) & 0xff; cmd[5] = (sr << 4) & 0xf0; - deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %Lu (%Lx)\n", - fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, sr, sr); + deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n", + fep->frequency,freq,freq, fep->u.qpsk.symbol_rate, + (unsigned long) sr, (unsigned long) sr); /* if (fep->inversion == INVERSION_ON) cmd[6] |= 0x80; */ diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 94233168d241..37d5e0af1683 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -181,6 +181,11 @@ config DVB_OR51211 help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. + This driver needs external firmware. Please use the command + "/Documentation/dvb/get_dvb_firmware or51211" to + download it, and then copy it to /usr/lib/hotplug/firmware + or /lib/firmware (depending on configuration of firmware hotplug). + config DVB_OR51132 tristate "Oren OR51132 based" depends on DVB_CORE @@ -189,6 +194,13 @@ config DVB_OR51132 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. + This driver needs external firmware. Please use the commands + "/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or + "/Documentation/dvb/get_dvb_firmware or51132_qam" to + download firmwares for 8VSB and QAM64/256, respectively. Copy them to + /usr/lib/hotplug/firmware or /lib/firmware (depending on + configuration of firmware hotplug). + config DVB_BCM3510 tristate "Broadcom BCM3510" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index 8e8df7b4ca0e..b83dafa4e12c 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -52,7 +52,6 @@ struct tda1004x_state { struct dvb_frontend frontend; /* private demod data */ - u8 initialised; enum tda1004x_demod demod_type; }; @@ -594,9 +593,6 @@ static int tda10045_init(struct dvb_frontend* fe) dprintk("%s\n", __FUNCTION__); - if (state->initialised) - return 0; - if (tda10045_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); return -EIO; @@ -626,7 +622,6 @@ static int tda10045_init(struct dvb_frontend* fe) tda1004x_write_mask(state, 0x1f, 0x01, state->config->invert_oclk); - state->initialised = 1; return 0; } @@ -635,9 +630,6 @@ static int tda10046_init(struct dvb_frontend* fe) struct tda1004x_state* state = fe->demodulator_priv; dprintk("%s\n", __FUNCTION__); - if (state->initialised) - return 0; - if (tda10046_fwupload(fe)) { printk("tda1004x: firmware upload failed\n"); return -EIO; @@ -697,7 +689,6 @@ static int tda10046_init(struct dvb_frontend* fe) // tda1004x_write_mask(state, 0x50, 0x80, 0x80); // handle out of guard echoes tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7); - state->initialised = 1; return 0; } @@ -1207,7 +1198,6 @@ static int tda1004x_sleep(struct dvb_frontend* fe) tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); break; } - state->initialised = 0; return 0; } @@ -1271,7 +1261,6 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, state->config = config; state->i2c = i2c; memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); - state->initialised = 0; state->demod_type = TDA1004X_DEMOD_TDA10045; /* check if the demod is there */ @@ -1330,7 +1319,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, state->config = config; state->i2c = i2c; memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); - state->initialised = 0; state->demod_type = TDA1004X_DEMOD_TDA10046; /* check if the demod is there */ diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 840efec32cb6..d028245c8eed 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -87,6 +87,7 @@ static int volume = 255; static int budgetpatch; static int wss_cfg_4_3 = 0x4008; static int wss_cfg_16_9 = 0x0007; +static int tv_standard; module_param_named(debug, av7110_debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); @@ -109,6 +110,8 @@ module_param(wss_cfg_4_3, int, 0444); MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); module_param(wss_cfg_16_9, int, 0444); MODULE_PARM_DESC(wss_cfg_16_9, "WSS 16:9 - default 0x0007 - bit 15: disable, 14: burst mode, 13..0: wss data"); +module_param(tv_standard, int, 0444); +MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); static void restart_feeds(struct av7110 *av7110); @@ -2123,7 +2126,7 @@ static int frontend_init(struct av7110 *av7110) read_pwm(av7110)); break; case 0x0003: - /* Haupauge DVB-C 2.1 VES1820/ALPS TDBE2 */ + /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */ av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); break; @@ -2543,6 +2546,9 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, av7110->osdwin = 1; mutex_init(&av7110->osd_mutex); + /* TV standard */ + av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; + /* ARM "watchdog" */ init_waitqueue_head(&av7110->arm_wait); av7110->arm_thread = NULL; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 400facec7407..2eff09f638d3 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -1479,8 +1479,6 @@ int av7110_av_init(struct av7110 *av7110) void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb }; int i, ret; - av7110->vidmode = VIDEO_MODE_PAL; - for (i = 0; i < 2; i++) { struct ipack *ipack = av7110->ipack + i; diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 9dd4745f5312..8efe3ce5f66c 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -60,11 +60,11 @@ struct budget_av { struct dvb_ca_en50221 ca; }; -/* GPIO CI Connections: - * 0 - Vcc/Reset (Reset is controlled by capacitor) - * 1 - Attribute Memory - * 2 - Card Enable (Active Low) - * 3 - Card Detect +/* GPIO Connections: + * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! + * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory + * 2 - CI Card Enable (Active Low) + * 3 - CI Card Detect */ /**************************************************************************** @@ -214,6 +214,9 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d) msleep(100); + /* reinitialise the frontend */ + dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); + if (timeout <= 0) { printk(KERN_ERR "budget-av: cam reset failed (timeout).\n"); diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index 633e68c341c8..ea2066d461fc 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -39,9 +39,21 @@ #include "budget.h" #include "ttpci-eeprom.h" +#define TS_WIDTH (2 * TS_SIZE) +#define TS_WIDTH_ACTIVY TS_SIZE +#define TS_HEIGHT_MASK 0xf00 +#define TS_HEIGHT_MASK_ACTIVY 0xc00 +#define TS_MIN_BUFSIZE_K 188 +#define TS_MAX_BUFSIZE_K 1410 +#define TS_MAX_BUFSIZE_K_ACTIVY 564 +#define BUFFER_WARNING_WAIT (30*HZ) + int budget_debug; +static int dma_buffer_size = TS_MIN_BUFSIZE_K; module_param_named(debug, budget_debug, int, 0644); +module_param_named(bufsize, dma_buffer_size, int, 0444); MODULE_PARM_DESC(debug, "Turn on/off budget debugging (default:off)."); +MODULE_PARM_DESC(bufsize, "DMA buffer size in KB, default: 188, min: 188, max: 1410 (Activy: 564)"); /**************************************************************************** * TT budget / WinTV Nova @@ -70,11 +82,10 @@ static int start_ts_capture(struct budget *budget) saa7146_write(dev, MC1, MASK_20); // DMA3 off - memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH); + memset(budget->grabbing, 0x00, budget->buffer_size); saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); - budget->tsf = 0xff; budget->ttbp = 0; /* @@ -115,16 +126,12 @@ static int start_ts_capture(struct budget *budget) saa7146_write(dev, BASE_ODD3, 0); saa7146_write(dev, BASE_EVEN3, 0); - saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, PROT_ADDR3, budget->buffer_size); saa7146_write(dev, BASE_PAGE3, budget->pt.dma | ME1 | 0x90); - if (budget->card->type == BUDGET_FS_ACTIVY) { - saa7146_write(dev, PITCH3, TS_WIDTH / 2); - saa7146_write(dev, NUM_LINE_BYTE3, ((TS_HEIGHT * 2) << 16) | (TS_WIDTH / 2)); - } else { - saa7146_write(dev, PITCH3, TS_WIDTH); - saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); - } + saa7146_write(dev, PITCH3, budget->buffer_width); + saa7146_write(dev, NUM_LINE_BYTE3, + (budget->buffer_height << 16) | budget->buffer_width); saa7146_write(dev, MC2, (MASK_04 | MASK_20)); @@ -141,11 +148,12 @@ static void vpeirq(unsigned long data) u8 *mem = (u8 *) (budget->grabbing); u32 olddma = budget->ttbp; u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + u32 count; /* nearest lower position divisible by 188 */ newdma -= newdma % 188; - if (newdma >= TS_BUFLEN) + if (newdma >= budget->buffer_size) return; budget->ttbp = newdma; @@ -154,11 +162,24 @@ static void vpeirq(unsigned long data) return; if (newdma > olddma) { /* no wraparound, dump olddma..newdma */ - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (newdma - olddma) / 188); + count = newdma - olddma; + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); } else { /* wraparound, dump olddma..buflen and 0..newdma */ - dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, (TS_BUFLEN - olddma) / 188); + count = budget->buffer_size - olddma; + dvb_dmx_swfilter_packets(&budget->demux, mem + olddma, count / 188); + count += newdma; dvb_dmx_swfilter_packets(&budget->demux, mem, newdma / 188); } + + if (count > budget->buffer_warning_threshold) + budget->buffer_warnings++; + + if (budget->buffer_warnings && time_after(jiffies, budget->buffer_warning_time)) { + printk("%s %s: used %d times >80%% of buffer (%u bytes now)\n", + budget->dev->name, __FUNCTION__, budget->buffer_warnings, count); + budget->buffer_warning_time = jiffies + BUFFER_WARNING_WAIT; + budget->buffer_warnings = 0; + } } @@ -341,9 +362,10 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, struct saa7146_pci_extension_data *info, struct module *owner) { - int length = TS_WIDTH * TS_HEIGHT; int ret = 0; struct budget_info *bi = info->ext_priv; + int max_bufsize; + int height_mask; memset(budget, 0, sizeof(struct budget)); @@ -352,6 +374,32 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, budget->card = bi; budget->dev = (struct saa7146_dev *) dev; + if (budget->card->type == BUDGET_FS_ACTIVY) { + budget->buffer_width = TS_WIDTH_ACTIVY; + max_bufsize = TS_MAX_BUFSIZE_K_ACTIVY; + height_mask = TS_HEIGHT_MASK_ACTIVY; + } else { + budget->buffer_width = TS_WIDTH; + max_bufsize = TS_MAX_BUFSIZE_K; + height_mask = TS_HEIGHT_MASK; + } + + if (dma_buffer_size < TS_MIN_BUFSIZE_K) + dma_buffer_size = TS_MIN_BUFSIZE_K; + else if (dma_buffer_size > max_bufsize) + dma_buffer_size = max_bufsize; + + budget->buffer_height = dma_buffer_size * 1024 / budget->buffer_width; + budget->buffer_height &= height_mask; + budget->buffer_size = budget->buffer_height * budget->buffer_width; + budget->buffer_warning_threshold = budget->buffer_size * 80/100; + budget->buffer_warnings = 0; + budget->buffer_warning_time = jiffies; + + dprintk(2, "%s: width = %d, height = %d\n", + budget->dev->name, budget->buffer_width, budget->buffer_height); + printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); + dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner); /* set dd1 stream a & b */ @@ -392,7 +440,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, ttpci_eeprom_parse_mac(&budget->i2c_adap, budget->dvb_adapter.proposed_mac); if (NULL == - (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, length, &budget->pt))) { + (budget->grabbing = saa7146_vmalloc_build_pgtable(dev->pci, budget->buffer_size, &budget->pt))) { ret = -ENOMEM; goto err; } diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 9fc9185a8426..1b3aaac5e763 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -577,20 +577,6 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // Set RPS1 Address register to point to RPS code (r108 p42) saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); - // Set Source Line Counter Threshold, using BRS (rCC p43) - // It generates HS event every TS_HEIGHT lines - // this is related to TS_WIDTH set in register - // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE - // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188 - //,then RPS_THRESH1 - // should be set to trigger every TS_HEIGHT (512) lines. - // - saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 ); - - // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); - // Enable RPS1 (rFC p33) - saa7146_write(dev, MC1, (MASK_13 | MASK_29)); - if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) return -ENOMEM; @@ -602,6 +588,20 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte return err; } + // Set Source Line Counter Threshold, using BRS (rCC p43) + // It generates HS event every TS_HEIGHT lines + // this is related to TS_WIDTH set in register + // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE + // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188 + //,then RPS_THRESH1 + // should be set to trigger every TS_HEIGHT (512) lines. + // + saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 ); + + // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); + // Enable RPS1 (rFC p33) + saa7146_write(dev, MC1, (MASK_13 | MASK_29)); + dev->ext_priv = budget; diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h index 4ac0f4d08025..ecea3a13030e 100644 --- a/drivers/media/dvb/ttpci/budget.h +++ b/drivers/media/dvb/ttpci/budget.h @@ -58,7 +58,13 @@ struct budget { int ci_present; int video_port; - u8 tsf; + u32 buffer_width; + u32 buffer_height; + u32 buffer_size; + u32 buffer_warning_threshold; + u32 buffer_warnings; + unsigned long buffer_warning_time; + u32 ttbp; int feeding; @@ -79,11 +85,6 @@ static struct saa7146_pci_extension_data x_var = { \ .ext_priv = &x_var ## _info, \ .ext = &budget_extension }; -#define TS_WIDTH (376) -#define TS_HEIGHT (512) -#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT) -#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE) - #define BUDGET_TT 0 #define BUDGET_TT_HW_DISEQC 1 #define BUDGET_PATCH 3 diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index f31a19890b15..85888a8a93c9 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -300,7 +300,7 @@ config VIDEO_OVCAMCHIP camera drivers. To compile this driver as a module, choose M here: the - module will be called ovcamchip + module will be called ovcamchip. config VIDEO_M32R_AR tristate "AR devices" @@ -316,6 +316,13 @@ config VIDEO_M32R_AR_M64278 Say Y here to use the Renesas M64278E-800 camera module, which supports VGA(640x480 pixcels) size of images. +# +# Encoder / Decoder module configuration +# + +menu "Encoders and Decoders" + depends on VIDEO_DEV + config VIDEO_MSP3400 tristate "Micronas MSP34xx audio decoders" depends on VIDEO_DEV && I2C @@ -323,7 +330,7 @@ config VIDEO_MSP3400 Support for the Micronas MSP34xx series of audio decoders. To compile this driver as a module, choose M here: the - module will be called msp3400 + module will be called msp3400. config VIDEO_CS53L32A tristate "Cirrus Logic CS53L32A audio ADC" @@ -333,17 +340,27 @@ config VIDEO_CS53L32A stereo A/D converter. To compile this driver as a module, choose M here: the - module will be called cs53l32a + module will be called cs53l32a. config VIDEO_WM8775 - tristate "Wolfson Microelectronics WM8775 audio ADC" + tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" depends on VIDEO_DEV && I2C && EXPERIMENTAL ---help--- - Support for the Wolfson Microelectronics WM8775 - high performance stereo A/D Converter. + Support for the Wolfson Microelectronics WM8775 high + performance stereo A/D Converter with a 4 channel input mixer. To compile this driver as a module, choose M here: the - module will be called wm8775 + module will be called wm8775. + +config VIDEO_WM8739 + tristate "Wolfson Microelectronics WM8739 stereo audio ADC" + depends on VIDEO_DEV && I2C && EXPERIMENTAL + ---help--- + Support for the Wolfson Microelectronics WM8739 + stereo A/D Converter. + + To compile this driver as a module, choose M here: the + module will be called wm8739. source "drivers/media/video/cx25840/Kconfig" @@ -354,7 +371,7 @@ config VIDEO_SAA711X Support for the Philips SAA7113/4/5 video decoders. To compile this driver as a module, choose M here: the - module will be called saa7115 + module will be called saa7115. config VIDEO_SAA7127 tristate "Philips SAA7127/9 digital video encoders" @@ -363,7 +380,32 @@ config VIDEO_SAA7127 Support for the Philips SAA7127/9 digital video encoders. To compile this driver as a module, choose M here: the - module will be called saa7127 + module will be called saa7127. + +config VIDEO_UPD64031A + tristate "NEC Electronics uPD64031A Ghost Reduction" + depends on VIDEO_DEV && I2C && EXPERIMENTAL + ---help--- + Support for the NEC Electronics uPD64031A Ghost Reduction + video chip. It is most often found in NTSC TV cards made for + Japan and is used to reduce the 'ghosting' effect that can + be present in analog TV broadcasts. + + To compile this driver as a module, choose M here: the + module will be called upd64031a. + +config VIDEO_UPD64083 + tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" + depends on VIDEO_DEV && I2C && EXPERIMENTAL + ---help--- + Support for the NEC Electronics uPD64083 3-Dimensional Y/C + separation video chip. It is used to improve the quality of + the colors of a composite signal. + + To compile this driver as a module, choose M here: the + module will be called upd64083. + +endmenu # encoder / decoder chips # # USB Multimedia device configuration @@ -374,20 +416,6 @@ menu "V4L USB devices" source "drivers/media/video/em28xx/Kconfig" -config USB_VICAM - tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)" - depends on USB && VIDEO_DEV && EXPERIMENTAL - ---help--- - Say Y here if you have 3com homeconnect camera (vicam). - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Multimedia Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . - - To compile this driver as a module, choose M here: the - module will be called vicam. - config USB_DSBR tristate "D-Link USB FM radio support (EXPERIMENTAL)" depends on USB && VIDEO_DEV && EXPERIMENTAL @@ -397,79 +425,20 @@ config USB_DSBR you must connect the line out connector to a sound card or a set of speakers. - This driver uses the Video For Linux API. You must enable - (Y or M in config) Video For Linux (under Character Devices) - to use this driver. Information on this API and pointers to - "v4l" programs may be found at - . - To compile this driver as a module, choose M here: the module will be called dsbr100. -config USB_ET61X251 - tristate "USB ET61X[12]51 PC Camera Controller support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want support for cameras based on Etoms ET61X151 - or ET61X251 PC Camera Controllers. +source "drivers/media/video/usbvideo/Kconfig" - See for more informations. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. - - To compile this driver as a module, choose M here: the - module will be called et61x251. - -config USB_IBMCAM - tristate "USB IBM (Xirlink) C-it Camera support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want to connect a IBM "C-It" camera, also known as - "Xirlink PC Camera" to your computer's USB port. For more - information, read . - - This driver uses the Video For Linux API. You must enable - (Y or M in config) Video For Linux (under Character Devices) - to use this driver. Information on this API and pointers to - "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called ibmcam. - - This camera has several configuration options which - can be specified when you load the module. Read - to learn more. - -config USB_KONICAWC - tristate "USB Konica Webcam support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want support for webcams based on a Konica - chipset. This is known to work with the Intel YC76 webcam. - - This driver uses the Video For Linux API. You must enable - (Y or M in config) Video For Linux (under Character Devices) - to use this driver. Information on this API and pointers to - "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called konicawc. +source "drivers/media/video/et61x251/Kconfig" config USB_OV511 tristate "USB OV511 Camera support" depends on USB && VIDEO_DEV ---help--- Say Y here if you want to connect this type of camera to your - computer's USB port. See for more - information and for a list of supported cameras. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Character Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . + computer's USB port. See + for more information and for a list of supported cameras. To compile this driver as a module, choose M here: the module will be called ov511. @@ -479,31 +448,13 @@ config USB_SE401 depends on USB && VIDEO_DEV ---help--- Say Y here if you want to connect this type of camera to your - computer's USB port. See for more - information and for a list of supported cameras. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Multimedia Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . + computer's USB port. See + for more information and for a list of supported cameras. To compile this driver as a module, choose M here: the module will be called se401. -config USB_SN9C102 - tristate "USB SN9C10x PC Camera Controller support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want support for cameras based on SONiX SN9C101, - SN9C102 or SN9C103 PC Camera Controllers. - - See for more informations. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. - - To compile this driver as a module, choose M here: the - module will be called sn9c102. +source "drivers/media/video/sn9c102/Kconfig" config USB_STV680 tristate "USB STV680 (Pencam) Camera support" @@ -511,20 +462,16 @@ config USB_STV680 ---help--- Say Y here if you want to connect this type of camera to your computer's USB port. This includes the Pencam line of cameras. - See for more information and for - a list of supported cameras. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Multimedia Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . + See for more information + and for a list of supported cameras. To compile this driver as a module, choose M here: the module will be called stv680. config USB_W9968CF tristate "USB W996[87]CF JPEG Dual Mode Camera support" - depends on USB && VIDEO_DEV && I2C && VIDEO_OVCAMCHIP + depends on USB && VIDEO_DEV && I2C + select VIDEO_OVCAMCHIP ---help--- Say Y here if you want support for cameras based on OV681 or Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips. @@ -534,64 +481,14 @@ config USB_W9968CF resolutions and framerates, but cannot be included in the official Linux kernel for performance purposes. - See for more informations. - - This driver uses the Video For Linux and the I2C APIs. It needs the - OmniVision Camera Chip support as well. You must say Y or M to - "Video For Linux", "I2C Support" and "OmniVision Camera Chip - support" to use this driver. + See for more info. To compile this driver as a module, choose M here: the module will be called w9968cf. -config USB_ZC0301 - tristate "USB ZC0301 Image Processor and Control Chip support" - depends on USB && VIDEO_DEV - ---help--- - Say Y here if you want support for cameras based on the ZC0301 - Image Processor and Control Chip. +source "drivers/media/video/zc0301/Kconfig" - See for more informations. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. - - To compile this driver as a module, choose M here: the - module will be called zc0301. - -config USB_PWC - tristate "USB Philips Cameras" - depends on USB && VIDEO_DEV - ---help--- - Say Y or M here if you want to use one of these Philips & OEM - webcams: - * Philips PCA645, PCA646 - * Philips PCVC675, PCVC680, PCVC690 - * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 - * Askey VC010 - * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' - and 'Orbit'/'Sphere' - * Samsung MPC-C10, MPC-C30 - * Creative Webcam 5, Pro Ex - * SOTEC Afina Eye - * Visionite VCS-UC300, VCS-UM100 - - The PCA635, PCVC665 and PCVC720/20 are not supported by this driver - and never will be, but the 665 and 720/20 are supported by other - drivers. - - See for more information and - installation instructions. - - The built-in microphone is enabled by selecting USB Audio support. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" (under Character Devices) to use this driver. - Information on this API and pointers to "v4l" programs may be found - at . - - To compile this driver as a module, choose M here: the - module will be called pwc. +source "drivers/media/video/pwc/Kconfig" endmenu # V4L USB devices diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 1c0e72e5a593..b3ea2d63db9b 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o +obj-$(CONFIG_VIDEO_WM8739) += wm8739.o obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_MXB) += saa7111.o tda9840.o tea6415c.o tea6420.o mxb.o @@ -64,9 +65,8 @@ obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o obj-$(CONFIG_VIDEO_CX25840) += cx25840/ obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o - -et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o -zc0301-objs := zc0301_core.o zc0301_pas202bcb.o +obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o +obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_USB_DABUSB) += dabusb.o obj-$(CONFIG_USB_DSBR) += dsbr100.o @@ -84,4 +84,4 @@ obj-$(CONFIG_USB_IBMCAM) += usbvideo/ obj-$(CONFIG_USB_KONICAWC) += usbvideo/ obj-$(CONFIG_USB_VICAM) += usbvideo/ -EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index 94350f21cdc0..db641a36b197 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -9,4 +9,4 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ obj-$(CONFIG_VIDEO_BT848) += bttv.o EXTRA_CFLAGS += -I$(src)/.. -EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 74def9c23952..423e954948be 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -973,12 +973,12 @@ audio_mux(struct bttv *btv, int input, int mute) For now this is sufficient. */ switch (input) { case TVAUDIO_INPUT_RADIO: - route.input = MSP_INPUT(MSP_IN_SCART_2, MSP_IN_TUNER_1, - MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART); + route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); break; case TVAUDIO_INPUT_EXTERN: - route.input = MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1, - MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART); + route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); break; case TVAUDIO_INPUT_INTERN: /* Yes, this is the same input as for RADIO. I doubt @@ -986,8 +986,8 @@ audio_mux(struct bttv *btv, int input, int mute) input is the BTTV_BOARD_AVERMEDIA98. I wonder how that was tested. My guess is that the whole INTERN input does not work. */ - route.input = MSP_INPUT(MSP_IN_SCART_2, MSP_IN_TUNER_1, - MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART); + route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); break; case TVAUDIO_INPUT_TUNER: default: @@ -1023,14 +1023,11 @@ audio_input(struct bttv *btv, int input) static void i2c_vidiocschan(struct bttv *btv) { - struct video_channel c; + v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id; - memset(&c,0,sizeof(c)); - c.norm = btv->tvnorm; - c.channel = btv->input; - bttv_call_i2c_clients(btv,VIDIOCSCHAN,&c); + bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std); if (btv->c.type == BTTV_BOARD_VOODOOTV_FM) - bttv_tda9880_setnorm(btv,c.norm); + bttv_tda9880_setnorm(btv,btv->tvnorm); } static int @@ -1184,11 +1181,27 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) break; if (i == BTTV_CTLS) return -EINVAL; - if (i >= 4 && i <= 8) { + if (btv->audio_hook && i >= 4 && i <= 8) { memset(&va,0,sizeof(va)); - bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); - if (btv->audio_hook) - btv->audio_hook(btv,&va,0); + btv->audio_hook(btv,&va,0); + switch (c->id) { + case V4L2_CID_AUDIO_MUTE: + c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0; + break; + case V4L2_CID_AUDIO_VOLUME: + c->value = va.volume; + break; + case V4L2_CID_AUDIO_BALANCE: + c->value = va.balance; + break; + case V4L2_CID_AUDIO_BASS: + c->value = va.bass; + break; + case V4L2_CID_AUDIO_TREBLE: + c->value = va.treble; + break; + } + return 0; } switch (c->id) { case V4L2_CID_BRIGHTNESS: @@ -1205,19 +1218,11 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) break; case V4L2_CID_AUDIO_MUTE: - c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0; - break; case V4L2_CID_AUDIO_VOLUME: - c->value = va.volume; - break; case V4L2_CID_AUDIO_BALANCE: - c->value = va.balance; - break; case V4L2_CID_AUDIO_BASS: - c->value = va.bass; - break; case V4L2_CID_AUDIO_TREBLE: - c->value = va.treble; + bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c); break; case V4L2_CID_PRIVATE_CHROMA_AGC: @@ -1269,11 +1274,35 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) break; if (i == BTTV_CTLS) return -EINVAL; - if (i >= 4 && i <= 8) { + if (btv->audio_hook && i >= 4 && i <= 8) { memset(&va,0,sizeof(va)); - bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); - if (btv->audio_hook) - btv->audio_hook(btv,&va,0); + btv->audio_hook(btv,&va,0); + switch (c->id) { + case V4L2_CID_AUDIO_MUTE: + if (c->value) { + va.flags |= VIDEO_AUDIO_MUTE; + audio_mute(btv, 1); + } else { + va.flags &= ~VIDEO_AUDIO_MUTE; + audio_mute(btv, 0); + } + break; + + case V4L2_CID_AUDIO_VOLUME: + va.volume = c->value; + break; + case V4L2_CID_AUDIO_BALANCE: + va.balance = c->value; + break; + case V4L2_CID_AUDIO_BASS: + va.bass = c->value; + break; + case V4L2_CID_AUDIO_TREBLE: + va.treble = c->value; + break; + } + btv->audio_hook(btv,&va,1); + return 0; } switch (c->id) { case V4L2_CID_BRIGHTNESS: @@ -1289,26 +1318,13 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) bt848_sat(btv,c->value); break; case V4L2_CID_AUDIO_MUTE: - if (c->value) { - va.flags |= VIDEO_AUDIO_MUTE; - audio_mute(btv, 1); - } else { - va.flags &= ~VIDEO_AUDIO_MUTE; - audio_mute(btv, 0); - } - break; - + audio_mute(btv, c->value); + /* fall through */ case V4L2_CID_AUDIO_VOLUME: - va.volume = c->value; - break; case V4L2_CID_AUDIO_BALANCE: - va.balance = c->value; - break; case V4L2_CID_AUDIO_BASS: - va.bass = c->value; - break; case V4L2_CID_AUDIO_TREBLE: - va.treble = c->value; + bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c); break; case V4L2_CID_PRIVATE_CHROMA_AGC: @@ -1364,11 +1380,6 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) default: return -EINVAL; } - if (i >= 4 && i <= 8) { - bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va); - if (btv->audio_hook) - btv->audio_hook(btv,&va,1); - } return 0; } @@ -1591,12 +1602,16 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) } case VIDIOCSFREQ: { - unsigned long *freq = arg; + struct v4l2_frequency freq; + + memset(&freq, 0, sizeof(freq)); + freq.frequency = *(unsigned long *)arg; mutex_lock(&btv->lock); - btv->freq=*freq; - bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq); + freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + btv->freq = *(unsigned long *)arg; + bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq); if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv,*freq); + tea5757_set_freq(btv,*(unsigned long *)arg); mutex_unlock(&btv->lock); return 0; } @@ -1827,33 +1842,26 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) return -EINVAL; mutex_lock(&btv->lock); memset(t,0,sizeof(*t)); - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; t->rxsubchans = V4L2_TUNER_SUB_MONO; + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + strcpy(t->name, "Television"); + t->capability = V4L2_TUNER_CAP_NORM; + t->type = V4L2_TUNER_ANALOG_TV; if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) t->signal = 0xffff; - { - struct video_tuner tuner; - memset(&tuner, 0, sizeof (tuner)); - tuner.rangehigh = 0xffffffffUL; - bttv_call_i2c_clients(btv, VIDIOCGTUNER, &tuner); - t->rangelow = tuner.rangelow; - t->rangehigh = tuner.rangehigh; - } - { + if (btv->audio_hook) { /* Hmmm ... */ struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); - bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); - if (btv->audio_hook) - btv->audio_hook(btv,&va,0); + btv->audio_hook(btv,&va,0); + t->audmode = V4L2_TUNER_MODE_MONO; + t->rxsubchans = V4L2_TUNER_SUB_MONO; if(va.mode & VIDEO_SOUND_STEREO) { - t->audmode = V4L2_TUNER_MODE_STEREO; - t->rxsubchans |= V4L2_TUNER_SUB_STEREO; + t->audmode = V4L2_TUNER_MODE_STEREO; + t->rxsubchans = V4L2_TUNER_SUB_STEREO; } - if(va.mode & VIDEO_SOUND_LANG1) { + if(va.mode & VIDEO_SOUND_LANG2) { t->audmode = V4L2_TUNER_MODE_LANG1; t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; @@ -1872,10 +1880,10 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) if (0 != t->index) return -EINVAL; mutex_lock(&btv->lock); - { + bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); + if (btv->audio_hook) { struct video_audio va; memset(&va, 0, sizeof(struct video_audio)); - bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); if (t->audmode == V4L2_TUNER_MODE_MONO) va.mode = VIDEO_SOUND_MONO; else if (t->audmode == V4L2_TUNER_MODE_STEREO || @@ -1885,9 +1893,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) va.mode = VIDEO_SOUND_LANG1; else if (t->audmode == V4L2_TUNER_MODE_LANG2) va.mode = VIDEO_SOUND_LANG2; - bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va); - if (btv->audio_hook) - btv->audio_hook(btv,&va,1); + btv->audio_hook(btv,&va,1); } mutex_unlock(&btv->lock); return 0; @@ -1912,7 +1918,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) return -EINVAL; mutex_lock(&btv->lock); btv->freq = f->frequency; - bttv_call_i2c_clients(btv,VIDIOCSFREQ,&btv->freq); + bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f); if (btv->has_matchbox && btv->radio_user) tea5757_set_freq(btv,btv->freq); mutex_unlock(&btv->lock); @@ -1920,7 +1926,9 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) } case VIDIOC_LOG_STATUS: { + printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr); bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); + printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr); return 0; } @@ -2870,12 +2878,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, return 0; } *c = bttv_ctls[i]; - if (i >= 4 && i <= 8) { + if (btv->audio_hook && i >= 4 && i <= 8) { struct video_audio va; memset(&va,0,sizeof(va)); - bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); - if (btv->audio_hook) - btv->audio_hook(btv,&va,0); + btv->audio_hook(btv,&va,0); switch (bttv_ctls[i].id) { case V4L2_CID_AUDIO_VOLUME: if (!(va.flags & VIDEO_AUDIO_VOLUME)) diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index e20ff238e409..8c9f0f7cf467 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -184,7 +184,7 @@ void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f) - tvnorm->vbistart[0]; count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1] - tvnorm->vbistart[1]; - count = clamp (max (count0, count1), 1LL, (s64) VBI_MAXLINES); + count = clamp (max (count0, count1), (s64) 1, (s64) VBI_MAXLINES); f->fmt.vbi.start[0] = tvnorm->vbistart[0]; f->fmt.vbi.start[1] = tvnorm->vbistart[1]; diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 2227c5640c12..85d84e89d8f4 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -64,14 +64,13 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("video"); #endif -static unsigned short colorspace_conv = 0; +static unsigned short colorspace_conv; module_param(colorspace_conv, ushort, 0444); MODULE_PARM_DESC(colorspace_conv, - "\n Colorspace conversion:" - "\n0 = disable" - "\n1 = enable" - "\nDefault value is 0" - "\n"); + " Colorspace conversion:" + "\n 0 = disable, 1 = enable" + "\n Default value is 0" + ); #define ABOUT "V4L-Driver for Vision CPiA based cameras" @@ -4042,7 +4041,7 @@ static int __init cpia_init(void) "allowed, it is disabled by default now. Users should fix the " "applications in case they don't work without conversion " "reenabled by setting the 'colorspace_conv' module " - "parameter to 1"); + "parameter to 1\n"); #ifdef CONFIG_PROC_FS proc_cpia_create(); diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h index 8394283993f6..1764991b0ac9 100644 --- a/drivers/media/video/cpia2/cpia2.h +++ b/drivers/media/video/cpia2/cpia2.h @@ -456,7 +456,7 @@ int cpia2_init_camera(struct camera_data *cam); int cpia2_allocate_buffers(struct camera_data *cam); void cpia2_free_buffers(struct camera_data *cam); long cpia2_read(struct camera_data *cam, - char *buf, unsigned long count, int noblock); + char __user *buf, unsigned long count, int noblock); unsigned int cpia2_poll(struct camera_data *cam, struct file *filp, poll_table *wait); int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma); diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c index 3021f21aae36..0b00e6027dfb 100644 --- a/drivers/media/video/cpia_pp.c +++ b/drivers/media/video/cpia_pp.c @@ -873,7 +873,7 @@ static int __init cpia_pp_setup(char *str) parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE; } - return 0; + return 1; } __setup("cpia_pp=", cpia_pp_setup); diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile index 32a896c23d1e..6e8665be8954 100644 --- a/drivers/media/video/cx25840/Makefile +++ b/drivers/media/video/cx25840/Makefile @@ -3,4 +3,4 @@ cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ obj-$(CONFIG_VIDEO_CX25840) += cx25840.o -EXTRA_CFLAGS += -I$(src)/.. +EXTRA_CFLAGS += -Idrivers/media/video diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index a4540e858f21..9a4b813152e5 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -19,8 +19,9 @@ #include #include #include +#include -#include "cx25840.h" +#include "cx25840-core.h" static int set_audclk_freq(struct i2c_client *client, u32 freq) { diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index a65b3cc4bf03..a961bb2ab0fd 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -32,8 +32,9 @@ #include #include #include +#include -#include "cx25840.h" +#include "cx25840-core.h" MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver"); MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford"); @@ -668,6 +669,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, { struct cx25840_state *state = i2c_get_clientdata(client); struct v4l2_tuner *vt = arg; + struct v4l2_routing *route = arg; switch (cmd) { #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -749,19 +751,21 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, state->radio = 1; break; - case VIDIOC_G_INPUT: - *(int *)arg = state->vid_input; + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = state->vid_input; + route->output = 0; break; - case VIDIOC_S_INPUT: - return set_input(client, *(enum cx25840_video_input *)arg, state->aud_input); + case VIDIOC_INT_S_VIDEO_ROUTING: + return set_input(client, route->input, state->aud_input); - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *input = arg; + case VIDIOC_INT_G_AUDIO_ROUTING: + route->input = state->aud_input; + route->output = 0; + break; - return set_input(client, state->vid_input, input->index); - } + case VIDIOC_INT_S_AUDIO_ROUTING: + return set_input(client, state->vid_input, route->input); case VIDIOC_S_FREQUENCY: input_change(client); diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840-core.h similarity index 72% rename from drivers/media/video/cx25840/cx25840.h rename to drivers/media/video/cx25840/cx25840-core.h index dd70664d1dd9..1736929fc204 100644 --- a/drivers/media/video/cx25840/cx25840.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -1,4 +1,4 @@ -/* cx25840 API header +/* cx25840 internal API header * * Copyright (C) 2003-2004 Chris Kennedy * @@ -17,8 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _CX25840_H_ -#define _CX25840_H_ +#ifndef _CX25840_CORE_H_ +#define _CX25840_CORE_H_ #include @@ -32,46 +32,6 @@ providing this information. */ #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0) -enum cx25840_video_input { - /* Composite video inputs In1-In8 */ - CX25840_COMPOSITE1 = 1, - CX25840_COMPOSITE2, - CX25840_COMPOSITE3, - CX25840_COMPOSITE4, - CX25840_COMPOSITE5, - CX25840_COMPOSITE6, - CX25840_COMPOSITE7, - CX25840_COMPOSITE8, - - /* S-Video inputs consist of one luma input (In1-In4) ORed with one - chroma input (In5-In8) */ - CX25840_SVIDEO_LUMA1 = 0x10, - CX25840_SVIDEO_LUMA2 = 0x20, - CX25840_SVIDEO_LUMA3 = 0x30, - CX25840_SVIDEO_LUMA4 = 0x40, - CX25840_SVIDEO_CHROMA4 = 0x400, - CX25840_SVIDEO_CHROMA5 = 0x500, - CX25840_SVIDEO_CHROMA6 = 0x600, - CX25840_SVIDEO_CHROMA7 = 0x700, - CX25840_SVIDEO_CHROMA8 = 0x800, - - /* S-Video aliases for common luma/chroma combinations */ - CX25840_SVIDEO1 = 0x510, - CX25840_SVIDEO2 = 0x620, - CX25840_SVIDEO3 = 0x730, - CX25840_SVIDEO4 = 0x840, -}; - -enum cx25840_audio_input { - /* Audio inputs: serial or In4-In8 */ - CX25840_AUDIO_SERIAL, - CX25840_AUDIO4 = 4, - CX25840_AUDIO5, - CX25840_AUDIO6, - CX25840_AUDIO7, - CX25840_AUDIO8, -}; - struct cx25840_state { int pvr150_workaround; int radio; diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index e1a7823d82cd..f59ced181c55 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c @@ -20,11 +20,22 @@ #include #include #include +#include -#include "cx25840.h" +#include "cx25840-core.h" #define FWFILE "v4l-cx25840.fw" -#define FWSEND 1024 + +/* + * Mike Isely - The FWSEND parameter controls the + * size of the firmware chunks sent down the I2C bus to the chip. + * Previously this had been set to 1024 but unfortunately some I2C + * implementations can't transfer data in such big gulps. + * Specifically, the pvrusb2 driver has a hard limit of around 60 + * bytes, due to the encapsulation there of I2C traffic into USB + * messages. So we have to significantly reduce this parameter. + */ +#define FWSEND 48 #define FWDEV(x) &((x)->adapter->dev) diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index e96fd1f1d6dc..57feca288d2b 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -19,8 +19,9 @@ #include #include #include +#include -#include "cx25840.h" +#include "cx25840-core.h" static int odd_parity(u8 c) { @@ -151,7 +152,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_G_FMT: { static u16 lcr2vbi[] = { - 0, V4L2_SLICED_TELETEXT_PAL_B, 0, /* 1 */ + 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ 0, V4L2_SLICED_WSS_625, 0, /* 4 */ V4L2_SLICED_CAPTION_525, /* 6 */ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ @@ -231,7 +232,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) for (i = 7; i <= 23; i++) { for (x = 0; x <= 1; x++) { switch (svbi->service_lines[1-x][i]) { - case V4L2_SLICED_TELETEXT_PAL_B: + case V4L2_SLICED_TELETEXT_B: lcr[i] |= 1 << (4 * x); break; case V4L2_SLICED_WSS_625: @@ -282,7 +283,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) switch (id2) { case 1: - id2 = V4L2_SLICED_TELETEXT_PAL_B; + id2 = V4L2_SLICED_TELETEXT_B; break; case 4: id2 = V4L2_SLICED_WSS_625; diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index ff0f72340d69..630273992a41 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -1,3 +1,7 @@ +config VIDEO_CX88_VP3054 + tristate + depends on VIDEO_CX88_DVB && DVB_MT352 + config VIDEO_CX88 tristate "Conexant 2388x (bt878 successor) support" depends on VIDEO_DEV && PCI && I2C @@ -25,7 +29,7 @@ config VIDEO_CX88_ALSA It only works with boards with function 01 enabled. To check if your board supports, use lspci -n. - If supported, you should see 1471:8801 or 1471:8811 + If supported, you should see 14f1:8801 or 14f1:8811 PCI device. To compile this driver as a module, choose M here: the @@ -73,10 +77,11 @@ config VIDEO_CX88_DVB_MT352 This adds DVB-T support for cards based on the Connexant 2388x chip and the MT352 demodulator. -config VIDEO_CX88_VP3054 - tristate "VP-3054 Secondary I2C Bus Support" - default m - depends on DVB_MT352 +config VIDEO_CX88_DVB_VP3054 + bool "VP-3054 Secondary I2C Bus Support" + default y + depends on VIDEO_CX88_DVB_MT352 + select VIDEO_CX88_VP3054 ---help--- This adds DVB-T support for cards based on the Connexant 2388x chip and the MT352 demodulator, diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 6482b9aa6a1f..0dcd09b9b727 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -8,9 +8,9 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o -EXTRA_CFLAGS += -I$(src)/.. -EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core -EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1 extra-cflags-$(CONFIG_DVB_CX22702) += -DHAVE_CX22702=1 diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index da457a05b0dd..826d0e340753 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -3,4 +3,4 @@ em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o -EXTRA_CFLAGS += -I$(src)/.. +EXTRA_CFLAGS += -Idrivers/media/video diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index f62fd706b45a..3ba3439db580 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -151,8 +151,8 @@ struct em28xx_board em28xx_boards[] = { },{ .type = EM28XX_VMUX_SVIDEO, .vmux = 2, - .amux = MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1, - MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART), + .amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, + MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), }}, }, [EM2820_BOARD_MSI_VOX_USB_2] = { diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index dfba33d0fa61..ddc92cbb5276 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -222,7 +222,7 @@ static void video_mux(struct em28xx *dev, int index) if (dev->i2s_speed) em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed); route.input = dev->ctl_ainput; - route.output = MSP_OUTPUT(MSP_OUT_SCART1_DA); + route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); /* Note: this is msp3400 specific */ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route); ainput = EM28XX_AUDIO_SRC_TUNER; @@ -1141,26 +1141,16 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_G_TUNER: { struct v4l2_tuner *t = arg; - int status = 0; if (0 != t->index) return -EINVAL; memset(t, 0, sizeof(*t)); strcpy(t->name, "Tuner"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */ -/* t->signal = 0xffff;*/ -/* em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/ - /* No way to get signal strength? */ mutex_lock(&dev->lock); - em28xx_i2c_call_clients(dev, DECODER_GET_STATUS, - &status); + /* let clients fill in the remainder of this struct */ + em28xx_i2c_call_clients(dev, cmd, t); mutex_unlock(&dev->lock); - t->signal = - (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0; - em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal, t->afc); return 0; @@ -1168,26 +1158,13 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; - int status = 0; if (0 != t->index) return -EINVAL; - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Tuner"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */ -/* t->signal = 0xffff; */ - /* No way to get signal strength? */ mutex_lock(&dev->lock); - em28xx_i2c_call_clients(dev, DECODER_GET_STATUS, - &status); + /* let clients handle this */ + em28xx_i2c_call_clients(dev, cmd, t); mutex_unlock(&dev->lock); - t->signal = - (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0; - - em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n", - t->signal, t->afc); return 0; } case VIDIOC_G_FREQUENCY: diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig new file mode 100644 index 000000000000..6c43a90c6569 --- /dev/null +++ b/drivers/media/video/et61x251/Kconfig @@ -0,0 +1,14 @@ +config USB_ET61X251 + tristate "USB ET61X[12]51 PC Camera Controller support" + depends on USB && VIDEO_DEV + ---help--- + Say Y here if you want support for cameras based on Etoms ET61X151 + or ET61X251 PC Camera Controllers. + + See for more info. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" to use this driver. + + To compile this driver as a module, choose M here: the + module will be called et61x251. diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 95bacf435414..7e66d83fe0ce 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -411,6 +411,9 @@ static int ir_probe(struct i2c_adapter *adap) case I2C_HW_B_BT848: probe = probe_bttv; break; + case I2C_HW_B_CX2341X: + probe = probe_bttv; + break; case I2C_HW_SAA7134: probe = probe_saa7134; break; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index c40e8ba9a2ea..b806999d6e0f 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -279,20 +279,8 @@ void msp_set_scart(struct i2c_client *client, int in, int out) msp_write_dsp(client, 0x13, state->acb); /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ - msp_write_dem(client, 0x40, state->i2s_mode); -} - -void msp_set_mute(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - - v4l_dbg(1, msp_debug, client, "mute audio\n"); - msp_write_dsp(client, 0x0000, 0); - msp_write_dsp(client, 0x0007, 1); - if (state->has_scart2_out_volume) - msp_write_dsp(client, 0x0040, 1); - if (state->has_headphones) - msp_write_dsp(client, 0x0006, 0); + if (state->has_i2s_conf) + msp_write_dem(client, 0x40, state->i2s_mode); } void msp_set_audio(struct i2c_client *client) @@ -300,17 +288,19 @@ void msp_set_audio(struct i2c_client *client) struct msp_state *state = i2c_get_clientdata(client); int bal = 0, bass, treble, loudness; int val = 0; + int reallymuted = state->muted | state->scan_in_progress; - if (!state->muted) + if (!reallymuted) val = (state->volume * 0x7f / 65535) << 8; - v4l_dbg(1, msp_debug, client, "mute=%s volume=%d\n", - state->muted ? "on" : "off", state->volume); + v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", + state->muted ? "on" : "off", state->scan_in_progress ? "yes" : "no", + state->volume); msp_write_dsp(client, 0x0000, val); - msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1)); + msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1)); if (state->has_scart2_out_volume) - msp_write_dsp(client, 0x0040, state->muted ? 0x1 : (val | 0x1)); + msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1)); if (state->has_headphones) msp_write_dsp(client, 0x0006, val); if (!state->has_sound_processing) @@ -346,7 +336,6 @@ static void msp_wake_thread(struct i2c_client *client) if (NULL == state->kthread) return; - msp_set_mute(client); state->watch_stereo = 0; state->restart = 1; wake_up_interruptible(&state->wq); @@ -374,19 +363,15 @@ int msp_sleep(struct msp_state *state, int timeout) /* ------------------------------------------------------------------------ */ -static int msp_mode_v4l2_to_v4l1(int rxsubchans) +static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode) { - int mode = 0; - - if (rxsubchans & V4L2_TUNER_SUB_STEREO) - mode |= VIDEO_SOUND_STEREO; - if (rxsubchans & V4L2_TUNER_SUB_LANG2) - mode |= VIDEO_SOUND_LANG2 | VIDEO_SOUND_STEREO; - if (rxsubchans & V4L2_TUNER_SUB_LANG1) - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_STEREO; - if (mode == 0) - mode |= VIDEO_SOUND_MONO; - return mode; + if (rxsubchans == V4L2_TUNER_SUB_MONO) + return VIDEO_SOUND_MONO; + if (rxsubchans == V4L2_TUNER_SUB_STEREO) + return VIDEO_SOUND_STEREO; + if (audmode == V4L2_TUNER_MODE_LANG2) + return VIDEO_SOUND_LANG2; + return VIDEO_SOUND_LANG1; } static int msp_mode_v4l1_to_v4l2(int mode) @@ -605,7 +590,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) break; if (state->opmode == OPMODE_AUTOSELECT) msp_detect_stereo(client); - va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans); + va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans, state->audmode); break; } @@ -620,7 +605,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) state->treble = va->treble; msp_set_audio(client); - if (va->mode != 0 && state->radio == 0) { + if (va->mode != 0 && state->radio == 0 && + state->audmode != msp_mode_v4l1_to_v4l2(va->mode)) { state->audmode = msp_mode_v4l1_to_v4l2(va->mode); msp_set_audmode(client); } @@ -687,21 +673,23 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) int sc_in = rt->input & 0x7; int sc1_out = rt->output & 0xf; int sc2_out = (rt->output >> 4) & 0xf; - u16 val; + u16 val, reg; + if (state->routing.input == rt->input && + state->routing.output == rt->output) + break; state->routing = *rt; - if (state->opmode == OPMODE_AUTOSELECT) { - val = msp_read_dem(client, 0x30) & ~0x100; - msp_write_dem(client, 0x30, val | (tuner ? 0x100 : 0)); - } else { - val = msp_read_dem(client, 0xbb) & ~0x100; - msp_write_dem(client, 0xbb, val | (tuner ? 0x100 : 0)); - } msp_set_scart(client, sc_in, 0); msp_set_scart(client, sc1_out, 1); msp_set_scart(client, sc2_out, 2); msp_set_audmode(client); - msp_wake_thread(client); + reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb; + val = msp_read_dem(client, reg); + if (tuner != ((val >> 8) & 1)) { + msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8)); + /* wake thread when a new tuner input is chosen */ + msp_wake_thread(client); + } break; } @@ -715,7 +703,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) msp_detect_stereo(client); vt->audmode = state->audmode; vt->rxsubchans = state->rxsubchans; - vt->capability = V4L2_TUNER_CAP_STEREO | + vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; break; } @@ -726,6 +714,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (state->radio) /* TODO: add mono/stereo support for radio */ break; + if (state->audmode == vt->audmode) + break; state->audmode = vt->audmode; /* only set audmode */ msp_set_audmode(client); @@ -887,7 +877,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) memset(state, 0, sizeof(*state)); state->v4l2_std = V4L2_STD_NTSC; - state->audmode = V4L2_TUNER_MODE_LANG1; + state->audmode = V4L2_TUNER_MODE_STEREO; state->volume = 58880; /* 0db gain */ state->balance = 32768; /* 0db gain */ state->bass = 32768; @@ -931,13 +921,16 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) state->has_radio = msp_revision >= 'G'; /* Has headphones output: not for stripped down products */ state->has_headphones = msp_prod_lo < 5; + /* Has scart2 input: not in stripped down products of the '3' family */ + state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7; + /* Has scart3 input: not in stripped down products of the '3' family */ + state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5; /* Has scart4 input: not in pre D revisions, not in stripped D revs */ state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); - /* Has scart2 and scart3 inputs and scart2 output: not in stripped - down products of the '3' family */ - state->has_scart23_in_scart2_out = msp_family >= 4 || msp_prod_lo < 5; + /* Has scart2 output: not in stripped down products of the '3' family */ + state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5; /* Has scart2 a volume control? Not in pre-D revisions. */ - state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart23_in_scart2_out; + state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out; /* Has a configurable i2s out? */ state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7; /* Has subwoofer output: not in pre-D revs and not in stripped down products */ diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h index 1940748bb633..4e451049013d 100644 --- a/drivers/media/video/msp3400-driver.h +++ b/drivers/media/video/msp3400-driver.h @@ -54,8 +54,10 @@ struct msp_state { u8 has_radio; u8 has_headphones; u8 has_ntsc_jp_d_k3; + u8 has_scart2; + u8 has_scart3; u8 has_scart4; - u8 has_scart23_in_scart2_out; + u8 has_scart2_out; u8 has_scart2_out_volume; u8 has_i2s_conf; u8 has_subwoofer; @@ -83,6 +85,7 @@ struct msp_state { int volume, muted; int balance, loudness; int bass, treble; + int scan_in_progress; /* thread */ struct task_struct *kthread; @@ -98,7 +101,6 @@ int msp_read_dem(struct i2c_client *client, int addr); int msp_read_dsp(struct i2c_client *client, int addr); int msp_reset(struct i2c_client *client); void msp_set_scart(struct i2c_client *client, int in, int out); -void msp_set_mute(struct i2c_client *client); void msp_set_audio(struct i2c_client *client); int msp_sleep(struct msp_state *state, int timeout); diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index c3984ea9ca07..633a10213789 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -170,7 +170,7 @@ static void msp_set_source(struct i2c_client *client, u16 src) msp_write_dsp(client, 0x000a, src); msp_write_dsp(client, 0x000b, src); msp_write_dsp(client, 0x000c, src); - if (state->has_scart23_in_scart2_out) + if (state->has_scart2_out) msp_write_dsp(client, 0x0041, src); } @@ -228,6 +228,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) char *modestr = (state->audmode >= 0 && state->audmode < 5) ? strmode[state->audmode] : "unknown"; int src = 0; /* channel source: FM/AM, nicam or SCART */ + int audmode = state->audmode; if (state->opmode == OPMODE_AUTOSELECT) { /* this method would break everything, let's make sure @@ -239,11 +240,29 @@ static void msp3400c_set_audmode(struct i2c_client *client) return; } + /* Note: for the C and D revs no NTSC stereo + SAP is possible as + the hardware does not support SAP. So the rxsubchans combination + of STEREO | LANG2 does not occur. */ + + /* switch to mono if only mono is available */ + if (state->rxsubchans == V4L2_TUNER_SUB_MONO) + audmode = V4L2_TUNER_MODE_MONO; + /* if bilingual */ + else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) { + /* and mono or stereo, then fallback to lang1 */ + if (audmode == V4L2_TUNER_MODE_MONO || + audmode == V4L2_TUNER_MODE_STEREO) + audmode = V4L2_TUNER_MODE_LANG1; + } + /* if stereo, and audmode is not mono, then switch to stereo */ + else if (audmode != V4L2_TUNER_MODE_MONO) + audmode = V4L2_TUNER_MODE_STEREO; + /* switch demodulator */ switch (state->mode) { case MSP_MODE_FM_TERRA: v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr); - switch (state->audmode) { + switch (audmode) { case V4L2_TUNER_MODE_STEREO: msp_write_dsp(client, 0x000e, 0x3001); break; @@ -257,7 +276,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) break; case MSP_MODE_FM_SAT: v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr); - switch (state->audmode) { + switch (audmode) { case V4L2_TUNER_MODE_MONO: msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); break; @@ -296,7 +315,8 @@ static void msp3400c_set_audmode(struct i2c_client *client) } /* switch audio */ - switch (state->audmode) { + v4l_dbg(1, msp_debug, client, "set audmode %d\n", audmode); + switch (audmode) { case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1_LANG2: src |= 0x0020; @@ -314,10 +334,6 @@ static void msp3400c_set_audmode(struct i2c_client *client) src = 0x0030; break; case V4L2_TUNER_MODE_LANG1: - /* switch to stereo for stereo transmission, otherwise - keep first language */ - if (state->rxsubchans & V4L2_TUNER_SUB_STEREO) - src |= 0x0020; break; case V4L2_TUNER_MODE_LANG2: src |= 0x0010; @@ -367,7 +383,7 @@ static int msp3400c_detect_stereo(struct i2c_client *client) if (val > 32767) val -= 65536; v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val); - if (val > 4096) { + if (val > 8192) { rxsubchans = V4L2_TUNER_SUB_STEREO; } else if (val < -4096) { rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; @@ -464,19 +480,22 @@ int msp3400c_thread(void *data) if (state->radio || MSP_MODE_EXTERN == state->mode) { /* no carrier scan, just unmute */ v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); + state->scan_in_progress = 0; msp_set_audio(client); continue; } - /* mute */ - msp_set_mute(client); + /* mute audio */ + state->scan_in_progress = 1; + msp_set_audio(client); + msp3400c_set_mode(client, MSP_MODE_AM_DETECT); val1 = val2 = 0; max1 = max2 = -1; state->watch_stereo = 0; state->nicam_on = 0; - /* some time for the tuner to sync */ + /* wait for tuner to settle down after a channel change */ if (msp_sleep(state, 200)) goto restart; @@ -552,7 +571,6 @@ int msp3400c_thread(void *data) /* B/G NICAM */ state->second = msp3400c_carrier_detect_55[max2].cdo; msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); - msp3400c_set_carrier(client, state->second, state->main); state->nicam_on = 1; state->watch_stereo = 1; } else { @@ -563,7 +581,6 @@ int msp3400c_thread(void *data) /* PAL I NICAM */ state->second = MSP_CARRIER(6.552); msp3400c_set_mode(client, MSP_MODE_FM_NICAM2); - msp3400c_set_carrier(client, state->second, state->main); state->nicam_on = 1; state->watch_stereo = 1; break; @@ -577,13 +594,11 @@ int msp3400c_thread(void *data) /* L NICAM or AM-mono */ state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_set_mode(client, MSP_MODE_AM_NICAM); - msp3400c_set_carrier(client, state->second, state->main); state->watch_stereo = 1; } else if (max2 == 0 && state->has_nicam) { /* D/K NICAM */ state->second = msp3400c_carrier_detect_65[max2].cdo; msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); - msp3400c_set_carrier(client, state->second, state->main); state->nicam_on = 1; state->watch_stereo = 1; } else { @@ -595,25 +610,25 @@ int msp3400c_thread(void *data) no_second: state->second = msp3400c_carrier_detect_main[max1].cdo; msp3400c_set_mode(client, MSP_MODE_FM_TERRA); - msp3400c_set_carrier(client, state->second, state->main); - state->rxsubchans = V4L2_TUNER_SUB_MONO; break; } + msp3400c_set_carrier(client, state->second, state->main); /* unmute */ - msp_set_audio(client); + state->scan_in_progress = 0; msp3400c_set_audmode(client); + msp_set_audio(client); if (msp_debug) msp3400c_print_mode(client); /* monitor tv audio mode, the first time don't wait so long to get a quick stereo/bilingual result */ - if (msp_sleep(state, 1000)) - goto restart; + count = 3; while (state->watch_stereo) { - if (msp_sleep(state, 5000)) + if (msp_sleep(state, count ? 1000 : 5000)) goto restart; + if (count) count--; watch_stereo(client); } } @@ -626,7 +641,7 @@ int msp3410d_thread(void *data) { struct i2c_client *client = data; struct msp_state *state = i2c_get_clientdata(client); - int val, i, std; + int val, i, std, count; v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); @@ -644,16 +659,14 @@ int msp3410d_thread(void *data) if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); + state->scan_in_progress = 0; msp_set_audio(client); continue; } - /* put into sane state (and mute) */ - msp_reset(client); - - /* some time for the tuner to sync */ - if (msp_sleep(state,200)) - goto restart; + /* mute audio */ + state->scan_in_progress = 1; + msp_set_audio(client); /* start autodetect. Note: autodetect is not supported for NTSC-M and radio, hence we force the standard in those cases. */ @@ -664,6 +677,10 @@ int msp3410d_thread(void *data) state->watch_stereo = 0; state->nicam_on = 0; + /* wait for tuner to settle down after a channel change */ + if (msp_sleep(state, 200)) + goto restart; + if (msp_debug) v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n", msp_standard_std_name(std), std); @@ -693,6 +710,7 @@ int msp3410d_thread(void *data) state->main = msp_stdlist[i].main; state->second = msp_stdlist[i].second; state->std = val; + state->rxsubchans = V4L2_TUNER_SUB_MONO; if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) { @@ -714,20 +732,17 @@ int msp3410d_thread(void *data) else state->mode = MSP_MODE_FM_NICAM1; /* just turn on stereo */ - state->rxsubchans = V4L2_TUNER_SUB_STEREO; state->nicam_on = 1; state->watch_stereo = 1; break; case 0x0009: state->mode = MSP_MODE_AM_NICAM; - state->rxsubchans = V4L2_TUNER_SUB_MONO; state->nicam_on = 1; state->watch_stereo = 1; break; case 0x0020: /* BTSC */ /* The pre-'G' models only have BTSC-mono */ state->mode = MSP_MODE_BTSC; - state->rxsubchans = V4L2_TUNER_SUB_MONO; break; case 0x0040: /* FM radio */ state->mode = MSP_MODE_FM_RADIO; @@ -737,15 +752,12 @@ int msp3410d_thread(void *data) msp3400c_set_mode(client, MSP_MODE_FM_RADIO); msp3400c_set_carrier(client, MSP_CARRIER(10.7), MSP_CARRIER(10.7)); - /* scart routing (this doesn't belong here I think) */ - msp_set_scart(client,SCART_IN2,0); break; case 0x0002: case 0x0003: case 0x0004: case 0x0005: state->mode = MSP_MODE_FM_TERRA; - state->rxsubchans = V4L2_TUNER_SUB_MONO; state->watch_stereo = 1; break; } @@ -759,20 +771,19 @@ int msp3410d_thread(void *data) if (state->has_i2s_conf) msp_write_dem(client, 0x40, state->i2s_mode); - /* unmute, restore misc registers */ - msp_set_audio(client); - - msp_write_dsp(client, 0x13, state->acb); + /* unmute */ msp3400c_set_audmode(client); + state->scan_in_progress = 0; + msp_set_audio(client); /* monitor tv audio mode, the first time don't wait so long to get a quick stereo/bilingual result */ - if (msp_sleep(state, 1000)) - goto restart; + count = 3; while (state->watch_stereo) { - watch_stereo(client); - if (msp_sleep(state, 5000)) + if (msp_sleep(state, count ? 1000 : 5000)) goto restart; + if (count) count--; + watch_stereo(client); } } v4l_dbg(1, msp_debug, client, "thread: exit\n"); @@ -829,27 +840,27 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) source = 0; /* mono only */ matrix = 0x30; break; - case V4L2_TUNER_MODE_LANG1: - source = 3; /* stereo or A */ - matrix = 0x00; - break; case V4L2_TUNER_MODE_LANG2: source = 4; /* stereo or B */ matrix = 0x10; break; - case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1_LANG2: - default: source = 1; /* stereo or A|B */ matrix = 0x20; break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + default: + source = 3; /* stereo or A */ + matrix = 0x00; + break; } - if (in == MSP_DSP_OUT_TUNER) + if (in == MSP_DSP_IN_TUNER) source = (source << 8) | 0x20; /* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14 instead of 11, 12, 13. So we add one for that msp version. */ - else if (in >= MSP_DSP_OUT_MAIN_AVC && state->has_dolby_pro_logic) + else if (in >= MSP_DSP_IN_MAIN_AVC && state->has_dolby_pro_logic) source = ((in + 1) << 8) | matrix; else source = (in << 8) | matrix; @@ -869,7 +880,7 @@ static void msp34xxg_set_sources(struct i2c_client *client) msp34xxg_set_source(client, 0x000c, (in >> 4) & 0xf); msp34xxg_set_source(client, 0x0009, (in >> 8) & 0xf); msp34xxg_set_source(client, 0x000a, (in >> 12) & 0xf); - if (state->has_scart23_in_scart2_out) + if (state->has_scart2_out) msp34xxg_set_source(client, 0x0041, (in >> 16) & 0xf); msp34xxg_set_source(client, 0x000b, (in >> 20) & 0xf); } @@ -887,10 +898,6 @@ static void msp34xxg_reset(struct i2c_client *client) msp_reset(client); - /* make sure that input/output is muted (paranoid mode) */ - /* ACB, mute DSP input, mute SCART 1 */ - msp_write_dsp(client, 0x13, 0x0f20); - if (state->has_i2s_conf) msp_write_dem(client, 0x40, state->i2s_mode); @@ -1028,7 +1035,7 @@ static void msp34xxg_set_audmode(struct i2c_client *client) if (state->std == 0x20) { if ((state->rxsubchans & V4L2_TUNER_SUB_SAP) && - (state->audmode == V4L2_TUNER_MODE_STEREO || + (state->audmode == V4L2_TUNER_MODE_LANG1_LANG2 || state->audmode == V4L2_TUNER_MODE_LANG2)) { msp_write_dem(client, 0x20, 0x21); } else { diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index 522e9ddeb089..d9e3cada52f4 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c @@ -2156,7 +2156,7 @@ static int find_planb(void) struct pci_dev *pdev; int rc; - if (_machine != _MACH_Pmac) + if (!machine_is(powermac)) return 0; planb_devices = find_devices("planb"); diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig new file mode 100644 index 000000000000..86376556f108 --- /dev/null +++ b/drivers/media/video/pwc/Kconfig @@ -0,0 +1,28 @@ +config USB_PWC + tristate "USB Philips Cameras" + depends on USB && VIDEO_DEV + ---help--- + Say Y or M here if you want to use one of these Philips & OEM + webcams: + * Philips PCA645, PCA646 + * Philips PCVC675, PCVC680, PCVC690 + * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 + * Askey VC010 + * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' + and 'Orbit'/'Sphere' + * Samsung MPC-C10, MPC-C30 + * Creative Webcam 5, Pro Ex + * SOTEC Afina Eye + * Visionite VCS-UC300, VCS-UM100 + + The PCA635, PCVC665 and PCVC720/20 are not supported by this driver + and never will be, but the 665 and 720/20 are supported by other + drivers. + + See for more information and + installation instructions. + + The built-in microphone is enabled by selecting USB Audio support. + + To compile this driver as a module, choose M here: the + module will be called pwc. diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index b05015282601..dceebc0b1250 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -40,6 +40,7 @@ #include #include #include +#include #include MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver"); @@ -53,7 +54,7 @@ module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); static unsigned short normal_i2c[] = { - 0x4a >>1, 0x48 >>1, /* SAA7113 */ + 0x4a >> 1, 0x48 >> 1, /* SAA7113 */ 0x42 >> 1, 0x40 >> 1, /* SAA7114 and SAA7115 */ I2C_CLIENT_END }; @@ -722,16 +723,16 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std) 100 reserved NTSC-Japan (3.58MHz) */ if (state->ident == V4L2_IDENT_SAA7113) { - u8 reg = saa7115_read(client, 0x0e) & 0x8f; + u8 reg = saa7115_read(client, 0x0e) & 0x8f; if (std == V4L2_STD_PAL_M) { - reg|=0x30; + reg |= 0x30; } else if (std == V4L2_STD_PAL_N) { - reg|=0x20; + reg |= 0x20; } else if (std == V4L2_STD_PAL_60) { - reg|=0x10; + reg |= 0x10; } else if (std == V4L2_STD_NTSC_M_JP) { - reg|=0x40; + reg |= 0x40; } saa7115_write(client, 0x0e, reg); } @@ -811,7 +812,7 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo u8 lcr[24]; int i, x; - /* saa7113/71144 doesn't yet support VBI */ + /* saa7113/7114 doesn't yet support VBI */ if (state->ident != V4L2_IDENT_SAA7115) return; @@ -851,7 +852,7 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo case 0: lcr[i] |= 0xf << (4 * x); break; - case V4L2_SLICED_TELETEXT_PAL_B: + case V4L2_SLICED_TELETEXT_B: lcr[i] |= 1 << (4 * x); break; case V4L2_SLICED_CAPTION_525: @@ -880,7 +881,7 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) { static u16 lcr2vbi[] = { - 0, V4L2_SLICED_TELETEXT_PAL_B, 0, /* 1 */ + 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ 0, V4L2_SLICED_CAPTION_525, /* 4 */ V4L2_SLICED_WSS_625, 0, /* 5 */ V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */ @@ -1045,7 +1046,7 @@ static void saa7115_decode_vbi_line(struct i2c_client *client, /* decode payloads */ switch (id2) { case 1: - vbi->type = V4L2_SLICED_TELETEXT_PAL_B; + vbi->type = V4L2_SLICED_TELETEXT_B; break; case 4: if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1])) @@ -1180,6 +1181,46 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar state->radio = 1; break; + case VIDIOC_INT_G_VIDEO_ROUTING: + { + struct v4l2_routing *route = arg; + + route->input = state->input; + route->output = 0; + break; + } + + case VIDIOC_INT_S_VIDEO_ROUTING: + { + struct v4l2_routing *route = arg; + + v4l_dbg(1, debug, client, "decoder set input %d\n", route->input); + /* saa7113 does not have these inputs */ + if (state->ident == V4L2_IDENT_SAA7113 && + (route->input == SAA7115_COMPOSITE4 || + route->input == SAA7115_COMPOSITE5)) { + return -EINVAL; + } + if (route->input > SAA7115_SVIDEO3) + return -EINVAL; + if (state->input == route->input) + break; + v4l_dbg(1, debug, client, "now setting %s input\n", + (route->input >= SAA7115_SVIDEO0) ? "S-Video" : "Composite"); + state->input = route->input; + + /* select mode */ + saa7115_write(client, 0x02, + (saa7115_read(client, 0x02) & 0xf0) | + state->input); + + /* bypass chrominance trap for S-Video modes */ + saa7115_write(client, 0x09, + (saa7115_read(client, 0x09) & 0x7f) | + (state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0)); + break; + } + case VIDIOC_G_INPUT: *(int *)arg = state->input; break; @@ -1321,7 +1362,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) saa7115_write(client, 0, 5); chip_id = saa7115_read(client, 0) & 0x0f; - if (chip_id <3 && chip_id > 5) { + if (chip_id < 3 && chip_id > 5) { v4l_dbg(1, debug, client, "saa7115 not found\n"); kfree(client); return 0; @@ -1360,7 +1401,7 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) v4l_dbg(1, debug, client, "writing init values\n"); /* init to 60hz/48khz */ - if (state->ident==V4L2_IDENT_SAA7113) + if (state->ident == V4L2_IDENT_SAA7113) saa7115_writeregs(client, saa7113_init_auto_input); else saa7115_writeregs(client, saa7115_init_auto_input); diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 992c71774f30..133f9e5252fe 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -54,6 +54,7 @@ #include #include #include +#include static int debug = 0; static int test_image = 0; @@ -222,22 +223,6 @@ static struct i2c_reg_value saa7127_init_config_50hz[] = { { 0, 0 } }; -/* Enumeration for the Supported input types */ -enum saa7127_input_type { - SAA7127_INPUT_TYPE_NORMAL, - SAA7127_INPUT_TYPE_TEST_IMAGE -}; - -/* Enumeration for the Supported Output signal types */ -enum saa7127_output_type { - SAA7127_OUTPUT_TYPE_BOTH, - SAA7127_OUTPUT_TYPE_COMPOSITE, - SAA7127_OUTPUT_TYPE_SVIDEO, - SAA7127_OUTPUT_TYPE_RGB, - SAA7127_OUTPUT_TYPE_YUV_C, - SAA7127_OUTPUT_TYPE_YUV_V -}; - /* ********************************************************************** * @@ -561,7 +546,7 @@ static int saa7127_command(struct i2c_client *client, { struct saa7127_state *state = i2c_get_clientdata(client); struct v4l2_format *fmt = arg; - int *iarg = arg; + struct v4l2_routing *route = arg; switch (cmd) { case VIDIOC_S_STD: @@ -573,15 +558,23 @@ static int saa7127_command(struct i2c_client *client, *(v4l2_std_id *)arg = state->std; break; - case VIDIOC_S_INPUT: - if (state->input_type == *iarg) - break; - return saa7127_set_input_type(client, *iarg); + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = state->input_type; + route->output = state->output_type; + break; - case VIDIOC_S_OUTPUT: - if (state->output_type == *iarg) - break; - return saa7127_set_output_type(client, *iarg); + case VIDIOC_INT_S_VIDEO_ROUTING: + { + int rc = 0; + + if (state->input_type != route->input) { + rc = saa7127_set_input_type(client, route->input); + } + if (rc == 0 && state->output_type != route->output) { + rc = saa7127_set_output_type(client, route->output); + } + return rc; + } case VIDIOC_STREAMON: case VIDIOC_STREAMOFF: diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 86671a43e769..e1c1805df1fb 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -39,6 +39,7 @@ config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE select VIDEO_BUF_DVB + select FW_LOADER ---help--- This adds support for DVB cards based on the Philips saa7134 chip. diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index 1ba998424bbd..be7b9ee697d6 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -11,9 +11,9 @@ obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o -EXTRA_CFLAGS += -I$(src)/.. -EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core -EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1 extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1 diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index fdd7f48f3b76..e666a4465ca4 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -208,7 +208,7 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_FLYTVPLATINUM_FM] = { /* LifeView FlyTV Platinum FM (LR214WF) */ /* "Peter Missel */ - .name = "LifeView FlyTV Platinum FM", + .name = "LifeView FlyTV Platinum FM / Gold", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, @@ -2660,7 +2660,7 @@ struct saa7134_board saa7134_boards[] = { .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_comp1, - .vmux = 0, + .vmux = 1, .amux = LINE1, },{ .name = name_svideo, @@ -2671,7 +2671,7 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_FLYDVBT_LR301] = { /* LifeView FlyDVB-T */ /* Giampiero Giancipoli */ - .name = "LifeView FlyDVB-T", + .name = "LifeView FlyDVB-T / Genius VideoWonder DVB-T", .audio_clock = 0x00200000, .tuner_type = TUNER_ABSENT, .radio_type = UNSET, @@ -2808,6 +2808,40 @@ struct saa7134_board saa7134_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, }, + [SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = { + .name = "LifeView FlyDVB-T Hybrid Cardbus", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .gpiomask = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */ + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .gpio = 0x200000, /* GPIO21=High for TV input */ + .tv = 1, + },{ + .name = name_svideo, /* S-Video signal on S-Video input */ + .vmux = 8, + .amux = LINE2, + },{ + .name = name_comp1, /* Composite signal on S-Video input */ + .vmux = 0, + .amux = LINE2, + },{ + .name = name_comp2, /* Composite input */ + .vmux = 3, + .amux = LINE2, + }}, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -3332,6 +3366,30 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x16be, .subdevice = 0x0005, .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1489, + .subdevice = 0x0301, + .driver_data = SAA7134_BOARD_FLYDVBT_LR301, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5168, /* Animation Technologies (LifeView) */ + .subdevice = 0x0304, + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5168, + .subdevice = 0x3306, + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5168, + .subdevice = 0x3502, /* whats the difference to 0x3306 ?*/ + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -3462,6 +3520,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06); break; case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: + case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00); break; @@ -3633,6 +3692,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) } break; case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: + case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: /* make the tda10046 find its eeprom */ { u8 data[] = { 0x3c, 0x33, 0x62}; diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index c98571c9d5a6..13de05532e0a 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "saa7134-reg.h" #include "saa7134.h" @@ -870,7 +871,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat,pci_resource_start(pci_dev,0)); pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev,0xffffffff)) { + if (!pci_dma_supported(pci_dev, DMA_32BIT_MASK)) { printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name); err = -EIO; goto fail1; diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 86cfdb8514cb..222a36c38917 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1064,6 +1064,10 @@ static int dvb_init(struct saa7134_dev *dev) dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config, &dev->i2c_adap); break; + case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: + dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config, + &dev->i2c_adap); + break; #endif #ifdef HAVE_NXT200X case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 31ba293854c1..353af3a8b766 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -220,6 +220,7 @@ struct saa7134_format { #define SAA7134_BOARD_AVERMEDIA_A169_B 91 #define SAA7134_BOARD_AVERMEDIA_A169_B1 92 #define SAA7134_BOARD_MD7134_BRIDGE_2 93 +#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 diff --git a/drivers/media/video/sn9c102/Kconfig b/drivers/media/video/sn9c102/Kconfig new file mode 100644 index 000000000000..55f2bc11964b --- /dev/null +++ b/drivers/media/video/sn9c102/Kconfig @@ -0,0 +1,11 @@ +config USB_SN9C102 + tristate "USB SN9C10x PC Camera Controller support" + depends on USB && VIDEO_DEV + ---help--- + Say Y here if you want support for cameras based on SONiX SN9C101, + SN9C102 or SN9C103 PC Camera Controllers. + + See for more info. + + To compile this driver as a module, choose M here: the + module will be called sn9c102. diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index df195c905366..1013b4de89a2 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -401,7 +401,7 @@ static void tuner_status(struct i2c_client *client) } tuner_info("Tuner mode: %s\n", p); tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); - tuner_info("Standard: 0x%08llx\n", t->std); + tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) return; if (t->has_signal) { @@ -558,10 +558,10 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, static inline int check_v4l2(struct tuner *t) { - if (t->using_v4l2) { - tuner_dbg ("ignore v4l1 call\n"); - return EINVAL; - } + /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for + TV, v4l1 for radio), until that is fixed this code is disabled. + Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2) + first. */ return 0; } @@ -744,6 +744,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); tuner->type = t->mode; + if (t->mode == V4L2_TUNER_ANALOG_TV) + tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { tuner->rangelow = tv_range[0] * 16; tuner->rangehigh = tv_range[1] * 16; diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index 356bff455ad1..c2b756107548 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1706,21 +1706,6 @@ static int chip_command(struct i2c_client *client, break; } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *sarg = arg; - - if (!(desc->flags & CHIP_HAS_INPUTSEL) || sarg->index >= 4) - return -EINVAL; - /* There are four inputs: tuner, radio, extern and intern. */ - chip->input = sarg->index; - if (chip->muted) - break; - chip_write_masked(chip, desc->inputreg, - desc->inputmap[chip->input], desc->inputmask); - break; - } - case VIDIOC_S_TUNER: { struct v4l2_tuner *vt = arg; diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index e0d2ff83fc91..431c3e2f6c42 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -757,9 +757,9 @@ tveeprom_detect_client(struct i2c_adapter *adapter, static int tveeprom_attach_adapter (struct i2c_adapter *adapter) { - if (adapter->id != I2C_HW_B_BT848) - return 0; - return i2c_probe(adapter, &addr_data, tveeprom_detect_client); + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, tveeprom_detect_client); + return 0; } static int diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 69d0fe159f4d..dab4973bcf82 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -53,7 +53,7 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = { .minimum = 0, .maximum = 255, .step = 1, - .default_value = 0, + .default_value = 128, .flags = 0, }, { .id = V4L2_CID_CONTRAST, @@ -62,7 +62,7 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = { .minimum = 0, .maximum = 255, .step = 0x1, - .default_value = 0x10, + .default_value = 128, .flags = 0, }, { .id = V4L2_CID_SATURATION, @@ -71,7 +71,7 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = { .minimum = 0, .maximum = 255, .step = 0x1, - .default_value = 0x10, + .default_value = 128, .flags = 0, }, { .id = V4L2_CID_HUE, @@ -80,7 +80,7 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = { .minimum = -128, .maximum = 127, .step = 0x1, - .default_value = 0x10, + .default_value = 0, .flags = 0, } }; @@ -500,16 +500,21 @@ struct i2c_vbi_ram_value { static struct i2c_vbi_ram_value vbi_ram_default[] = { + /* FIXME: Current api doesn't handle all VBI types, those not + yet supported are placed under #if 0 */ +#if 0 {0x010, /* Teletext, SECAM, WST System A */ {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } }, +#endif {0x030, /* Teletext, PAL, WST System B */ - {V4L2_SLICED_TELETEXT_PAL_B,6,22,1}, + {V4L2_SLICED_TELETEXT_B,6,22,1}, { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } }, +#if 0 {0x050, /* Teletext, PAL, WST System C */ {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, @@ -535,6 +540,7 @@ static struct i2c_vbi_ram_value vbi_ram_default[] = { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } }, +#endif {0x0f0, /* Closed Caption, NTSC */ {V4L2_SLICED_CAPTION_525,21,21,1}, { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, @@ -545,6 +551,7 @@ static struct i2c_vbi_ram_value vbi_ram_default[] = { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } }, +#if 0 {0x130, /* Wide Screen Signal, NTSC C */ {V4L2_SLICED_WSS_525,20,20,1}, { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, @@ -560,6 +567,7 @@ static struct i2c_vbi_ram_value vbi_ram_default[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } }, +#endif {0x190, /* Video Program System (VPS), PAL */ {V4L2_SLICED_VPS,16,16,0}, { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, @@ -850,7 +858,6 @@ static int tvp5150_command(struct i2c_client *c, case 0: case VIDIOC_INT_RESET: - case DECODER_INIT: tvp5150_reset(c); break; case VIDIOC_S_STD: @@ -949,99 +956,15 @@ static int tvp5150_command(struct i2c_client *c, #endif case VIDIOC_LOG_STATUS: - case DECODER_DUMP: dump_reg(c); break; - case DECODER_GET_CAPABILITIES: + case VIDIOC_G_TUNER: { - struct video_decoder_capability *cap = arg; - - cap->flags = VIDEO_DECODER_PAL | - VIDEO_DECODER_NTSC | - VIDEO_DECODER_SECAM | - VIDEO_DECODER_AUTO | VIDEO_DECODER_CCIR; - cap->inputs = 3; - cap->outputs = 1; - break; - } - case DECODER_GET_STATUS: - { - int *iarg = arg; - int status; - int res=0; - status = tvp5150_read(c, 0x88); - if(status&0x08){ - res |= DECODER_STATUS_COLOR; - } - if(status&0x04 && status&0x02){ - res |= DECODER_STATUS_GOOD; - } - *iarg=res; - break; - } - - case DECODER_SET_GPIO: - break; - - case DECODER_SET_VBI_BYPASS: - break; - - case DECODER_SET_NORM: - { - int *iarg = arg; - - switch (*iarg) { - - case VIDEO_MODE_NTSC: - break; - - case VIDEO_MODE_PAL: - break; - - case VIDEO_MODE_SECAM: - break; - - case VIDEO_MODE_AUTO: - break; - - default: - return -EINVAL; - - } - decoder->norm = *iarg; - break; - } - case DECODER_SET_INPUT: - { - int *iarg = arg; - if (*iarg < 0 || *iarg > 3) { - return -EINVAL; - } - - decoder->input = *iarg; - tvp5150_selmux(c, decoder->input); - - break; - } - case DECODER_SET_OUTPUT: - { - int *iarg = arg; - - /* not much choice of outputs */ - if (*iarg != 0) { - return -EINVAL; - } - break; - } - case DECODER_ENABLE_OUTPUT: - { - int *iarg = arg; - - decoder->enable = (*iarg != 0); - - tvp5150_selmux(c, decoder->input); + struct v4l2_tuner *vt = arg; + int status = tvp5150_read(c, 0x88); + vt->signal = ((status & 0x04) && (status & 0x02)) ? 0xffff : 0x0; break; } case VIDIOC_QUERYCTRL: @@ -1087,35 +1010,6 @@ static int tvp5150_command(struct i2c_client *c, return -EINVAL; } - case DECODER_SET_PICTURE: - { - struct video_picture *pic = arg; - if (decoder->bright != pic->brightness) { - /* We want 0 to 255 we get 0-65535 */ - decoder->bright = pic->brightness; - tvp5150_write(c, TVP5150_BRIGHT_CTL, - decoder->bright >> 8); - } - if (decoder->contrast != pic->contrast) { - /* We want 0 to 255 we get 0-65535 */ - decoder->contrast = pic->contrast; - tvp5150_write(c, TVP5150_CONTRAST_CTL, - decoder->contrast >> 8); - } - if (decoder->sat != pic->colour) { - /* We want 0 to 255 we get 0-65535 */ - decoder->sat = pic->colour; - tvp5150_write(c, TVP5150_SATURATION_CTL, - decoder->contrast >> 8); - } - if (decoder->hue != pic->hue) { - /* We want -128 to 127 we get 0-65535 */ - decoder->hue = pic->hue; - tvp5150_write(c, TVP5150_HUE_CTL, - (decoder->hue - 32768) >> 8); - } - break; - } default: return -EINVAL; } diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c new file mode 100644 index 000000000000..fc52201d607e --- /dev/null +++ b/drivers/media/video/upd64031a.c @@ -0,0 +1,286 @@ +/* + * upd64031A - NEC Electronics Ghost Reduction for NTSC in Japan + * + * 2003 by T.Adachi + * 2003 by Takeru KOMORIYA + * 2006 by Hans Verkuil + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include + +// --------------------- read registers functions define ----------------------- + +/* bit masks */ +#define GR_MODE_MASK 0xc0 +#define DIRECT_3DYCS_CONNECT_MASK 0xc0 +#define SYNC_CIRCUIT_MASK 0xa0 + +// ----------------------------------------------------------------------------- + +MODULE_DESCRIPTION("uPD64031A driver"); +MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static int debug = 0; +module_param(debug, int, 0644); + +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +static unsigned short normal_i2c[] = { 0x24 >> 1, 0x26 >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; + +enum { + R00 = 0, R01, R02, R03, R04, + R05, R06, R07, R08, R09, + R0A, R0B, R0C, R0D, R0E, R0F, + /* unused registers + R10, R11, R12, R13, R14, + R15, R16, R17, + */ + TOT_REGS +}; + +struct upd64031a_state { + u8 regs[TOT_REGS]; + u8 gr_mode; + u8 direct_3dycs_connect; + u8 ext_comp_sync; + u8 ext_vert_sync; +}; + +static u8 upd64031a_init[] = { + 0x00, 0xb8, 0x48, 0xd2, 0xe6, + 0x03, 0x10, 0x0b, 0xaf, 0x7f, + 0x00, 0x00, 0x1d, 0x5e, 0x00, + 0xd0 +}; + +/* ------------------------------------------------------------------------ */ + +static u8 upd64031a_read(struct i2c_client *client, u8 reg) +{ + u8 buf[2]; + + if (reg >= sizeof(buf)) + return 0xff; + i2c_master_recv(client, buf, 2); + return buf[reg]; +} + +/* ------------------------------------------------------------------------ */ + +static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val) +{ + u8 buf[2]; + + buf[0] = reg; + buf[1] = val; + v4l_dbg(1, debug, client, "writing reg addr: %02X val: %02X\n", reg, val); + if (i2c_master_send(client, buf, 2) != 2) + v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val); +} + +/* ------------------------------------------------------------------------ */ + +/* The input changed due to new input or channel changed */ +static void upd64031a_change(struct i2c_client *client) +{ + struct upd64031a_state *state = i2c_get_clientdata(client); + u8 reg = state->regs[R00]; + + v4l_dbg(1, debug, client, "changed input or channel\n"); + upd64031a_write(client, R00, reg | 0x10); + upd64031a_write(client, R00, reg & ~0x10); +} + +/* ------------------------------------------------------------------------ */ + +static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct upd64031a_state *state = i2c_get_clientdata(client); + struct v4l2_routing *route = arg; + + switch (cmd) { + case VIDIOC_S_FREQUENCY: + upd64031a_change(client); + break; + + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = (state->gr_mode >> 6) | + (state->direct_3dycs_connect >> 4) | + (state->ext_comp_sync >> 1) | + (state->ext_vert_sync >> 2); + route->output = 0; + break; + + case VIDIOC_INT_S_VIDEO_ROUTING: + { + u8 r00, r05, r08; + + state->gr_mode = (route->input & 3) << 6; + state->direct_3dycs_connect = (route->input & 0xc) << 4; + state->ext_comp_sync = (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1; + state->ext_vert_sync = (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2; + r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode; + r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) | + state->ext_comp_sync | state->ext_vert_sync; + r08 = (state->regs[R08] & ~DIRECT_3DYCS_CONNECT_MASK) | + state->direct_3dycs_connect; + upd64031a_write(client, R00, r00); + upd64031a_write(client, R05, r05); + upd64031a_write(client, R08, r08); + upd64031a_change(client); + break; + } + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Status: SA00=0x%02x SA01=0x%02x\n", + upd64031a_read(client, 0), upd64031a_read(client, 1)); + break; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_INT_G_REGISTER: + { + struct v4l2_register *reg = arg; + + if (reg->i2c_id != I2C_DRIVERID_UPD64031A) + return -EINVAL; + reg->val = upd64031a_read(client, reg->reg & 0xff); + break; + } + + case VIDIOC_INT_S_REGISTER: + { + struct v4l2_register *reg = arg; + u8 addr = reg->reg & 0xff; + u8 val = reg->val & 0xff; + + if (reg->i2c_id != I2C_DRIVERID_UPD64031A) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + upd64031a_write(client, addr, val); + break; + } +#endif + + default: + break; + } + return 0; +} + +/* ------------------------------------------------------------------------ */ + +/* i2c implementation */ + +static struct i2c_driver i2c_driver; + +static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct upd64031a_state *state; + int i; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == NULL) { + return -ENOMEM; + } + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "uPD64031A"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + + state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + i2c_set_clientdata(client, state); + memcpy(state->regs, upd64031a_init, sizeof(state->regs)); + state->gr_mode = UPD64031A_GR_ON << 6; + state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4; + state->ext_comp_sync = state->ext_vert_sync = 0; + for (i = 0; i < TOT_REGS; i++) { + upd64031a_write(client, i, state->regs[i]); + } + + i2c_attach_client(client); + + return 0; +} + +static int upd64031a_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, upd64031a_attach); + return 0; +} + +static int upd64031a_detach(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) + return err; + + kfree(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "upd64031a", + }, + .id = I2C_DRIVERID_UPD64031A, + .attach_adapter = upd64031a_probe, + .detach_client = upd64031a_detach, + .command = upd64031a_command, +}; + + +static int __init upd64031a_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit upd64031a_exit_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(upd64031a_init_module); +module_exit(upd64031a_exit_module); diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c new file mode 100644 index 000000000000..c3a7ffe5c267 --- /dev/null +++ b/drivers/media/video/upd64083.c @@ -0,0 +1,262 @@ +/* + * upd6408x - NEC Electronics 3-Dimensional Y/C separation driver + * + * 2003 by T.Adachi (tadachi@tadachi-net.com) + * 2003 by Takeru KOMORIYA + * 2006 by Hans Verkuil + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("uPD64083 driver"); +MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static int debug = 0; +module_param(debug, bool, 0644); + +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, I2C_CLIENT_END }; + + +I2C_CLIENT_INSMOD; + +enum { + R00 = 0, R01, R02, R03, R04, + R05, R06, R07, R08, R09, + R0A, R0B, R0C, R0D, R0E, R0F, + R10, R11, R12, R13, R14, + R15, R16, + TOT_REGS +}; + +struct upd64083_state { + u8 mode; + u8 ext_y_adc; + u8 regs[TOT_REGS]; +}; + +/* Initial values when used in combination with the + NEC upd64031a ghost reduction chip. */ +static u8 upd64083_init[] = { + 0x1f, 0x01, 0xa0, 0x2d, 0x29, /* we use EXCSS=0 */ + 0x36, 0xdd, 0x05, 0x56, 0x48, + 0x00, 0x3a, 0xa0, 0x05, 0x08, + 0x44, 0x60, 0x08, 0x52, 0xf8, + 0x53, 0x60, 0x10 +}; + +/* ------------------------------------------------------------------------ */ + +static void upd64083_log_status(struct i2c_client *client) +{ + u8 buf[7]; + + i2c_master_recv(client, buf, 7); + v4l_info(client, "Status: SA00=%02x SA01=%02x SA02=%02x SA03=%02x " + "SA04=%02x SA05=%02x SA06=%02x\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); +} + +/* ------------------------------------------------------------------------ */ + +static void upd64083_write(struct i2c_client *client, u8 reg, u8 val) +{ + u8 buf[2]; + + buf[0] = reg; + buf[1] = val; + v4l_dbg(1, debug, client, "writing reg addr: %02x val: %02x\n", reg, val); + if (i2c_master_send(client, buf, 2) != 2) + v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val); +} + +/* ------------------------------------------------------------------------ */ + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static u8 upd64083_read(struct i2c_client *client, u8 reg) +{ + u8 buf[7]; + + if (reg >= sizeof(buf)) + return 0xff; + i2c_master_recv(client, buf, sizeof(buf)); + return buf[reg]; +} +#endif + +/* ------------------------------------------------------------------------ */ + +static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct upd64083_state *state = i2c_get_clientdata(client); + struct v4l2_routing *route = arg; + + switch (cmd) { + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = (state->mode >> 6) | (state->ext_y_adc >> 3); + route->output = 0; + break; + + case VIDIOC_INT_S_VIDEO_ROUTING: + { + u8 r00, r02; + + if (route->input > 7 || (route->input & 6) == 6) + return -EINVAL; + state->mode = (route->input & 3) << 6; + state->ext_y_adc = (route->input & UPD64083_EXT_Y_ADC) << 3; + r00 = (state->regs[R00] & ~(3 << 6)) | state->mode; + r02 = (state->regs[R02] & ~(1 << 5)) | state->ext_y_adc; + upd64083_write(client, R00, r00); + upd64083_write(client, R02, r02); + break; + } + + case VIDIOC_LOG_STATUS: + upd64083_log_status(client); + break; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_INT_G_REGISTER: + { + struct v4l2_register *reg = arg; + + if (reg->i2c_id != I2C_DRIVERID_UPD64083) + return -EINVAL; + reg->val = upd64083_read(client, reg->reg & 0xff); + break; + } + + case VIDIOC_INT_S_REGISTER: + { + struct v4l2_register *reg = arg; + u8 addr = reg->reg & 0xff; + u8 val = reg->val & 0xff; + + if (reg->i2c_id != I2C_DRIVERID_UPD64083) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + upd64083_write(client, addr, val); + break; + } +#endif + default: + break; + } + + return 0; +} + +/* ------------------------------------------------------------------------ */ + +/* i2c implementation */ + +static struct i2c_driver i2c_driver; + +static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct upd64083_state *state; + int i; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == NULL) { + return -ENOMEM; + } + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "uPD64083"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + + state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + i2c_set_clientdata(client, state); + /* Initially assume that a ghost reduction chip is present */ + state->mode = 0; /* YCS mode */ + state->ext_y_adc = (1 << 5); + memcpy(state->regs, upd64083_init, TOT_REGS); + for (i = 0; i < TOT_REGS; i++) { + upd64083_write(client, i, state->regs[i]); + } + i2c_attach_client(client); + + return 0; +} + +static int upd64083_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, upd64083_attach); + return 0; +} + +static int upd64083_detach(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) + return err; + + kfree(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "upd64083", + }, + .id = I2C_DRIVERID_UPD64083, + .attach_adapter = upd64083_probe, + .detach_client = upd64083_detach, + .command = upd64083_command, +}; + + +static int __init upd64083_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit upd64083_exit_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(upd64083_init_module); +module_exit(upd64083_exit_module); diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig new file mode 100644 index 000000000000..08a5d20bb2c0 --- /dev/null +++ b/drivers/media/video/usbvideo/Kconfig @@ -0,0 +1,38 @@ +config VIDEO_USBVIDEO + tristate + +config USB_VICAM + tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)" + depends on USB && VIDEO_DEV && EXPERIMENTAL + select VIDEO_USBVIDEO + ---help--- + Say Y here if you have 3com homeconnect camera (vicam). + + To compile this driver as a module, choose M here: the + module will be called vicam. + +config USB_IBMCAM + tristate "USB IBM (Xirlink) C-it Camera support" + depends on USB && VIDEO_DEV + select VIDEO_USBVIDEO + ---help--- + Say Y here if you want to connect a IBM "C-It" camera, also known as + "Xirlink PC Camera" to your computer's USB port. + + To compile this driver as a module, choose M here: the + module will be called ibmcam. + + This camera has several configuration options which + can be specified when you load the module. Read + to learn more. + +config USB_KONICAWC + tristate "USB Konica Webcam support" + depends on USB && VIDEO_DEV + select VIDEO_USBVIDEO + ---help--- + Say Y here if you want support for webcams based on a Konica + chipset. This is known to work with the Intel YC76 webcam. + + To compile this driver as a module, choose M here: the + module will be called konicawc. diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile index ed410a5ee8c9..bb52eb8dc2f9 100644 --- a/drivers/media/video/usbvideo/Makefile +++ b/drivers/media/video/usbvideo/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_USB_IBMCAM) += ibmcam.o usbvideo.o ultracam.o -obj-$(CONFIG_USB_KONICAWC) += konicawc.o usbvideo.o -obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o - +obj-$(CONFIG_VIDEO_USBVIDEO) += usbvideo.o +obj-$(CONFIG_USB_IBMCAM) += ibmcam.o ultracam.o +obj-$(CONFIG_USB_KONICAWC) += konicawc.o +obj-$(CONFIG_USB_VICAM) += vicam.o diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 11a97f30b876..d330fa985bcc 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -317,6 +317,7 @@ static const char *v4l2_int_ioctls[] = { [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", [_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG", + [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", [_IOC_NR(VIDIOC_INT_S_REGISTER)] = "VIDIOC_INT_S_REGISTER", [_IOC_NR(VIDIOC_INT_G_REGISTER)] = "VIDIOC_INT_G_REGISTER", [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", @@ -325,7 +326,12 @@ static const char *v4l2_int_ioctls[] = { [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", [_IOC_NR(VIDIOC_INT_G_CHIP_IDENT)] = "VIDIOC_INT_G_CHIP_IDENT", - [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ" + [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", + [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", + [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", + [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", + [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", + [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING" }; #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index d2ca0f08d0df..acc5ea936687 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -399,19 +399,25 @@ void videobuf_queue_pci(struct videobuf_queue* q) int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; + struct videobuf_queue_ops qops; q.dev=pci; - q.ops->vb_map_sg=(vb_map_sg_t *)pci_unmap_sg; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.ops = &qops; - return (videobuf_dma_unmap(&q,dma)); + return (videobuf_dma_map(&q,dma)); } int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma) { struct videobuf_queue q; + struct videobuf_queue_ops qops; q.dev=pci; - q.ops->vb_map_sg=(vb_map_sg_t *)pci_unmap_sg; + qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg; + qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg; + q.ops = &qops; return (videobuf_dma_unmap(&q,dma)); } @@ -923,7 +929,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, /* need to capture a new frame */ retval = -ENOMEM; q->read_buf = videobuf_alloc(q->msize); - dprintk(1,"video alloc=0x%08x\n",(unsigned int) q->read_buf); + dprintk(1,"video alloc=0x%p\n", q->read_buf); if (NULL == q->read_buf) goto done; q->read_buf->memory = V4L2_MEMORY_USERPTR; diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c new file mode 100644 index 000000000000..a9b59c35cd67 --- /dev/null +++ b/drivers/media/video/wm8739.c @@ -0,0 +1,355 @@ +/* + * wm8739 + * + * Copyright (C) 2005 T. Adachi + * + * Copyright (C) 2005 Hans Verkuil + * - Cleanup + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("wm8739 driver"); +MODULE_AUTHOR("T. Adachi, Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static int debug = 0; +static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END }; + +module_param(debug, int, 0644); + +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + + +I2C_CLIENT_INSMOD; + +/* ------------------------------------------------------------------------ */ + +enum { + R0 = 0, R1, + R5 = 5, R6, R7, R8, R9, R15 = 15, + TOT_REGS +}; + +struct wm8739_state { + u32 clock_freq; + u8 muted; + u16 volume; + u16 balance; + u8 vol_l; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */ + u8 vol_r; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */ +}; + +/* ------------------------------------------------------------------------ */ + +static int wm8739_write(struct i2c_client *client, int reg, u16 val) +{ + int i; + + if (reg < 0 || reg >= TOT_REGS) { + v4l_err(client, "Invalid register R%d\n", reg); + return -1; + } + + v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val); + + for (i = 0; i < 3; i++) { + if (i2c_smbus_write_byte_data(client, (reg << 1) | + (val >> 8), val & 0xff) == 0) { + return 0; + } + } + v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); + return -1; +} + +/* write regs to set audio volume etc */ +static void wm8739_set_audio(struct i2c_client *client) +{ + struct wm8739_state *state = i2c_get_clientdata(client); + u16 mute = state->muted ? 0x80 : 0; + + /* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB + * Default setting: 0x17 = 0 dB + */ + wm8739_write(client, R0, (state->vol_l & 0x1f) | mute); + wm8739_write(client, R1, (state->vol_r & 0x1f) | mute); +} + +static int wm8739_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct wm8739_state *state = i2c_get_clientdata(client); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = state->muted; + break; + + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = state->volume; + break; + + case V4L2_CID_AUDIO_BALANCE: + ctrl->value = state->balance; + break; + + default: + return -EINVAL; + } + return 0; +} + +static int wm8739_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) +{ + struct wm8739_state *state = i2c_get_clientdata(client); + unsigned int work_l, work_r; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + state->muted = ctrl->value; + break; + + case V4L2_CID_AUDIO_VOLUME: + state->volume = ctrl->value; + break; + + case V4L2_CID_AUDIO_BALANCE: + state->balance = ctrl->value; + break; + + default: + return -EINVAL; + } + + /* normalize ( 65535 to 0 -> 31 to 0 (12dB to -34.5dB) ) */ + work_l = (min(65536 - state->balance, 32768) * state->volume) / 32768; + work_r = (min(state->balance, (u16)32768) * state->volume) / 32768; + + state->vol_l = (long)work_l * 31 / 65535; + state->vol_r = (long)work_r * 31 / 65535; + + /* set audio volume etc. */ + wm8739_set_audio(client); + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static struct v4l2_queryctrl wm8739_qctrl[] = { + { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 58880, + .flags = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + },{ + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = 0, + .type = V4L2_CTRL_TYPE_BOOLEAN, + },{ + .id = V4L2_CID_AUDIO_BALANCE, + .name = "Balance", + .minimum = 0, + .maximum = 65535, + .step = 65535/100, + .default_value = 32768, + .flags = 0, + .type = V4L2_CTRL_TYPE_INTEGER, + } +}; + +/* ------------------------------------------------------------------------ */ + +static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct wm8739_state *state = i2c_get_clientdata(client); + + switch (cmd) { + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + { + u32 audiofreq = *(u32 *)arg; + + state->clock_freq = audiofreq; + wm8739_write(client, R9, 0x000); /* de-activate */ + switch (audiofreq) { + case 44100: + wm8739_write(client, R8, 0x020); /* 256fps, fs=44.1k */ + break; + case 48000: + wm8739_write(client, R8, 0x000); /* 256fps, fs=48k */ + break; + case 32000: + wm8739_write(client, R8, 0x018); /* 256fps, fs=32k */ + break; + default: + break; + } + wm8739_write(client, R9, 0x001); /* activate */ + break; + } + + case VIDIOC_G_CTRL: + return wm8739_get_ctrl(client, arg); + + case VIDIOC_S_CTRL: + return wm8739_set_ctrl(client, arg); + + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + int i; + + for (i = 0; i < ARRAY_SIZE(wm8739_qctrl); i++) + if (qc->id && qc->id == wm8739_qctrl[i].id) { + memcpy(qc, &wm8739_qctrl[i], sizeof(*qc)); + return 0; + } + return -EINVAL; + } + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Frequency: %u Hz\n", state->clock_freq); + v4l_info(client, "Volume L: %02x%s\n", state->vol_l & 0x1f, + state->muted ? " (muted)" : ""); + v4l_info(client, "Volume R: %02x%s\n", state->vol_r & 0x1f, + state->muted ? " (muted)" : ""); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ------------------------------------------------------------------------ */ + +/* i2c implementation */ + +static struct i2c_driver i2c_driver; + +static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct wm8739_state *state; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == NULL) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = &i2c_driver; + snprintf(client->name, sizeof(client->name) - 1, "wm8739"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + + state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL); + if (state == NULL) { + kfree(client); + return -ENOMEM; + } + state->vol_l = 0x17; /* 0dB */ + state->vol_r = 0x17; /* 0dB */ + state->muted = 0; + state->balance = 32768; + /* normalize (12dB(31) to -34.5dB(0) [0dB(23)] -> 65535 to 0) */ + state->volume = ((long)state->vol_l + 1) * 65535 / 31; + state->clock_freq = 48000; + i2c_set_clientdata(client, state); + + /* initialize wm8739 */ + wm8739_write(client, R15, 0x00); /* reset */ + wm8739_write(client, R5, 0x000); /* filter setting, high path, offet clear */ + wm8739_write(client, R6, 0x000); /* ADC, OSC, Power Off mode Disable */ + wm8739_write(client, R7, 0x049); /* Digital Audio interface format */ + /* Enable Master mode */ + /* 24 bit, MSB first/left justified */ + wm8739_write(client, R8, 0x000); /* sampling control */ + /* normal, 256fs, 48KHz sampling rate */ + wm8739_write(client, R9, 0x001); /* activate */ + wm8739_set_audio(client); /* set volume/mute */ + + i2c_attach_client(client); + + return 0; +} + +static int wm8739_probe(struct i2c_adapter *adapter) +{ + if (adapter->class & I2C_CLASS_TV_ANALOG) + return i2c_probe(adapter, &addr_data, wm8739_attach); + return 0; +} + +static int wm8739_detach(struct i2c_client *client) +{ + int err; + + err = i2c_detach_client(client); + if (err) + return err; + + kfree(client); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ +static struct i2c_driver i2c_driver = { + .driver = { + .name = "wm8739", + }, + .id = I2C_DRIVERID_WM8739, + .attach_adapter = wm8739_probe, + .detach_client = wm8739_detach, + .command = wm8739_command, +}; + + +static int __init wm8739_init_module(void) +{ + return i2c_add_driver(&i2c_driver); +} + +static void __exit wm8739_cleanup_module(void) +{ + i2c_del_driver(&i2c_driver); +} + +module_init(wm8739_init_module); +module_exit(wm8739_cleanup_module); diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig new file mode 100644 index 000000000000..c3bf886b80cd --- /dev/null +++ b/drivers/media/video/zc0301/Kconfig @@ -0,0 +1,11 @@ +config USB_ZC0301 + tristate "USB ZC0301 Image Processor and Control Chip support" + depends on USB && VIDEO_DEV + ---help--- + Say Y here if you want support for cameras based on the ZC0301 + Image Processor and Control Chip. + + See for more info. + + To compile this driver as a module, choose M here: the + module will be called zc0301. diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 010d4a39269b..e9716b10acea 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -366,7 +366,15 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, static int mptsas_slave_configure(struct scsi_device *sdev) { - sas_read_port_mode_page(sdev); + struct Scsi_Host *host = sdev->host; + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + + /* + * RAID volumes placed beyond the last expected port. + * Ignore sending sas mode pages in that case.. + */ + if (sdev->channel < hd->ioc->num_ports) + sas_read_port_mode_page(sdev); return mptscsih_slave_configure(sdev); } diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 3f5d77f633fa..003b077c2324 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -60,6 +60,17 @@ config MMC_SDHCI If unsure, say N. +config MMC_OMAP + tristate "TI OMAP Multimedia Card Interface support" + depends on ARCH_OMAP && MMC + select TPS65010 if MACH_OMAP_H2 + help + This selects the TI OMAP Multimedia card Interface. + If you have an OMAP board with a Multimedia Card slot, + say Y or M here. + + If unsure, say N. + config MMC_WBSD tristate "Winbond W83L51xD SD/MMC Card Interface support" depends on MMC && ISA_DMA_API @@ -80,4 +91,22 @@ config MMC_AU1X If unsure, say N. +config MMC_AT91RM9200 + tristate "AT91RM9200 SD/MMC Card Interface support" + depends on ARCH_AT91RM9200 && MMC + help + This selects the AT91RM9200 MCI controller. + + If unsure, say N. + +config MMC_IMX + tristate "Motorola i.MX Multimedia Card Interface support" + depends on ARCH_IMX && MMC + help + This selects the Motorola i.MX Multimedia card Interface. + If you have a i.MX platform with a Multimedia Card slot, + say Y or M here. + + If unsure, say N. + endmenu diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 769d545284a4..d2957e35cc6f 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -17,8 +17,15 @@ obj-$(CONFIG_MMC_BLOCK) += mmc_block.o # obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o +obj-$(CONFIG_MMC_IMX) += imxmmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o +obj-$(CONFIG_MMC_OMAP) += omap.o +obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o + +ifeq ($(CONFIG_MMC_DEBUG),y) +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c new file mode 100644 index 000000000000..6061c2d101a0 --- /dev/null +++ b/drivers/mmc/at91_mci.c @@ -0,0 +1,988 @@ +/* + * linux/drivers/mmc/at91_mci.c - ATMEL AT91RM9200 MCI Driver + * + * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved + * + * Copyright (C) 2006 Malcolm Noyes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + This is the AT91RM9200 MCI driver that has been tested with both MMC cards + and SD-cards. Boards that support write protect are now supported. + The CCAT91SBC001 board does not support SD cards. + + The three entry points are at91_mci_request, at91_mci_set_ios + and at91_mci_get_ro. + + SET IOS + This configures the device to put it into the correct mode and clock speed + required. + + MCI REQUEST + MCI request processes the commands sent in the mmc_request structure. This + can consist of a processing command and a stop command in the case of + multiple block transfers. + + There are three main types of request, commands, reads and writes. + + Commands are straight forward. The command is submitted to the controller and + the request function returns. When the controller generates an interrupt to indicate + the command is finished, the response to the command are read and the mmc_request_done + function called to end the request. + + Reads and writes work in a similar manner to normal commands but involve the PDC (DMA) + controller to manage the transfers. + + A read is done from the controller directly to the scatterlist passed in from the request. + Due to a bug in the controller, when a read is completed, all the words are byte + swapped in the scatterlist buffers. + + The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY + + A write is slightly different in that the bytes to write are read from the scatterlist + into a dma memory buffer (this is in case the source buffer should be read only). The + entire write buffer is then done from this single dma memory buffer. + + The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY + + GET RO + Gets the status of the write protect pin, if available. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "at91_mci" + +#undef SUPPORT_4WIRE + +#ifdef CONFIG_MMC_DEBUG +#define DBG(fmt...) \ + printk(fmt) +#else +#define DBG(fmt...) do { } while (0) +#endif + +static struct clk *mci_clk; + +#define FL_SENT_COMMAND (1 << 0) +#define FL_SENT_STOP (1 << 1) + + + +/* + * Read from a MCI register. + */ +static inline unsigned long at91_mci_read(unsigned int reg) +{ + void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI; + + return __raw_readl(mci_base + reg); +} + +/* + * Write to a MCI register. + */ +static inline void at91_mci_write(unsigned int reg, unsigned long value) +{ + void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI; + + __raw_writel(value, mci_base + reg); +} + +/* + * Low level type for this driver + */ +struct at91mci_host +{ + struct mmc_host *mmc; + struct mmc_command *cmd; + struct mmc_request *request; + + struct at91_mmc_data *board; + int present; + + /* + * Flag indicating when the command has been sent. This is used to + * work out whether or not to send the stop + */ + unsigned int flags; + /* flag for current bus settings */ + u32 bus_mode; + + /* DMA buffer used for transmitting */ + unsigned int* buffer; + dma_addr_t physical_address; + unsigned int total_length; + + /* Latest in the scatterlist that has been enabled for transfer, but not freed */ + int in_use_index; + + /* Latest in the scatterlist that has been enabled for transfer */ + int transfer_index; +}; + +/* + * Copy from sg to a dma block - used for transfers + */ +static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data) +{ + unsigned int len, i, size; + unsigned *dmabuf = host->buffer; + + size = host->total_length; + len = data->sg_len; + + /* + * Just loop through all entries. Size might not + * be the entire list though so make sure that + * we do not transfer too much. + */ + for (i = 0; i < len; i++) { + struct scatterlist *sg; + int amount; + int index; + unsigned int *sgbuffer; + + sg = &data->sg[i]; + + sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; + amount = min(size, sg->length); + size -= amount; + amount /= 4; + + for (index = 0; index < amount; index++) + *dmabuf++ = swab32(sgbuffer[index]); + + kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ); + + if (size == 0) + break; + } + + /* + * Check that we didn't get a request to transfer + * more data than can fit into the SG list. + */ + BUG_ON(size != 0); +} + +/* + * Prepare a dma read + */ +static void at91mci_pre_dma_read(struct at91mci_host *host) +{ + int i; + struct scatterlist *sg; + struct mmc_command *cmd; + struct mmc_data *data; + + DBG("pre dma read\n"); + + cmd = host->cmd; + if (!cmd) { + DBG("no command\n"); + return; + } + + data = cmd->data; + if (!data) { + DBG("no data\n"); + return; + } + + for (i = 0; i < 2; i++) { + /* nothing left to transfer */ + if (host->transfer_index >= data->sg_len) { + DBG("Nothing left to transfer (index = %d)\n", host->transfer_index); + break; + } + + /* Check to see if this needs filling */ + if (i == 0) { + if (at91_mci_read(AT91_PDC_RCR) != 0) { + DBG("Transfer active in current\n"); + continue; + } + } + else { + if (at91_mci_read(AT91_PDC_RNCR) != 0) { + DBG("Transfer active in next\n"); + continue; + } + } + + /* Setup the next transfer */ + DBG("Using transfer index %d\n", host->transfer_index); + + sg = &data->sg[host->transfer_index++]; + DBG("sg = %p\n", sg); + + sg->dma_address = dma_map_page(NULL, sg->page, sg->offset, sg->length, DMA_FROM_DEVICE); + + DBG("dma address = %08X, length = %d\n", sg->dma_address, sg->length); + + if (i == 0) { + at91_mci_write(AT91_PDC_RPR, sg->dma_address); + at91_mci_write(AT91_PDC_RCR, sg->length / 4); + } + else { + at91_mci_write(AT91_PDC_RNPR, sg->dma_address); + at91_mci_write(AT91_PDC_RNCR, sg->length / 4); + } + } + + DBG("pre dma read done\n"); +} + +/* + * Handle after a dma read + */ +static void at91mci_post_dma_read(struct at91mci_host *host) +{ + struct mmc_command *cmd; + struct mmc_data *data; + + DBG("post dma read\n"); + + cmd = host->cmd; + if (!cmd) { + DBG("no command\n"); + return; + } + + data = cmd->data; + if (!data) { + DBG("no data\n"); + return; + } + + while (host->in_use_index < host->transfer_index) { + unsigned int *buffer; + int index; + int len; + + struct scatterlist *sg; + + DBG("finishing index %d\n", host->in_use_index); + + sg = &data->sg[host->in_use_index++]; + + DBG("Unmapping page %08X\n", sg->dma_address); + + dma_unmap_page(NULL, sg->dma_address, sg->length, DMA_FROM_DEVICE); + + /* Swap the contents of the buffer */ + buffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset; + DBG("buffer = %p, length = %d\n", buffer, sg->length); + + data->bytes_xfered += sg->length; + + len = sg->length / 4; + + for (index = 0; index < len; index++) { + buffer[index] = swab32(buffer[index]); + } + kunmap_atomic(buffer, KM_BIO_SRC_IRQ); + flush_dcache_page(sg->page); + } + + /* Is there another transfer to trigger? */ + if (host->transfer_index < data->sg_len) + at91mci_pre_dma_read(host); + else { + at91_mci_write(AT91_MCI_IER, AT91_MCI_RXBUFF); + at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + } + + DBG("post dma read done\n"); +} + +/* + * Handle transmitted data + */ +static void at91_mci_handle_transmitted(struct at91mci_host *host) +{ + struct mmc_command *cmd; + struct mmc_data *data; + + DBG("Handling the transmit\n"); + + /* Disable the transfer */ + at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + + /* Now wait for cmd ready */ + at91_mci_write(AT91_MCI_IDR, AT91_MCI_TXBUFE); + at91_mci_write(AT91_MCI_IER, AT91_MCI_NOTBUSY); + + cmd = host->cmd; + if (!cmd) return; + + data = cmd->data; + if (!data) return; + + data->bytes_xfered = host->total_length; +} + +/* + * Enable the controller + */ +static void at91_mci_enable(void) +{ + at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN); + at91_mci_write(AT91_MCI_IDR, 0xFFFFFFFF); + at91_mci_write(AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); + at91_mci_write(AT91_MCI_MR, 0x834A); + at91_mci_write(AT91_MCI_SDCR, 0x0); +} + +/* + * Disable the controller + */ +static void at91_mci_disable(void) +{ + at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); +} + +/* + * Send a command + * return the interrupts to enable + */ +static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) +{ + unsigned int cmdr, mr; + unsigned int block_length; + struct mmc_data *data = cmd->data; + + unsigned int blocks; + unsigned int ier = 0; + + host->cmd = cmd; + + /* Not sure if this is needed */ +#if 0 + if ((at91_mci_read(AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { + DBG("Clearing timeout\n"); + at91_mci_write(AT91_MCI_ARGR, 0); + at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD); + while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) { + /* spin */ + DBG("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR)); + } + } +#endif + cmdr = cmd->opcode; + + if (mmc_resp_type(cmd) == MMC_RSP_NONE) + cmdr |= AT91_MCI_RSPTYP_NONE; + else { + /* if a response is expected then allow maximum response latancy */ + cmdr |= AT91_MCI_MAXLAT; + /* set 136 bit response for R2, 48 bit response otherwise */ + if (mmc_resp_type(cmd) == MMC_RSP_R2) + cmdr |= AT91_MCI_RSPTYP_136; + else + cmdr |= AT91_MCI_RSPTYP_48; + } + + if (data) { + block_length = 1 << data->blksz_bits; + blocks = data->blocks; + + /* always set data start - also set direction flag for read */ + if (data->flags & MMC_DATA_READ) + cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START); + else if (data->flags & MMC_DATA_WRITE) + cmdr |= AT91_MCI_TRCMD_START; + + if (data->flags & MMC_DATA_STREAM) + cmdr |= AT91_MCI_TRTYP_STREAM; + if (data->flags & MMC_DATA_MULTI) + cmdr |= AT91_MCI_TRTYP_MULTIPLE; + } + else { + block_length = 0; + blocks = 0; + } + + if (cmd->opcode == MMC_STOP_TRANSMISSION) + cmdr |= AT91_MCI_TRCMD_STOP; + + if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) + cmdr |= AT91_MCI_OPDCMD; + + /* + * Set the arguments and send the command + */ + DBG("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n", + cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(AT91_MCI_MR)); + + if (!data) { + at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS); + at91_mci_write(AT91_PDC_RPR, 0); + at91_mci_write(AT91_PDC_RCR, 0); + at91_mci_write(AT91_PDC_RNPR, 0); + at91_mci_write(AT91_PDC_RNCR, 0); + at91_mci_write(AT91_PDC_TPR, 0); + at91_mci_write(AT91_PDC_TCR, 0); + at91_mci_write(AT91_PDC_TNPR, 0); + at91_mci_write(AT91_PDC_TNCR, 0); + + at91_mci_write(AT91_MCI_ARGR, cmd->arg); + at91_mci_write(AT91_MCI_CMDR, cmdr); + return AT91_MCI_CMDRDY; + } + + mr = at91_mci_read(AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */ + at91_mci_write(AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); + + /* + * Disable the PDC controller + */ + at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS); + + if (cmdr & AT91_MCI_TRCMD_START) { + data->bytes_xfered = 0; + host->transfer_index = 0; + host->in_use_index = 0; + if (cmdr & AT91_MCI_TRDIR) { + /* + * Handle a read + */ + host->buffer = NULL; + host->total_length = 0; + + at91mci_pre_dma_read(host); + ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; + } + else { + /* + * Handle a write + */ + host->total_length = block_length * blocks; + host->buffer = dma_alloc_coherent(NULL, + host->total_length, + &host->physical_address, GFP_KERNEL); + + at91mci_sg_to_dma(host, data); + + DBG("Transmitting %d bytes\n", host->total_length); + + at91_mci_write(AT91_PDC_TPR, host->physical_address); + at91_mci_write(AT91_PDC_TCR, host->total_length / 4); + ier = AT91_MCI_TXBUFE; + } + } + + /* + * Send the command and then enable the PDC - not the other way round as + * the data sheet says + */ + + at91_mci_write(AT91_MCI_ARGR, cmd->arg); + at91_mci_write(AT91_MCI_CMDR, cmdr); + + if (cmdr & AT91_MCI_TRCMD_START) { + if (cmdr & AT91_MCI_TRDIR) + at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTEN); + else + at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTEN); + } + return ier; +} + +/* + * Wait for a command to complete + */ +static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd) +{ + unsigned int ier; + + ier = at91_mci_send_command(host, cmd); + + DBG("setting ier to %08X\n", ier); + + /* Stop on errors or the required value */ + at91_mci_write(AT91_MCI_IER, 0xffff0000 | ier); +} + +/* + * Process the next step in the request + */ +static void at91mci_process_next(struct at91mci_host *host) +{ + if (!(host->flags & FL_SENT_COMMAND)) { + host->flags |= FL_SENT_COMMAND; + at91mci_process_command(host, host->request->cmd); + } + else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) { + host->flags |= FL_SENT_STOP; + at91mci_process_command(host, host->request->stop); + } + else + mmc_request_done(host->mmc, host->request); +} + +/* + * Handle a command that has been completed + */ +static void at91mci_completed_command(struct at91mci_host *host) +{ + struct mmc_command *cmd = host->cmd; + unsigned int status; + + at91_mci_write(AT91_MCI_IDR, 0xffffffff); + + cmd->resp[0] = at91_mci_read(AT91_MCI_RSPR(0)); + cmd->resp[1] = at91_mci_read(AT91_MCI_RSPR(1)); + cmd->resp[2] = at91_mci_read(AT91_MCI_RSPR(2)); + cmd->resp[3] = at91_mci_read(AT91_MCI_RSPR(3)); + + if (host->buffer) { + dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address); + host->buffer = NULL; + } + + status = at91_mci_read(AT91_MCI_SR); + + DBG("Status = %08X [%08X %08X %08X %08X]\n", + status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); + + if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE | + AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE | + AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) { + if ((status & AT91_MCI_RCRCE) && + ((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) { + cmd->error = MMC_ERR_NONE; + } + else { + if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE)) + cmd->error = MMC_ERR_TIMEOUT; + else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE)) + cmd->error = MMC_ERR_BADCRC; + else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE)) + cmd->error = MMC_ERR_FIFO; + else + cmd->error = MMC_ERR_FAILED; + + DBG("Error detected and set to %d (cmd = %d, retries = %d)\n", + cmd->error, cmd->opcode, cmd->retries); + } + } + else + cmd->error = MMC_ERR_NONE; + + at91mci_process_next(host); +} + +/* + * Handle an MMC request + */ +static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct at91mci_host *host = mmc_priv(mmc); + host->request = mrq; + host->flags = 0; + + at91mci_process_next(host); +} + +/* + * Set the IOS + */ +static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + int clkdiv; + struct at91mci_host *host = mmc_priv(mmc); + unsigned long at91_master_clock = clk_get_rate(mci_clk); + + DBG("Clock %uHz, busmode %u, powermode %u, Vdd %u\n", + ios->clock, ios->bus_mode, ios->power_mode, ios->vdd); + + if (host) + host->bus_mode = ios->bus_mode; + else + printk("MMC: No host for bus_mode\n"); + + if (ios->clock == 0) { + /* Disable the MCI controller */ + at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS); + clkdiv = 0; + } + else { + /* Enable the MCI controller */ + at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN); + + if ((at91_master_clock % (ios->clock * 2)) == 0) + clkdiv = ((at91_master_clock / ios->clock) / 2) - 1; + else + clkdiv = (at91_master_clock / ios->clock) / 2; + + DBG("clkdiv = %d. mcck = %ld\n", clkdiv, + at91_master_clock / (2 * (clkdiv + 1))); + } + if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) { + DBG("MMC: Setting controller bus width to 4\n"); + at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) | AT91_MCI_SDCBUS); + } + else { + DBG("MMC: Setting controller bus width to 1\n"); + at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); + } + + /* Set the clock divider */ + at91_mci_write(AT91_MCI_MR, (at91_mci_read(AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv); + + /* maybe switch power to the card */ + if (host && host->board->vcc_pin) { + switch (ios->power_mode) { + case MMC_POWER_OFF: + at91_set_gpio_output(host->board->vcc_pin, 0); + break; + case MMC_POWER_UP: + case MMC_POWER_ON: + at91_set_gpio_output(host->board->vcc_pin, 1); + break; + } + } +} + +/* + * Handle an interrupt + */ +static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs) +{ + struct at91mci_host *host = devid; + int completed = 0; + + unsigned int int_status; + + if (host == NULL) + return IRQ_HANDLED; + + int_status = at91_mci_read(AT91_MCI_SR); + DBG("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR), + int_status & at91_mci_read(AT91_MCI_IMR)); + + if ((int_status & at91_mci_read(AT91_MCI_IMR)) & 0xffff0000) + completed = 1; + + int_status &= at91_mci_read(AT91_MCI_IMR); + + if (int_status & AT91_MCI_UNRE) + DBG("MMC: Underrun error\n"); + if (int_status & AT91_MCI_OVRE) + DBG("MMC: Overrun error\n"); + if (int_status & AT91_MCI_DTOE) + DBG("MMC: Data timeout\n"); + if (int_status & AT91_MCI_DCRCE) + DBG("MMC: CRC error in data\n"); + if (int_status & AT91_MCI_RTOE) + DBG("MMC: Response timeout\n"); + if (int_status & AT91_MCI_RENDE) + DBG("MMC: Response end bit error\n"); + if (int_status & AT91_MCI_RCRCE) + DBG("MMC: Response CRC error\n"); + if (int_status & AT91_MCI_RDIRE) + DBG("MMC: Response direction error\n"); + if (int_status & AT91_MCI_RINDE) + DBG("MMC: Response index error\n"); + + /* Only continue processing if no errors */ + if (!completed) { + if (int_status & AT91_MCI_TXBUFE) { + DBG("TX buffer empty\n"); + at91_mci_handle_transmitted(host); + } + + if (int_status & AT91_MCI_RXBUFF) { + DBG("RX buffer full\n"); + at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY); + } + + if (int_status & AT91_MCI_ENDTX) { + DBG("Transmit has ended\n"); + } + + if (int_status & AT91_MCI_ENDRX) { + DBG("Receive has ended\n"); + at91mci_post_dma_read(host); + } + + if (int_status & AT91_MCI_NOTBUSY) { + DBG("Card is ready\n"); + at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY); + } + + if (int_status & AT91_MCI_DTIP) { + DBG("Data transfer in progress\n"); + } + + if (int_status & AT91_MCI_BLKE) { + DBG("Block transfer has ended\n"); + } + + if (int_status & AT91_MCI_TXRDY) { + DBG("Ready to transmit\n"); + } + + if (int_status & AT91_MCI_RXRDY) { + DBG("Ready to receive\n"); + } + + if (int_status & AT91_MCI_CMDRDY) { + DBG("Command ready\n"); + completed = 1; + } + } + at91_mci_write(AT91_MCI_IDR, int_status); + + if (completed) { + DBG("Completed command\n"); + at91_mci_write(AT91_MCI_IDR, 0xffffffff); + at91mci_completed_command(host); + } + + return IRQ_HANDLED; +} + +static irqreturn_t at91_mmc_det_irq(int irq, void *_host, struct pt_regs *regs) +{ + struct at91mci_host *host = _host; + int present = !at91_get_gpio_value(irq); + + /* + * we expect this irq on both insert and remove, + * and use a short delay to debounce. + */ + if (present != host->present) { + host->present = present; + DBG("%s: card %s\n", mmc_hostname(host->mmc), + present ? "insert" : "remove"); + if (!present) { + DBG("****** Resetting SD-card bus width ******\n"); + at91_mci_write(AT91_MCI_SDCR, 0); + } + mmc_detect_change(host->mmc, msecs_to_jiffies(100)); + } + return IRQ_HANDLED; +} + +int at91_mci_get_ro(struct mmc_host *mmc) +{ + int read_only = 0; + struct at91mci_host *host = mmc_priv(mmc); + + if (host->board->wp_pin) { + read_only = at91_get_gpio_value(host->board->wp_pin); + printk(KERN_WARNING "%s: card is %s\n", mmc_hostname(mmc), + (read_only ? "read-only" : "read-write") ); + } + else { + printk(KERN_WARNING "%s: host does not support reading read-only " + "switch. Assuming write-enable.\n", mmc_hostname(mmc)); + } + return read_only; +} + +static struct mmc_host_ops at91_mci_ops = { + .request = at91_mci_request, + .set_ios = at91_mci_set_ios, + .get_ro = at91_mci_get_ro, +}; + +/* + * Probe for the device + */ +static int at91_mci_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct at91mci_host *host; + int ret; + + DBG("Probe MCI devices\n"); + at91_mci_disable(); + at91_mci_enable(); + + mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev); + if (!mmc) { + DBG("Failed to allocate mmc host\n"); + return -ENOMEM; + } + + mmc->ops = &at91_mci_ops; + mmc->f_min = 375000; + mmc->f_max = 25000000; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + + host = mmc_priv(mmc); + host->mmc = mmc; + host->buffer = NULL; + host->bus_mode = 0; + host->board = pdev->dev.platform_data; + if (host->board->wire4) { +#ifdef SUPPORT_4WIRE + mmc->caps |= MMC_CAP_4_BIT_DATA; +#else + printk("MMC: 4 wire bus mode not supported by this driver - using 1 wire\n"); +#endif + } + + /* + * Get Clock + */ + mci_clk = clk_get(&pdev->dev, "mci_clk"); + if (!mci_clk) { + printk(KERN_ERR "AT91 MMC: no clock defined.\n"); + return -ENODEV; + } + clk_enable(mci_clk); /* Enable the peripheral clock */ + + /* + * Allocate the MCI interrupt + */ + ret = request_irq(AT91_ID_MCI, at91_mci_irq, SA_SHIRQ, DRIVER_NAME, host); + if (ret) { + DBG("Failed to request MCI interrupt\n"); + return ret; + } + + platform_set_drvdata(pdev, mmc); + + /* + * Add host to MMC layer + */ + if (host->board->det_pin) + host->present = !at91_get_gpio_value(host->board->det_pin); + else + host->present = -1; + + mmc_add_host(mmc); + + /* + * monitor card insertion/removal if we can + */ + if (host->board->det_pin) { + ret = request_irq(host->board->det_pin, at91_mmc_det_irq, + SA_SAMPLE_RANDOM, DRIVER_NAME, host); + if (ret) + DBG("couldn't allocate MMC detect irq\n"); + } + + DBG(KERN_INFO "Added MCI driver\n"); + + return 0; +} + +/* + * Remove a device + */ +static int at91_mci_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct at91mci_host *host; + + if (!mmc) + return -1; + + host = mmc_priv(mmc); + + if (host->present != -1) { + free_irq(host->board->det_pin, host); + cancel_delayed_work(&host->mmc->detect); + } + + mmc_remove_host(mmc); + at91_mci_disable(); + free_irq(AT91_ID_MCI, host); + mmc_free_host(mmc); + + clk_disable(mci_clk); /* Disable the peripheral clock */ + clk_put(mci_clk); + + platform_set_drvdata(pdev, NULL); + + DBG("Removed\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + int ret = 0; + + if (mmc) + ret = mmc_suspend_host(mmc, state); + + return ret; +} + +static int at91_mci_resume(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + int ret = 0; + + if (mmc) + ret = mmc_resume_host(mmc); + + return ret; +} +#else +#define at91_mci_suspend NULL +#define at91_mci_resume NULL +#endif + +static struct platform_driver at91_mci_driver = { + .probe = at91_mci_probe, + .remove = at91_mci_remove, + .suspend = at91_mci_suspend, + .resume = at91_mci_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init at91_mci_init(void) +{ + return platform_driver_register(&at91_mci_driver); +} + +static void __exit at91_mci_exit(void) +{ + platform_driver_unregister(&at91_mci_driver); +} + +module_init(at91_mci_init); +module_exit(at91_mci_exit); + +MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver"); +MODULE_AUTHOR("Nick Randell"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index 85e89c77bdea..c0326bbc5f28 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -56,12 +56,11 @@ #define DRIVER_NAME "au1xxx-mmc" /* Set this to enable special debugging macros */ -/* #define MMC_DEBUG */ -#ifdef MMC_DEBUG -#define DEBUG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args) +#ifdef DEBUG +#define DBG(fmt, idx, args...) printk("au1xx(%d): DEBUG: " fmt, idx, ##args) #else -#define DEBUG(fmt, idx, args...) +#define DBG(fmt, idx, args...) #endif const struct { @@ -424,18 +423,18 @@ static void au1xmmc_receive_pio(struct au1xmmc_host *host) break; if (status & SD_STATUS_RC) { - DEBUG("RX CRC Error [%d + %d].\n", host->id, + DBG("RX CRC Error [%d + %d].\n", host->id, host->pio.len, count); break; } if (status & SD_STATUS_RO) { - DEBUG("RX Overrun [%d + %d]\n", host->id, + DBG("RX Overrun [%d + %d]\n", host->id, host->pio.len, count); break; } else if (status & SD_STATUS_RU) { - DEBUG("RX Underrun [%d + %d]\n", host->id, + DBG("RX Underrun [%d + %d]\n", host->id, host->pio.len, count); break; } @@ -721,7 +720,7 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios) { struct au1xmmc_host *host = mmc_priv(mmc); - DEBUG("set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n", + DBG("set_ios (power=%u, clock=%uHz, vdd=%u, mode=%u)\n", host->id, ios->power_mode, ios->clock, ios->vdd, ios->bus_mode); @@ -810,7 +809,7 @@ static irqreturn_t au1xmmc_irq(int irq, void *dev_id, struct pt_regs *regs) au1xmmc_receive_pio(host); } else if (status & 0x203FBC70) { - DEBUG("Unhandled status %8.8x\n", host->id, status); + DBG("Unhandled status %8.8x\n", host->id, status); handled = 0; } @@ -839,7 +838,7 @@ static void au1xmmc_poll_event(unsigned long arg) if (host->mrq != NULL) { u32 status = au_readl(HOST_STATUS(host)); - DEBUG("PENDING - %8.8x\n", host->id, status); + DBG("PENDING - %8.8x\n", host->id, status); } mod_timer(&host->timer, jiffies + AU1XMMC_DETECT_TIMEOUT); diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c new file mode 100644 index 000000000000..ffb7f55d3467 --- /dev/null +++ b/drivers/mmc/imxmmc.c @@ -0,0 +1,1096 @@ +/* + * linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver + * + * Copyright (C) 2004 Sascha Hauer, Pengutronix + * Copyright (C) 2006 Pavel Pisa, PiKRON + * + * derived from pxamci.c by Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 2005-04-17 Pavel Pisa + * Changed to conform redesigned i.MX scatter gather DMA interface + * + * 2005-11-04 Pavel Pisa + * Updated for 2.6.14 kernel + * + * 2005-12-13 Jay Monkman + * Found and corrected problems in the write path + * + * 2005-12-30 Pavel Pisa + * The event handling rewritten right way in softirq. + * Added many ugly hacks and delays to overcome SDHC + * deficiencies + * + */ +#include + +#ifdef CONFIG_MMC_DEBUG +#define DEBUG +#else +#undef DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "imxmmc.h" + +#define DRIVER_NAME "imx-mmc" + +#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \ + INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \ + INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO) + +struct imxmci_host { + struct mmc_host *mmc; + spinlock_t lock; + struct resource *res; + int irq; + imx_dmach_t dma; + unsigned int clkrt; + unsigned int cmdat; + volatile unsigned int imask; + unsigned int power_mode; + unsigned int present; + struct imxmmc_platform_data *pdata; + + struct mmc_request *req; + struct mmc_command *cmd; + struct mmc_data *data; + + struct timer_list timer; + struct tasklet_struct tasklet; + unsigned int status_reg; + unsigned long pending_events; + /* Next to fields are there for CPU driven transfers to overcome SDHC deficiencies */ + u16 *data_ptr; + unsigned int data_cnt; + atomic_t stuck_timeout; + + unsigned int dma_nents; + unsigned int dma_size; + unsigned int dma_dir; + int dma_allocated; + + unsigned char actual_bus_width; +}; + +#define IMXMCI_PEND_IRQ_b 0 +#define IMXMCI_PEND_DMA_END_b 1 +#define IMXMCI_PEND_DMA_ERR_b 2 +#define IMXMCI_PEND_WAIT_RESP_b 3 +#define IMXMCI_PEND_DMA_DATA_b 4 +#define IMXMCI_PEND_CPU_DATA_b 5 +#define IMXMCI_PEND_CARD_XCHG_b 6 +#define IMXMCI_PEND_SET_INIT_b 7 + +#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b) +#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b) +#define IMXMCI_PEND_DMA_ERR_m (1 << IMXMCI_PEND_DMA_ERR_b) +#define IMXMCI_PEND_WAIT_RESP_m (1 << IMXMCI_PEND_WAIT_RESP_b) +#define IMXMCI_PEND_DMA_DATA_m (1 << IMXMCI_PEND_DMA_DATA_b) +#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b) +#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b) +#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b) + +static void imxmci_stop_clock(struct imxmci_host *host) +{ + int i = 0; + MMC_STR_STP_CLK &= ~STR_STP_CLK_START_CLK; + while(i < 0x1000) { + if(!(i & 0x7f)) + MMC_STR_STP_CLK |= STR_STP_CLK_STOP_CLK; + + if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) { + /* Check twice before cut */ + if(!(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN)) + return; + } + + i++; + } + dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n"); +} + +static void imxmci_start_clock(struct imxmci_host *host) +{ + int i = 0; + MMC_STR_STP_CLK &= ~STR_STP_CLK_STOP_CLK; + while(i < 0x1000) { + if(!(i & 0x7f)) + MMC_STR_STP_CLK |= STR_STP_CLK_START_CLK; + + if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) { + /* Check twice before cut */ + if(MMC_STATUS & STATUS_CARD_BUS_CLK_RUN) + return; + } + + i++; + } + dev_dbg(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n"); +} + +static void imxmci_softreset(void) +{ + /* reset sequence */ + MMC_STR_STP_CLK = 0x8; + MMC_STR_STP_CLK = 0xD; + MMC_STR_STP_CLK = 0x5; + MMC_STR_STP_CLK = 0x5; + MMC_STR_STP_CLK = 0x5; + MMC_STR_STP_CLK = 0x5; + MMC_STR_STP_CLK = 0x5; + MMC_STR_STP_CLK = 0x5; + MMC_STR_STP_CLK = 0x5; + MMC_STR_STP_CLK = 0x5; + + MMC_RES_TO = 0xff; + MMC_BLK_LEN = 512; + MMC_NOB = 1; +} + +static int imxmci_busy_wait_for_status(struct imxmci_host *host, + unsigned int *pstat, unsigned int stat_mask, + int timeout, const char *where) +{ + int loops=0; + while(!(*pstat & stat_mask)) { + loops+=2; + if(loops >= timeout) { + dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n", + where, *pstat, stat_mask); + return -1; + } + udelay(2); + *pstat |= MMC_STATUS; + } + if(!loops) + return 0; + + dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n", + loops, where, *pstat, stat_mask); + return loops; +} + +static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data) +{ + unsigned int nob = data->blocks; + unsigned int blksz = 1 << data->blksz_bits; + unsigned int datasz = nob * blksz; + int i; + + if (data->flags & MMC_DATA_STREAM) + nob = 0xffff; + + host->data = data; + data->bytes_xfered = 0; + + MMC_NOB = nob; + MMC_BLK_LEN = blksz; + + /* + * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise. + * We are in big troubles for non-512 byte transfers according to note in the paragraph + * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least. + * The situation is even more complex in reality. The SDHC in not able to handle wll + * partial FIFO fills and reads. The length has to be rounded up to burst size multiple. + * This is required for SCR read at least. + */ + if (datasz < 64) { + host->dma_size = datasz; + if (data->flags & MMC_DATA_READ) { + host->dma_dir = DMA_FROM_DEVICE; + + /* Hack to enable read SCR */ + if(datasz < 16) { + MMC_NOB = 1; + MMC_BLK_LEN = 16; + } + } else { + host->dma_dir = DMA_TO_DEVICE; + } + + /* Convert back to virtual address */ + host->data_ptr = (u16*)(page_address(data->sg->page) + data->sg->offset); + host->data_cnt = 0; + + clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); + set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); + + return; + } + + if (data->flags & MMC_DATA_READ) { + host->dma_dir = DMA_FROM_DEVICE; + host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, host->dma_dir); + + imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz, + host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_READ); + + /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/ + CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN; + } else { + host->dma_dir = DMA_TO_DEVICE; + + host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, host->dma_dir); + + imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz, + host->res->start + MMC_BUFFER_ACCESS_OFS, DMA_MODE_WRITE); + + /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/ + CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN; + } + +#if 1 /* This code is there only for consistency checking and can be disabled in future */ + host->dma_size = 0; + for(i=0; idma_nents; i++) + host->dma_size+=data->sg[i].length; + + if (datasz > host->dma_size) { + dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n", + datasz, host->dma_size); + } +#endif + + host->dma_size = datasz; + + wmb(); + + if(host->actual_bus_width == MMC_BUS_WIDTH_4) + BLR(host->dma) = 0; /* burst 64 byte read / 64 bytes write */ + else + BLR(host->dma) = 16; /* burst 16 byte read / 16 bytes write */ + + RSSR(host->dma) = DMA_REQ_SDHC; + + set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events); + clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events); + + /* start DMA engine for read, write is delayed after initial response */ + if (host->dma_dir == DMA_FROM_DEVICE) { + imx_dma_enable(host->dma); + } +} + +static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat) +{ + unsigned long flags; + u32 imask; + + WARN_ON(host->cmd != NULL); + host->cmd = cmd; + + if (cmd->flags & MMC_RSP_BUSY) + cmdat |= CMD_DAT_CONT_BUSY; + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_R1: /* short CRC, OPCODE */ + case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */ + cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1; + break; + case MMC_RSP_R2: /* long 136 bit + CRC */ + cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2; + break; + case MMC_RSP_R3: /* short */ + cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3; + break; + case MMC_RSP_R6: /* short CRC */ + cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R6; + break; + default: + break; + } + + if ( test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events) ) + cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */ + + if ( host->actual_bus_width == MMC_BUS_WIDTH_4 ) + cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; + + MMC_CMD = cmd->opcode; + MMC_ARGH = cmd->arg >> 16; + MMC_ARGL = cmd->arg & 0xffff; + MMC_CMD_DAT_CONT = cmdat; + + atomic_set(&host->stuck_timeout, 0); + set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events); + + + imask = IMXMCI_INT_MASK_DEFAULT; + imask &= ~INT_MASK_END_CMD_RES; + if ( cmdat & CMD_DAT_CONT_DATA_ENABLE ) { + /*imask &= ~INT_MASK_BUF_READY;*/ + imask &= ~INT_MASK_DATA_TRAN; + if ( cmdat & CMD_DAT_CONT_WRITE ) + imask &= ~INT_MASK_WRITE_OP_DONE; + if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) + imask &= ~INT_MASK_BUF_READY; + } + + spin_lock_irqsave(&host->lock, flags); + host->imask = imask; + MMC_INT_MASK = host->imask; + spin_unlock_irqrestore(&host->lock, flags); + + dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n", + cmd->opcode, cmd->opcode, imask); + + imxmci_start_clock(host); +} + +static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m | + IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m); + + host->imask = IMXMCI_INT_MASK_DEFAULT; + MMC_INT_MASK = host->imask; + + spin_unlock_irqrestore(&host->lock, flags); + + host->req = NULL; + host->cmd = NULL; + host->data = NULL; + mmc_request_done(host->mmc, req); +} + +static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat) +{ + struct mmc_data *data = host->data; + int data_error; + + if(test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)){ + imx_dma_disable(host->dma); + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents, + host->dma_dir); + } + + if ( stat & STATUS_ERR_MASK ) { + dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat); + if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR)) + data->error = MMC_ERR_BADCRC; + else if(stat & STATUS_TIME_OUT_READ) + data->error = MMC_ERR_TIMEOUT; + else + data->error = MMC_ERR_FAILED; + } else { + data->bytes_xfered = host->dma_size; + } + + data_error = data->error; + + host->data = NULL; + + return data_error; +} + +static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat) +{ + struct mmc_command *cmd = host->cmd; + int i; + u32 a,b,c; + struct mmc_data *data = host->data; + + if (!cmd) + return 0; + + host->cmd = NULL; + + if (stat & STATUS_TIME_OUT_RESP) { + dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n"); + cmd->error = MMC_ERR_TIMEOUT; + } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) { + dev_dbg(mmc_dev(host->mmc), "cmd crc error\n"); + cmd->error = MMC_ERR_BADCRC; + } + + if(cmd->flags & MMC_RSP_PRESENT) { + if(cmd->flags & MMC_RSP_136) { + for (i = 0; i < 4; i++) { + u32 a = MMC_RES_FIFO & 0xffff; + u32 b = MMC_RES_FIFO & 0xffff; + cmd->resp[i] = a<<16 | b; + } + } else { + a = MMC_RES_FIFO & 0xffff; + b = MMC_RES_FIFO & 0xffff; + c = MMC_RES_FIFO & 0xffff; + cmd->resp[0] = a<<24 | b<<8 | c>>8; + } + } + + dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n", + cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error); + + if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) { + if (host->req->data->flags & MMC_DATA_WRITE) { + + /* Wait for FIFO to be empty before starting DMA write */ + + stat = MMC_STATUS; + if(imxmci_busy_wait_for_status(host, &stat, + STATUS_APPL_BUFF_FE, + 40, "imxmci_cmd_done DMA WR") < 0) { + cmd->error = MMC_ERR_FIFO; + imxmci_finish_data(host, stat); + if(host->req) + imxmci_finish_request(host, host->req); + dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n", + stat); + return 0; + } + + if(test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) { + imx_dma_enable(host->dma); + } + } + } else { + struct mmc_request *req; + imxmci_stop_clock(host); + req = host->req; + + if(data) + imxmci_finish_data(host, stat); + + if( req ) { + imxmci_finish_request(host, req); + } else { + dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n"); + } + } + + return 1; +} + +static int imxmci_data_done(struct imxmci_host *host, unsigned int stat) +{ + struct mmc_data *data = host->data; + int data_error; + + if (!data) + return 0; + + data_error = imxmci_finish_data(host, stat); + + if (host->req->stop && (data_error == MMC_ERR_NONE)) { + imxmci_stop_clock(host); + imxmci_start_cmd(host, host->req->stop, 0); + } else { + struct mmc_request *req; + req = host->req; + if( req ) { + imxmci_finish_request(host, req); + } else { + dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n"); + } + } + + return 1; +} + +static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat) +{ + int i; + int burst_len; + int flush_len; + int trans_done = 0; + unsigned int stat = *pstat; + + if(host->actual_bus_width == MMC_BUS_WIDTH_4) + burst_len = 16; + else + burst_len = 64; + + /* This is unfortunately required */ + dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n", + stat); + + if(host->dma_dir == DMA_FROM_DEVICE) { + imxmci_busy_wait_for_status(host, &stat, + STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE, + 20, "imxmci_cpu_driven_data read"); + + while((stat & (STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE)) && + (host->data_cnt < host->dma_size)) { + if(burst_len >= host->dma_size - host->data_cnt) { + flush_len = burst_len; + burst_len = host->dma_size - host->data_cnt; + flush_len -= burst_len; + host->data_cnt = host->dma_size; + trans_done = 1; + } else { + flush_len = 0; + host->data_cnt += burst_len; + } + + for(i = burst_len; i>=2 ; i-=2) { + *(host->data_ptr++) = MMC_BUFFER_ACCESS; + udelay(20); /* required for clocks < 8MHz*/ + } + + if(i == 1) + *(u8*)(host->data_ptr) = MMC_BUFFER_ACCESS; + + stat = MMC_STATUS; + + /* Flush extra bytes from FIFO */ + while(flush_len >= 2){ + flush_len -= 2; + i = MMC_BUFFER_ACCESS; + stat = MMC_STATUS; + stat &= ~STATUS_CRC_READ_ERR; /* Stupid but required there */ + } + + dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read burst %d STATUS = 0x%x\n", + burst_len, stat); + } + } else { + imxmci_busy_wait_for_status(host, &stat, + STATUS_APPL_BUFF_FE, + 20, "imxmci_cpu_driven_data write"); + + while((stat & STATUS_APPL_BUFF_FE) && + (host->data_cnt < host->dma_size)) { + if(burst_len >= host->dma_size - host->data_cnt) { + burst_len = host->dma_size - host->data_cnt; + host->data_cnt = host->dma_size; + trans_done = 1; + } else { + host->data_cnt += burst_len; + } + + for(i = burst_len; i>0 ; i-=2) + MMC_BUFFER_ACCESS = *(host->data_ptr++); + + stat = MMC_STATUS; + + dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n", + burst_len, stat); + } + } + + *pstat = stat; + + return trans_done; +} + +static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs) +{ + struct imxmci_host *host = devid; + uint32_t stat = MMC_STATUS; + + atomic_set(&host->stuck_timeout, 0); + host->status_reg = stat; + set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); + tasklet_schedule(&host->tasklet); +} + +static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs) +{ + struct imxmci_host *host = devid; + uint32_t stat = MMC_STATUS; + int handled = 1; + + MMC_INT_MASK = host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT; + + atomic_set(&host->stuck_timeout, 0); + host->status_reg = stat; + set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); + tasklet_schedule(&host->tasklet); + + return IRQ_RETVAL(handled);; +} + +static void imxmci_tasklet_fnc(unsigned long data) +{ + struct imxmci_host *host = (struct imxmci_host *)data; + u32 stat; + unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */ + int timeout = 0; + + if(atomic_read(&host->stuck_timeout) > 4) { + char *what; + timeout = 1; + stat = MMC_STATUS; + host->status_reg = stat; + if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) + if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) + what = "RESP+DMA"; + else + what = "RESP"; + else + if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) + if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events)) + what = "DATA"; + else + what = "DMA"; + else + what = "???"; + + dev_err(mmc_dev(host->mmc), "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n", + what, stat, MMC_INT_MASK); + dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n", + MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma)); + dev_err(mmc_dev(host->mmc), "CMD%d, bus %d-bit, dma_size = 0x%x\n", + host->cmd?host->cmd->opcode:0, 1<actual_bus_width, host->dma_size); + } + + if(!host->present || timeout) + host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ | + STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR; + + if(test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) { + clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events); + + stat = MMC_STATUS; + /* + * This is not required in theory, but there is chance to miss some flag + * which clears automatically by mask write, FreeScale original code keeps + * stat from IRQ time so do I + */ + stat |= host->status_reg; + + if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) { + imxmci_busy_wait_for_status(host, &stat, + STATUS_END_CMD_RESP | STATUS_ERR_MASK, + 20, "imxmci_tasklet_fnc resp (ERRATUM #4)"); + } + + if(stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) { + if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) + imxmci_cmd_done(host, stat); + if(host->data && (stat & STATUS_ERR_MASK)) + imxmci_data_done(host, stat); + } + + if(test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) { + stat |= MMC_STATUS; + if(imxmci_cpu_driven_data(host, &stat)){ + if(test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) + imxmci_cmd_done(host, stat); + atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m, + &host->pending_events); + imxmci_data_done(host, stat); + } + } + } + + if(test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) && + !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) { + + stat = MMC_STATUS; + /* Same as above */ + stat |= host->status_reg; + + if(host->dma_dir == DMA_TO_DEVICE) { + data_dir_mask = STATUS_WRITE_OP_DONE; + } else { + data_dir_mask = STATUS_DATA_TRANS_DONE; + } + + imxmci_busy_wait_for_status(host, &stat, + data_dir_mask, + 50, "imxmci_tasklet_fnc data"); + + if(stat & data_dir_mask) { + clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); + imxmci_data_done(host, stat); + } + } + + if(test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) { + + if(host->cmd) + imxmci_cmd_done(host, STATUS_TIME_OUT_RESP); + + if(host->data) + imxmci_data_done(host, STATUS_TIME_OUT_READ | + STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR); + + if(host->req) + imxmci_finish_request(host, host->req); + + mmc_detect_change(host->mmc, msecs_to_jiffies(100)); + + } +} + +static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req) +{ + struct imxmci_host *host = mmc_priv(mmc); + unsigned int cmdat; + + WARN_ON(host->req != NULL); + + host->req = req; + + cmdat = 0; + + if (req->data) { + imxmci_setup_data(host, req->data); + + cmdat |= CMD_DAT_CONT_DATA_ENABLE; + + if (req->data->flags & MMC_DATA_WRITE) + cmdat |= CMD_DAT_CONT_WRITE; + + if (req->data->flags & MMC_DATA_STREAM) { + cmdat |= CMD_DAT_CONT_STREAM_BLOCK; + } + } + + imxmci_start_cmd(host, req->cmd, cmdat); +} + +#define CLK_RATE 19200000 + +static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct imxmci_host *host = mmc_priv(mmc); + int prescaler; + + dev_dbg(mmc_dev(host->mmc), "clock %u power %u vdd %u width %u\n", + ios->clock, ios->power_mode, ios->vdd, + (ios->bus_width==MMC_BUS_WIDTH_4)?4:1); + + if( ios->bus_width==MMC_BUS_WIDTH_4 ) { + host->actual_bus_width = MMC_BUS_WIDTH_4; + imx_gpio_mode(PB11_PF_SD_DAT3); + }else{ + host->actual_bus_width = MMC_BUS_WIDTH_1; + imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); + } + + if ( host->power_mode != ios->power_mode ) { + switch (ios->power_mode) { + case MMC_POWER_OFF: + break; + case MMC_POWER_UP: + set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events); + break; + case MMC_POWER_ON: + break; + } + host->power_mode = ios->power_mode; + } + + if ( ios->clock ) { + unsigned int clk; + + /* The prescaler is 5 for PERCLK2 equal to 96MHz + * then 96MHz / 5 = 19.2 MHz + */ + clk=imx_get_perclk2(); + prescaler=(clk+(CLK_RATE*7)/8)/CLK_RATE; + switch(prescaler) { + case 0: + case 1: prescaler = 0; + break; + case 2: prescaler = 1; + break; + case 3: prescaler = 2; + break; + case 4: prescaler = 4; + break; + default: + case 5: prescaler = 5; + break; + } + + dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n", + clk, prescaler); + + for(clk=0; clk<8; clk++) { + int x; + x = CLK_RATE / (1<clock) + break; + } + + MMC_STR_STP_CLK |= STR_STP_CLK_ENABLE; /* enable controller */ + + imxmci_stop_clock(host); + MMC_CLK_RATE = (prescaler<<3) | clk; + imxmci_start_clock(host); + + dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE); + } else { + imxmci_stop_clock(host); + } +} + +static struct mmc_host_ops imxmci_ops = { + .request = imxmci_request, + .set_ios = imxmci_set_ios, +}; + +static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr) +{ + int i; + + for (i = 0; i < dev->num_resources; i++) + if (dev->resource[i].flags == mask && nr-- == 0) + return &dev->resource[i]; + return NULL; +} + +static int platform_device_irq(struct platform_device *dev, int nr) +{ + int i; + + for (i = 0; i < dev->num_resources; i++) + if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0) + return dev->resource[i].start; + return NO_IRQ; +} + +static void imxmci_check_status(unsigned long data) +{ + struct imxmci_host *host = (struct imxmci_host *)data; + + if( host->pdata->card_present() != host->present ) { + host->present ^= 1; + dev_info(mmc_dev(host->mmc), "card %s\n", + host->present ? "inserted" : "removed"); + + set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events); + tasklet_schedule(&host->tasklet); + } + + if(test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) || + test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) { + atomic_inc(&host->stuck_timeout); + if(atomic_read(&host->stuck_timeout) > 4) + tasklet_schedule(&host->tasklet); + } else { + atomic_set(&host->stuck_timeout, 0); + + } + + mod_timer(&host->timer, jiffies + (HZ>>1)); +} + +static int imxmci_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct imxmci_host *host = NULL; + struct resource *r; + int ret = 0, irq; + + printk(KERN_INFO "i.MX mmc driver\n"); + + r = platform_device_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_device_irq(pdev, 0); + if (!r || irq == NO_IRQ) + return -ENXIO; + + r = request_mem_region(r->start, 0x100, "IMXMCI"); + if (!r) + return -EBUSY; + + mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev); + if (!mmc) { + ret = -ENOMEM; + goto out; + } + + mmc->ops = &imxmci_ops; + mmc->f_min = 150000; + mmc->f_max = CLK_RATE/2; + mmc->ocr_avail = MMC_VDD_32_33; + mmc->caps |= MMC_CAP_4_BIT_DATA; + + /* MMC core transfer sizes tunable parameters */ + mmc->max_hw_segs = 64; + mmc->max_phys_segs = 64; + mmc->max_sectors = 64; /* default 1 << (PAGE_CACHE_SHIFT - 9) */ + mmc->max_seg_size = 64*512; /* default PAGE_CACHE_SIZE */ + + host = mmc_priv(mmc); + host->mmc = mmc; + host->dma_allocated = 0; + host->pdata = pdev->dev.platform_data; + + spin_lock_init(&host->lock); + host->res = r; + host->irq = irq; + + imx_gpio_mode(PB8_PF_SD_DAT0); + imx_gpio_mode(PB9_PF_SD_DAT1); + imx_gpio_mode(PB10_PF_SD_DAT2); + /* Configured as GPIO with pull-up to ensure right MCC card mode */ + /* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */ + imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11); + /* imx_gpio_mode(PB11_PF_SD_DAT3); */ + imx_gpio_mode(PB12_PF_SD_CLK); + imx_gpio_mode(PB13_PF_SD_CMD); + + imxmci_softreset(); + + if ( MMC_REV_NO != 0x390 ) { + dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n", + MMC_REV_NO); + goto out; + } + + MMC_READ_TO = 0x2db4; /* recommended in data sheet */ + + host->imask = IMXMCI_INT_MASK_DEFAULT; + MMC_INT_MASK = host->imask; + + + if(imx_dma_request_by_prio(&host->dma, DRIVER_NAME, DMA_PRIO_LOW)<0){ + dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n"); + ret = -EBUSY; + goto out; + } + host->dma_allocated=1; + imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host); + + tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host); + host->status_reg=0; + host->pending_events=0; + + ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host); + if (ret) + goto out; + + host->present = host->pdata->card_present(); + init_timer(&host->timer); + host->timer.data = (unsigned long)host; + host->timer.function = imxmci_check_status; + add_timer(&host->timer); + mod_timer(&host->timer, jiffies + (HZ>>1)); + + platform_set_drvdata(pdev, mmc); + + mmc_add_host(mmc); + + return 0; + +out: + if (host) { + if(host->dma_allocated){ + imx_dma_free(host->dma); + host->dma_allocated=0; + } + } + if (mmc) + mmc_free_host(mmc); + release_resource(r); + return ret; +} + +static int imxmci_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (mmc) { + struct imxmci_host *host = mmc_priv(mmc); + + tasklet_disable(&host->tasklet); + + del_timer_sync(&host->timer); + mmc_remove_host(mmc); + + free_irq(host->irq, host); + if(host->dma_allocated){ + imx_dma_free(host->dma); + host->dma_allocated=0; + } + + tasklet_kill(&host->tasklet); + + release_resource(host->res); + + mmc_free_host(mmc); + } + return 0; +} + +#ifdef CONFIG_PM +static int imxmci_suspend(struct platform_device *dev, pm_message_t state) +{ + struct mmc_host *mmc = platform_get_drvdata(dev); + int ret = 0; + + if (mmc) + ret = mmc_suspend_host(mmc, state); + + return ret; +} + +static int imxmci_resume(struct platform_device *dev) +{ + struct mmc_host *mmc = platform_get_drvdata(dev); + struct imxmci_host *host; + int ret = 0; + + if (mmc) { + host = mmc_priv(mmc); + if(host) + set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events); + ret = mmc_resume_host(mmc); + } + + return ret; +} +#else +#define imxmci_suspend NULL +#define imxmci_resume NULL +#endif /* CONFIG_PM */ + +static struct platform_driver imxmci_driver = { + .probe = imxmci_probe, + .remove = imxmci_remove, + .suspend = imxmci_suspend, + .resume = imxmci_resume, + .driver = { + .name = DRIVER_NAME, + } +}; + +static int __init imxmci_init(void) +{ + return platform_driver_register(&imxmci_driver); +} + +static void __exit imxmci_exit(void) +{ + platform_driver_unregister(&imxmci_driver); +} + +module_init(imxmci_init); +module_exit(imxmci_exit); + +MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver"); +MODULE_AUTHOR("Sascha Hauer, Pengutronix"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/imxmmc.h b/drivers/mmc/imxmmc.h new file mode 100644 index 000000000000..e5339e334dbb --- /dev/null +++ b/drivers/mmc/imxmmc.h @@ -0,0 +1,67 @@ + +# define __REG16(x) (*((volatile u16 *)IO_ADDRESS(x))) + +#define MMC_STR_STP_CLK __REG16(IMX_MMC_BASE + 0x00) +#define MMC_STATUS __REG16(IMX_MMC_BASE + 0x04) +#define MMC_CLK_RATE __REG16(IMX_MMC_BASE + 0x08) +#define MMC_CMD_DAT_CONT __REG16(IMX_MMC_BASE + 0x0C) +#define MMC_RES_TO __REG16(IMX_MMC_BASE + 0x10) +#define MMC_READ_TO __REG16(IMX_MMC_BASE + 0x14) +#define MMC_BLK_LEN __REG16(IMX_MMC_BASE + 0x18) +#define MMC_NOB __REG16(IMX_MMC_BASE + 0x1C) +#define MMC_REV_NO __REG16(IMX_MMC_BASE + 0x20) +#define MMC_INT_MASK __REG16(IMX_MMC_BASE + 0x24) +#define MMC_CMD __REG16(IMX_MMC_BASE + 0x28) +#define MMC_ARGH __REG16(IMX_MMC_BASE + 0x2C) +#define MMC_ARGL __REG16(IMX_MMC_BASE + 0x30) +#define MMC_RES_FIFO __REG16(IMX_MMC_BASE + 0x34) +#define MMC_BUFFER_ACCESS __REG16(IMX_MMC_BASE + 0x38) +#define MMC_BUFFER_ACCESS_OFS 0x38 + + +#define STR_STP_CLK_ENDIAN (1<<5) +#define STR_STP_CLK_RESET (1<<3) +#define STR_STP_CLK_ENABLE (1<<2) +#define STR_STP_CLK_START_CLK (1<<1) +#define STR_STP_CLK_STOP_CLK (1<<0) +#define STATUS_CARD_PRESENCE (1<<15) +#define STATUS_SDIO_INT_ACTIVE (1<<14) +#define STATUS_END_CMD_RESP (1<<13) +#define STATUS_WRITE_OP_DONE (1<<12) +#define STATUS_DATA_TRANS_DONE (1<<11) +#define STATUS_WR_CRC_ERROR_CODE_MASK (3<<10) +#define STATUS_CARD_BUS_CLK_RUN (1<<8) +#define STATUS_APPL_BUFF_FF (1<<7) +#define STATUS_APPL_BUFF_FE (1<<6) +#define STATUS_RESP_CRC_ERR (1<<5) +#define STATUS_CRC_READ_ERR (1<<3) +#define STATUS_CRC_WRITE_ERR (1<<2) +#define STATUS_TIME_OUT_RESP (1<<1) +#define STATUS_TIME_OUT_READ (1<<0) +#define STATUS_ERR_MASK 0x2f +#define CLK_RATE_PRESCALER(x) ((x) & 0x7) +#define CLK_RATE_CLK_RATE(x) (((x) & 0x7) << 3) +#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1<<12) +#define CMD_DAT_CONT_STOP_READWAIT (1<<11) +#define CMD_DAT_CONT_START_READWAIT (1<<10) +#define CMD_DAT_CONT_BUS_WIDTH_1 (0<<8) +#define CMD_DAT_CONT_BUS_WIDTH_4 (2<<8) +#define CMD_DAT_CONT_INIT (1<<7) +#define CMD_DAT_CONT_BUSY (1<<6) +#define CMD_DAT_CONT_STREAM_BLOCK (1<<5) +#define CMD_DAT_CONT_WRITE (1<<4) +#define CMD_DAT_CONT_DATA_ENABLE (1<<3) +#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1) +#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2) +#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3) +#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4) +#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5) +#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6) +#define INT_MASK_AUTO_CARD_DETECT (1<<6) +#define INT_MASK_DAT0_EN (1<<5) +#define INT_MASK_SDIO (1<<4) +#define INT_MASK_BUF_READY (1<<3) +#define INT_MASK_END_CMD_RES (1<<2) +#define INT_MASK_WRITE_OP_DONE (1<<1) +#define INT_MASK_DATA_TRAN (1<<0) +#define INT_ALL (0x7f) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 1888060c5e0c..da6ddd910fc5 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -27,12 +27,6 @@ #include "mmc.h" -#ifdef CONFIG_MMC_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) -#else -#define DBG(x...) do { } while (0) -#endif - #define CMD_RETRIES 3 /* @@ -77,8 +71,9 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) { struct mmc_command *cmd = mrq->cmd; int err = mrq->cmd->error; - DBG("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", cmd->opcode, - err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); + pr_debug("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", + cmd->opcode, err, cmd->resp[0], cmd->resp[1], + cmd->resp[2], cmd->resp[3]); if (err && cmd->retries) { cmd->retries--; @@ -102,8 +97,8 @@ EXPORT_SYMBOL(mmc_request_done); void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) { - DBG("MMC: starting cmd %02x arg %08x flags %08x\n", - mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); + pr_debug("MMC: starting cmd %02x arg %08x flags %08x\n", + mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags); WARN_ON(host->card_busy == NULL); @@ -976,8 +971,8 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) max_dtr = card->csd.max_dtr; - DBG("MMC: selected %d.%03dMHz transfer rate\n", - max_dtr / 1000000, (max_dtr / 1000) % 1000); + pr_debug("MMC: selected %d.%03dMHz transfer rate\n", + max_dtr / 1000000, (max_dtr / 1000) % 1000); return max_dtr; } diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c index 9fef29d978b5..df7e861e2fc7 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/mmci.c @@ -33,12 +33,8 @@ #define DRIVER_NAME "mmci-pl18x" -#ifdef CONFIG_MMC_DEBUG #define DBG(host,fmt,args...) \ pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args) -#else -#define DBG(host,fmt,args...) do { } while (0) -#endif static unsigned int fmax = 515633; diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c new file mode 100644 index 000000000000..becb3c68c34d --- /dev/null +++ b/drivers/mmc/omap.c @@ -0,0 +1,1226 @@ +/* + * linux/drivers/media/mmc/omap.c + * + * Copyright (C) 2004 Nokia Corporation + * Written by Tuukka Tikkanen and Juha Yrjölä + * Misc hacks here and there by Tony Lindgren + * Other hacks (DMA, SD, etc) by David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "omap.h" + +#define DRIVER_NAME "mmci-omap" +#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) + +/* Specifies how often in millisecs to poll for card status changes + * when the cover switch is open */ +#define OMAP_MMC_SWITCH_POLL_DELAY 500 + +static int mmc_omap_enable_poll = 1; + +struct mmc_omap_host { + int initialized; + int suspended; + struct mmc_request * mrq; + struct mmc_command * cmd; + struct mmc_data * data; + struct mmc_host * mmc; + struct device * dev; + unsigned char id; /* 16xx chips have 2 MMC blocks */ + struct clk * iclk; + struct clk * fclk; + void __iomem *base; + int irq; + unsigned char bus_mode; + unsigned char hw_bus_mode; + + unsigned int sg_len; + int sg_idx; + u16 * buffer; + u32 buffer_bytes_left; + u32 total_bytes_left; + + unsigned use_dma:1; + unsigned brs_received:1, dma_done:1; + unsigned dma_is_read:1; + unsigned dma_in_use:1; + int dma_ch; + spinlock_t dma_lock; + struct timer_list dma_timer; + unsigned dma_len; + + short power_pin; + short wp_pin; + + int switch_pin; + struct work_struct switch_work; + struct timer_list switch_timer; + int switch_last_state; +}; + +static inline int +mmc_omap_cover_is_open(struct mmc_omap_host *host) +{ + if (host->switch_pin < 0) + return 0; + return omap_get_gpio_datain(host->switch_pin); +} + +static ssize_t +mmc_omap_show_cover_switch(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mmc_omap_host *host = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", mmc_omap_cover_is_open(host) ? "open" : + "closed"); +} + +static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL); + +static ssize_t +mmc_omap_show_enable_poll(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", mmc_omap_enable_poll); +} + +static ssize_t +mmc_omap_store_enable_poll(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) +{ + int enable_poll; + + if (sscanf(buf, "%10d", &enable_poll) != 1) + return -EINVAL; + + if (enable_poll != mmc_omap_enable_poll) { + struct mmc_omap_host *host = dev_get_drvdata(dev); + + mmc_omap_enable_poll = enable_poll; + if (enable_poll && host->switch_pin >= 0) + schedule_work(&host->switch_work); + } + return size; +} + +static DEVICE_ATTR(enable_poll, 0664, + mmc_omap_show_enable_poll, mmc_omap_store_enable_poll); + +static void +mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd) +{ + u32 cmdreg; + u32 resptype; + u32 cmdtype; + + host->cmd = cmd; + + resptype = 0; + cmdtype = 0; + + /* Our hardware needs to know exact type */ + switch (RSP_TYPE(mmc_resp_type(cmd))) { + case RSP_TYPE(MMC_RSP_R1): + /* resp 1, resp 1b */ + resptype = 1; + break; + case RSP_TYPE(MMC_RSP_R2): + resptype = 2; + break; + case RSP_TYPE(MMC_RSP_R3): + resptype = 3; + break; + default: + break; + } + + if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) { + cmdtype = OMAP_MMC_CMDTYPE_ADTC; + } else if (mmc_cmd_type(cmd) == MMC_CMD_BC) { + cmdtype = OMAP_MMC_CMDTYPE_BC; + } else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) { + cmdtype = OMAP_MMC_CMDTYPE_BCR; + } else { + cmdtype = OMAP_MMC_CMDTYPE_AC; + } + + cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12); + + if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) + cmdreg |= 1 << 6; + + if (cmd->flags & MMC_RSP_BUSY) + cmdreg |= 1 << 11; + + if (host->data && !(host->data->flags & MMC_DATA_WRITE)) + cmdreg |= 1 << 15; + + clk_enable(host->fclk); + + OMAP_MMC_WRITE(host->base, CTO, 200); + OMAP_MMC_WRITE(host->base, ARGL, cmd->arg & 0xffff); + OMAP_MMC_WRITE(host->base, ARGH, cmd->arg >> 16); + OMAP_MMC_WRITE(host->base, IE, + OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL | + OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT | + OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT | + OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR | + OMAP_MMC_STAT_END_OF_DATA); + OMAP_MMC_WRITE(host->base, CMD, cmdreg); +} + +static void +mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) +{ + if (host->dma_in_use) { + enum dma_data_direction dma_data_dir; + + BUG_ON(host->dma_ch < 0); + if (data->error != MMC_ERR_NONE) + omap_stop_dma(host->dma_ch); + /* Release DMA channel lazily */ + mod_timer(&host->dma_timer, jiffies + HZ); + if (data->flags & MMC_DATA_WRITE) + dma_data_dir = DMA_TO_DEVICE; + else + dma_data_dir = DMA_FROM_DEVICE; + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len, + dma_data_dir); + } + host->data = NULL; + host->sg_len = 0; + clk_disable(host->fclk); + + /* NOTE: MMC layer will sometimes poll-wait CMD13 next, issuing + * dozens of requests until the card finishes writing data. + * It'd be cheaper to just wait till an EOFB interrupt arrives... + */ + + if (!data->stop) { + host->mrq = NULL; + mmc_request_done(host->mmc, data->mrq); + return; + } + + mmc_omap_start_command(host, data->stop); +} + +static void +mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data) +{ + unsigned long flags; + int done; + + if (!host->dma_in_use) { + mmc_omap_xfer_done(host, data); + return; + } + done = 0; + spin_lock_irqsave(&host->dma_lock, flags); + if (host->dma_done) + done = 1; + else + host->brs_received = 1; + spin_unlock_irqrestore(&host->dma_lock, flags); + if (done) + mmc_omap_xfer_done(host, data); +} + +static void +mmc_omap_dma_timer(unsigned long data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + + BUG_ON(host->dma_ch < 0); + omap_free_dma(host->dma_ch); + host->dma_ch = -1; +} + +static void +mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data) +{ + unsigned long flags; + int done; + + done = 0; + spin_lock_irqsave(&host->dma_lock, flags); + if (host->brs_received) + done = 1; + else + host->dma_done = 1; + spin_unlock_irqrestore(&host->dma_lock, flags); + if (done) + mmc_omap_xfer_done(host, data); +} + +static void +mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd) +{ + host->cmd = NULL; + + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) { + /* response type 2 */ + cmd->resp[3] = + OMAP_MMC_READ(host->base, RSP0) | + (OMAP_MMC_READ(host->base, RSP1) << 16); + cmd->resp[2] = + OMAP_MMC_READ(host->base, RSP2) | + (OMAP_MMC_READ(host->base, RSP3) << 16); + cmd->resp[1] = + OMAP_MMC_READ(host->base, RSP4) | + (OMAP_MMC_READ(host->base, RSP5) << 16); + cmd->resp[0] = + OMAP_MMC_READ(host->base, RSP6) | + (OMAP_MMC_READ(host->base, RSP7) << 16); + } else { + /* response types 1, 1b, 3, 4, 5, 6 */ + cmd->resp[0] = + OMAP_MMC_READ(host->base, RSP6) | + (OMAP_MMC_READ(host->base, RSP7) << 16); + } + } + + if (host->data == NULL || cmd->error != MMC_ERR_NONE) { + host->mrq = NULL; + clk_disable(host->fclk); + mmc_request_done(host->mmc, cmd->mrq); + } +} + +/* PIO only */ +static void +mmc_omap_sg_to_buf(struct mmc_omap_host *host) +{ + struct scatterlist *sg; + + sg = host->data->sg + host->sg_idx; + host->buffer_bytes_left = sg->length; + host->buffer = page_address(sg->page) + sg->offset; + if (host->buffer_bytes_left > host->total_bytes_left) + host->buffer_bytes_left = host->total_bytes_left; +} + +/* PIO only */ +static void +mmc_omap_xfer_data(struct mmc_omap_host *host, int write) +{ + int n; + void __iomem *reg; + u16 *p; + + if (host->buffer_bytes_left == 0) { + host->sg_idx++; + BUG_ON(host->sg_idx == host->sg_len); + mmc_omap_sg_to_buf(host); + } + n = 64; + if (n > host->buffer_bytes_left) + n = host->buffer_bytes_left; + host->buffer_bytes_left -= n; + host->total_bytes_left -= n; + host->data->bytes_xfered += n; + + if (write) { + __raw_writesw(host->base + OMAP_MMC_REG_DATA, host->buffer, n); + } else { + __raw_readsw(host->base + OMAP_MMC_REG_DATA, host->buffer, n); + } +} + +static inline void mmc_omap_report_irq(u16 status) +{ + static const char *mmc_omap_status_bits[] = { + "EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO", + "CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR" + }; + int i, c = 0; + + for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++) + if (status & (1 << i)) { + if (c) + printk(" "); + printk("%s", mmc_omap_status_bits[i]); + c++; + } +} + +static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id; + u16 status; + int end_command; + int end_transfer; + int transfer_error; + + if (host->cmd == NULL && host->data == NULL) { + status = OMAP_MMC_READ(host->base, STAT); + dev_info(mmc_dev(host->mmc),"spurious irq 0x%04x\n", status); + if (status != 0) { + OMAP_MMC_WRITE(host->base, STAT, status); + OMAP_MMC_WRITE(host->base, IE, 0); + } + return IRQ_HANDLED; + } + + end_command = 0; + end_transfer = 0; + transfer_error = 0; + + while ((status = OMAP_MMC_READ(host->base, STAT)) != 0) { + OMAP_MMC_WRITE(host->base, STAT, status); +#ifdef CONFIG_MMC_DEBUG + dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ", + status, host->cmd != NULL ? host->cmd->opcode : -1); + mmc_omap_report_irq(status); + printk("\n"); +#endif + if (host->total_bytes_left) { + if ((status & OMAP_MMC_STAT_A_FULL) || + (status & OMAP_MMC_STAT_END_OF_DATA)) + mmc_omap_xfer_data(host, 0); + if (status & OMAP_MMC_STAT_A_EMPTY) + mmc_omap_xfer_data(host, 1); + } + + if (status & OMAP_MMC_STAT_END_OF_DATA) { + end_transfer = 1; + } + + if (status & OMAP_MMC_STAT_DATA_TOUT) { + dev_dbg(mmc_dev(host->mmc), "data timeout\n"); + if (host->data) { + host->data->error |= MMC_ERR_TIMEOUT; + transfer_error = 1; + } + } + + if (status & OMAP_MMC_STAT_DATA_CRC) { + if (host->data) { + host->data->error |= MMC_ERR_BADCRC; + dev_dbg(mmc_dev(host->mmc), + "data CRC error, bytes left %d\n", + host->total_bytes_left); + transfer_error = 1; + } else { + dev_dbg(mmc_dev(host->mmc), "data CRC error\n"); + } + } + + if (status & OMAP_MMC_STAT_CMD_TOUT) { + /* Timeouts are routine with some commands */ + if (host->cmd) { + if (host->cmd->opcode != MMC_ALL_SEND_CID && + host->cmd->opcode != + MMC_SEND_OP_COND && + host->cmd->opcode != + MMC_APP_CMD && + !mmc_omap_cover_is_open(host)) + dev_err(mmc_dev(host->mmc), + "command timeout, CMD %d\n", + host->cmd->opcode); + host->cmd->error = MMC_ERR_TIMEOUT; + end_command = 1; + } + } + + if (status & OMAP_MMC_STAT_CMD_CRC) { + if (host->cmd) { + dev_err(mmc_dev(host->mmc), + "command CRC error (CMD%d, arg 0x%08x)\n", + host->cmd->opcode, host->cmd->arg); + host->cmd->error = MMC_ERR_BADCRC; + end_command = 1; + } else + dev_err(mmc_dev(host->mmc), + "command CRC error without cmd?\n"); + } + + if (status & OMAP_MMC_STAT_CARD_ERR) { + if (host->cmd && host->cmd->opcode == MMC_STOP_TRANSMISSION) { + u32 response = OMAP_MMC_READ(host->base, RSP6) + | (OMAP_MMC_READ(host->base, RSP7) << 16); + /* STOP sometimes sets must-ignore bits */ + if (!(response & (R1_CC_ERROR + | R1_ILLEGAL_COMMAND + | R1_COM_CRC_ERROR))) { + end_command = 1; + continue; + } + } + + dev_dbg(mmc_dev(host->mmc), "card status error (CMD%d)\n", + host->cmd->opcode); + if (host->cmd) { + host->cmd->error = MMC_ERR_FAILED; + end_command = 1; + } + if (host->data) { + host->data->error = MMC_ERR_FAILED; + transfer_error = 1; + } + } + + /* + * NOTE: On 1610 the END_OF_CMD may come too early when + * starting a write + */ + if ((status & OMAP_MMC_STAT_END_OF_CMD) && + (!(status & OMAP_MMC_STAT_A_EMPTY))) { + end_command = 1; + } + } + + if (end_command) { + mmc_omap_cmd_done(host, host->cmd); + } + if (transfer_error) + mmc_omap_xfer_done(host, host->data); + else if (end_transfer) + mmc_omap_end_of_data(host, host->data); + + return IRQ_HANDLED; +} + +static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id; + + schedule_work(&host->switch_work); + + return IRQ_HANDLED; +} + +static void mmc_omap_switch_timer(unsigned long arg) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) arg; + + schedule_work(&host->switch_work); +} + +/* FIXME: Handle card insertion and removal properly. Maybe use a mask + * for MMC state? */ +static void mmc_omap_switch_callback(unsigned long data, u8 mmc_mask) +{ +} + +static void mmc_omap_switch_handler(void *data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + struct mmc_card *card; + static int complained = 0; + int cards = 0, cover_open; + + if (host->switch_pin == -1) + return; + cover_open = mmc_omap_cover_is_open(host); + if (cover_open != host->switch_last_state) { + kobject_uevent(&host->dev->kobj, KOBJ_CHANGE); + host->switch_last_state = cover_open; + } + mmc_detect_change(host->mmc, 0); + list_for_each_entry(card, &host->mmc->cards, node) { + if (mmc_card_present(card)) + cards++; + } + if (mmc_omap_cover_is_open(host)) { + if (!complained) { + dev_info(mmc_dev(host->mmc), "cover is open"); + complained = 1; + } + if (mmc_omap_enable_poll) + mod_timer(&host->switch_timer, jiffies + + msecs_to_jiffies(OMAP_MMC_SWITCH_POLL_DELAY)); + } else { + complained = 0; + } +} + +/* Prepare to transfer the next segment of a scatterlist */ +static void +mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) +{ + int dma_ch = host->dma_ch; + unsigned long data_addr; + u16 buf, frame; + u32 count; + struct scatterlist *sg = &data->sg[host->sg_idx]; + int src_port = 0; + int dst_port = 0; + int sync_dev = 0; + + data_addr = io_v2p((u32) host->base) + OMAP_MMC_REG_DATA; + frame = 1 << data->blksz_bits; + count = sg_dma_len(sg); + + if ((data->blocks == 1) && (count > (1 << data->blksz_bits))) + count = frame; + + host->dma_len = count; + + /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx. + * Use 16 or 32 word frames when the blocksize is at least that large. + * Blocksize is usually 512 bytes; but not for some SD reads. + */ + if (cpu_is_omap15xx() && frame > 32) + frame = 32; + else if (frame > 64) + frame = 64; + count /= frame; + frame >>= 1; + + if (!(data->flags & MMC_DATA_WRITE)) { + buf = 0x800f | ((frame - 1) << 8); + + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dst_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_is_omap24xx()) + sync_dev = OMAP24XX_DMA_MMC1_RX; + + omap_set_dma_src_params(dma_ch, src_port, + OMAP_DMA_AMODE_CONSTANT, + data_addr, 0, 0); + omap_set_dma_dest_params(dma_ch, dst_port, + OMAP_DMA_AMODE_POST_INC, + sg_dma_address(sg), 0, 0); + omap_set_dma_dest_data_pack(dma_ch, 1); + omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); + } else { + buf = 0x0f80 | ((frame - 1) << 0); + + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_EMIFF; + dst_port = OMAP_DMA_PORT_TIPB; + } + if (cpu_is_omap24xx()) + sync_dev = OMAP24XX_DMA_MMC1_TX; + + omap_set_dma_dest_params(dma_ch, dst_port, + OMAP_DMA_AMODE_CONSTANT, + data_addr, 0, 0); + omap_set_dma_src_params(dma_ch, src_port, + OMAP_DMA_AMODE_POST_INC, + sg_dma_address(sg), 0, 0); + omap_set_dma_src_data_pack(dma_ch, 1); + omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); + } + + /* Max limit for DMA frame count is 0xffff */ + if (unlikely(count > 0xffff)) + BUG(); + + OMAP_MMC_WRITE(host->base, BUF, buf); + omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16, + frame, count, OMAP_DMA_SYNC_FRAME, + sync_dev, 0); +} + +/* A scatterlist segment completed */ +static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data) +{ + struct mmc_omap_host *host = (struct mmc_omap_host *) data; + struct mmc_data *mmcdat = host->data; + + if (unlikely(host->dma_ch < 0)) { + dev_err(mmc_dev(host->mmc), "DMA callback while DMA not + enabled\n"); + return; + } + /* FIXME: We really should do something to _handle_ the errors */ + if (ch_status & OMAP_DMA_TOUT_IRQ) { + dev_err(mmc_dev(host->mmc),"DMA timeout\n"); + return; + } + if (ch_status & OMAP_DMA_DROP_IRQ) { + dev_err(mmc_dev(host->mmc), "DMA sync error\n"); + return; + } + if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) { + return; + } + mmcdat->bytes_xfered += host->dma_len; + host->sg_idx++; + if (host->sg_idx < host->sg_len) { + mmc_omap_prepare_dma(host, host->data); + omap_start_dma(host->dma_ch); + } else + mmc_omap_dma_done(host, host->data); +} + +static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data) +{ + const char *dev_name; + int sync_dev, dma_ch, is_read, r; + + is_read = !(data->flags & MMC_DATA_WRITE); + del_timer_sync(&host->dma_timer); + if (host->dma_ch >= 0) { + if (is_read == host->dma_is_read) + return 0; + omap_free_dma(host->dma_ch); + host->dma_ch = -1; + } + + if (is_read) { + if (host->id == 1) { + sync_dev = OMAP_DMA_MMC_RX; + dev_name = "MMC1 read"; + } else { + sync_dev = OMAP_DMA_MMC2_RX; + dev_name = "MMC2 read"; + } + } else { + if (host->id == 1) { + sync_dev = OMAP_DMA_MMC_TX; + dev_name = "MMC1 write"; + } else { + sync_dev = OMAP_DMA_MMC2_TX; + dev_name = "MMC2 write"; + } + } + r = omap_request_dma(sync_dev, dev_name, mmc_omap_dma_cb, + host, &dma_ch); + if (r != 0) { + dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r); + return r; + } + host->dma_ch = dma_ch; + host->dma_is_read = is_read; + + return 0; +} + +static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req) +{ + u16 reg; + + reg = OMAP_MMC_READ(host->base, SDIO); + reg &= ~(1 << 5); + OMAP_MMC_WRITE(host->base, SDIO, reg); + /* Set maximum timeout */ + OMAP_MMC_WRITE(host->base, CTO, 0xff); +} + +static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req) +{ + int timeout; + u16 reg; + + /* Convert ns to clock cycles by assuming 20MHz frequency + * 1 cycle at 20MHz = 500 ns + */ + timeout = req->data->timeout_clks + req->data->timeout_ns / 500; + + /* Check if we need to use timeout multiplier register */ + reg = OMAP_MMC_READ(host->base, SDIO); + if (timeout > 0xffff) { + reg |= (1 << 5); + timeout /= 1024; + } else + reg &= ~(1 << 5); + OMAP_MMC_WRITE(host->base, SDIO, reg); + OMAP_MMC_WRITE(host->base, DTO, timeout); +} + +static void +mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req) +{ + struct mmc_data *data = req->data; + int i, use_dma, block_size; + unsigned sg_len; + + host->data = data; + if (data == NULL) { + OMAP_MMC_WRITE(host->base, BLEN, 0); + OMAP_MMC_WRITE(host->base, NBLK, 0); + OMAP_MMC_WRITE(host->base, BUF, 0); + host->dma_in_use = 0; + set_cmd_timeout(host, req); + return; + } + + + block_size = 1 << data->blksz_bits; + + OMAP_MMC_WRITE(host->base, NBLK, data->blocks - 1); + OMAP_MMC_WRITE(host->base, BLEN, block_size - 1); + set_data_timeout(host, req); + + /* cope with calling layer confusion; it issues "single + * block" writes using multi-block scatterlists. + */ + sg_len = (data->blocks == 1) ? 1 : data->sg_len; + + /* Only do DMA for entire blocks */ + use_dma = host->use_dma; + if (use_dma) { + for (i = 0; i < sg_len; i++) { + if ((data->sg[i].length % block_size) != 0) { + use_dma = 0; + break; + } + } + } + + host->sg_idx = 0; + if (use_dma) { + if (mmc_omap_get_dma_channel(host, data) == 0) { + enum dma_data_direction dma_data_dir; + + if (data->flags & MMC_DATA_WRITE) + dma_data_dir = DMA_TO_DEVICE; + else + dma_data_dir = DMA_FROM_DEVICE; + + host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, + sg_len, dma_data_dir); + host->total_bytes_left = 0; + mmc_omap_prepare_dma(host, req->data); + host->brs_received = 0; + host->dma_done = 0; + host->dma_in_use = 1; + } else + use_dma = 0; + } + + /* Revert to PIO? */ + if (!use_dma) { + OMAP_MMC_WRITE(host->base, BUF, 0x1f1f); + host->total_bytes_left = data->blocks * block_size; + host->sg_len = sg_len; + mmc_omap_sg_to_buf(host); + host->dma_in_use = 0; + } +} + +static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req) +{ + struct mmc_omap_host *host = mmc_priv(mmc); + + WARN_ON(host->mrq != NULL); + + host->mrq = req; + + /* only touch fifo AFTER the controller readies it */ + mmc_omap_prepare_data(host, req); + mmc_omap_start_command(host, req->cmd); + if (host->dma_in_use) + omap_start_dma(host->dma_ch); +} + +static void innovator_fpga_socket_power(int on) +{ +#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP15XX) + + if (on) { + fpga_write(fpga_read(OMAP1510_FPGA_POWER) | (1 << 3), + OMAP1510_FPGA_POWER); + } else { + fpga_write(fpga_read(OMAP1510_FPGA_POWER) & ~(1 << 3), + OMAP1510_FPGA_POWER); + } +#endif +} + +/* + * Turn the socket power on/off. Innovator uses FPGA, most boards + * probably use GPIO. + */ +static void mmc_omap_power(struct mmc_omap_host *host, int on) +{ + if (on) { + if (machine_is_omap_innovator()) + innovator_fpga_socket_power(1); + else if (machine_is_omap_h2()) + tps65010_set_gpio_out_value(GPIO3, HIGH); + else if (machine_is_omap_h3()) + /* GPIO 4 of TPS65010 sends SD_EN signal */ + tps65010_set_gpio_out_value(GPIO4, HIGH); + else if (cpu_is_omap24xx()) { + u16 reg = OMAP_MMC_READ(host->base, CON); + OMAP_MMC_WRITE(host->base, CON, reg | (1 << 11)); + } else + if (host->power_pin >= 0) + omap_set_gpio_dataout(host->power_pin, 1); + } else { + if (machine_is_omap_innovator()) + innovator_fpga_socket_power(0); + else if (machine_is_omap_h2()) + tps65010_set_gpio_out_value(GPIO3, LOW); + else if (machine_is_omap_h3()) + tps65010_set_gpio_out_value(GPIO4, LOW); + else if (cpu_is_omap24xx()) { + u16 reg = OMAP_MMC_READ(host->base, CON); + OMAP_MMC_WRITE(host->base, CON, reg & ~(1 << 11)); + } else + if (host->power_pin >= 0) + omap_set_gpio_dataout(host->power_pin, 0); + } +} + +static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mmc_omap_host *host = mmc_priv(mmc); + int dsor; + int realclock, i; + + realclock = ios->clock; + + if (ios->clock == 0) + dsor = 0; + else { + int func_clk_rate = clk_get_rate(host->fclk); + + dsor = func_clk_rate / realclock; + if (dsor < 1) + dsor = 1; + + if (func_clk_rate / dsor > realclock) + dsor++; + + if (dsor > 250) + dsor = 250; + dsor++; + + if (ios->bus_width == MMC_BUS_WIDTH_4) + dsor |= 1 << 15; + } + + switch (ios->power_mode) { + case MMC_POWER_OFF: + mmc_omap_power(host, 0); + break; + case MMC_POWER_UP: + case MMC_POWER_ON: + mmc_omap_power(host, 1); + dsor |= 1<<11; + break; + } + + host->bus_mode = ios->bus_mode; + host->hw_bus_mode = host->bus_mode; + + clk_enable(host->fclk); + + /* On insanely high arm_per frequencies something sometimes + * goes somehow out of sync, and the POW bit is not being set, + * which results in the while loop below getting stuck. + * Writing to the CON register twice seems to do the trick. */ + for (i = 0; i < 2; i++) + OMAP_MMC_WRITE(host->base, CON, dsor); + if (ios->power_mode == MMC_POWER_UP) { + /* Send clock cycles, poll completion */ + OMAP_MMC_WRITE(host->base, IE, 0); + OMAP_MMC_WRITE(host->base, STAT, 0xffff); + OMAP_MMC_WRITE(host->base, CMD, 1<<7); + while (0 == (OMAP_MMC_READ(host->base, STAT) & 1)); + OMAP_MMC_WRITE(host->base, STAT, 1); + } + clk_disable(host->fclk); +} + +static int mmc_omap_get_ro(struct mmc_host *mmc) +{ + struct mmc_omap_host *host = mmc_priv(mmc); + + return host->wp_pin && omap_get_gpio_datain(host->wp_pin); +} + +static struct mmc_host_ops mmc_omap_ops = { + .request = mmc_omap_request, + .set_ios = mmc_omap_set_ios, + .get_ro = mmc_omap_get_ro, +}; + +static int __init mmc_omap_probe(struct platform_device *pdev) +{ + struct omap_mmc_conf *minfo = pdev->dev.platform_data; + struct mmc_host *mmc; + struct mmc_omap_host *host = NULL; + int ret = 0; + + if (platform_get_resource(pdev, IORESOURCE_MEM, 0) || + platform_get_irq(pdev, IORESOURCE_IRQ, 0)) { + dev_err(&pdev->dev, "mmc_omap_probe: invalid resource type\n"); + return -ENODEV; + } + + if (!request_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1, + pdev->name)) { + dev_dbg(&pdev->dev, "request_mem_region failed\n"); + return -EBUSY; + } + + mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev); + if (!mmc) { + ret = -ENOMEM; + goto out; + } + + host = mmc_priv(mmc); + host->mmc = mmc; + + spin_lock_init(&host->dma_lock); + init_timer(&host->dma_timer); + host->dma_timer.function = mmc_omap_dma_timer; + host->dma_timer.data = (unsigned long) host; + + host->id = pdev->id; + + if (cpu_is_omap24xx()) { + host->iclk = clk_get(&pdev->dev, "mmc_ick"); + if (IS_ERR(host->iclk)) + goto out; + clk_enable(host->iclk); + } + + if (!cpu_is_omap24xx()) + host->fclk = clk_get(&pdev->dev, "mmc_ck"); + else + host->fclk = clk_get(&pdev->dev, "mmc_fck"); + + if (IS_ERR(host->fclk)) { + ret = PTR_ERR(host->fclk); + goto out; + } + + /* REVISIT: + * Also, use minfo->cover to decide how to manage + * the card detect sensing. + */ + host->power_pin = minfo->power_pin; + host->switch_pin = minfo->switch_pin; + host->wp_pin = minfo->wp_pin; + host->use_dma = 1; + host->dma_ch = -1; + + host->irq = pdev->resource[1].start; + host->base = ioremap(pdev->res.start, SZ_4K); + if (!host->base) { + ret = -ENOMEM; + goto out; + } + + if (minfo->wire4) + mmc->caps |= MMC_CAP_4_BIT_DATA; + + mmc->ops = &mmc_omap_ops; + mmc->f_min = 400000; + mmc->f_max = 24000000; + mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; + + /* Use scatterlist DMA to reduce per-transfer costs. + * NOTE max_seg_size assumption that small blocks aren't + * normally used (except e.g. for reading SD registers). + */ + mmc->max_phys_segs = 32; + mmc->max_hw_segs = 32; + mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */ + mmc->max_seg_size = mmc->max_sectors * 512; + + if (host->power_pin >= 0) { + if ((ret = omap_request_gpio(host->power_pin)) != 0) { + dev_err(mmc_dev(host->mmc), "Unable to get GPIO + pin for MMC power\n"); + goto out; + } + omap_set_gpio_direction(host->power_pin, 0); + } + + ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host); + if (ret) + goto out; + + host->dev = &pdev->dev; + platform_set_drvdata(pdev, host); + + mmc_add_host(mmc); + + if (host->switch_pin >= 0) { + INIT_WORK(&host->switch_work, mmc_omap_switch_handler, host); + init_timer(&host->switch_timer); + host->switch_timer.function = mmc_omap_switch_timer; + host->switch_timer.data = (unsigned long) host; + if (omap_request_gpio(host->switch_pin) != 0) { + dev_warn(mmc_dev(host->mmc), "Unable to get GPIO pin for MMC cover switch\n"); + host->switch_pin = -1; + goto no_switch; + } + + omap_set_gpio_direction(host->switch_pin, 1); + ret = request_irq(OMAP_GPIO_IRQ(host->switch_pin), + mmc_omap_switch_irq, SA_TRIGGER_RISING, DRIVER_NAME, host); + if (ret) { + dev_warn(mmc_dev(host->mmc), "Unable to get IRQ for MMC cover switch\n"); + omap_free_gpio(host->switch_pin); + host->switch_pin = -1; + goto no_switch; + } + ret = device_create_file(&pdev->dev, &dev_attr_cover_switch); + if (ret == 0) { + ret = device_create_file(&pdev->dev, &dev_attr_enable_poll); + if (ret != 0) + device_remove_file(&pdev->dev, &dev_attr_cover_switch); + } + if (ret) { + dev_wan(mmc_dev(host->mmc), "Unable to create sysfs attributes\n"); + free_irq(OMAP_GPIO_IRQ(host->switch_pin), host); + omap_free_gpio(host->switch_pin); + host->switch_pin = -1; + goto no_switch; + } + if (mmc_omap_enable_poll && mmc_omap_cover_is_open(host)) + schedule_work(&host->switch_work); + } + +no_switch: + return 0; + +out: + /* FIXME: Free other resources too. */ + if (host) { + if (host->iclk && !IS_ERR(host->iclk)) + clk_put(host->iclk); + if (host->fclk && !IS_ERR(host->fclk)) + clk_put(host->fclk); + mmc_free_host(host->mmc); + } + return ret; +} + +static int mmc_omap_remove(struct platform_device *pdev) +{ + struct mmc_omap_host *host = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (host) { + mmc_remove_host(host->mmc); + free_irq(host->irq, host); + + if (host->power_pin >= 0) + omap_free_gpio(host->power_pin); + if (host->switch_pin >= 0) { + device_remove_file(&pdev->dev, &dev_attr_enable_poll); + device_remove_file(&pdev->dev, &dev_attr_cover_switch); + free_irq(OMAP_GPIO_IRQ(host->switch_pin), host); + omap_free_gpio(host->switch_pin); + host->switch_pin = -1; + del_timer_sync(&host->switch_timer); + flush_scheduled_work(); + } + if (host->iclk && !IS_ERR(host->iclk)) + clk_put(host->iclk); + if (host->fclk && !IS_ERR(host->fclk)) + clk_put(host->fclk); + mmc_free_host(host->mmc); + } + + release_mem_region(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); + + return 0; +} + +#ifdef CONFIG_PM +static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + int ret = 0; + struct mmc_omap_host *host = platform_get_drvdata(pdev); + + if (host && host->suspended) + return 0; + + if (host) { + ret = mmc_suspend_host(host->mmc, mesg); + if (ret == 0) + host->suspended = 1; + } + return ret; +} + +static int mmc_omap_resume(struct platform_device *pdev) +{ + int ret = 0; + struct mmc_omap_host *host = platform_get_drvdata(pdev); + + if (host && !host->suspended) + return 0; + + if (host) { + ret = mmc_resume_host(host->mmc); + if (ret == 0) + host->suspended = 0; + } + + return ret; +} +#else +#define mmc_omap_suspend NULL +#define mmc_omap_resume NULL +#endif + +static struct platform_driver mmc_omap_driver = { + .probe = mmc_omap_probe, + .remove = mmc_omap_remove, + .suspend = mmc_omap_suspend, + .resume = mmc_omap_resume, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init mmc_omap_init(void) +{ + return platform_driver_register(&mmc_omap_driver); +} + +static void __exit mmc_omap_exit(void) +{ + platform_driver_unregister(&mmc_omap_driver); +} + +module_init(mmc_omap_init); +module_exit(mmc_omap_exit); + +MODULE_DESCRIPTION("OMAP Multimedia Card driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS(DRIVER_NAME); +MODULE_AUTHOR("Juha Yrjölä"); diff --git a/drivers/mmc/omap.h b/drivers/mmc/omap.h new file mode 100644 index 000000000000..c954d355a5e3 --- /dev/null +++ b/drivers/mmc/omap.h @@ -0,0 +1,55 @@ +#ifndef DRIVERS_MEDIA_MMC_OMAP_H +#define DRIVERS_MEDIA_MMC_OMAP_H + +#define OMAP_MMC_REG_CMD 0x00 +#define OMAP_MMC_REG_ARGL 0x04 +#define OMAP_MMC_REG_ARGH 0x08 +#define OMAP_MMC_REG_CON 0x0c +#define OMAP_MMC_REG_STAT 0x10 +#define OMAP_MMC_REG_IE 0x14 +#define OMAP_MMC_REG_CTO 0x18 +#define OMAP_MMC_REG_DTO 0x1c +#define OMAP_MMC_REG_DATA 0x20 +#define OMAP_MMC_REG_BLEN 0x24 +#define OMAP_MMC_REG_NBLK 0x28 +#define OMAP_MMC_REG_BUF 0x2c +#define OMAP_MMC_REG_SDIO 0x34 +#define OMAP_MMC_REG_REV 0x3c +#define OMAP_MMC_REG_RSP0 0x40 +#define OMAP_MMC_REG_RSP1 0x44 +#define OMAP_MMC_REG_RSP2 0x48 +#define OMAP_MMC_REG_RSP3 0x4c +#define OMAP_MMC_REG_RSP4 0x50 +#define OMAP_MMC_REG_RSP5 0x54 +#define OMAP_MMC_REG_RSP6 0x58 +#define OMAP_MMC_REG_RSP7 0x5c +#define OMAP_MMC_REG_IOSR 0x60 +#define OMAP_MMC_REG_SYSC 0x64 +#define OMAP_MMC_REG_SYSS 0x68 + +#define OMAP_MMC_STAT_CARD_ERR (1 << 14) +#define OMAP_MMC_STAT_CARD_IRQ (1 << 13) +#define OMAP_MMC_STAT_OCR_BUSY (1 << 12) +#define OMAP_MMC_STAT_A_EMPTY (1 << 11) +#define OMAP_MMC_STAT_A_FULL (1 << 10) +#define OMAP_MMC_STAT_CMD_CRC (1 << 8) +#define OMAP_MMC_STAT_CMD_TOUT (1 << 7) +#define OMAP_MMC_STAT_DATA_CRC (1 << 6) +#define OMAP_MMC_STAT_DATA_TOUT (1 << 5) +#define OMAP_MMC_STAT_END_BUSY (1 << 4) +#define OMAP_MMC_STAT_END_OF_DATA (1 << 3) +#define OMAP_MMC_STAT_CARD_BUSY (1 << 2) +#define OMAP_MMC_STAT_END_OF_CMD (1 << 0) + +#define OMAP_MMC_READ(base, reg) __raw_readw((base) + OMAP_MMC_REG_##reg) +#define OMAP_MMC_WRITE(base, reg, val) __raw_writew((val), (base) + OMAP_MMC_REG_##reg) + +/* + * Command types + */ +#define OMAP_MMC_CMDTYPE_BC 0 +#define OMAP_MMC_CMDTYPE_BCR 1 +#define OMAP_MMC_CMDTYPE_AC 2 +#define OMAP_MMC_CMDTYPE_ADTC 3 + +#endif diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index c32fad1ce51c..eb9a8826e9b5 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -37,12 +37,6 @@ #include "pxamci.h" -#ifdef CONFIG_MMC_DEBUG -#define DBG(x...) printk(KERN_DEBUG x) -#else -#define DBG(x...) do { } while (0) -#endif - #define DRIVER_NAME "pxa2xx-mci" #define NR_SG 1 @@ -206,7 +200,7 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq) { - DBG("PXAMCI: request done\n"); + pr_debug("PXAMCI: request done\n"); host->mrq = NULL; host->cmd = NULL; host->data = NULL; @@ -252,7 +246,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) if ((cmd->resp[0] & 0x80000000) == 0) cmd->error = MMC_ERR_BADCRC; } else { - DBG("ignoring CRC from command %d - *risky*\n",cmd->opcode); + pr_debug("ignoring CRC from command %d - *risky*\n",cmd->opcode); } #else cmd->error = MMC_ERR_BADCRC; @@ -317,12 +311,12 @@ static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs) ireg = readl(host->base + MMC_I_REG); - DBG("PXAMCI: irq %08x\n", ireg); + pr_debug("PXAMCI: irq %08x\n", ireg); if (ireg) { unsigned stat = readl(host->base + MMC_STAT); - DBG("PXAMCI: stat %08x\n", stat); + pr_debug("PXAMCI: stat %08x\n", stat); if (ireg & END_CMD_RES) handled |= pxamci_cmd_done(host, stat); @@ -376,9 +370,9 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct pxamci_host *host = mmc_priv(mmc); - DBG("pxamci_set_ios: clock %u power %u vdd %u.%02u\n", - ios->clock, ios->power_mode, ios->vdd / 100, - ios->vdd % 100); + pr_debug("pxamci_set_ios: clock %u power %u vdd %u.%02u\n", + ios->clock, ios->power_mode, ios->vdd / 100, + ios->vdd % 100); if (ios->clock) { unsigned int clk = CLOCKRATE / ios->clock; @@ -405,8 +399,8 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->cmdat |= CMDAT_INIT; } - DBG("pxamci_set_ios: clkrt = %x cmdat = %x\n", - host->clkrt, host->cmdat); + pr_debug("pxamci_set_ios: clkrt = %x cmdat = %x\n", + host->clkrt, host->cmdat); } static struct mmc_host_ops pxamci_ops = { diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 8b811d94371c..bdbfca050029 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -31,12 +31,8 @@ #define BUGMAIL "" -#ifdef CONFIG_MMC_DEBUG #define DBG(f, x...) \ - printk(KERN_DEBUG DRIVER_NAME " [%s()]: " f, __func__,## x) -#else -#define DBG(f, x...) do { } while (0) -#endif + pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x) static const struct pci_device_id pci_ids[] __devinitdata = { /* handle any SD host controller */ diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 3be397d436fa..511f7b0b31d2 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -44,15 +44,10 @@ #define DRIVER_NAME "wbsd" #define DRIVER_VERSION "1.5" -#ifdef CONFIG_MMC_DEBUG #define DBG(x...) \ - printk(KERN_DEBUG DRIVER_NAME ": " x) + pr_debug(DRIVER_NAME ": " x) #define DBGF(f, x...) \ - printk(KERN_DEBUG DRIVER_NAME " [%s()]: " f, __func__ , ##x) -#else -#define DBG(x...) do { } while (0) -#define DBGF(x...) do { } while (0) -#endif + pr_debug(DRIVER_NAME " [%s()]: " f, __func__ , ##x) /* * Device resources diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index 0f6bb2e625d8..a7ec5954caf5 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -200,27 +200,6 @@ config MTD_CFI_AMDSTD provides support for one of those command sets, used on chips including the AMD Am29LV320. -config MTD_CFI_AMDSTD_RETRY - int "Retry failed commands (erase/program)" - depends on MTD_CFI_AMDSTD - default "0" - help - Some chips, when attached to a shared bus, don't properly filter - bus traffic that is destined to other devices. This broken - behavior causes erase and program sequences to be aborted when - the sequences are mixed with traffic for other devices. - - SST49LF040 (and related) chips are know to be broken. - -config MTD_CFI_AMDSTD_RETRY_MAX - int "Max retries of failed commands (erase/program)" - depends on MTD_CFI_AMDSTD_RETRY - default "0" - help - If you have an SST49LF040 (or related chip) then this value should - be set to at least 1. This can also be adjusted at driver load - time with the retry_cmd_max module parameter. - config MTD_CFI_STAA tristate "Support for ST (Advanced Architecture) flash chips" depends on MTD_GEN_PROBE diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c index fdb91b6f1d97..57115618c496 100644 --- a/drivers/mtd/chips/amd_flash.c +++ b/drivers/mtd/chips/amd_flash.c @@ -664,7 +664,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) printk("%s: Probing for AMD compatible flash...\n", map->name); if ((table_pos[0] = probe_new_chip(mtd, 0, NULL, &temp, table, - sizeof(table)/sizeof(table[0]))) + ARRAY_SIZE(table))) == -1) { printk(KERN_WARNING "%s: Found no AMD compatible device at location zero\n", @@ -696,7 +696,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) base += (1 << temp.chipshift)) { int numchips = temp.numchips; table_pos[numchips] = probe_new_chip(mtd, base, chips, - &temp, table, sizeof(table)/sizeof(table[0])); + &temp, table, ARRAY_SIZE(table)); } mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index edb306c03c0a..517ea33e7260 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -34,6 +34,7 @@ #define MANUFACTURER_MACRONIX 0x00C2 #define MANUFACTURER_NEC 0x0010 #define MANUFACTURER_PMC 0x009D +#define MANUFACTURER_SHARP 0x00b0 #define MANUFACTURER_SST 0x00BF #define MANUFACTURER_ST 0x0020 #define MANUFACTURER_TOSHIBA 0x0098 @@ -124,6 +125,9 @@ #define PM49FL004 0x006E #define PM49FL008 0x006A +/* Sharp */ +#define LH28F640BF 0x00b0 + /* ST - www.st.com */ #define M29W800DT 0x00D7 #define M29W800DB 0x005B @@ -1267,6 +1271,19 @@ static const struct amd_flash_info jedec_table[] = { .regions = { ERASEINFO( 0x01000, 256 ) } + }, { + .mfr_id = MANUFACTURER_SHARP, + .dev_id = LH28F640BF, + .name = "LH28F640BF", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x40000,16), + } }, { .mfr_id = MANUFACTURER_SST, .dev_id = SST39LF512, @@ -2035,7 +2052,7 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, DEBUG(MTD_DEBUG_LEVEL3, "Search for id:(%02x %02x) interleave(%d) type(%d)\n", cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); - for (i=0; i\n"); diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 6b8bb2e4dcfd..a7a7bfe33879 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -42,7 +42,8 @@ /* special size referring to all the remaining space in a partition */ -#define SIZE_REMAINING 0xffffffff +#define SIZE_REMAINING UINT_MAX +#define OFFSET_CONTINUOUS UINT_MAX struct cmdline_mtd_partition { struct cmdline_mtd_partition *next; @@ -75,7 +76,7 @@ static struct mtd_partition * newpart(char *s, { struct mtd_partition *parts; unsigned long size; - unsigned long offset = 0; + unsigned long offset = OFFSET_CONTINUOUS; char *name; int name_len; unsigned char *extra_mem; @@ -314,7 +315,7 @@ static int parse_cmdline_partitions(struct mtd_info *master, { for(i = 0, offset = 0; i < part->num_parts; i++) { - if (!part->parts[i].offset) + if (part->parts[i].offset == OFFSET_CONTINUOUS) part->parts[i].offset = offset; else offset = part->parts[i].offset; diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index dd628cb51e31..7fac438b5c32 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -129,8 +129,8 @@ config MTDRAM_ABS_POS allocating space from Linux's available memory. Otherwise, leave this set to zero. Most people will want to leave this as zero. -config MTD_BLKMTD - tristate "MTD emulation using block device" +config MTD_BLOCK2MTD + tristate "MTD using block device" depends on MTD help This driver allows a block device to appear as an MTD. It would @@ -141,15 +141,6 @@ config MTD_BLKMTD Testing MTD users (eg JFFS2) on large media and media that might be removed during a write (using the floppy drive). -config MTD_BLOCK2MTD - tristate "MTD using block device (rewrite)" - depends on MTD && EXPERIMENTAL - help - This driver is basically the same at MTD_BLKMTD above, but - experienced some interface changes plus serious speedups. In - the long term, it should replace MTD_BLKMTD. Right now, you - shouldn't entrust important data to it yet. - comment "Disk-On-Chip Device Drivers" config MTD_DOC2000 diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 7c5ed2178380..b6573670316f 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_MTD_PMC551) += pmc551.o obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o obj-$(CONFIG_MTD_MTDRAM) += mtdram.o obj-$(CONFIG_MTD_LART) += lart.o -obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c deleted file mode 100644 index 04f864d238db..000000000000 --- a/drivers/mtd/devices/blkmtd.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * $Id: blkmtd.c,v 1.27 2005/11/07 11:14:24 gleixner Exp $ - * - * blkmtd.c - use a block device as a fake MTD - * - * Author: Simon Evans - * - * Copyright (C) 2001,2002 Simon Evans - * - * Licence: GPL - * - * How it works: - * The driver uses raw/io to read/write the device and the page - * cache to cache access. Writes update the page cache with the - * new data and mark it dirty and add the page into a BIO which - * is then written out. - * - * It can be loaded Read-Only to prevent erases and writes to the - * medium. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg) -#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg) -#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg) - - -/* Default erase size in K, always make it a multiple of PAGE_SIZE */ -#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */ -#define VERSION "$Revision: 1.27 $" - -/* Info for the block device */ -struct blkmtd_dev { - struct list_head list; - struct block_device *blkdev; - struct mtd_info mtd_info; - struct semaphore wrbuf_mutex; -}; - - -/* Static info about the MTD, used in cleanup_module */ -static LIST_HEAD(blkmtd_device_list); - - -static void blkmtd_sync(struct mtd_info *mtd); - -#define MAX_DEVICES 4 - -/* Module parameters passed by insmod/modprobe */ -static char *device[MAX_DEVICES]; /* the block device to use */ -static int erasesz[MAX_DEVICES]; /* optional default erase size */ -static int ro[MAX_DEVICES]; /* optional read only flag */ -static int sync; - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Simon Evans "); -MODULE_DESCRIPTION("Emulate an MTD using a block device"); -module_param_array(device, charp, NULL, 0); -MODULE_PARM_DESC(device, "block device to use"); -module_param_array(erasesz, int, NULL, 0); -MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB."); -module_param_array(ro, bool, NULL, 0); -MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors"); -module_param(sync, bool, 0); -MODULE_PARM_DESC(sync, "1=Synchronous writes"); - - -/* completion handler for BIO reads */ -static int bi_read_complete(struct bio *bio, unsigned int bytes_done, int error) -{ - if (bio->bi_size) - return 1; - - complete((struct completion*)bio->bi_private); - return 0; -} - - -/* completion handler for BIO writes */ -static int bi_write_complete(struct bio *bio, unsigned int bytes_done, int error) -{ - const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); - struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - - if (bio->bi_size) - return 1; - - if(!uptodate) - err("bi_write_complete: not uptodate\n"); - - do { - struct page *page = bvec->bv_page; - DEBUG(3, "Cleaning up page %ld\n", page->index); - if (--bvec >= bio->bi_io_vec) - prefetchw(&bvec->bv_page->flags); - - if (uptodate) { - SetPageUptodate(page); - } else { - ClearPageUptodate(page); - SetPageError(page); - } - clear_page_dirty(page); - unlock_page(page); - page_cache_release(page); - } while (bvec >= bio->bi_io_vec); - - complete((struct completion*)bio->bi_private); - return 0; -} - - -/* read one page from the block device */ -static int blkmtd_readpage(struct blkmtd_dev *dev, struct page *page) -{ - struct bio *bio; - struct completion event; - int err = -ENOMEM; - - if(PageUptodate(page)) { - DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index); - unlock_page(page); - return 0; - } - - ClearPageUptodate(page); - ClearPageError(page); - - bio = bio_alloc(GFP_KERNEL, 1); - if(bio) { - init_completion(&event); - bio->bi_bdev = dev->blkdev; - bio->bi_sector = page->index << (PAGE_SHIFT-9); - bio->bi_private = &event; - bio->bi_end_io = bi_read_complete; - if(bio_add_page(bio, page, PAGE_SIZE, 0) == PAGE_SIZE) { - submit_bio(READ_SYNC, bio); - wait_for_completion(&event); - err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO; - bio_put(bio); - } - } - - if(err) - SetPageError(page); - else - SetPageUptodate(page); - flush_dcache_page(page); - unlock_page(page); - return err; -} - - -/* write out the current BIO and wait for it to finish */ -static int blkmtd_write_out(struct bio *bio) -{ - struct completion event; - int err; - - if(!bio->bi_vcnt) { - bio_put(bio); - return 0; - } - - init_completion(&event); - bio->bi_private = &event; - bio->bi_end_io = bi_write_complete; - submit_bio(WRITE_SYNC, bio); - wait_for_completion(&event); - DEBUG(3, "submit_bio completed, bi_vcnt = %d\n", bio->bi_vcnt); - err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO; - bio_put(bio); - return err; -} - - -/** - * blkmtd_add_page - add a page to the current BIO - * @bio: bio to add to (NULL to alloc initial bio) - * @blkdev: block device - * @page: page to add - * @pagecnt: pages left to add - * - * Adds a page to the current bio, allocating it if necessary. If it cannot be - * added, the current bio is written out and a new one is allocated. Returns - * the new bio to add or NULL on error - */ -static struct bio *blkmtd_add_page(struct bio *bio, struct block_device *blkdev, - struct page *page, int pagecnt) -{ - - retry: - if(!bio) { - bio = bio_alloc(GFP_KERNEL, pagecnt); - if(!bio) - return NULL; - bio->bi_sector = page->index << (PAGE_SHIFT-9); - bio->bi_bdev = blkdev; - } - - if(bio_add_page(bio, page, PAGE_SIZE, 0) != PAGE_SIZE) { - blkmtd_write_out(bio); - bio = NULL; - goto retry; - } - return bio; -} - - -/** - * write_pages - write block of data to device via the page cache - * @dev: device to write to - * @buf: data source or NULL if erase (output is set to 0xff) - * @to: offset into output device - * @len: amount to data to write - * @retlen: amount of data written - * - * Grab pages from the page cache and fill them with the source data. - * Non page aligned start and end result in a readin of the page and - * part of the page being modified. Pages are added to the bio and then written - * out. - */ -static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to, - size_t len, size_t *retlen) -{ - int pagenr, offset; - size_t start_len = 0, end_len; - int pagecnt = 0; - int err = 0; - struct bio *bio = NULL; - size_t thislen = 0; - - pagenr = to >> PAGE_SHIFT; - offset = to & ~PAGE_MASK; - - DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %zd pagenr = %d offset = %d\n", - buf, (long)to, len, pagenr, offset); - - /* see if we have to do a partial write at the start */ - if(offset) { - start_len = ((offset + len) > PAGE_SIZE) ? PAGE_SIZE - offset : len; - len -= start_len; - } - - /* calculate the length of the other two regions */ - end_len = len & ~PAGE_MASK; - len -= end_len; - - if(start_len) - pagecnt++; - - if(len) - pagecnt += len >> PAGE_SHIFT; - - if(end_len) - pagecnt++; - - down(&dev->wrbuf_mutex); - - DEBUG(3, "blkmtd: write: start_len = %zd len = %zd end_len = %zd pagecnt = %d\n", - start_len, len, end_len, pagecnt); - - if(start_len) { - /* do partial start region */ - struct page *page; - - DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %zd offset = %d\n", - pagenr, start_len, offset); - - BUG_ON(!buf); - page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev); - lock_page(page); - if(PageDirty(page)) { - err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d\n", - to, start_len, len, end_len, pagenr); - BUG(); - } - memcpy(page_address(page)+offset, buf, start_len); - set_page_dirty(page); - SetPageUptodate(page); - buf += start_len; - thislen = start_len; - bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt); - if(!bio) { - err = -ENOMEM; - err("bio_add_page failed\n"); - goto write_err; - } - pagecnt--; - pagenr++; - } - - /* Now do the main loop to a page aligned, n page sized output */ - if(len) { - int pagesc = len >> PAGE_SHIFT; - DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n", - pagenr, pagesc); - while(pagesc) { - struct page *page; - - /* see if page is in the page cache */ - DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr); - page = grab_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr); - if(PageDirty(page)) { - BUG(); - } - if(!page) { - warn("write: cannot grab cache page %d", pagenr); - err = -ENOMEM; - goto write_err; - } - if(!buf) { - memset(page_address(page), 0xff, PAGE_SIZE); - } else { - memcpy(page_address(page), buf, PAGE_SIZE); - buf += PAGE_SIZE; - } - bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt); - if(!bio) { - err = -ENOMEM; - err("bio_add_page failed\n"); - goto write_err; - } - pagenr++; - pagecnt--; - set_page_dirty(page); - SetPageUptodate(page); - pagesc--; - thislen += PAGE_SIZE; - } - } - - if(end_len) { - /* do the third region */ - struct page *page; - DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %zd\n", - pagenr, end_len); - BUG_ON(!buf); - page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev); - lock_page(page); - if(PageDirty(page)) { - err("to = %lld start_len = %zd len = %zd end_len = %zd pagenr = %d\n", - to, start_len, len, end_len, pagenr); - BUG(); - } - memcpy(page_address(page), buf, end_len); - set_page_dirty(page); - SetPageUptodate(page); - DEBUG(3, "blkmtd: write: writing out partial end\n"); - thislen += end_len; - bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt); - if(!bio) { - err = -ENOMEM; - err("bio_add_page failed\n"); - goto write_err; - } - pagenr++; - } - - DEBUG(3, "blkmtd: write: got %d vectors to write\n", bio->bi_vcnt); - write_err: - if(bio) - blkmtd_write_out(bio); - - DEBUG(2, "blkmtd: write: end, retlen = %zd, err = %d\n", *retlen, err); - up(&dev->wrbuf_mutex); - - if(retlen) - *retlen = thislen; - return err; -} - - -/* erase a specified part of the device */ -static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr) -{ - struct blkmtd_dev *dev = mtd->priv; - struct mtd_erase_region_info *einfo = mtd->eraseregions; - int numregions = mtd->numeraseregions; - size_t from; - u_long len; - int err = -EIO; - size_t retlen; - - instr->state = MTD_ERASING; - from = instr->addr; - len = instr->len; - - /* check erase region has valid start and length */ - DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%zx len = 0x%lx\n", - mtd->name+9, from, len); - while(numregions) { - DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n", - einfo->offset, einfo->erasesize, einfo->numblocks); - if(from >= einfo->offset - && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) { - if(len == einfo->erasesize - && ( (from - einfo->offset) % einfo->erasesize == 0)) - break; - } - numregions--; - einfo++; - } - - if(!numregions) { - /* Not a valid erase block */ - err("erase: invalid erase request 0x%lX @ 0x%08zX", len, from); - instr->state = MTD_ERASE_FAILED; - err = -EIO; - } - - if(instr->state != MTD_ERASE_FAILED) { - /* do the erase */ - DEBUG(3, "Doing erase from = %zd len = %ld\n", from, len); - err = write_pages(dev, NULL, from, len, &retlen); - if(err || retlen != len) { - err("erase failed err = %d", err); - instr->state = MTD_ERASE_FAILED; - } else { - instr->state = MTD_ERASE_DONE; - } - } - - DEBUG(3, "blkmtd: erase: checking callback\n"); - mtd_erase_callback(instr); - DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err); - return err; -} - - -/* read a range of the data via the page cache */ -static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) -{ - struct blkmtd_dev *dev = mtd->priv; - int err = 0; - int offset; - int pagenr, pages; - size_t thislen = 0; - - DEBUG(2, "blkmtd: read: dev = `%s' from = %lld len = %zd buf = %p\n", - mtd->name+9, from, len, buf); - - if(from > mtd->size) - return -EINVAL; - if(from + len > mtd->size) - len = mtd->size - from; - - pagenr = from >> PAGE_SHIFT; - offset = from - (pagenr << PAGE_SHIFT); - - pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT; - DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n", - pagenr, offset, pages); - - while(pages) { - struct page *page; - int cpylen; - - DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr); - page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev); - if(IS_ERR(page)) { - err = -EIO; - goto readerr; - } - - cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE; - if(offset+cpylen > PAGE_SIZE) - cpylen = PAGE_SIZE-offset; - - memcpy(buf + thislen, page_address(page) + offset, cpylen); - offset = 0; - len -= cpylen; - thislen += cpylen; - pagenr++; - pages--; - if(!PageDirty(page)) - page_cache_release(page); - } - - readerr: - if(retlen) - *retlen = thislen; - DEBUG(2, "blkmtd: end read: retlen = %zd, err = %d\n", thislen, err); - return err; -} - - -/* write data to the underlying device */ -static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - struct blkmtd_dev *dev = mtd->priv; - int err; - - if(!len) - return 0; - - DEBUG(2, "blkmtd: write: dev = `%s' to = %lld len = %zd buf = %p\n", - mtd->name+9, to, len, buf); - - if(to >= mtd->size) { - return -ENOSPC; - } - - if(to + len > mtd->size) { - len = mtd->size - to; - } - - err = write_pages(dev, buf, to, len, retlen); - if(err > 0) - err = 0; - DEBUG(2, "blkmtd: write: end, err = %d\n", err); - return err; -} - - -/* sync the device - wait until the write queue is empty */ -static void blkmtd_sync(struct mtd_info *mtd) -{ - /* Currently all writes are synchronous */ -} - - -static void free_device(struct blkmtd_dev *dev) -{ - DEBUG(2, "blkmtd: free_device() dev = %p\n", dev); - if(dev) { - kfree(dev->mtd_info.eraseregions); - kfree(dev->mtd_info.name); - if(dev->blkdev) { - invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping); - close_bdev_excl(dev->blkdev); - } - kfree(dev); - } -} - - -/* For a given size and initial erase size, calculate the number - * and size of each erase region. Goes round the loop twice, - * once to find out how many regions, then allocates space, - * then round the loop again to fill it in. - */ -static struct mtd_erase_region_info *calc_erase_regions( - size_t erase_size, size_t total_size, int *regions) -{ - struct mtd_erase_region_info *info = NULL; - - DEBUG(2, "calc_erase_regions, es = %zd size = %zd regions = %d\n", - erase_size, total_size, *regions); - /* Make any user specified erasesize be a power of 2 - and at least PAGE_SIZE */ - if(erase_size) { - int es = erase_size; - erase_size = 1; - while(es != 1) { - es >>= 1; - erase_size <<= 1; - } - if(erase_size < PAGE_SIZE) - erase_size = PAGE_SIZE; - } else { - erase_size = CONFIG_MTD_BLKDEV_ERASESIZE; - } - - *regions = 0; - - do { - int tot_size = total_size; - int er_size = erase_size; - int count = 0, offset = 0, regcnt = 0; - - while(tot_size) { - count = tot_size / er_size; - if(count) { - tot_size = tot_size % er_size; - if(info) { - DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n", - offset, er_size, count); - (info+regcnt)->offset = offset; - (info+regcnt)->erasesize = er_size; - (info+regcnt)->numblocks = count; - (*regions)++; - } - regcnt++; - offset += (count * er_size); - } - while(er_size > tot_size) - er_size >>= 1; - } - if(info == NULL) { - info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL); - if(!info) - break; - } - } while(!(*regions)); - DEBUG(2, "calc_erase_regions done, es = %zd size = %zd regions = %d\n", - erase_size, total_size, *regions); - return info; -} - - -extern dev_t __init name_to_dev_t(const char *line); - -static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size) -{ - struct block_device *bdev; - int mode; - struct blkmtd_dev *dev; - - if(!devname) - return NULL; - - /* Get a handle on the device */ - - -#ifdef MODULE - mode = (readonly) ? O_RDONLY : O_RDWR; - bdev = open_bdev_excl(devname, mode, NULL); -#else - mode = (readonly) ? FMODE_READ : FMODE_WRITE; - bdev = open_by_devnum(name_to_dev_t(devname), mode); -#endif - if(IS_ERR(bdev)) { - err("error: cannot open device %s", devname); - DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev)); - return NULL; - } - - DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", - MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev)); - - if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { - err("attempting to use an MTD device as a block device"); - blkdev_put(bdev); - return NULL; - } - - dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL); - if(dev == NULL) { - blkdev_put(bdev); - return NULL; - } - - memset(dev, 0, sizeof(struct blkmtd_dev)); - dev->blkdev = bdev; - if(!readonly) { - init_MUTEX(&dev->wrbuf_mutex); - } - - dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; - - /* Setup the MTD structure */ - /* make the name contain the block device in */ - dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL); - if(dev->mtd_info.name == NULL) - goto devinit_err; - - sprintf(dev->mtd_info.name, "blkmtd: %s", devname); - dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size, - &dev->mtd_info.numeraseregions); - if(dev->mtd_info.eraseregions == NULL) - goto devinit_err; - - dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize; - DEBUG(1, "blkmtd: init: found %d erase regions\n", - dev->mtd_info.numeraseregions); - - if(readonly) { - dev->mtd_info.type = MTD_ROM; - dev->mtd_info.flags = MTD_CAP_ROM; - } else { - dev->mtd_info.type = MTD_RAM; - dev->mtd_info.flags = MTD_CAP_RAM; - dev->mtd_info.erase = blkmtd_erase; - dev->mtd_info.write = blkmtd_write; - dev->mtd_info.writev = default_mtd_writev; - dev->mtd_info.sync = blkmtd_sync; - } - dev->mtd_info.read = blkmtd_read; - dev->mtd_info.readv = default_mtd_readv; - dev->mtd_info.priv = dev; - dev->mtd_info.owner = THIS_MODULE; - - list_add(&dev->list, &blkmtd_device_list); - if (add_mtd_device(&dev->mtd_info)) { - /* Device didnt get added, so free the entry */ - list_del(&dev->list); - goto devinit_err; - } else { - info("mtd%d: [%s] erase_size = %dKiB %s", - dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "), - dev->mtd_info.erasesize >> 10, - readonly ? "(read-only)" : ""); - } - - return dev; - - devinit_err: - free_device(dev); - return NULL; -} - - -/* Cleanup and exit - sync the device and kill of the kernel thread */ -static void __devexit cleanup_blkmtd(void) -{ - struct list_head *temp1, *temp2; - - /* Remove the MTD devices */ - list_for_each_safe(temp1, temp2, &blkmtd_device_list) { - struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev, - list); - blkmtd_sync(&dev->mtd_info); - del_mtd_device(&dev->mtd_info); - info("mtd%d: [%s] removed", dev->mtd_info.index, - dev->mtd_info.name + strlen("blkmtd: ")); - list_del(&dev->list); - free_device(dev); - } -} - -#ifndef MODULE - -/* Handle kernel boot params */ - - -static int __init param_blkmtd_device(char *str) -{ - int i; - - for(i = 0; i < MAX_DEVICES; i++) { - device[i] = str; - DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]); - strsep(&str, ","); - } - return 1; -} - - -static int __init param_blkmtd_erasesz(char *str) -{ - int i; - for(i = 0; i < MAX_DEVICES; i++) { - char *val = strsep(&str, ","); - if(val) - erasesz[i] = simple_strtoul(val, NULL, 0); - DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]); - } - - return 1; -} - - -static int __init param_blkmtd_ro(char *str) -{ - int i; - for(i = 0; i < MAX_DEVICES; i++) { - char *val = strsep(&str, ","); - if(val) - ro[i] = simple_strtoul(val, NULL, 0); - DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]); - } - - return 1; -} - - -static int __init param_blkmtd_sync(char *str) -{ - if(str[0] == '1') - sync = 1; - return 1; -} - -__setup("blkmtd_device=", param_blkmtd_device); -__setup("blkmtd_erasesz=", param_blkmtd_erasesz); -__setup("blkmtd_ro=", param_blkmtd_ro); -__setup("blkmtd_sync=", param_blkmtd_sync); - -#endif - - -/* Startup */ -static int __init init_blkmtd(void) -{ - int i; - - info("version " VERSION); - /* Check args - device[0] is the bare minimum*/ - if(!device[0]) { - err("error: missing `device' name\n"); - return -EINVAL; - } - - for(i = 0; i < MAX_DEVICES; i++) - add_device(device[i], ro[i], erasesz[i] << 10); - - if(list_empty(&blkmtd_device_list)) - return -EINVAL; - - return 0; -} - -module_init(init_blkmtd); -module_exit(cleanup_blkmtd); diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 7ff403b2a0a0..4160b8334c53 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -18,6 +18,7 @@ #include #include #include +#include #define VERSION "$Revision: 1.30 $" @@ -31,7 +32,7 @@ struct block2mtd_dev { struct list_head list; struct block_device *blkdev; struct mtd_info mtd; - struct semaphore write_mutex; + struct mutex write_mutex; }; @@ -134,9 +135,9 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr) int err; instr->state = MTD_ERASING; - down(&dev->write_mutex); + mutex_lock(&dev->write_mutex); err = _block2mtd_erase(dev, from, len); - up(&dev->write_mutex); + mutex_unlock(&dev->write_mutex); if (err) { ERROR("erase failed err = %d", err); instr->state = MTD_ERASE_FAILED; @@ -249,9 +250,9 @@ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len, if (to + len > mtd->size) len = mtd->size - to; - down(&dev->write_mutex); + mutex_lock(&dev->write_mutex); err = _block2mtd_write(dev, buf, to, len, retlen); - up(&dev->write_mutex); + mutex_unlock(&dev->write_mutex); if (err > 0) err = 0; return err; @@ -310,7 +311,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) goto devinit_err; } - init_MUTEX(&dev->write_mutex); + mutex_init(&dev->write_mutex); /* Setup the MTD structure */ /* make the name contain the block device in */ diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index e4345cf744a2..23e7a5c7d2c1 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -605,7 +606,7 @@ static void DoC2k_init(struct mtd_info *mtd) this->curfloor = -1; this->curchip = -1; - init_MUTEX(&this->lock); + mutex_init(&this->lock); /* Ident all the chips present. */ DoC_ScanChips(this, maxchips); @@ -645,7 +646,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, if (from >= this->totlen) return -EINVAL; - down(&this->lock); + mutex_lock(&this->lock); *retlen = 0; while (left) { @@ -774,7 +775,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, buf += len; } - up(&this->lock); + mutex_unlock(&this->lock); return ret; } @@ -803,7 +804,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, if (to >= this->totlen) return -EINVAL; - down(&this->lock); + mutex_lock(&this->lock); *retlen = 0; while (left) { @@ -873,7 +874,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, printk(KERN_ERR "Error programming flash\n"); /* Error in programming */ *retlen = 0; - up(&this->lock); + mutex_unlock(&this->lock); return -EIO; } @@ -935,7 +936,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, printk(KERN_ERR "Error programming flash\n"); /* Error in programming */ *retlen = 0; - up(&this->lock); + mutex_unlock(&this->lock); return -EIO; } @@ -956,7 +957,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); if (ret) { - up(&this->lock); + mutex_unlock(&this->lock); return ret; } } @@ -966,7 +967,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, buf += len; } - up(&this->lock); + mutex_unlock(&this->lock); return 0; } @@ -975,13 +976,13 @@ static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, u_char *eccbuf, struct nand_oobinfo *oobsel) { static char static_buf[512]; - static DECLARE_MUTEX(writev_buf_sem); + static DEFINE_MUTEX(writev_buf_mutex); size_t totretlen = 0; size_t thisvecofs = 0; int ret= 0; - down(&writev_buf_sem); + mutex_lock(&writev_buf_mutex); while(count) { size_t thislen, thisretlen; @@ -1024,7 +1025,7 @@ static int doc_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs, to += thislen; } - up(&writev_buf_sem); + mutex_unlock(&writev_buf_mutex); *retlen = totretlen; return ret; } @@ -1037,7 +1038,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, int len256 = 0, ret; struct Nand *mychip; - down(&this->lock); + mutex_lock(&this->lock); mychip = &this->chips[ofs >> this->chipshift]; @@ -1083,7 +1084,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, ret = DoC_WaitReady(this); - up(&this->lock); + mutex_unlock(&this->lock); return ret; } @@ -1197,10 +1198,10 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, struct DiskOnChip *this = mtd->priv; int ret; - down(&this->lock); + mutex_lock(&this->lock); ret = doc_write_oob_nolock(mtd, ofs, len, retlen, buf); - up(&this->lock); + mutex_unlock(&this->lock); return ret; } @@ -1214,10 +1215,10 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr) struct Nand *mychip; int status; - down(&this->lock); + mutex_lock(&this->lock); if (ofs & (mtd->erasesize-1) || len & (mtd->erasesize-1)) { - up(&this->lock); + mutex_unlock(&this->lock); return -EINVAL; } @@ -1265,7 +1266,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr) callback: mtd_erase_callback(instr); - up(&this->lock); + mutex_unlock(&this->lock); return 0; } diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 1e876fcb0408..29b0ddaa324e 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -581,8 +581,6 @@ static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen /***************************************************************************************************/ -#define NB_OF(x) (sizeof (x) / sizeof (x[0])) - static struct mtd_info mtd; static struct mtd_erase_region_info erase_regions[] = { @@ -640,7 +638,7 @@ int __init lart_flash_init (void) mtd.flags = MTD_CAP_NORFLASH; mtd.size = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM + FLASH_BLOCKSIZE_MAIN * FLASH_NUMBLOCKS_16m_MAIN; mtd.erasesize = FLASH_BLOCKSIZE_MAIN; - mtd.numeraseregions = NB_OF (erase_regions); + mtd.numeraseregions = ARRAY_SIZE(erase_regions); mtd.eraseregions = erase_regions; mtd.erase = flash_erase; mtd.read = flash_read; @@ -670,9 +668,9 @@ int __init lart_flash_init (void) result,mtd.eraseregions[result].numblocks); #ifdef HAVE_PARTITIONS - printk ("\npartitions = %d\n",NB_OF (lart_partitions)); + printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions)); - for (result = 0; result < NB_OF (lart_partitions); result++) + for (result = 0; result < ARRAY_SIZE(lart_partitions); result++) printk (KERN_DEBUG "\n\n" "lart_partitions[%d].name = %s\n" @@ -687,7 +685,7 @@ int __init lart_flash_init (void) #ifndef HAVE_PARTITIONS result = add_mtd_device (&mtd); #else - result = add_mtd_partitions (&mtd,lart_partitions,NB_OF (lart_partitions)); + result = add_mtd_partitions (&mtd,lart_partitions, ARRAY_SIZE(lart_partitions)); #endif return (result); diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index d5f24089be71..04e65d5dae00 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -186,7 +186,7 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) struct m25p *flash = mtd_to_m25p(mtd); u32 addr,len; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", + DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", flash->spi->dev.bus_id, __FUNCTION__, "at", (u32)instr->addr, instr->len); diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 0ff2e4378244..485f663493d2 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c @@ -308,7 +308,7 @@ static int __init ms02nv_init(void) break; } - for (i = 0; i < (sizeof(ms02nv_addrs) / sizeof(*ms02nv_addrs)); i++) + for (i = 0; i < ARRAY_SIZE(ms02nv_addrs); i++) if (!ms02nv_init_one(ms02nv_addrs[i] << stride)) count++; diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 8a544890173d..a3b92479719d 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -47,9 +47,6 @@ */ #define MAX_LOOPS 10000 -extern void INFTL_dumptables(struct INFTLrecord *inftl); -extern void INFTL_dumpVUchains(struct INFTLrecord *inftl); - static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { struct INFTLrecord *inftl; @@ -132,7 +129,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } #ifdef PSYCHO_DEBUG - printk(KERN_INFO "INFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a'); + printk(KERN_INFO "INFTL: Found new inftl%c\n", inftl->mbd.devnum + 'a'); #endif return; } @@ -885,8 +882,6 @@ static struct mtd_blktrans_ops inftl_tr = { .owner = THIS_MODULE, }; -extern char inftlmountrev[]; - static int __init init_inftl(void) { printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, " diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c index a57791a6ce40..b933a2a27b18 100644 --- a/drivers/mtd/maps/alchemy-flash.c +++ b/drivers/mtd/maps/alchemy-flash.c @@ -126,8 +126,6 @@ static struct mtd_partition alchemy_partitions[] = { } }; -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - static struct mtd_info *mymtd; int __init alchemy_mtd_init(void) @@ -154,7 +152,7 @@ int __init alchemy_mtd_init(void) * Static partition definition selection */ parts = alchemy_partitions; - nb_parts = NB_OF(alchemy_partitions); + nb_parts = ARRAY_SIZE(alchemy_partitions); alchemy_map.size = window_size; /* diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index 6a8c0415bde8..fd0f0d3187de 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -86,7 +86,7 @@ struct mtd_partition flagadm_parts[] = { } }; -#define PARTITION_COUNT (sizeof(flagadm_parts)/sizeof(struct mtd_partition)) +#define PARTITION_COUNT ARRAY_SIZE(flagadm_parts) static struct mtd_info *mymtd; diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c index 49d90542fc75..652813cd6c2d 100644 --- a/drivers/mtd/maps/dbox2-flash.c +++ b/drivers/mtd/maps/dbox2-flash.c @@ -57,7 +57,7 @@ static struct mtd_partition partition_info[]= { } }; -#define NUM_PARTITIONS (sizeof(partition_info) / sizeof(partition_info[0])) +#define NUM_PARTITIONS ARRAY_SIZE(partition_info) #define WINDOW_ADDR 0x10000000 #define WINDOW_SIZE 0x800000 diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index efb221692641..c299d10b33e6 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c @@ -300,7 +300,7 @@ static struct mtd_partition partition_info[]= }, }; -#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) +#define NUM_PARTITIONS ARRAY_SIZE(partition_info) static struct mtd_info *mymtd; static struct mtd_info *lowlvl_parts[NUM_PARTITIONS]; @@ -345,7 +345,7 @@ static struct mtd_partition higlvl_partition_info[]= }, }; -#define NUM_HIGHLVL_PARTITIONS (sizeof(higlvl_partition_info)/sizeof(partition_info[0])) +#define NUM_HIGHLVL_PARTITIONS ARRAY_SIZE(higlvl_partition_info) static int dnp_adnp_probe(void) diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c index b993ac01a9a5..2bb3c0f0f970 100644 --- a/drivers/mtd/maps/dmv182.c +++ b/drivers/mtd/maps/dmv182.c @@ -99,7 +99,7 @@ static struct mtd_info *this_mtd; static int __init init_svme182(void) { struct mtd_partition *partitions; - int num_parts = sizeof(svme182_partitions) / sizeof(struct mtd_partition); + int num_parts = ARRAY_SIZE(svme182_partitions); partitions = svme182_partitions; diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 319094821101..0667101ccbe1 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -59,7 +59,7 @@ static struct mtd_partition h720x_partitions[] = { } }; -#define NUM_PARTITIONS (sizeof(h720x_partitions)/sizeof(h720x_partitions[0])) +#define NUM_PARTITIONS ARRAY_SIZE(h720x_partitions) static int nr_mtd_parts; static struct mtd_partition *mtd_parts; diff --git a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c index 33060a315722..ed215470158b 100644 --- a/drivers/mtd/maps/netsc520.c +++ b/drivers/mtd/maps/netsc520.c @@ -76,7 +76,7 @@ static struct mtd_partition partition_info[]={ .size = 0x80000 }, }; -#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) +#define NUM_PARTITIONS ARRAY_SIZE(partition_info) #define WINDOW_SIZE 0x00100000 #define WINDOW_ADDR 0x00200000 @@ -88,7 +88,7 @@ static struct map_info netsc520_map = { .phys = WINDOW_ADDR, }; -#define NUM_FLASH_BANKS (sizeof(netsc520_map)/sizeof(struct map_info)) +#define NUM_FLASH_BANKS ARRAY_SIZE(netsc520_map) static struct mtd_info *mymtd; diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 632eb2aa968f..54a3102ab19a 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -128,8 +128,7 @@ static struct mtd_partition nettel_amd_partitions[] = { } }; -#define NUM_AMD_PARTITIONS \ - (sizeof(nettel_amd_partitions)/sizeof(nettel_amd_partitions[0])) +#define NUM_AMD_PARTITIONS ARRAY_SIZE(nettel_amd_partitions) /****************************************************************************/ diff --git a/drivers/mtd/maps/ocotea.c b/drivers/mtd/maps/ocotea.c index c223514ca2eb..a21fcd195ab4 100644 --- a/drivers/mtd/maps/ocotea.c +++ b/drivers/mtd/maps/ocotea.c @@ -58,8 +58,6 @@ static struct mtd_partition ocotea_large_partitions[] = { } }; -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - int __init init_ocotea(void) { u8 fpga0_reg; @@ -97,7 +95,7 @@ int __init init_ocotea(void) if (flash) { flash->owner = THIS_MODULE; add_mtd_partitions(flash, ocotea_small_partitions, - NB_OF(ocotea_small_partitions)); + ARRAY_SIZE(ocotea_small_partitions)); } else { printk("map probe failed for flash\n"); return -ENXIO; @@ -118,7 +116,7 @@ int __init init_ocotea(void) if (flash) { flash->owner = THIS_MODULE; add_mtd_partitions(flash, ocotea_large_partitions, - NB_OF(ocotea_large_partitions)); + ARRAY_SIZE(ocotea_large_partitions)); } else { printk("map probe failed for flash\n"); return -ENXIO; diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c index 21822c2edbe4..d2ab1bae9c34 100644 --- a/drivers/mtd/maps/pci.c +++ b/drivers/mtd/maps/pci.c @@ -334,9 +334,6 @@ mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return 0; release: - if (mtd) - map_destroy(mtd); - if (map) { map->exit(dev, map); kfree(map); diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index f988c817e196..d27f4129afd3 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -54,7 +54,7 @@ static const int debug = 0; #define MAX_PCMCIA_ADDR 0x4000000 struct pcmciamtd_dev { - dev_link_t link; /* PCMCIA link */ + struct pcmcia_device *p_dev; dev_node_t node; /* device node */ caddr_t win_base; /* ioremapped address of PCMCIA window */ unsigned int win_size; /* size of window */ @@ -111,8 +111,8 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) memreq_t mrq; int ret; - if(!(dev->link.state & DEV_PRESENT)) { - DEBUG(1, "device removed state = 0x%4.4X", dev->link.state); + if (!pcmcia_dev_present(dev->p_dev)) { + DEBUG(1, "device removed"); return 0; } @@ -122,7 +122,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) dev->offset, mrq.CardOffset); mrq.Page = 0; if( (ret = pcmcia_map_mem_page(win, &mrq)) != CS_SUCCESS) { - cs_error(dev->link.handle, MapMemPage, ret); + cs_error(dev->p_dev, MapMemPage, ret); return NULL; } dev->offset = mrq.CardOffset; @@ -238,7 +238,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v /* read/write{8,16} copy_{from,to} routines with direct access */ -#define DEV_REMOVED(x) (!(*(u_int *)x->map_priv_1 & DEV_PRESENT)) +#define DEV_REMOVED(x) (!(pcmcia_dev_present(((struct pcmciamtd_dev *)map->map_priv_1)->p_dev))) static map_word pcmcia_read8(struct map_info *map, unsigned long ofs) { @@ -319,7 +319,7 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f static void pcmciamtd_set_vpp(struct map_info *map, int on) { struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; - dev_link_t *link = &dev->link; + struct pcmcia_device *link = dev->p_dev; modconf_t mod; int ret; @@ -328,9 +328,9 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on) mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0; DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp); - ret = pcmcia_modify_configuration(link->handle, &mod); + ret = pcmcia_modify_configuration(link, &mod); if(ret != CS_SUCCESS) { - cs_error(link->handle, ModifyConfiguration, ret); + cs_error(link, ModifyConfiguration, ret); } } @@ -340,7 +340,7 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on) * still open, this will be postponed until it is closed. */ -static void pcmciamtd_release(dev_link_t *link) +static void pcmciamtd_release(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; @@ -353,12 +353,11 @@ static void pcmciamtd_release(dev_link_t *link) } pcmcia_release_window(link->win); } - pcmcia_release_configuration(link->handle); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } -static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_name) +static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *link, int *new_name) { int rc; tuple_t tuple; @@ -371,16 +370,16 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ tuple.TupleOffset = 0; tuple.DesiredTuple = RETURN_FIRST_TUPLE; - rc = pcmcia_get_first_tuple(link->handle, &tuple); + rc = pcmcia_get_first_tuple(link, &tuple); while(rc == CS_SUCCESS) { - rc = pcmcia_get_tuple_data(link->handle, &tuple); + rc = pcmcia_get_tuple_data(link, &tuple); if(rc != CS_SUCCESS) { - cs_error(link->handle, GetTupleData, rc); + cs_error(link, GetTupleData, rc); break; } - rc = pcmcia_parse_tuple(link->handle, &tuple, &parse); + rc = pcmcia_parse_tuple(link, &tuple, &parse); if(rc != CS_SUCCESS) { - cs_error(link->handle, ParseTuple, rc); + cs_error(link, ParseTuple, rc); break; } @@ -451,7 +450,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ DEBUG(2, "Unknown tuple code %d", tuple.TupleCode); } - rc = pcmcia_get_next_tuple(link->handle, &tuple); + rc = pcmcia_get_next_tuple(link, &tuple); } if(!dev->pcmcia_map.size) dev->pcmcia_map.size = MAX_PCMCIA_ADDR; @@ -488,7 +487,7 @@ static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_ #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void pcmciamtd_config(dev_link_t *link) +static int pcmciamtd_config(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; struct mtd_info *mtd = NULL; @@ -504,13 +503,10 @@ static void pcmciamtd_config(dev_link_t *link) DEBUG(3, "link=0x%p", link); - /* Configure card */ - link->state |= DEV_CONFIG; - DEBUG(2, "Validating CIS"); - ret = pcmcia_validate_cis(link->handle, &cisinfo); + ret = pcmcia_validate_cis(link, &cisinfo); if(ret != CS_SUCCESS) { - cs_error(link->handle, GetTupleData, ret); + cs_error(link, GetTupleData, ret); } else { DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains); } @@ -538,7 +534,7 @@ static void pcmciamtd_config(dev_link_t *link) req.Attributes |= (dev->pcmcia_map.bankwidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16; req.Base = 0; req.AccessSpeed = mem_speed; - link->win = (window_handle_t)link->handle; + link->win = (window_handle_t)link; req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR; dev->win_size = 0; @@ -546,7 +542,7 @@ static void pcmciamtd_config(dev_link_t *link) int ret; DEBUG(2, "requesting window with size = %dKiB memspeed = %d", req.Size >> 10, req.AccessSpeed); - ret = pcmcia_request_window(&link->handle, &req, &link->win); + ret = pcmcia_request_window(&link, &req, &link->win); DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size); if(ret) { req.Size >>= 1; @@ -562,19 +558,19 @@ static void pcmciamtd_config(dev_link_t *link) if(!dev->win_size) { err("Cant allocate memory window"); pcmciamtd_release(link); - return; + return -ENODEV; } DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); /* Get write protect status */ - CS_CHECK(GetStatus, pcmcia_get_status(link->handle, &status)); + CS_CHECK(GetStatus, pcmcia_get_status(link, &status)); DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", status.CardState, (unsigned long)link->win); dev->win_base = ioremap(req.Base, req.Size); if(!dev->win_base) { err("ioremap(%lu, %u) failed", req.Base, req.Size); pcmciamtd_release(link); - return; + return -ENODEV; } DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x", dev, req.Base, dev->win_base, req.Size); @@ -584,17 +580,14 @@ static void pcmciamtd_config(dev_link_t *link) dev->pcmcia_map.map_priv_2 = (unsigned long)link->win; DEBUG(2, "Getting configuration"); - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link->handle, &t)); + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &t)); DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2); dev->vpp = (vpp) ? vpp : t.Vpp1; link->conf.Attributes = 0; - link->conf.Vcc = t.Vcc; if(setvpp == 2) { - link->conf.Vpp1 = dev->vpp; - link->conf.Vpp2 = dev->vpp; + link->conf.Vpp = dev->vpp; } else { - link->conf.Vpp1 = 0; - link->conf.Vpp2 = 0; + link->conf.Vpp = 0; } link->conf.IntType = INT_MEMORY; @@ -606,9 +599,10 @@ static void pcmciamtd_config(dev_link_t *link) link->conf.ConfigIndex = 0; link->conf.Present = t.Present; DEBUG(2, "Setting Configuration"); - ret = pcmcia_request_configuration(link->handle, &link->conf); + ret = pcmcia_request_configuration(link, &link->conf); if(ret != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, ret); + cs_error(link, RequestConfiguration, ret); + return -ENODEV; } if(mem_type == 1) { @@ -616,7 +610,7 @@ static void pcmciamtd_config(dev_link_t *link) } else if(mem_type == 2) { mtd = do_map_probe("map_rom", &dev->pcmcia_map); } else { - for(i = 0; i < sizeof(probes) / sizeof(char *); i++) { + for(i = 0; i < ARRAY_SIZE(probes); i++) { DEBUG(1, "Trying %s", probes[i]); mtd = do_map_probe(probes[i], &dev->pcmcia_map); if(mtd) @@ -629,7 +623,7 @@ static void pcmciamtd_config(dev_link_t *link) if(!mtd) { DEBUG(1, "Cant find an MTD"); pcmciamtd_release(link); - return; + return -ENODEV; } dev->mtd_info = mtd; @@ -654,7 +648,6 @@ static void pcmciamtd_config(dev_link_t *link) use the faster non-remapping read/write functions */ if(mtd->size <= dev->win_size) { DEBUG(1, "Using non remapping memory functions"); - dev->pcmcia_map.map_priv_1 = (unsigned long)&(dev->link.state); dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base; if (dev->pcmcia_map.bankwidth == 1) { dev->pcmcia_map.read = pcmcia_read8; @@ -672,19 +665,18 @@ static void pcmciamtd_config(dev_link_t *link) dev->mtd_info = NULL; err("Couldnt register MTD device"); pcmciamtd_release(link); - return; + return -ENODEV; } snprintf(dev->node.dev_name, sizeof(dev->node.dev_name), "mtd%d", mtd->index); info("mtd%d: %s", mtd->index, mtd->name); - link->state &= ~DEV_CONFIG_PENDING; - link->dev = &dev->node; - return; + link->dev_node = &dev->node; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); err("CS Error, exiting"); pcmciamtd_release(link); - return; + return -ENODEV; } @@ -713,21 +705,18 @@ static int pcmciamtd_resume(struct pcmcia_device *dev) * when the device is released. */ -static void pcmciamtd_detach(struct pcmcia_device *p_dev) +static void pcmciamtd_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); + struct pcmciamtd_dev *dev = link->priv; DEBUG(3, "link=0x%p", link); - if(link->state & DEV_CONFIG) { - struct pcmciamtd_dev *dev = link->priv; - if(dev->mtd_info) { - del_mtd_device(dev->mtd_info); - info("mtd%d: Removed", dev->mtd_info->index); - } - - pcmciamtd_release(link); + if(dev->mtd_info) { + del_mtd_device(dev->mtd_info); + info("mtd%d: Removed", dev->mtd_info->index); } + + pcmciamtd_release(link); } @@ -736,10 +725,9 @@ static void pcmciamtd_detach(struct pcmcia_device *p_dev) * with Card Services. */ -static int pcmciamtd_attach(struct pcmcia_device *p_dev) +static int pcmciamtd_probe(struct pcmcia_device *link) { struct pcmciamtd_dev *dev; - dev_link_t *link; /* Create new memory card device */ dev = kmalloc(sizeof(*dev), GFP_KERNEL); @@ -747,20 +735,13 @@ static int pcmciamtd_attach(struct pcmcia_device *p_dev) DEBUG(1, "dev=0x%p", dev); memset(dev, 0, sizeof(*dev)); - link = &dev->link; + dev->p_dev = link; link->priv = dev; link->conf.Attributes = 0; link->conf.IntType = INT_MEMORY; - link->next = NULL; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - pcmciamtd_config(link); - - return 0; + return pcmciamtd_config(link); } static struct pcmcia_device_id pcmciamtd_ids[] = { @@ -794,7 +775,7 @@ static struct pcmcia_driver pcmciamtd_driver = { .drv = { .name = "pcmciamtd" }, - .probe = pcmciamtd_attach, + .probe = pcmciamtd_probe, .remove = pcmciamtd_detach, .owner = THIS_MODULE, .id_table = pcmciamtd_ids, diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index 5b76ed886185..50b14033613f 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c @@ -121,8 +121,7 @@ struct map_info redwood_flash_map = { }; -#define NUM_REDWOOD_FLASH_PARTITIONS \ - (sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0])) +#define NUM_REDWOOD_FLASH_PARTITIONS ARRAY_SIZE(redwood_flash_partitions) static struct mtd_info *redwood_mtd; diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c index 225cdd9ba5b2..350286dc1d2e 100644 --- a/drivers/mtd/maps/sbc8240.c +++ b/drivers/mtd/maps/sbc8240.c @@ -66,7 +66,7 @@ static struct map_info sbc8240_map[2] = { } }; -#define NUM_FLASH_BANKS (sizeof(sbc8240_map) / sizeof(struct map_info)) +#define NUM_FLASH_BANKS ARRAY_SIZE(sbc8240_map) /* * The following defines the partition layout of SBC8240 boards. @@ -125,8 +125,6 @@ static struct mtd_partition sbc8240_fs_partitions [] = { } }; -#define NB_OF(x) (sizeof (x) / sizeof (x[0])) - /* trivial struct to describe partition information */ struct mtd_part_def { @@ -190,10 +188,10 @@ int __init init_sbc8240_mtd (void) #ifdef CONFIG_MTD_PARTITIONS sbc8240_part_banks[0].mtd_part = sbc8240_uboot_partitions; sbc8240_part_banks[0].type = "static image"; - sbc8240_part_banks[0].nums = NB_OF(sbc8240_uboot_partitions); + sbc8240_part_banks[0].nums = ARRAY_SIZE(sbc8240_uboot_partitions); sbc8240_part_banks[1].mtd_part = sbc8240_fs_partitions; sbc8240_part_banks[1].type = "static file system"; - sbc8240_part_banks[1].nums = NB_OF(sbc8240_fs_partitions); + sbc8240_part_banks[1].nums = ARRAY_SIZE(sbc8240_fs_partitions); for (i = 0; i < NUM_FLASH_BANKS; i++) { diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index ed92afadd8a9..e8c130e1efd3 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c @@ -107,7 +107,7 @@ static struct map_info sc520cdp_map[] = { }, }; -#define NUM_FLASH_BANKS (sizeof(sc520cdp_map)/sizeof(struct map_info)) +#define NUM_FLASH_BANKS ARRAY_SIZE(sc520cdp_map) static struct mtd_info *mymtd[NUM_FLASH_BANKS]; static struct mtd_info *merged_mtd; diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c index 2c91dff8bb60..28b8a571a91a 100644 --- a/drivers/mtd/maps/scx200_docflash.c +++ b/drivers/mtd/maps/scx200_docflash.c @@ -70,7 +70,7 @@ static struct mtd_partition partition_info[] = { .size = 0x80000 }, }; -#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) +#define NUM_PARTITIONS ARRAY_SIZE(partition_info) #endif diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index 999f4bb3d845..12fe53c0d2fc 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c @@ -49,8 +49,6 @@ static struct mtd_partition sharpsl_partitions[1] = { } }; -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - int __init init_sharpsl(void) { struct mtd_partition *parts; @@ -92,7 +90,7 @@ int __init init_sharpsl(void) } parts = sharpsl_partitions; - nb_parts = NB_OF(sharpsl_partitions); + nb_parts = ARRAY_SIZE(sharpsl_partitions); printk(KERN_NOTICE "Using %s partision definition\n", part_type); add_mtd_partitions(mymtd, parts, nb_parts); diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index 4b372bcb17f1..a7422c200567 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c @@ -64,7 +64,7 @@ static struct mtd_partition ts5500_partitions[] = { } }; -#define NUM_PARTITIONS (sizeof(ts5500_partitions)/sizeof(struct mtd_partition)) +#define NUM_PARTITIONS ARRAY_SIZE(ts5500_partitions) static struct mtd_info *mymtd; diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 79d92808b766..f7264dc2ac9b 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -37,7 +37,7 @@ struct mtd_partition uclinux_romfs[] = { { .name = "ROMfs" } }; -#define NUM_PARTITIONS (sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0])) +#define NUM_PARTITIONS ARRAY_SIZE(uclinux_romfs) /****************************************************************************/ diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c index e0063941c0df..b3e487395435 100644 --- a/drivers/mtd/maps/vmax301.c +++ b/drivers/mtd/maps/vmax301.c @@ -182,7 +182,7 @@ int __init init_vmax301(void) } } - if (!vmax_mtd[1] && !vmax_mtd[2]) { + if (!vmax_mtd[0] && !vmax_mtd[1]) { iounmap((void *)iomapadr); return -ENXIO; } diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 840dd66ce2dc..458d3c8ae1ee 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -19,12 +19,12 @@ #include #include #include -#include +#include #include static LIST_HEAD(blktrans_majors); -extern struct semaphore mtd_table_mutex; +extern struct mutex mtd_table_mutex; extern struct mtd_info *mtd_table[]; struct mtd_blkcore_priv { @@ -122,9 +122,9 @@ static int mtd_blktrans_thread(void *arg) spin_unlock_irq(rq->queue_lock); - down(&dev->sem); + mutex_lock(&dev->lock); res = do_blktrans_request(tr, dev, req); - up(&dev->sem); + mutex_unlock(&dev->lock); spin_lock_irq(rq->queue_lock); @@ -235,8 +235,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) int last_devnum = -1; struct gendisk *gd; - if (!down_trylock(&mtd_table_mutex)) { - up(&mtd_table_mutex); + if (!!mutex_trylock(&mtd_table_mutex)) { + mutex_unlock(&mtd_table_mutex); BUG(); } @@ -267,7 +267,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) return -EBUSY; } - init_MUTEX(&new->sem); + mutex_init(&new->lock); list_add_tail(&new->list, &tr->devs); added: if (!tr->writesect) @@ -313,8 +313,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) { - if (!down_trylock(&mtd_table_mutex)) { - up(&mtd_table_mutex); + if (!!mutex_trylock(&mtd_table_mutex)) { + mutex_unlock(&mtd_table_mutex); BUG(); } @@ -378,14 +378,14 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv)); - down(&mtd_table_mutex); + mutex_lock(&mtd_table_mutex); ret = register_blkdev(tr->major, tr->name); if (ret) { printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", tr->name, tr->major, ret); kfree(tr->blkcore_priv); - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); return ret; } spin_lock_init(&tr->blkcore_priv->queue_lock); @@ -396,7 +396,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) if (!tr->blkcore_priv->rq) { unregister_blkdev(tr->major, tr->name); kfree(tr->blkcore_priv); - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); return -ENOMEM; } @@ -407,7 +407,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) blk_cleanup_queue(tr->blkcore_priv->rq); unregister_blkdev(tr->major, tr->name); kfree(tr->blkcore_priv); - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); return ret; } @@ -419,7 +419,7 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) tr->add_mtd(tr, mtd_table[i]); } - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); return 0; } @@ -428,7 +428,7 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) { struct list_head *this, *next; - down(&mtd_table_mutex); + mutex_lock(&mtd_table_mutex); /* Clean up the kernel thread */ tr->blkcore_priv->exiting = 1; @@ -446,7 +446,7 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) blk_cleanup_queue(tr->blkcore_priv->rq); unregister_blkdev(tr->major, tr->name); - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); kfree(tr->blkcore_priv); diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index e84756644fd1..2cef280e388c 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -19,11 +19,13 @@ #include #include +#include + static struct mtdblk_dev { struct mtd_info *mtd; int count; - struct semaphore cache_sem; + struct mutex cache_mutex; unsigned char *cache_data; unsigned long cache_offset; unsigned int cache_size; @@ -284,7 +286,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) mtdblk->count = 1; mtdblk->mtd = mtd; - init_MUTEX (&mtdblk->cache_sem); + mutex_init(&mtdblk->cache_mutex); mtdblk->cache_state = STATE_EMPTY; if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM && mtdblk->mtd->erasesize) { @@ -306,9 +308,9 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); - down(&mtdblk->cache_sem); + mutex_lock(&mtdblk->cache_mutex); write_cached_data(mtdblk); - up(&mtdblk->cache_sem); + mutex_unlock(&mtdblk->cache_mutex); if (!--mtdblk->count) { /* It was the last usage. Free the device */ @@ -327,9 +329,9 @@ static int mtdblock_flush(struct mtd_blktrans_dev *dev) { struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; - down(&mtdblk->cache_sem); + mutex_lock(&mtdblk->cache_mutex); write_cached_data(mtdblk); - up(&mtdblk->cache_sem); + mutex_unlock(&mtdblk->cache_mutex); if (mtdblk->mtd->sync) mtdblk->mtd->sync(mtdblk->mtd); diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index dade02ab0687..9905870f56e5 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -19,15 +19,13 @@ #include #include #include -#ifdef CONFIG_PROC_FS #include -#endif #include /* These are exported solely for the purpose of mtd_blkdevs.c. You should not use them for _anything_ else */ -DECLARE_MUTEX(mtd_table_mutex); +DEFINE_MUTEX(mtd_table_mutex); struct mtd_info *mtd_table[MAX_MTD_DEVICES]; EXPORT_SYMBOL_GPL(mtd_table_mutex); @@ -49,7 +47,7 @@ int add_mtd_device(struct mtd_info *mtd) { int i; - down(&mtd_table_mutex); + mutex_lock(&mtd_table_mutex); for (i=0; i < MAX_MTD_DEVICES; i++) if (!mtd_table[i]) { @@ -67,7 +65,7 @@ int add_mtd_device(struct mtd_info *mtd) not->add(mtd); } - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); /* We _know_ we aren't being removed, because our caller is still holding us here. So none of this try_ nonsense, and no bitching about it @@ -76,7 +74,7 @@ int add_mtd_device(struct mtd_info *mtd) return 0; } - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); return 1; } @@ -94,7 +92,7 @@ int del_mtd_device (struct mtd_info *mtd) { int ret; - down(&mtd_table_mutex); + mutex_lock(&mtd_table_mutex); if (mtd_table[mtd->index] != mtd) { ret = -ENODEV; @@ -118,7 +116,7 @@ int del_mtd_device (struct mtd_info *mtd) ret = 0; } - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); return ret; } @@ -135,7 +133,7 @@ void register_mtd_user (struct mtd_notifier *new) { int i; - down(&mtd_table_mutex); + mutex_lock(&mtd_table_mutex); list_add(&new->list, &mtd_notifiers); @@ -145,7 +143,7 @@ void register_mtd_user (struct mtd_notifier *new) if (mtd_table[i]) new->add(mtd_table[i]); - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); } /** @@ -162,7 +160,7 @@ int unregister_mtd_user (struct mtd_notifier *old) { int i; - down(&mtd_table_mutex); + mutex_lock(&mtd_table_mutex); module_put(THIS_MODULE); @@ -171,7 +169,7 @@ int unregister_mtd_user (struct mtd_notifier *old) old->remove(mtd_table[i]); list_del(&old->list); - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); return 0; } @@ -193,7 +191,7 @@ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) struct mtd_info *ret = NULL; int i; - down(&mtd_table_mutex); + mutex_lock(&mtd_table_mutex); if (num == -1) { for (i=0; i< MAX_MTD_DEVICES; i++) @@ -211,7 +209,7 @@ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) if (ret) ret->usecount++; - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); return ret; } @@ -219,9 +217,9 @@ void put_mtd_device(struct mtd_info *mtd) { int c; - down(&mtd_table_mutex); + mutex_lock(&mtd_table_mutex); c = --mtd->usecount; - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); BUG_ON(c < 0); module_put(mtd->owner); @@ -296,10 +294,11 @@ EXPORT_SYMBOL(unregister_mtd_user); EXPORT_SYMBOL(default_mtd_writev); EXPORT_SYMBOL(default_mtd_readv); +#ifdef CONFIG_PROC_FS + /*====================================================================*/ /* Support for /proc/mtd */ -#ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_mtd; static inline int mtd_proc_info (char *buf, int i) @@ -319,7 +318,7 @@ static int mtd_read_proc (char *page, char **start, off_t off, int count, int len, l, i; off_t begin = 0; - down(&mtd_table_mutex); + mutex_lock(&mtd_table_mutex); len = sprintf(page, "dev: size erasesize name\n"); for (i=0; i< MAX_MTD_DEVICES; i++) { @@ -337,38 +336,34 @@ static int mtd_read_proc (char *page, char **start, off_t off, int count, *eof = 1; done: - up(&mtd_table_mutex); + mutex_unlock(&mtd_table_mutex); if (off >= len+begin) return 0; *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } -#endif /* CONFIG_PROC_FS */ - /*====================================================================*/ /* Init code */ static int __init init_mtd(void) { -#ifdef CONFIG_PROC_FS if ((proc_mtd = create_proc_entry( "mtd", 0, NULL ))) proc_mtd->read_proc = mtd_read_proc; -#endif return 0; } static void __exit cleanup_mtd(void) { -#ifdef CONFIG_PROC_FS if (proc_mtd) remove_proc_entry( "mtd", NULL); -#endif } module_init(init_mtd); module_exit(cleanup_mtd); +#endif /* CONFIG_PROC_FS */ + MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse "); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 1fc4c134d939..cfe288a6e853 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -178,17 +178,16 @@ config MTD_NAND_DISKONCHIP_BBTWRITE Even if you leave this disabled, you can enable BBT writes at module load time (assuming you build diskonchip as a module) with the module parameter "inftl_bbt_write=1". - - config MTD_NAND_SHARPSL - bool "Support for NAND Flash on Sharp SL Series (C7xx + others)" - depends on MTD_NAND && ARCH_PXA - - config MTD_NAND_NANDSIM - bool "Support for NAND Flash Simulator" - depends on MTD_NAND && MTD_PARTITIONS +config MTD_NAND_SHARPSL + tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" + depends on MTD_NAND && ARCH_PXA + +config MTD_NAND_NANDSIM + tristate "Support for NAND Flash Simulator" + depends on MTD_NAND && MTD_PARTITIONS help The simulator may simulate verious NAND flash chips for the MTD nand layer. - + endmenu diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 201e1362da14..bde3550910a2 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -55,8 +55,6 @@ static const struct mtd_partition partition_info[] = { .size = MTDPART_SIZ_FULL } }; -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - /** * au_read_byte - read one byte from the chip @@ -462,7 +460,7 @@ int __init au1xxx_nand_init (void) } /* Register the partitions */ - add_mtd_partitions(au1550_mtd, partition_info, NB_OF(partition_info)); + add_mtd_partitions(au1550_mtd, partition_info, ARRAY_SIZE(partition_info)); return 0; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5d222460b42a..95e96fa1fceb 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -80,6 +80,7 @@ #include #include #include +#include #include #ifdef CONFIG_MTD_PARTITIONS @@ -515,6 +516,8 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i return nand_isbad_bbt (mtd, ofs, allowbbt); } +DEFINE_LED_TRIGGER(nand_led_trigger); + /* * Wait for the ready pin, after a command * The timeout is catched later. @@ -524,12 +527,14 @@ static void nand_wait_ready(struct mtd_info *mtd) struct nand_chip *this = mtd->priv; unsigned long timeo = jiffies + 2; + led_trigger_event(nand_led_trigger, LED_FULL); /* wait until command is processed or timeout occures */ do { if (this->dev_ready(mtd)) - return; + break; touch_softlockup_watchdog(); } while (time_before(jiffies, timeo)); + led_trigger_event(nand_led_trigger, LED_OFF); } /** @@ -817,6 +822,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) else timeo += (HZ * 20) / 1000; + led_trigger_event(nand_led_trigger, LED_FULL); + /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); @@ -840,6 +847,8 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) } cond_resched(); } + led_trigger_event(nand_led_trigger, LED_OFF); + status = (int) this->read_byte(mtd); return status; } @@ -2724,6 +2733,21 @@ void nand_release (struct mtd_info *mtd) EXPORT_SYMBOL_GPL (nand_scan); EXPORT_SYMBOL_GPL (nand_release); + +static int __init nand_base_init(void) +{ + led_trigger_register_simple("nand-disk", &nand_led_trigger); + return 0; +} + +static void __exit nand_base_exit(void) +{ + led_trigger_unregister_simple(nand_led_trigger); +} + +module_init(nand_base_init); +module_exit(nand_base_exit); + MODULE_LICENSE ("GPL"); MODULE_AUTHOR ("Steven J. Hill , Thomas Gleixner "); MODULE_DESCRIPTION ("Generic NAND flash driver code"); diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 8815c8dbef2d..c077d2ec9cdd 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -85,10 +85,6 @@ static int parse_redboot_partitions(struct mtd_info *master, numslots = (master->erasesize / sizeof(struct fis_image_desc)); for (i = 0; i < numslots; i++) { - if (buf[i].name[0] == 0xff) { - i = numslots; - break; - } if (!memcmp(buf[i].name, "FIS directory", 14)) { /* This is apparently the FIS directory entry for the * FIS directory itself. The FIS directory size is @@ -128,7 +124,7 @@ static int parse_redboot_partitions(struct mtd_info *master, struct fis_list *new_fl, **prev; if (buf[i].name[0] == 0xff) - break; + continue; if (!redboot_checksum(&buf[i])) break; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 70f63891b19c..274b0138d442 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -788,7 +788,7 @@ struct vortex_private { int options; /* User-settable misc. driver options. */ unsigned int media_override:4, /* Passed-in media type. */ default_media:4, /* Read from the EEPROM/Wn3_Config. */ - full_duplex:1, force_fd:1, autoselect:1, + full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */ @@ -1633,12 +1633,6 @@ vortex_set_duplex(struct net_device *dev) ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl); - - issue_and_wait(dev, TxReset); - /* - * Don't reset the PHY - that upsets autonegotiation during DHCP operations. - */ - issue_and_wait(dev, RxReset|0x04); } static void vortex_check_media(struct net_device *dev, unsigned int init) @@ -1663,7 +1657,7 @@ vortex_up(struct net_device *dev) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; unsigned int config; - int i; + int i, mii_reg1, mii_reg5; if (VORTEX_PCI(vp)) { pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */ @@ -1723,14 +1717,23 @@ vortex_up(struct net_device *dev) printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); iowrite32(config, ioaddr + Wn3_Config); - netif_carrier_off(dev); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { EL3WINDOW(4); + mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR); + mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA); + vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); + vortex_check_media(dev, 1); } else vortex_set_duplex(dev); + issue_and_wait(dev, TxReset); + /* + * Don't reset the PHY - that upsets autonegotiation during DHCP operations. + */ + issue_and_wait(dev, RxReset|0x04); + iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD); @@ -2083,16 +2086,14 @@ vortex_error(struct net_device *dev, int status) } if (tx_status & 0x14) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; + if (tx_status & 0x08) vp->xstats.tx_max_collisions++; iowrite8(0, ioaddr + TxStatus); if (tx_status & 0x30) { /* txJabber or txUnderrun */ do_tx_reset = 1; - } else if (tx_status & 0x08) { /* maxCollisions */ - vp->xstats.tx_max_collisions++; - if (vp->drv_flags & MAX_COLLISION_RESET) { - do_tx_reset = 1; - reset_mask = 0x0108; /* Reset interface logic, but not download logic */ - } - } else { /* Merely re-enable the transmitter. */ + } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */ + do_tx_reset = 1; + reset_mask = 0x0108; /* Reset interface logic, but not download logic */ + } else { /* Merely re-enable the transmitter. */ iowrite16(TxEnable, ioaddr + EL3_CMD); } } diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index ce99845d8266..066e22b01a94 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -539,8 +539,7 @@ rx_status_loop: unsigned buflen; skb = cp->rx_skb[rx_tail].skb; - if (!skb) - BUG(); + BUG_ON(!skb); desc = &cp->rx_ring[rx_tail]; status = le32_to_cpu(desc->opts1); @@ -723,8 +722,7 @@ static void cp_tx (struct cp_private *cp) break; skb = cp->tx_skb[tx_tail].skb; - if (!skb) - BUG(); + BUG_ON(!skb); pci_unmap_single(cp->pdev, cp->tx_skb[tx_tail].mapping, cp->tx_skb[tx_tail].len, PCI_DMA_TODEVICE); @@ -1550,8 +1548,7 @@ static void cp_get_ethtool_stats (struct net_device *dev, tmp_stats[i++] = le16_to_cpu(nic_stats->tx_abort); tmp_stats[i++] = le16_to_cpu(nic_stats->tx_underrun); tmp_stats[i++] = cp->cp_stats.rx_frags; - if (i != CP_NUM_STATS) - BUG(); + BUG_ON(i != CP_NUM_STATS); pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma); } @@ -1856,8 +1853,7 @@ static void cp_remove_one (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct cp_private *cp = netdev_priv(dev); - if (!dev) - BUG(); + BUG_ON(!dev); unregister_netdev(dev); iounmap(cp->regs); if (cp->wol_enabled) pci_set_power_state (pdev, PCI_D0); diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 599b68d8c45f..51e39dcd0603 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -134,7 +134,7 @@ struct ei_device { #define inb_p(_p) inb(_p) #define outb_p(_v,_p) outb(_v,_p) -#elif defined(CONFIG_NET_CBUS) || defined(CONFIG_NE_H8300) || defined(CONFIG_NE_H8300_MODULE) +#elif defined(CONFIG_NE_H8300) || defined(CONFIG_NE_H8300_MODULE) #define EI_SHIFT(x) (ei_local->reg_offset[x]) #else #define EI_SHIFT(x) (x) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e20b849a22e8..bdaaad8f2123 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2313,13 +2313,11 @@ config S2IO_NAPI endmenu -if !UML source "drivers/net/tokenring/Kconfig" source "drivers/net/wireless/Kconfig" source "drivers/net/pcmcia/Kconfig" -endif source "drivers/net/wan/Kconfig" diff --git a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h index 6d625d595622..d7882dd783c8 100644 --- a/drivers/net/acenic_firmware.h +++ b/drivers/net/acenic_firmware.h @@ -4397,7 +4397,7 @@ static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = { 0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 }; -static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { +static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, @@ -4571,7 +4571,7 @@ static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x0, 0x14c38, 0x14c38, 0x14b80, 0x14bc4, 0x14c38, 0x14c38, 0x0, 0x0, 0x0 }; -static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { +static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __devinitdata = { 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, @@ -4612,7 +4612,7 @@ static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { #define tigon2FwSbssLen 0xcc #define tigon2FwBssAddr 0x00016f50 #define tigon2FwBssLen 0x20c0 -static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { +static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = { 0x0, 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, @@ -9154,7 +9154,7 @@ static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x24020001, 0x8f430328, 0x1021, 0x24630001, 0x3e00008, 0xaf430328, 0x3e00008, 0x0, 0x0, 0x0, 0x0, 0x0 }; -static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { +static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, @@ -9425,7 +9425,7 @@ static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, 0x14ed8, 0x7365746d, 0x61636163, 0x74000000, 0x0, 0x0 }; -static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = { +static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __devinitdata = { 0x1, 0x1, 0x1, 0xc001fc, 0x3ffc, 0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 64e2caf3083d..fabc0607b0f1 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -765,8 +765,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) BUGMSG(D_DURING, "in arcnet_interrupt\n"); lp = dev->priv; - if (!lp) - BUG(); + BUG_ON(!lp); spin_lock(&lp->lock); diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index 43150b2bd13f..0d45553ff75c 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -125,11 +125,11 @@ static void __init com90xx_probe(void) if (!io && !irq && !shmem && !*device && com90xx_skip_probe) return; - shmems = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(unsigned long), + shmems = kzalloc(((0x100000-0xa0000) / 0x800) * sizeof(unsigned long), GFP_KERNEL); if (!shmems) return; - iomem = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(void __iomem *), + iomem = kzalloc(((0x100000-0xa0000) / 0x800) * sizeof(void __iomem *), GFP_KERNEL); if (!iomem) { kfree(shmems); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index c3267e4e1bb0..3d306681919e 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2,6 +2,7 @@ * * Copyright (C) 2002 David S. Miller (davem@redhat.com) * Fixed by Pekka Pietikainen (pp@ee.oulu.fi) + * Copyright (C) 2006 Broadcom Corporation. * * Distribute under GPL. */ @@ -28,8 +29,8 @@ #define DRV_MODULE_NAME "b44" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.97" -#define DRV_MODULE_RELDATE "Nov 30, 2005" +#define DRV_MODULE_VERSION "1.00" +#define DRV_MODULE_RELDATE "Apr 7, 2006" #define B44_DEF_MSG_ENABLE \ (NETIF_MSG_DRV | \ @@ -136,7 +137,7 @@ static inline unsigned long br32(const struct b44 *bp, unsigned long reg) return readl(bp->regs + reg); } -static inline void bw32(const struct b44 *bp, +static inline void bw32(const struct b44 *bp, unsigned long reg, unsigned long val) { writel(val, bp->regs + reg); @@ -286,13 +287,13 @@ static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index) val |= ((u32) data[4]) << 8; val |= ((u32) data[5]) << 0; bw32(bp, B44_CAM_DATA_LO, val); - val = (CAM_DATA_HI_VALID | + val = (CAM_DATA_HI_VALID | (((u32) data[0]) << 8) | (((u32) data[1]) << 0)); bw32(bp, B44_CAM_DATA_HI, val); bw32(bp, B44_CAM_CTRL, (CAM_CTRL_WRITE | (index << CAM_CTRL_INDEX_SHIFT))); - b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); + b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1); } static inline void __b44_disable_ints(struct b44 *bp) @@ -410,25 +411,18 @@ static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags) static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote) { - u32 pause_enab = bp->flags & (B44_FLAG_TX_PAUSE | - B44_FLAG_RX_PAUSE); + u32 pause_enab = 0; - if (local & ADVERTISE_PAUSE_CAP) { - if (local & ADVERTISE_PAUSE_ASYM) { - if (remote & LPA_PAUSE_CAP) - pause_enab |= (B44_FLAG_TX_PAUSE | - B44_FLAG_RX_PAUSE); - else if (remote & LPA_PAUSE_ASYM) - pause_enab |= B44_FLAG_RX_PAUSE; - } else { - if (remote & LPA_PAUSE_CAP) - pause_enab |= (B44_FLAG_TX_PAUSE | - B44_FLAG_RX_PAUSE); - } - } else if (local & ADVERTISE_PAUSE_ASYM) { - if ((remote & LPA_PAUSE_CAP) && - (remote & LPA_PAUSE_ASYM)) - pause_enab |= B44_FLAG_TX_PAUSE; + /* The driver supports only rx pause by default because + the b44 mac tx pause mechanism generates excessive + pause frames. + Use ethtool to turn on b44 tx pause if necessary. + */ + if ((local & ADVERTISE_PAUSE_CAP) && + (local & ADVERTISE_PAUSE_ASYM)){ + if ((remote & LPA_PAUSE_ASYM) && + !(remote & LPA_PAUSE_CAP)) + pause_enab |= B44_FLAG_RX_PAUSE; } __b44_set_flow_ctrl(bp, pause_enab); @@ -608,8 +602,7 @@ static void b44_tx(struct b44 *bp) struct ring_info *rp = &bp->tx_buffers[cons]; struct sk_buff *skb = rp->skb; - if (unlikely(skb == NULL)) - BUG(); + BUG_ON(skb == NULL); pci_unmap_single(bp->pdev, pci_unmap_addr(rp, mapping), @@ -1064,7 +1057,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu) spin_unlock_irq(&bp->lock); b44_enable_ints(bp); - + return 0; } @@ -1339,6 +1332,9 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) if (netif_running(dev)) return -EBUSY; + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); spin_lock_irq(&bp->lock); @@ -1379,7 +1375,7 @@ static void b44_init_hw(struct b44 *bp) bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); bw32(bp, B44_DMARX_PTR, bp->rx_pending); - bp->rx_prod = bp->rx_pending; + bp->rx_prod = bp->rx_pending; bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); @@ -1551,9 +1547,9 @@ static void __b44_set_rx_mode(struct net_device *dev) val |= RXCONFIG_ALLMULTI; else i = __b44_load_mcast(bp, dev); - + for (; i < 64; i++) { - __b44_cam_write(bp, zero, i); + __b44_cam_write(bp, zero, i); } bw32(bp, B44_RXCONFIG, val); val = br32(bp, B44_CAM_CTRL); @@ -1735,7 +1731,7 @@ static int b44_set_ringparam(struct net_device *dev, spin_unlock_irq(&bp->lock); b44_enable_ints(bp); - + return 0; } @@ -1780,7 +1776,7 @@ static int b44_set_pauseparam(struct net_device *dev, spin_unlock_irq(&bp->lock); b44_enable_ints(bp); - + return 0; } @@ -1876,6 +1872,12 @@ static int __devinit b44_get_invariants(struct b44 *bp) bp->dev->dev_addr[3] = eeprom[80]; bp->dev->dev_addr[4] = eeprom[83]; bp->dev->dev_addr[5] = eeprom[82]; + + if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){ + printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n"); + return -EINVAL; + } + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); bp->phy_addr = eeprom[90] & 0x1f; @@ -1890,7 +1892,7 @@ static int __devinit b44_get_invariants(struct b44 *bp) bp->core_unit = ssb_core_unit(bp); bp->dma_offset = SB_PCI_DMA; - /* XXX - really required? + /* XXX - really required? bp->flags |= B44_FLAG_BUGGY_TXPTR; */ out: @@ -1938,7 +1940,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev, "aborting.\n"); goto err_out_free_res; } - + err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK); if (err) { printk(KERN_ERR PFX "No usable DMA configuration, " @@ -2033,6 +2035,11 @@ static int __devinit b44_init_one(struct pci_dev *pdev, pci_save_state(bp->pdev); + /* Chip reset provides power to the b44 MAC & PCI cores, which + * is necessary for MAC register access. + */ + b44_chip_reset(bp); + printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], @@ -2078,10 +2085,10 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) del_timer_sync(&bp->timer); - spin_lock_irq(&bp->lock); + spin_lock_irq(&bp->lock); b44_halt(bp); - netif_carrier_off(bp->dev); + netif_carrier_off(bp->dev); netif_device_detach(bp->dev); b44_free_rings(bp); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 2671da20a496..5ca99e26660a 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -63,7 +63,7 @@ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (5*HZ) -static char version[] __devinitdata = +static const char version[] __devinitdata = "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Michael Chan "); diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index f3f5825469d6..6a407070c2e8 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2294,6 +2294,34 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) port->sm_vars |= AD_PORT_BEGIN; } +/* + * set link state for bonding master: if we have an active partnered + * aggregator, we're up, if not, we're down. Presumes that we cannot + * have an active aggregator if there are no slaves with link up. + * + * Called by bond_set_carrier(). Return zero if carrier state does not + * change, nonzero if it does. + */ +int bond_3ad_set_carrier(struct bonding *bond) +{ + struct aggregator *agg; + + agg = __get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator)); + if (agg && MAC_ADDRESS_COMPARE(&agg->partner_system, &null_mac_addr)) { + if (!netif_carrier_ok(bond->dev)) { + netif_carrier_on(bond->dev); + return 1; + } + return 0; + } + + if (netif_carrier_ok(bond->dev)) { + netif_carrier_off(bond->dev); + return 1; + } + return 0; +} + /** * bond_3ad_get_active_agg_info - get information of the active aggregator * @bond: bonding struct to work on diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 5ee2cef5b037..6ad5ad6e65d5 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -283,5 +283,6 @@ void bond_3ad_handle_link_change(struct slave *slave, char link); int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev); +int bond_3ad_set_carrier(struct bonding *bond); #endif //__BOND_3AD_H__ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f13a539dc169..55d236726d11 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -558,6 +558,42 @@ out: /*------------------------------- Link status -------------------------------*/ +/* + * Set the carrier state for the master according to the state of its + * slaves. If any slaves are up, the master is up. In 802.3ad mode, + * do special 802.3ad magic. + * + * Returns zero if carrier state does not change, nonzero if it does. + */ +static int bond_set_carrier(struct bonding *bond) +{ + struct slave *slave; + int i; + + if (bond->slave_cnt == 0) + goto down; + + if (bond->params.mode == BOND_MODE_8023AD) + return bond_3ad_set_carrier(bond); + + bond_for_each_slave(bond, slave, i) { + if (slave->link == BOND_LINK_UP) { + if (!netif_carrier_ok(bond->dev)) { + netif_carrier_on(bond->dev); + return 1; + } + return 0; + } + } + +down: + if (netif_carrier_ok(bond->dev)) { + netif_carrier_off(bond->dev); + return 1; + } + return 0; +} + /* * Get link speed and duplex from the slave's base driver * using ethtool. If for some reason the call fails or the @@ -1074,10 +1110,24 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) void bond_select_active_slave(struct bonding *bond) { struct slave *best_slave; + int rv; best_slave = bond_find_best_slave(bond); if (best_slave != bond->curr_active_slave) { bond_change_active_slave(bond, best_slave); + rv = bond_set_carrier(bond); + if (!rv) + return; + + if (netif_carrier_ok(bond->dev)) { + printk(KERN_INFO DRV_NAME + ": %s: first active interface up!\n", + bond->dev->name); + } else { + printk(KERN_INFO DRV_NAME ": %s: " + "now running without any active interface !\n", + bond->dev->name); + } } } @@ -1458,10 +1508,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (((!bond->curr_active_slave) || (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) && (new_slave->link != BOND_LINK_DOWN)) { - dprintk("This is the first active slave\n"); /* first slave or no active slave yet, and this link is OK, so make this interface the active one */ bond_change_active_slave(bond, new_slave); + printk(KERN_INFO DRV_NAME + ": %s: first active interface up!\n", + bond->dev->name); + netif_carrier_on(bond->dev); + } else { dprintk("This is just a backup slave\n"); bond_set_slave_inactive_flags(new_slave); @@ -1517,6 +1571,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) break; } /* switch(bond_mode) */ + bond_set_carrier(bond); + write_unlock_bh(&bond->lock); res = bond_create_slave_symlinks(bond_dev, slave_dev); @@ -1656,18 +1712,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_alb_deinit_slave(bond, slave); } - if (oldcurrent == slave) { + if (oldcurrent == slave) bond_select_active_slave(bond); - if (!bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME - ": %s: now running without any active " - "interface !\n", - bond_dev->name); - } - } - if (bond->slave_cnt == 0) { + bond_set_carrier(bond); + /* if the last slave was removed, zero the mac address * of the master so it will be set by the application * to the mac address of the first slave @@ -1751,6 +1801,8 @@ static int bond_release_all(struct net_device *bond_dev) write_lock_bh(&bond->lock); + netif_carrier_off(bond_dev); + if (bond->slave_cnt == 0) { goto out; } @@ -2187,15 +2239,9 @@ void bond_mii_monitor(struct net_device *bond_dev) bond_select_active_slave(bond); - if (oldcurrent && !bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME - ": %s: now running without any active " - "interface !\n", - bond_dev->name); - } - write_unlock(&bond->curr_slave_lock); - } + } else + bond_set_carrier(bond); re_arm: if (bond->params.miimon) { @@ -2499,13 +2545,6 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev) bond_select_active_slave(bond); - if (oldcurrent && !bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME - ": %s: now running without any active " - "interface !\n", - bond_dev->name); - } - write_unlock(&bond->curr_slave_lock); } @@ -2579,12 +2618,15 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) bond->current_arp_slave = NULL; } + bond_set_carrier(bond); + if (slave == bond->curr_active_slave) { printk(KERN_INFO DRV_NAME ": %s: %s is up and now the " "active interface\n", bond_dev->name, slave->dev->name); + netif_carrier_on(bond->dev); } else { printk(KERN_INFO DRV_NAME ": %s: backup interface %s is " @@ -2844,7 +2886,8 @@ static void bond_info_show_master(struct seq_file *seq) (curr) ? curr->dev->name : "None"); } - seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down"); + seq_printf(seq, "MII Status: %s\n", netif_carrier_ok(bond->dev) ? + "up" : "down"); seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon); seq_printf(seq, "Up Delay (ms): %d\n", bond->params.updelay * bond->params.miimon); @@ -4531,6 +4574,8 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond if (newbond) *newbond = bond_dev->priv; + netif_carrier_off(bond_dev); + rtnl_unlock(); /* allows sysfs registration of net device */ res = bond_create_sysfs_entry(bond_dev->priv); goto done; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index ce9dc9b4e2dc..0bdfe2c71453 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.0.2" -#define DRV_RELDATE "February 21, 2006" +#define DRV_VERSION "3.0.3" +#define DRV_RELDATE "March 23, 2006" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile index 91e927827c43..54c78d94f48b 100644 --- a/drivers/net/chelsio/Makefile +++ b/drivers/net/chelsio/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_CHELSIO_T1) += cxgb.o -EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/chelsio $(DEBUG_FLAGS) +EXTRA_CFLAGS += -Idrivers/net/chelsio $(DEBUG_FLAGS) cxgb-objs := cxgb2.o espi.o pm3393.o sge.o subr.o mv88x201x.o diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 30ff8ea1a402..4391bf4bf573 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1093,8 +1093,7 @@ static int process_responses(struct adapter *adapter, int budget) if (likely(e->DataValid)) { struct freelQ *fl = &sge->freelQ[e->FreelistQid]; - if (unlikely(!e->Sop || !e->Eop)) - BUG(); + BUG_ON(!e->Sop || !e->Eop); if (unlikely(e->Offload)) unexpected_offload(adapter, fl); else diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 49cd096a3c3d..add8dc4aa7b0 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3308,8 +3308,7 @@ e1000_clean(struct net_device *poll_dev, int *budget) while (poll_dev != &adapter->polling_netdev[i]) { i++; - if (unlikely(i == adapter->num_rx_queues)) - BUG(); + BUG_ON(i == adapter->num_rx_queues); } if (likely(adapter->num_tx_queues == 1)) { diff --git a/drivers/net/eql.c b/drivers/net/eql.c index aa1569182fd6..815436c6170f 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -203,8 +203,7 @@ static int eql_open(struct net_device *dev) printk(KERN_INFO "%s: remember to turn off Van-Jacobson compression on " "your slave devices.\n", dev->name); - if (!list_empty(&eql->queue.all_slaves)) - BUG(); + BUG_ON(!list_empty(&eql->queue.all_slaves)); eql->min_slaves = 1; eql->max_slaves = EQL_DEFAULT_MAX_SLAVES; /* 4 usually... */ diff --git a/drivers/net/hydra.h b/drivers/net/hydra.h deleted file mode 100644 index 37414146258d..000000000000 --- a/drivers/net/hydra.h +++ /dev/null @@ -1,177 +0,0 @@ -/* $Linux: hydra.h,v 1.0 1994/10/26 02:03:47 cgd Exp $ */ - -/* - * Copyright (c) 1994 Timo Rossi - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Timo Rossi - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * The Hydra Systems card uses the National Semiconductor - * 8390 NIC (Network Interface Controller) chip, located - * at card base address + 0xffe1. NIC registers are accessible - * only at odd byte addresses, so the register offsets must - * be multiplied by two. - * - * Card address PROM is located at card base + 0xffc0 (even byte addresses) - * - * RAM starts at the card base address, and is 16K or 64K. - * The current Amiga NetBSD hydra driver is hardwired for 16K. - * It seems that the RAM should be accessed as words or longwords only. - * - */ - -/* adapted for Linux by Topi Kanerva 03/29/95 - with original author's permission */ - -#define HYDRA_NIC_BASE 0xffe1 - -/* Page0 registers */ - -#define NIC_CR 0 /* Command register */ -#define NIC_PSTART (1*2) /* Page start (write) */ -#define NIC_PSTOP (2*2) /* Page stop (write) */ -#define NIC_BNDRY (3*2) /* Boundary pointer */ -#define NIC_TSR (4*2) /* Transmit status (read) */ -#define NIC_TPSR (4*2) /* Transmit page start (write) */ -#define NIC_NCR (5*2) /* Number of collisions, read */ -#define NIC_TBCR0 (5*2) /* Transmit byte count low (write) */ -#define NIC_FIFO (6*2) /* FIFO reg. (read) */ -#define NIC_TBCR1 (6*2) /* Transmit byte count high (write) */ -#define NIC_ISR (7*2) /* Interrupt status register */ -#define NIC_RBCR0 (0xa*2) /* Remote byte count low (write) */ -#define NIC_RBCR1 (0xb*2) /* Remote byte count high (write) */ -#define NIC_RSR (0xc*2) /* Receive status (read) */ -#define NIC_RCR (0xc*2) /* Receive config (write) */ -#define NIC_CNTR0 (0xd*2) /* Frame alignment error count (read) */ -#define NIC_TCR (0xd*2) /* Transmit config (write) */ -#define NIC_CNTR1 (0xe*2) /* CRC error counter (read) */ -#define NIC_DCR (0xe*2) /* Data config (write) */ -#define NIC_CNTR2 (0xf*2) /* missed packet counter (read) */ -#define NIC_IMR (0xf*2) /* Interrupt mask reg. (write) */ - -/* Page1 registers */ - -#define NIC_PAR0 (1*2) /* Physical address */ -#define NIC_PAR1 (2*2) -#define NIC_PAR2 (3*2) -#define NIC_PAR3 (4*2) -#define NIC_PAR4 (5*2) -#define NIC_PAR5 (6*2) -#define NIC_CURR (7*2) /* Current RX ring-buffer page */ -#define NIC_MAR0 (8*2) /* Multicast address */ -#define NIC_MAR1 (9*2) -#define NIC_MAR2 (0xa*2) -#define NIC_MAR3 (0xb*2) -#define NIC_MAR4 (0xc*2) -#define NIC_MAR5 (0xd*2) -#define NIC_MAR6 (0xe*2) -#define NIC_MAR7 (0xf*2) - -/* Command register definitions */ - -#define CR_STOP 0x01 /* Stop -- software reset command */ -#define CR_START 0x02 /* Start */ -#define CR_TXP 0x04 /* Transmit packet */ - -#define CR_RD0 0x08 /* Remote DMA cmd */ -#define CR_RD1 0x10 -#define CR_RD2 0x20 - -#define CR_NODMA CR_RD2 - -#define CR_PS0 0x40 /* Page select */ -#define CR_PS1 0x80 - -#define CR_PAGE0 0 -#define CR_PAGE1 CR_PS0 -#define CR_PAGE2 CR_PS1 - -/* Interrupt status reg. definitions */ - -#define ISR_PRX 0x01 /* Packet received without errors */ -#define ISR_PTX 0x02 /* Packet transmitted without errors */ -#define ISR_RXE 0x04 /* Receive error */ -#define ISR_TXE 0x08 /* Transmit error */ -#define ISR_OVW 0x10 /* Ring buffer overrun */ -#define ISR_CNT 0x20 /* Counter overflow */ -#define ISR_RDC 0x40 /* Remote DMA compile */ -#define ISR_RST 0x80 /* Reset status */ - -/* Data config reg. definitions */ - -#define DCR_WTS 0x01 /* Word transfer select */ -#define DCR_BOS 0x02 /* Byte order select */ -#define DCR_LAS 0x04 /* Long address select */ -#define DCR_LS 0x08 /* Loopback select */ -#define DCR_AR 0x10 /* Auto-init remote */ -#define DCR_FT0 0x20 /* FIFO threshold select */ -#define DCR_FT1 0x40 - -/* Transmit config reg. definitions */ - -#define TCR_CRC 0x01 /* Inhibit CRC */ -#define TCR_LB0 0x02 /* Loopback control */ -#define TCR_LB1 0x04 -#define TCR_ATD 0x08 /* Auto transmit disable */ -#define TCR_OFST 0x10 /* Collision offset enable */ - -/* Transmit status reg. definitions */ - -#define TSR_PTX 0x01 /* Packet transmitted */ -#define TSR_COL 0x04 /* Transmit collided */ -#define TSR_ABT 0x08 /* Transmit aborted */ -#define TSR_CRS 0x10 /* Carrier sense lost */ -#define TSR_FU 0x20 /* FIFO underrun */ -#define TSR_CDH 0x40 /* CD Heartbeat */ -#define TSR_OWC 0x80 /* Out of Window Collision */ - -/* Receiver config register definitions */ - -#define RCR_SEP 0x01 /* Save errored packets */ -#define RCR_AR 0x02 /* Accept runt packets */ -#define RCR_AB 0x04 /* Accept broadcast */ -#define RCR_AM 0x08 /* Accept multicast */ -#define RCR_PRO 0x10 /* Promiscuous mode */ -#define RCR_MON 0x20 /* Monitor mode */ - -/* Receiver status register definitions */ - -#define RSR_PRX 0x01 /* Packet received without error */ -#define RSR_CRC 0x02 /* CRC error */ -#define RSR_FAE 0x04 /* Frame alignment error */ -#define RSR_FO 0x08 /* FIFO overrun */ -#define RSR_MPA 0x10 /* Missed packet */ -#define RSR_PHY 0x20 /* Physical address */ -#define RSR_DIS 0x40 /* Received disabled */ -#define RSR_DFR 0x80 /* Deferring (jabber) */ - -/* Hydra System card address PROM offset */ - -#define HYDRA_ADDRPROM 0xffc0 - - diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index ceb98fd398af..52d01027d9e7 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -235,7 +235,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { pool->free_map[free_index] = index; pool->skbuff[index] = NULL; pool->consumer_index--; @@ -373,7 +373,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_debug_printk("h_add_logical_lan_buffer failed during recycle rc=%ld", lpar_rc); ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator); } @@ -511,7 +511,7 @@ static int ibmveth_open(struct net_device *netdev) adapter->filter_list_dma, mac_address); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc); ibmveth_error_printk("buffer TCE:0x%lx filter TCE:0x%lx rxq desc:0x%lx MAC:0x%lx\n", adapter->buffer_list_dma, @@ -527,7 +527,7 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_error_printk("unable to request irq 0x%x, rc %d\n", netdev->irq, rc); do { rc = h_free_logical_lan(adapter->vdev->unit_address); - } while (H_isLongBusy(rc) || (rc == H_Busy)); + } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); ibmveth_cleanup(adapter); return rc; @@ -556,9 +556,9 @@ static int ibmveth_close(struct net_device *netdev) do { lpar_rc = h_free_logical_lan(adapter->vdev->unit_address); - } while (H_isLongBusy(lpar_rc) || (lpar_rc == H_Busy)); + } while (H_IS_LONG_BUSY(lpar_rc) || (lpar_rc == H_BUSY)); - if(lpar_rc != H_Success) + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_free_logical_lan failed with %lx, continuing with close\n", lpar_rc); @@ -693,9 +693,9 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) desc[4].desc, desc[5].desc, correlator); - } while ((lpar_rc == H_Busy) && (retry_count--)); + } while ((lpar_rc == H_BUSY) && (retry_count--)); - if(lpar_rc != H_Success && lpar_rc != H_Dropped) { + if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) { int i; ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc); for(i = 0; i < 6; i++) { @@ -786,14 +786,14 @@ static int ibmveth_poll(struct net_device *netdev, int *budget) /* we think we are done - reenable interrupts, then check once more to make sure we are done */ lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_ENABLE); - ibmveth_assert(lpar_rc == H_Success); + ibmveth_assert(lpar_rc == H_SUCCESS); netif_rx_complete(netdev); if(ibmveth_rxq_pending_buffer(adapter) && netif_rx_reschedule(netdev, frames_processed)) { lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); - ibmveth_assert(lpar_rc == H_Success); + ibmveth_assert(lpar_rc == H_SUCCESS); more_work = 1; goto restart_poll; } @@ -813,7 +813,7 @@ static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs if(netif_rx_schedule_prep(netdev)) { lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); - ibmveth_assert(lpar_rc == H_Success); + ibmveth_assert(lpar_rc == H_SUCCESS); __netif_rx_schedule(netdev); } return IRQ_HANDLED; @@ -835,7 +835,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) IbmVethMcastEnableRecv | IbmVethMcastDisableFiltering, 0); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_multicast_ctrl rc=%ld when entering promisc mode\n", lpar_rc); } } else { @@ -847,7 +847,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) IbmVethMcastDisableFiltering | IbmVethMcastClearFilterTable, 0); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_multicast_ctrl rc=%ld when attempting to clear filter table\n", lpar_rc); } /* add the addresses to the filter table */ @@ -858,7 +858,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address, IbmVethMcastAddFilter, mcast_addr); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_multicast_ctrl rc=%ld when adding an entry to the filter table\n", lpar_rc); } } @@ -867,7 +867,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address, IbmVethMcastEnableFiltering, 0); - if(lpar_rc != H_Success) { + if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_multicast_ctrl rc=%ld when enabling filtering\n", lpar_rc); } } diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 6e2ec56cde0b..96bdb73c2283 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1,7 +1,7 @@ /***************************************************************************** * * Filename: irda-usb.c - * Version: 0.9b + * Version: 0.10 * Description: IrDA-USB Driver * Status: Experimental * Author: Dag Brattli @@ -9,6 +9,9 @@ * Copyright (C) 2000, Roman Weissgaerber * Copyright (C) 2001, Dag Brattli * Copyright (C) 2001, Jean Tourrilhes + * Copyright (C) 2004, SigmaTel, Inc. + * Copyright (C) 2005, Milan Beno + * Copyright (C) 2006, Nick Fedchik * * 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 @@ -61,6 +64,7 @@ #include #include #include +#include #include "irda-usb.h" @@ -78,8 +82,12 @@ static struct usb_device_id dongles[] = { { USB_DEVICE(0x50f, 0x180), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, /* Extended Systems, Inc., XTNDAccess IrDA USB (ESI-9685) */ { USB_DEVICE(0x8e9, 0x100), .driver_info = IUC_SPEED_BUG | IUC_NO_WINDOW }, + /* SigmaTel STIR4210/4220/4116 USB IrDA (VFIR) Bridge */ + { USB_DEVICE(0x66f, 0x4210), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, + { USB_DEVICE(0x66f, 0x4220), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, + { USB_DEVICE(0x66f, 0x4116), .driver_info = IUC_STIR_4210 | IUC_SPEED_BUG }, { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | - USB_DEVICE_ID_MATCH_INT_SUBCLASS, + USB_DEVICE_ID_MATCH_INT_SUBCLASS, .bInterfaceClass = USB_CLASS_APP_SPEC, .bInterfaceSubClass = USB_CLASS_IRDA, .driver_info = IUC_DEFAULT, }, @@ -99,6 +107,7 @@ MODULE_DEVICE_TABLE(usb, dongles); /*------------------------------------------------------------------*/ +static void irda_usb_init_qos(struct irda_usb_cb *self) ; static struct irda_class_desc *irda_usb_find_class_desc(struct usb_interface *intf); static void irda_usb_disconnect(struct usb_interface *intf); static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self); @@ -141,7 +150,24 @@ static void irda_usb_build_header(struct irda_usb_cb *self, __u8 *header, int force) { - /* Set the negotiated link speed */ + /* Here we check if we have an STIR421x chip, + * and if either speed or xbofs (or both) needs + * to be changed. + */ + if (self->capability & IUC_STIR_4210 && + ((self->new_speed != -1) || (self->new_xbofs != -1))) { + + /* With STIR421x, speed and xBOFs must be set at the same + * time, even if only one of them changes. + */ + if (self->new_speed == -1) + self->new_speed = self->speed ; + + if (self->new_xbofs == -1) + self->new_xbofs = self->xbofs ; + } + + /* Set the link speed */ if (self->new_speed != -1) { /* Hum... Ugly hack :-( * Some device are not compliant with the spec and change @@ -191,7 +217,11 @@ static void irda_usb_build_header(struct irda_usb_cb *self, *header = SPEED_4000000; self->new_xbofs = 0; break; - } + case 16000000: + *header = SPEED_16000000; + self->new_xbofs = 0; + break; + } } else /* No change */ *header = 0; @@ -235,6 +265,32 @@ static void irda_usb_build_header(struct irda_usb_cb *self, } } +/* +* calculate turnaround time for SigmaTel header +*/ +static __u8 get_turnaround_time(struct sk_buff *skb) +{ + int turnaround_time = irda_get_mtt(skb); + + if ( turnaround_time == 0 ) + return 0; + else if ( turnaround_time <= 10 ) + return 1; + else if ( turnaround_time <= 50 ) + return 2; + else if ( turnaround_time <= 100 ) + return 3; + else if ( turnaround_time <= 500 ) + return 4; + else if ( turnaround_time <= 1000 ) + return 5; + else if ( turnaround_time <= 5000 ) + return 6; + else + return 7; +} + + /*------------------------------------------------------------------*/ /* * Send a command to change the speed of the dongle @@ -262,12 +318,18 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) /* Set the new speed and xbofs in this fake frame */ irda_usb_build_header(self, frame, 1); + if ( self->capability & IUC_STIR_4210 ) { + if (frame[0] == 0) return ; // do nothing if no change + frame[1] = 0; // other parameters don't change here + frame[2] = 0; + } + /* Submit the 0 length IrDA frame to trigger new speed settings */ usb_fill_bulk_urb(urb, self->usbdev, usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), frame, IRDA_USB_SPEED_MTU, speed_bulk_callback, self); - urb->transfer_buffer_length = USB_IRDA_HEADER; + urb->transfer_buffer_length = self->header_length; urb->transfer_flags = 0; /* Irq disabled -> GFP_ATOMIC */ @@ -383,16 +445,35 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) * allocation will be done lower in skb_push(). * Also, we don't use directly skb_cow(), because it require * headroom >= 16, which force unnecessary copies - Jean II */ - if (skb_headroom(skb) < USB_IRDA_HEADER) { + if (skb_headroom(skb) < self->header_length) { IRDA_DEBUG(0, "%s(), Insuficient skb headroom.\n", __FUNCTION__); - if (skb_cow(skb, USB_IRDA_HEADER)) { + if (skb_cow(skb, self->header_length)) { IRDA_WARNING("%s(), failed skb_cow() !!!\n", __FUNCTION__); goto drop; } } /* Change setting for next frame */ - irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0); + + if ( self->capability & IUC_STIR_4210 ) { + __u8 turnaround_time; + __u8* frame; + turnaround_time = get_turnaround_time( skb ); + frame= skb_push(skb, self->header_length); + irda_usb_build_header(self, frame, 0); + frame[2] = turnaround_time; + if ((skb->len != 0) && + ((skb->len % 128) == 0) && + ((skb->len % 512) != 0)) { + /* add extra byte for special SigmaTel feature */ + frame[1] = 1; + skb_put(skb, 1); + } else { + frame[1] = 0; + } + } else { + irda_usb_build_header(self, skb_push(skb, self->header_length), 0); + } /* FIXME: Make macro out of this one */ ((struct irda_skb_cb *)skb->cb)->context = self; @@ -795,7 +876,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) } /* Check for empty frames */ - if (urb->actual_length <= USB_IRDA_HEADER) { + if (urb->actual_length <= self->header_length) { IRDA_WARNING("%s(), empty frame!\n", __FUNCTION__); goto done; } @@ -816,7 +897,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); /* Allocate a new skb */ - newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); + if ( self->capability & IUC_STIR_4210 ) + newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU + USB_IRDA_SIGMATEL_HEADER); + else + newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); + if (!newskb) { self->stats.rx_dropped++; /* We could deliver the current skb, but this would stall @@ -845,7 +930,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) /* Set proper length on skb & remove USB-IrDA header */ skb_put(dataskb, urb->actual_length); - skb_pull(dataskb, USB_IRDA_HEADER); + skb_pull(dataskb, self->header_length); /* Ask the networking layer to queue the packet for the IrDA stack */ dataskb->dev = self->netdev; @@ -937,6 +1022,191 @@ static int irda_usb_is_receiving(struct irda_usb_cb *self) return 0; /* For now */ } + +#define STIR421X_PATCH_PRODUCT_VERSION_STR "Product Version: " +#define STIR421X_PATCH_COMPONENT_VERSION_STR "Component Version: " +#define STIR421X_PATCH_DATA_TAG_STR "STMP" +#define STIR421X_PATCH_FILE_VERSION_MAX_OFFSET 512 /* version info is before here */ +#define STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET 512 /* patch image starts before here */ +#define STIR421X_PATCH_FILE_END_OF_HEADER_TAG 0x1A /* marks end of patch file header (PC DOS text file EOF character) */ + +/* + * Known firmware patches for STIR421x dongles + */ +static char * stir421x_patches[] = { + "42101001.sb", + "42101002.sb", +}; + +static int stir421x_get_patch_version(unsigned char * patch, const unsigned long patch_len) +{ + unsigned int version_offset; + unsigned long version_major, version_minor, version_build; + unsigned char * version_start; + int version_found = 0; + + for (version_offset = 0; + version_offset < STIR421X_PATCH_FILE_END_OF_HEADER_TAG; + version_offset++) { + if (!memcmp(patch + version_offset, + STIR421X_PATCH_PRODUCT_VERSION_STR, + sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1)) { + version_found = 1; + version_start = patch + + version_offset + + sizeof(STIR421X_PATCH_PRODUCT_VERSION_STR) - 1; + break; + } + } + + /* We couldn't find a product version on this patch */ + if (!version_found) + return -EINVAL; + + /* Let's check if the product version is dotted */ + if (version_start[3] != '.' || + version_start[7] != '.') + return -EINVAL; + + version_major = simple_strtoul(version_start, NULL, 10); + version_minor = simple_strtoul(version_start + 4, NULL, 10); + version_build = simple_strtoul(version_start + 8, NULL, 10); + + IRDA_DEBUG(2, "%s(), Major: %ld Minor: %ld Build: %ld\n", + __FUNCTION__, + version_major, version_minor, version_build); + + return (((version_major) << 12) + + ((version_minor) << 8) + + ((version_build / 10) << 4) + + (version_build % 10)); + +} + + +static int stir421x_upload_patch (struct irda_usb_cb *self, + unsigned char * patch, + const unsigned int patch_len) +{ + int retval = 0; + int actual_len; + unsigned int i = 0, download_amount = 0; + unsigned char * patch_chunk; + + IRDA_DEBUG (2, "%s(), Uploading STIR421x Patch\n", __FUNCTION__); + + patch_chunk = kzalloc(STIR421X_MAX_PATCH_DOWNLOAD_SIZE, GFP_KERNEL); + if (patch_chunk == NULL) + return -ENOMEM; + + /* break up patch into 1023-byte sections */ + for (i = 0; retval >= 0 && i < patch_len; i += download_amount) { + download_amount = patch_len - i; + if (download_amount > STIR421X_MAX_PATCH_DOWNLOAD_SIZE) + download_amount = STIR421X_MAX_PATCH_DOWNLOAD_SIZE; + + /* download the patch section */ + memcpy(patch_chunk, patch + i, download_amount); + + retval = usb_bulk_msg (self->usbdev, + usb_sndbulkpipe (self->usbdev, + self->bulk_out_ep), + patch_chunk, download_amount, + &actual_len, msecs_to_jiffies (500)); + IRDA_DEBUG (2, "%s(), Sent %u bytes\n", __FUNCTION__, + actual_len); + if (retval == 0) + mdelay(10); + } + + kfree(patch_chunk); + + if (i != patch_len) { + IRDA_ERROR ("%s(), Pushed %d bytes (!= patch_len (%d))\n", + __FUNCTION__, i, patch_len); + retval = -EIO; + } + + if (retval < 0) + /* todo - mark device as not ready */ + IRDA_ERROR ("%s(), STIR421x patch upload failed (%d)\n", + __FUNCTION__, retval); + + return retval; +} + + +static int stir421x_patch_device(struct irda_usb_cb *self) +{ + unsigned int i, patch_found = 0, data_found = 0, data_offset; + int patch_version, ret = 0; + const struct firmware *fw_entry; + + for (i = 0; i < ARRAY_SIZE(stir421x_patches); i++) { + if(request_firmware(&fw_entry, stir421x_patches[i], &self->usbdev->dev) != 0) { + IRDA_ERROR( "%s(), Patch %s is not available\n", __FUNCTION__, stir421x_patches[i]); + continue; + } + + /* We found a patch from userspace */ + patch_version = stir421x_get_patch_version (fw_entry->data, fw_entry->size); + + if (patch_version < 0) { + /* Couldn't fetch a version, let's move on to the next file */ + IRDA_ERROR("%s(), version parsing failed\n", __FUNCTION__); + ret = patch_version; + release_firmware(fw_entry); + continue; + } + + if (patch_version != self->usbdev->descriptor.bcdDevice) { + /* Patch version and device don't match */ + IRDA_ERROR ("%s(), wrong patch version (%d <-> %d)\n", + __FUNCTION__, + patch_version, self->usbdev->descriptor.bcdDevice); + ret = -EINVAL; + release_firmware(fw_entry); + continue; + } + + /* If we're here, we've found a correct patch */ + patch_found = 1; + break; + + } + + /* We couldn't find a valid firmware, let's leave */ + if (!patch_found) + return ret; + + /* The actual image starts after the "STMP" keyword */ + for (data_offset = 0; data_offset < STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET; data_offset++) { + if (!memcmp(fw_entry->data + data_offset, + STIR421X_PATCH_DATA_TAG_STR, + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))) { + IRDA_DEBUG(2, "%s(), found patch data for STIR421x at offset %d\n", + __FUNCTION__, data_offset); + data_found = 1; + break; + } + } + + /* We couldn't find "STMP" from the header */ + if (!data_found) + return -EINVAL; + + /* Let's upload the patch to the target */ + ret = stir421x_upload_patch(self, + &fw_entry->data[data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET)], + fw_entry->size - (data_offset + sizeof(STIR421X_PATCH_FILE_IMAGE_MAX_OFFSET))); + + release_firmware(fw_entry); + + return ret; + +} + + /********************** IRDA DEVICE CALLBACKS **********************/ /* * Main calls from the IrDA/Network subsystem. @@ -972,6 +1242,11 @@ static int irda_usb_net_open(struct net_device *netdev) return -1; } + if(self->needspatch) { + IRDA_WARNING("%s(), device needs patch\n", __FUNCTION__) ; + return -EIO ; + } + /* Initialise default speed and xbofs value * (IrLAP will change that soon) */ self->speed = -1; @@ -1050,7 +1325,7 @@ static int irda_usb_net_close(struct net_device *netdev) del_timer(&self->rx_defer_timer); /* Deallocate all the Rx path buffers (URBs and skb) */ - for (i = 0; i < IU_MAX_RX_URBS; i++) { + for (i = 0; i < self->max_rx_urb; i++) { struct urb *urb = self->rx_urb[i]; struct sk_buff *skb = (struct sk_buff *) urb->context; /* Cancel the receive command */ @@ -1426,8 +1701,22 @@ static int irda_usb_probe(struct usb_interface *intf, spin_lock_init(&self->lock); init_timer(&self->rx_defer_timer); + self->capability = id->driver_info; + self->needspatch = ((self->capability & IUC_STIR_4210) != 0) ; + /* Create all of the needed urbs */ - for (i = 0; i < IU_MAX_RX_URBS; i++) { + if (self->capability & IUC_STIR_4210) { + self->max_rx_urb = IU_SIGMATEL_MAX_RX_URBS; + self->header_length = USB_IRDA_SIGMATEL_HEADER; + } else { + self->max_rx_urb = IU_MAX_RX_URBS; + self->header_length = USB_IRDA_HEADER; + } + + self->rx_urb = kzalloc(self->max_rx_urb * sizeof(struct urb *), + GFP_KERNEL); + + for (i = 0; i < self->max_rx_urb; i++) { self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL); if (!self->rx_urb[i]) { goto err_out_1; @@ -1479,17 +1768,28 @@ static int irda_usb_probe(struct usb_interface *intf, goto err_out_3; } + self->usbdev = dev; + /* Find IrDA class descriptor */ irda_desc = irda_usb_find_class_desc(intf); ret = -ENODEV; if (irda_desc == NULL) goto err_out_3; + if (self->needspatch) { + ret = usb_control_msg (self->usbdev, usb_sndctrlpipe (self->usbdev, 0), + 0x02, 0x40, 0, 0, 0, 0, msecs_to_jiffies(500)); + if (ret < 0) { + IRDA_DEBUG (0, "usb_control_msg failed %d\n", ret); + goto err_out_3; + } else { + mdelay(10); + } + } + self->irda_desc = irda_desc; self->present = 1; self->netopen = 0; - self->capability = id->driver_info; - self->usbdev = dev; self->usbintf = intf; /* Allocate the buffer for speed changes */ @@ -1508,8 +1808,32 @@ static int irda_usb_probe(struct usb_interface *intf, IRDA_MESSAGE("IrDA: Registered device %s\n", net->name); usb_set_intfdata(intf, self); + + if (self->needspatch) { + /* Now we fetch and upload the firmware patch */ + ret = stir421x_patch_device(self); + self->needspatch = (ret < 0); + if (ret < 0) { + printk("patch_device failed\n"); + goto err_out_5; + } + + /* replace IrDA class descriptor with what patched device is now reporting */ + irda_desc = irda_usb_find_class_desc (self->usbintf); + if (irda_desc == NULL) { + ret = -ENODEV; + goto err_out_5; + } + if (self->irda_desc) + kfree (self->irda_desc); + self->irda_desc = irda_desc; + irda_usb_init_qos(self); + } + return 0; +err_out_5: + unregister_netdev(self->netdev); err_out_4: kfree(self->speed_buff); err_out_3: @@ -1518,7 +1842,7 @@ err_out_3: err_out_2: usb_free_urb(self->tx_urb); err_out_1: - for (i = 0; i < IU_MAX_RX_URBS; i++) { + for (i = 0; i < self->max_rx_urb; i++) { if (self->rx_urb[i]) usb_free_urb(self->rx_urb[i]); } @@ -1571,7 +1895,7 @@ static void irda_usb_disconnect(struct usb_interface *intf) /*netif_device_detach(self->netdev);*/ netif_stop_queue(self->netdev); /* Stop all the receive URBs. Must be synchronous. */ - for (i = 0; i < IU_MAX_RX_URBS; i++) + for (i = 0; i < self->max_rx_urb; i++) usb_kill_urb(self->rx_urb[i]); /* Cancel Tx and speed URB. * Make sure it's synchronous to avoid races. */ @@ -1586,8 +1910,9 @@ static void irda_usb_disconnect(struct usb_interface *intf) self->usbintf = NULL; /* Clean up our urbs */ - for (i = 0; i < IU_MAX_RX_URBS; i++) + for (i = 0; i < self->max_rx_urb; i++) usb_free_urb(self->rx_urb[i]); + kfree(self->rx_urb); /* Clean up Tx and speed URB */ usb_free_urb(self->tx_urb); usb_free_urb(self->speed_urb); @@ -1648,6 +1973,6 @@ module_exit(usb_irda_cleanup); */ module_param(qos_mtt_bits, int, 0); MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time"); -MODULE_AUTHOR("Roman Weissgaerber , Dag Brattli and Jean Tourrilhes "); -MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); +MODULE_AUTHOR("Roman Weissgaerber , Dag Brattli , Jean Tourrilhes and Nick Fedchik "); +MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h index 4026af42dd47..d833db52cebf 100644 --- a/drivers/net/irda/irda-usb.h +++ b/drivers/net/irda/irda-usb.h @@ -1,7 +1,7 @@ /***************************************************************************** * * Filename: irda-usb.h - * Version: 0.9b + * Version: 0.10 * Description: IrDA-USB Driver * Status: Experimental * Author: Dag Brattli @@ -9,6 +9,9 @@ * Copyright (C) 2001, Roman Weissgaerber * Copyright (C) 2000, Dag Brattli * Copyright (C) 2001, Jean Tourrilhes + * Copyright (C) 2004, SigmaTel, Inc. + * Copyright (C) 2005, Milan Beno + * Copyright (C) 2006, Nick FEdchik * * 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 @@ -31,6 +34,9 @@ #include #include /* struct irlap_cb */ +#define PATCH_FILE_SIZE_MAX 65536 +#define PATCH_FILE_SIZE_MIN 80 + #define RX_COPY_THRESHOLD 200 #define IRDA_USB_MAX_MTU 2051 #define IRDA_USB_SPEED_MTU 64 /* Weird, but work like this */ @@ -79,15 +85,16 @@ /* Inbound header */ #define MEDIA_BUSY 0x80 -#define SPEED_2400 0x01 -#define SPEED_9600 0x02 -#define SPEED_19200 0x03 -#define SPEED_38400 0x04 -#define SPEED_57600 0x05 -#define SPEED_115200 0x06 -#define SPEED_576000 0x07 -#define SPEED_1152000 0x08 -#define SPEED_4000000 0x09 +#define SPEED_2400 0x01 +#define SPEED_9600 0x02 +#define SPEED_19200 0x03 +#define SPEED_38400 0x04 +#define SPEED_57600 0x05 +#define SPEED_115200 0x06 +#define SPEED_576000 0x07 +#define SPEED_1152000 0x08 +#define SPEED_4000000 0x09 +#define SPEED_16000000 0x0a /* Basic capabilities */ #define IUC_DEFAULT 0x00 /* Basic device compliant with 1.0 spec */ @@ -100,11 +107,14 @@ #define IUC_SMALL_PKT 0x10 /* Device doesn't behave with big Rx packets */ #define IUC_MAX_WINDOW 0x20 /* Device underestimate the Rx window */ #define IUC_MAX_XBOFS 0x40 /* Device need more xbofs than advertised */ +#define IUC_STIR_4210 0x80 /* SigmaTel 4210/4220/4116 VFIR */ /* USB class definitions */ -#define USB_IRDA_HEADER 0x01 -#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ -#define USB_DT_IRDA 0x21 +#define USB_IRDA_HEADER 0x01 +#define USB_CLASS_IRDA 0x02 /* USB_CLASS_APP_SPEC subclass */ +#define USB_DT_IRDA 0x21 +#define USB_IRDA_SIGMATEL_HEADER 0x03 +#define IU_SIGMATEL_MAX_RX_URBS (IU_MAX_ACTIVE_RX_URBS + USB_IRDA_SIGMATEL_HEADER) struct irda_class_desc { __u8 bLength; @@ -123,6 +133,7 @@ struct irda_class_desc { * (6.2.5, USB-IrDA class spec 1.0) */ #define IU_REQ_GET_CLASS_DESC 0x06 +#define STIR421X_MAX_PATCH_DOWNLOAD_SIZE 1023 struct irda_usb_cb { struct irda_class_desc *irda_desc; @@ -136,7 +147,8 @@ struct irda_usb_cb { __u16 bulk_out_mtu; /* Max Tx packet size in bytes */ __u8 bulk_int_ep; /* Interrupt Endpoint assignments */ - struct urb *rx_urb[IU_MAX_RX_URBS]; /* URBs used to receive data frames */ + __u8 max_rx_urb; + struct urb **rx_urb; /* URBs used to receive data frames */ struct urb *idle_rx_urb; /* Pointer to idle URB in Rx path */ struct urb *tx_urb; /* URB used to send data frames */ struct urb *speed_urb; /* URB used to send speed commands */ @@ -157,6 +169,9 @@ struct irda_usb_cb { __u32 speed; /* Current speed */ __s32 new_speed; /* speed we need to set */ + __u8 header_length; /* USB-IrDA frame header size */ + int needspatch; /* device needs firmware patch */ + struct timer_list rx_defer_timer; /* Wait for Rx error to clear */ }; diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index 63d38fbbd04e..f530686bd09f 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -695,8 +695,7 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) /* * We must not be transmitting... */ - if (si->txskb) - BUG(); + BUG_ON(si->txskb); netif_stop_queue(dev); diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index ec94ecdb103d..58f76cefbc83 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -11,6 +11,7 @@ * Copyright (c) 2002 Daniele Peri * All Rights Reserved. * Copyright (c) 2002 Jean Tourrilhes + * Copyright (c) 2006 Linus Walleij * * * Based on smc-ircc.c: @@ -61,6 +62,9 @@ #include #include +#ifdef CONFIG_PCI +#include +#endif #include #include @@ -100,6 +104,22 @@ MODULE_PARM_DESC(ircc_transceiver, "Transceiver type"); /* Types */ +#ifdef CONFIG_PCI +struct smsc_ircc_subsystem_configuration { + unsigned short vendor; /* PCI vendor ID */ + unsigned short device; /* PCI vendor ID */ + unsigned short subvendor; /* PCI subsystem vendor ID */ + unsigned short subdevice; /* PCI sybsystem device ID */ + unsigned short sir_io; /* I/O port for SIR */ + unsigned short fir_io; /* I/O port for FIR */ + unsigned char fir_irq; /* FIR IRQ */ + unsigned char fir_dma; /* FIR DMA */ + unsigned short cfg_base; /* I/O port for chip configuration */ + int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */ + const char *name; /* name shown as info */ +}; +#endif + struct smsc_transceiver { char *name; void (*set_for_speed)(int fir_base, u32 speed); @@ -202,6 +222,18 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); static int __init smsc_superio_fdc(unsigned short cfg_base); static int __init smsc_superio_lpc(unsigned short cfg_base); +#ifdef CONFIG_PCI +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); +static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static void __init preconfigure_ali_port(struct pci_dev *dev, + unsigned short port); +static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq); +#endif /* Transceivers specific functions */ @@ -353,6 +385,13 @@ static int __init smsc_ircc_init(void) return ret; } +#ifdef CONFIG_PCI + if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) { + /* Ignore errors from preconfiguration */ + IRDA_ERROR("%s, Preconfiguration failed !\n", driver_name); + } +#endif + dev_count = 0; if (ircc_fir > 0 && ircc_sir > 0) { @@ -2285,6 +2324,490 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) return ret; } +/* + * Look for some specific subsystem setups that need + * pre-configuration not properly done by the BIOS (especially laptops) + * This code is based in part on smcinit.c, tosh1800-smcinit.c + * and tosh2450-smcinit.c. The table lists the device entries + * for ISA bridges with an LPC (Low Pin Count) controller which + * handles the communication with the SMSC device. After the LPC + * controller is initialized through PCI, the SMSC device is initialized + * through a dedicated port in the ISA port-mapped I/O area, this latter + * area is used to configure the SMSC device with default + * SIR and FIR I/O ports, DMA and IRQ. Different vendors have + * used different sets of parameters and different control port + * addresses making a subsystem device table necessary. + */ +#ifdef CONFIG_PCI +#define PCIID_VENDOR_INTEL 0x8086 +#define PCIID_VENDOR_ALI 0x10b9 +static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = { + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x088c, + /* Quite certain these are the same for nc8000 as for nc6000 */ + .sir_io = 0x02f8, + .fir_io = 0x0130, + .fir_irq = 0x05, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc8000", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ + .device = 0x24cc, + .subvendor = 0x103c, + .subdevice = 0x0890, + .sir_io = 0x02f8, + .fir_io = 0x0130, + .fir_irq = 0x05, + .fir_dma = 0x03, + .cfg_base = 0x004e, + .preconfigure = preconfigure_through_82801, + .name = "HP nc6000", + }, + { + /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ + .vendor = PCIID_VENDOR_INTEL, + .device = 0x24c0, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x07, + .fir_dma = 0x01, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba laptop with Intel 82801DB/DBL LPC bridge", + }, + { + .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ + .device = 0x248c, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x03, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba laptop with Intel 82801CAM ISA bridge", + }, + { + /* 82801DBM (ICH4-M) LPC Interface Bridge */ + .vendor = PCIID_VENDOR_INTEL, + .device = 0x24cc, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x03f8, + .fir_io = 0x0130, + .fir_irq = 0x03, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_82801, + .name = "Toshiba laptop with Intel 8281DBM LPC bridge", + }, + { + /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ + .vendor = PCIID_VENDOR_ALI, + .device = 0x1533, + .subvendor = 0x1179, + .subdevice = 0xffff, /* 0xffff is "any" */ + .sir_io = 0x02e8, + .fir_io = 0x02f8, + .fir_irq = 0x07, + .fir_dma = 0x03, + .cfg_base = 0x002e, + .preconfigure = preconfigure_through_ali, + .name = "Toshiba laptop with ALi ISA bridge", + }, + { } // Terminator +}; + + +/* + * This sets up the basic SMSC parameters + * (FIR port, SIR port, FIR DMA, FIR IRQ) + * through the chip configuration port. + */ +static int __init preconfigure_smsc_chip(struct + smsc_ircc_subsystem_configuration + *conf) +{ + unsigned short iobase = conf->cfg_base; + unsigned char tmpbyte; + + outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state + outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID + tmpbyte = inb(iobase +1); // Read device ID + IRDA_DEBUG(0, + "Detected Chip id: 0x%02x, setting up registers...\n", + tmpbyte); + + /* Disable UART1 and set up SIR I/O port */ + outb(0x24, iobase); // select CR24 - UART1 base addr + outb(0x00, iobase + 1); // disable UART1 + outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr + outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8 + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->sir_io >> 2) ) { + IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); + IRDA_WARNING("Try to supply ircc_cfg argument.\n"); + return -ENXIO; + } + + /* Set up FIR IRQ channel for UART2 */ + outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select + tmpbyte = inb(iobase + 1); + tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion + tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK); + outb(tmpbyte, iobase + 1); + tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; + if (tmpbyte != conf->fir_irq) { + IRDA_WARNING("ERROR: could not configure FIR IRQ channel.\n"); + return -ENXIO; + } + + /* Set up FIR I/O port */ + outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr + outb((conf->fir_io >> 3), iobase + 1); + tmpbyte = inb(iobase + 1); + if (tmpbyte != (conf->fir_io >> 3) ) { + IRDA_WARNING("ERROR: could not configure FIR I/O port.\n"); + return -ENXIO; + } + + /* Set up FIR DMA channel */ + outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select + outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA + tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK; + if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) { + IRDA_WARNING("ERROR: could not configure FIR DMA channel.\n"); + return -ENXIO; + } + + outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode + tmpbyte = inb(iobase + 1); + tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | + SMSCSIOFLAT_UART2MODE_VAL_IRDA; + outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed + + outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down + + /* This one was not part of tosh1800 */ + outb(0x0a, iobase); // CR0a - ecp fifo / ir mux + tmpbyte = inb(iobase + 1); + outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port + + outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down + + outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle + tmpbyte = inb(iobase + 1); + outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done + + outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration + + return 0; +} + +/* 82801CAM generic registers */ +#define VID 0x00 +#define DID 0x02 +#define PIRQ_A_D_ROUT 0x60 +#define SIRQ_CNTL 0x64 +#define PIRQ_E_H_ROUT 0x68 +#define PCI_DMA_C 0x90 +/* LPC-specific registers */ +#define COM_DEC 0xe0 +#define GEN1_DEC 0xe4 +#define LPC_EN 0xe6 +#define GEN2_DEC 0xec +/* + * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge + * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. + * They all work the same way! + */ +static int __init preconfigure_through_82801(struct pci_dev *dev, + struct + smsc_ircc_subsystem_configuration + *conf) +{ + unsigned short tmpword; + unsigned char tmpbyte; + + IRDA_MESSAGE("Setting up Intel 82801 controller and SMSC device\n"); + /* + * Select the range for the COMA COM port (SIR) + * Register COM_DEC: + * Bit 7: reserved + * Bit 6-4, COMB decode range + * Bit 3: reserved + * Bit 2-0, COMA decode range + * + * Decode ranges: + * 000 = 0x3f8-0x3ff (COM1) + * 001 = 0x2f8-0x2ff (COM2) + * 010 = 0x220-0x227 + * 011 = 0x228-0x22f + * 100 = 0x238-0x23f + * 101 = 0x2e8-0x2ef (COM4) + * 110 = 0x338-0x33f + * 111 = 0x3e8-0x3ef (COM3) + */ + pci_read_config_byte(dev, COM_DEC, &tmpbyte); + tmpbyte &= 0xf8; /* mask COMA bits */ + switch(conf->sir_io) { + case 0x3f8: + tmpbyte |= 0x00; + break; + case 0x2f8: + tmpbyte |= 0x01; + break; + case 0x220: + tmpbyte |= 0x02; + break; + case 0x228: + tmpbyte |= 0x03; + break; + case 0x238: + tmpbyte |= 0x04; + break; + case 0x2e8: + tmpbyte |= 0x05; + break; + case 0x338: + tmpbyte |= 0x06; + break; + case 0x3e8: + tmpbyte |= 0x07; + break; + default: + tmpbyte |= 0x01; /* COM2 default */ + } + IRDA_DEBUG(1, "COM_DEC (write): 0x%02x\n", tmpbyte); + pci_write_config_byte(dev, COM_DEC, tmpbyte); + + /* Enable Low Pin Count interface */ + pci_read_config_word(dev, LPC_EN, &tmpword); + /* These seem to be set up at all times, + * just make sure it is properly set. + */ + switch(conf->cfg_base) { + case 0x04e: + tmpword |= 0x2000; + break; + case 0x02e: + tmpword |= 0x1000; + break; + case 0x062: + tmpword |= 0x0800; + break; + case 0x060: + tmpword |= 0x0400; + break; + default: + IRDA_WARNING("Uncommon I/O base address: 0x%04x\n", + conf->cfg_base); + break; + } + tmpword &= 0xfffd; /* disable LPC COMB */ + tmpword |= 0x0001; /* set bit 0 : enable LPC COMA addr range (GEN2) */ + IRDA_DEBUG(1, "LPC_EN (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, LPC_EN, tmpword); + + /* + * Configure LPC DMA channel + * PCI_DMA_C bits: + * Bit 15-14: DMA channel 7 select + * Bit 13-12: DMA channel 6 select + * Bit 11-10: DMA channel 5 select + * Bit 9-8: Reserved + * Bit 7-6: DMA channel 3 select + * Bit 5-4: DMA channel 2 select + * Bit 3-2: DMA channel 1 select + * Bit 1-0: DMA channel 0 select + * 00 = Reserved value + * 01 = PC/PCI DMA + * 10 = Reserved value + * 11 = LPC I/F DMA + */ + pci_read_config_word(dev, PCI_DMA_C, &tmpword); + switch(conf->fir_dma) { + case 0x07: + tmpword |= 0xc000; + break; + case 0x06: + tmpword |= 0x3000; + break; + case 0x05: + tmpword |= 0x0c00; + break; + case 0x03: + tmpword |= 0x00c0; + break; + case 0x02: + tmpword |= 0x0030; + break; + case 0x01: + tmpword |= 0x000c; + break; + case 0x00: + tmpword |= 0x0003; + break; + default: + break; /* do not change settings */ + } + IRDA_DEBUG(1, "PCI_DMA_C (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, PCI_DMA_C, tmpword); + + /* + * GEN2_DEC bits: + * Bit 15-4: Generic I/O range + * Bit 3-1: reserved (read as 0) + * Bit 0: enable GEN2 range on LPC I/F + */ + tmpword = conf->fir_io & 0xfff8; + tmpword |= 0x0001; + IRDA_DEBUG(1, "GEN2_DEC (write): 0x%04x\n", tmpword); + pci_write_config_word(dev, GEN2_DEC, tmpword); + + /* Pre-configure chip */ + return preconfigure_smsc_chip(conf); +} + +/* + * Pre-configure a certain port on the ALi 1533 bridge. + * This is based on reverse-engineering since ALi does not + * provide any data sheet for the 1533 chip. + */ +static void __init preconfigure_ali_port(struct pci_dev *dev, + unsigned short port) +{ + unsigned char reg; + /* These bits obviously control the different ports */ + unsigned char mask; + unsigned char tmpbyte; + + switch(port) { + case 0x0130: + case 0x0178: + reg = 0xb0; + mask = 0x80; + break; + case 0x03f8: + reg = 0xb4; + mask = 0x80; + break; + case 0x02f8: + reg = 0xb4; + mask = 0x30; + break; + case 0x02e8: + reg = 0xb4; + mask = 0x08; + break; + default: + IRDA_ERROR("Failed to configure unsupported port on ALi 1533 bridge: 0x%04x\n", port); + return; + } + + pci_read_config_byte(dev, reg, &tmpbyte); + /* Turn on the right bits */ + tmpbyte |= mask; + pci_write_config_byte(dev, reg, tmpbyte); + IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); + return; +} + +static int __init preconfigure_through_ali(struct pci_dev *dev, + struct + smsc_ircc_subsystem_configuration + *conf) +{ + /* Configure the two ports on the ALi 1533 */ + preconfigure_ali_port(dev, conf->sir_io); + preconfigure_ali_port(dev, conf->fir_io); + + /* Pre-configure chip */ + return preconfigure_smsc_chip(conf); +} + +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, + unsigned short ircc_fir, + unsigned short ircc_sir, + unsigned char ircc_dma, + unsigned char ircc_irq) +{ + struct pci_dev *dev = NULL; + unsigned short ss_vendor = 0x0000; + unsigned short ss_device = 0x0000; + int ret = 0; + + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + + while (dev != NULL) { + struct smsc_ircc_subsystem_configuration *conf; + + /* + * Cache the subsystem vendor/device: + * some manufacturers fail to set this for all components, + * so we save it in case there is just 0x0000 0x0000 on the + * device we want to check. + */ + if (dev->subsystem_vendor != 0x0000U) { + ss_vendor = dev->subsystem_vendor; + ss_device = dev->subsystem_device; + } + conf = subsystem_configurations; + for( ; conf->subvendor; conf++) { + if(conf->vendor == dev->vendor && + conf->device == dev->device && + conf->subvendor == ss_vendor && + /* Sometimes these are cached values */ + (conf->subdevice == ss_device || + conf->subdevice == 0xffff)) { + struct smsc_ircc_subsystem_configuration + tmpconf; + + memcpy(&tmpconf, conf, + sizeof(struct smsc_ircc_subsystem_configuration)); + + /* + * Override the default values with anything + * passed in as parameter + */ + if (ircc_cfg != 0) + tmpconf.cfg_base = ircc_cfg; + if (ircc_fir != 0) + tmpconf.fir_io = ircc_fir; + if (ircc_sir != 0) + tmpconf.sir_io = ircc_sir; + if (ircc_dma != 0xff) + tmpconf.fir_dma = ircc_dma; + if (ircc_irq != 0xff) + tmpconf.fir_irq = ircc_irq; + + IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name); + if (conf->preconfigure) + ret = conf->preconfigure(dev, &tmpconf); + else + ret = -ENODEV; + } + } + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + } + + return ret; +} +#endif // CONFIG_PCI + /************************************************ * * Transceivers specific functions diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index f9f77e4f5965..cfd67d812f0d 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -357,18 +357,20 @@ ixgb_probe(struct pci_dev *pdev, if((err = pci_enable_device(pdev))) return err; - if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + if(!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && + !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { pci_using_dac = 1; } else { - if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { + if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) || + (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) { IXGB_ERR("No usable DMA configuration, aborting\n"); - return err; + goto err_dma_mask; } pci_using_dac = 0; } if((err = pci_request_regions(pdev, ixgb_driver_name))) - return err; + goto err_request_regions; pci_set_master(pdev); @@ -502,6 +504,9 @@ err_ioremap: free_netdev(netdev); err_alloc_etherdev: pci_release_regions(pdev); +err_request_regions: +err_dma_mask: + pci_disable_device(pdev); return err; } diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 77f104a005f3..fbc2d21020f4 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -299,10 +299,7 @@ int ixpdev_init(int __nds_count, struct net_device **__nds, int i; int err; - if (RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192) { - static void __too_many_rx_or_tx_buffers(void); - __too_many_rx_or_tx_buffers(); - } + BUILD_BUG_ON(RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192); printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 9f2661355a4a..ea62a3e7d586 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -281,10 +281,16 @@ static void mv643xx_eth_tx_timeout_task(struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); - netif_device_detach(dev); + if (!netif_running(dev)) + return; + + netif_stop_queue(dev); + eth_port_reset(mp->port_num); eth_port_start(dev); - netif_device_attach(dev); + + if (mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB) + netif_wake_queue(dev); } /** @@ -552,9 +558,9 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, #else if (eth_int_cause & ETH_INT_CAUSE_RX) mv643xx_eth_receive_queue(dev, INT_MAX); +#endif if (eth_int_cause_ext & ETH_INT_CAUSE_TX) mv643xx_eth_free_completed_tx_descs(dev); -#endif /* * If no real interrupt occured, exit. @@ -1186,7 +1192,12 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(netif_queue_stopped(dev)); BUG_ON(skb == NULL); - BUG_ON(mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB); + + if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) { + printk(KERN_ERR "%s: transmit with queue full\n", dev->name); + netif_stop_queue(dev); + return 1; + } if (has_tiny_unaligned_frags(skb)) { if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 8d4999837b65..90627756d6fa 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -226,7 +226,7 @@ static int full_duplex[MAX_UNITS]; NATSEMI_PG1_NREGS) #define NATSEMI_REGS_VER 1 /* v1 added RFDR registers */ #define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32)) -#define NATSEMI_EEPROM_SIZE 24 /* 12 16-bit values */ +#define NATSEMI_DEF_EEPROM_SIZE 24 /* 12 16-bit values */ /* Buffer sizes: * The nic writes 32-bit values, even if the upper bytes of @@ -238,7 +238,7 @@ static int full_duplex[MAX_UNITS]; #define NATSEMI_RX_LIMIT 2046 /* maximum supported by hardware */ /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static const char version[] __devinitdata = KERN_INFO DRV_NAME " dp8381x driver, version " DRV_VERSION ", " DRV_RELDATE "\n" KERN_INFO " originally by Donald Becker \n" @@ -714,6 +714,8 @@ struct netdev_private { unsigned int iosize; spinlock_t lock; u32 msg_enable; + /* EEPROM data */ + int eeprom_size; }; static void move_int_phy(struct net_device *dev, int addr); @@ -890,6 +892,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, np->msg_enable = (debug >= 0) ? (1<hands_off = 0; np->intr_status = 0; + np->eeprom_size = NATSEMI_DEF_EEPROM_SIZE; /* Initial port: * - If the nic was configured to use an external phy and if find_mii @@ -2582,7 +2585,8 @@ static int get_regs_len(struct net_device *dev) static int get_eeprom_len(struct net_device *dev) { - return NATSEMI_EEPROM_SIZE; + struct netdev_private *np = netdev_priv(dev); + return np->eeprom_size; } static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) @@ -2669,15 +2673,20 @@ static u32 get_link(struct net_device *dev) static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { struct netdev_private *np = netdev_priv(dev); - u8 eebuf[NATSEMI_EEPROM_SIZE]; + u8 *eebuf; int res; + eebuf = kmalloc(np->eeprom_size, GFP_KERNEL); + if (!eebuf) + return -ENOMEM; + eeprom->magic = PCI_VENDOR_ID_NS | (PCI_DEVICE_ID_NS_83815<<16); spin_lock_irq(&np->lock); res = netdev_get_eeprom(dev, eebuf); spin_unlock_irq(&np->lock); if (!res) memcpy(data, eebuf+eeprom->offset, eeprom->len); + kfree(eebuf); return res; } @@ -3033,9 +3042,10 @@ static int netdev_get_eeprom(struct net_device *dev, u8 *buf) int i; u16 *ebuf = (u16 *)buf; void __iomem * ioaddr = ns_ioaddr(dev); + struct netdev_private *np = netdev_priv(dev); /* eeprom_read reads 16 bits, and indexes by 16 bits */ - for (i = 0; i < NATSEMI_EEPROM_SIZE/2; i++) { + for (i = 0; i < np->eeprom_size/2; i++) { ebuf[i] = eeprom_read(ioaddr, i); /* The EEPROM itself stores data bit-swapped, but eeprom_read * reads it back "sanely". So we swap it back here in order to diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index d11821dd86ed..ced9fdb8335c 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -645,9 +645,7 @@ static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - if (!dev) - BUG(); - + BUG_ON(!dev); unregister_netdev(dev); release_region(dev->base_addr, NE_IO_EXTENT); free_netdev(dev); diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index edd1b5306b16..66e74f740261 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -87,6 +87,7 @@ static void write_msg(struct console *con, const char *msg, unsigned int len) } static struct console netconsole = { + .name = "netcon", .flags = CON_ENABLED | CON_PRINTBUFFER, .write = write_msg }; @@ -94,7 +95,7 @@ static struct console netconsole = { static int option_setup(char *opt) { configured = !netpoll_parse_options(&np, opt); - return 0; + return 1; } __setup("netconsole=", option_setup); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 8e9b1a537dee..706aed7d717f 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -568,8 +568,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb) #endif sg = dev->rx_info.descs + (next_empty * DESC_SIZE); - if (unlikely(NULL != dev->rx_info.skbs[next_empty])) - BUG(); + BUG_ON(NULL != dev->rx_info.skbs[next_empty]); dev->rx_info.skbs[next_empty] = skb; dev->rx_info.next_empty = (next_empty + 1) % NR_RX_DESC; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index ce90becb8bdf..fab93360f017 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -204,7 +204,7 @@ enum Window4 { /* Window 4: Xcvr/media bits. */ #define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ struct el3_private { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct net_device_stats stats; u16 advertising, partner; /* NWay media advertisement */ @@ -225,8 +225,8 @@ static char mii_preamble_required = 0; /* Index of functions. */ -static void tc574_config(dev_link_t *link); -static void tc574_release(dev_link_t *link); +static int tc574_config(struct pcmcia_device *link); +static void tc574_release(struct pcmcia_device *link); static void mdio_sync(kio_addr_t ioaddr, int bits); static int mdio_read(kio_addr_t ioaddr, int phy_id, int location); @@ -256,10 +256,9 @@ static void tc574_detach(struct pcmcia_device *p_dev); with Card Services. */ -static int tc574_attach(struct pcmcia_device *p_dev) +static int tc574_probe(struct pcmcia_device *link) { struct el3_private *lp; - dev_link_t *link; struct net_device *dev; DEBUG(0, "3c574_attach()\n"); @@ -269,8 +268,8 @@ static int tc574_attach(struct pcmcia_device *p_dev) if (!dev) return -ENOMEM; lp = netdev_priv(dev); - link = &lp->link; link->priv = dev; + lp->p_dev = link; spin_lock_init(&lp->window_lock); link->io.NumPorts1 = 32; @@ -280,7 +279,6 @@ static int tc574_attach(struct pcmcia_device *p_dev) link->irq.Handler = &el3_interrupt; link->irq.Instance = dev; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; @@ -298,13 +296,7 @@ static int tc574_attach(struct pcmcia_device *p_dev) dev->watchdog_timeo = TX_TIMEOUT; #endif - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - tc574_config(link); - - return 0; + return tc574_config(link); } /* tc574_attach */ /* @@ -316,18 +308,16 @@ static int tc574_attach(struct pcmcia_device *p_dev) */ -static void tc574_detach(struct pcmcia_device *p_dev) +static void tc574_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "3c574_detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - if (link->state & DEV_CONFIG) - tc574_release(link); + tc574_release(link); free_netdev(dev); } /* tc574_detach */ @@ -343,9 +333,8 @@ static void tc574_detach(struct pcmcia_device *p_dev) static const char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; -static void tc574_config(dev_link_t *link) +static int tc574_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; struct el3_private *lp = netdev_priv(dev); tuple_t tuple; @@ -363,30 +352,27 @@ static void tc574_config(dev_link_t *link) tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - link->io.IOAddrLines = 16; for (i = j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); goto failed; } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -397,8 +383,8 @@ static void tc574_config(dev_link_t *link) the hardware address. The future products may include a modem chip and put the address in the CIS. */ tuple.DesiredTuple = 0x88; - if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) { - pcmcia_get_tuple_data(handle, &tuple); + if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) { + pcmcia_get_tuple_data(link, &tuple); for (i = 0; i < 3; i++) phys_addr[i] = htons(buf[i]); } else { @@ -412,9 +398,9 @@ static void tc574_config(dev_link_t *link) } } tuple.DesiredTuple = CISTPL_VERS_1; - if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS && - pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS && - pcmcia_parse_tuple(handle, &tuple, &parse) == CS_SUCCESS) { + if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS && + pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS && + pcmcia_parse_tuple(link, &tuple, &parse) == CS_SUCCESS) { cardname = parse.version_1.str + parse.version_1.ofs[1]; } else cardname = "3Com 3c574"; @@ -473,13 +459,12 @@ static void tc574_config(dev_link_t *link) } } - link->state &= ~DEV_CONFIG_PENDING; - link->dev = &lp->node; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &lp->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto failed; } @@ -493,13 +478,13 @@ static void tc574_config(dev_link_t *link) 8 << config.u.ram_size, ram_split[config.u.ram_split], config.u.autoselect ? "autoselect " : ""); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: tc574_release(link); - return; + return -ENODEV; } /* tc574_config */ @@ -509,44 +494,28 @@ failed: still open, this will be postponed until it is closed. */ -static void tc574_release(dev_link_t *link) +static void tc574_release(struct pcmcia_device *link) { - DEBUG(0, "3c574_release(0x%p)\n", link); - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } -static int tc574_suspend(struct pcmcia_device *p_dev) +static int tc574_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } + if (link->open) + netif_device_detach(dev); return 0; } -static int tc574_resume(struct pcmcia_device *p_dev) +static int tc574_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - tc574_reset(dev); - netif_device_attach(dev); - } + if (link->open) { + tc574_reset(dev); + netif_device_attach(dev); } return 0; @@ -757,9 +726,9 @@ static void tc574_reset(struct net_device *dev) static int el3_open(struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; link->open++; @@ -1203,11 +1172,11 @@ static int el3_close(struct net_device *dev) { kio_addr_t ioaddr = dev->base_addr; struct el3_private *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; DEBUG(2, "%s: shutting down ethercard.\n", dev->name); - if (DEV_OK(link)) { + if (pcmcia_dev_present(link)) { unsigned long flags; /* Turn off statistics ASAP. We update lp->stats below. */ @@ -1246,7 +1215,7 @@ static struct pcmcia_driver tc574_driver = { .drv = { .name = "3c574_cs", }, - .probe = tc574_attach, + .probe = tc574_probe, .remove = tc574_detach, .id_table = tc574_ids, .suspend = tc574_suspend, diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 3dba50849da7..875a0fe251e7 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -105,7 +105,7 @@ enum RxFilter { #define TX_TIMEOUT ((400*HZ)/1000) struct el3_private { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct net_device_stats stats; /* For transceiver monitoring */ @@ -142,8 +142,8 @@ DRV_NAME ".c " DRV_VERSION " 2001/10/13 00:08:50 (David Hinds)"; /*====================================================================*/ -static void tc589_config(dev_link_t *link); -static void tc589_release(dev_link_t *link); +static int tc589_config(struct pcmcia_device *link); +static void tc589_release(struct pcmcia_device *link); static u16 read_eeprom(kio_addr_t ioaddr, int index); static void tc589_reset(struct net_device *dev); @@ -170,10 +170,9 @@ static void tc589_detach(struct pcmcia_device *p_dev); ======================================================================*/ -static int tc589_attach(struct pcmcia_device *p_dev) +static int tc589_probe(struct pcmcia_device *link) { struct el3_private *lp; - dev_link_t *link; struct net_device *dev; DEBUG(0, "3c589_attach()\n"); @@ -183,8 +182,8 @@ static int tc589_attach(struct pcmcia_device *p_dev) if (!dev) return -ENOMEM; lp = netdev_priv(dev); - link = &lp->link; link->priv = dev; + lp->p_dev = link; spin_lock_init(&lp->lock); link->io.NumPorts1 = 16; @@ -194,7 +193,6 @@ static int tc589_attach(struct pcmcia_device *p_dev) link->irq.Handler = &el3_interrupt; link->irq.Instance = dev; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; @@ -213,13 +211,7 @@ static int tc589_attach(struct pcmcia_device *p_dev) #endif SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - tc589_config(link); - - return 0; + return tc589_config(link); } /* tc589_attach */ /*====================================================================== @@ -231,18 +223,16 @@ static int tc589_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void tc589_detach(struct pcmcia_device *p_dev) +static void tc589_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "3c589_detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - if (link->state & DEV_CONFIG) - tc589_release(link); + tc589_release(link); free_netdev(dev); } /* tc589_detach */ @@ -258,9 +248,8 @@ static void tc589_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void tc589_config(dev_link_t *link) +static int tc589_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; struct el3_private *lp = netdev_priv(dev); tuple_t tuple; @@ -275,43 +264,40 @@ static void tc589_config(dev_link_t *link) phys_addr = (u16 *)dev->dev_addr; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Is this a 3c562? */ tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; - if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && - (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) { + if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && + (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) { if (le16_to_cpu(buf[0]) != MANFID_3COM) printk(KERN_INFO "3c589_cs: hmmm, is this really a " "3Com card??\n"); multi = (le16_to_cpu(buf[1]) == PRODID_3COM_3C562); } - - /* Configure card */ - link->state |= DEV_CONFIG; /* For the 3c562, the base address must be xx00-xx7f */ link->io.IOAddrLines = 16; for (i = j = 0; j < 0x400; j += 0x10) { if (multi && (j & 0x80)) continue; link->io.BasePort1 = j ^ 0x300; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); goto failed; } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -321,8 +307,8 @@ static void tc589_config(dev_link_t *link) /* The 3c589 has an extra EEPROM for configuration info, including the hardware address. The 3c562 puts the address in the CIS. */ tuple.DesiredTuple = 0x88; - if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) { - pcmcia_get_tuple_data(handle, &tuple); + if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) { + pcmcia_get_tuple_data(link, &tuple); for (i = 0; i < 3; i++) phys_addr[i] = htons(buf[i]); } else { @@ -346,13 +332,12 @@ static void tc589_config(dev_link_t *link) else printk(KERN_ERR "3c589_cs: invalid if_port requested\n"); - link->dev = &lp->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &lp->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); if (register_netdev(dev) != 0) { printk(KERN_ERR "3c589_cs: register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto failed; } @@ -366,14 +351,13 @@ static void tc589_config(dev_link_t *link) printk(KERN_INFO " %dK FIFO split %s Rx:Tx, %s xcvr\n", (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], if_names[dev->if_port]); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: tc589_release(link); - return; - + return -ENODEV; } /* tc589_config */ /*====================================================================== @@ -384,44 +368,28 @@ failed: ======================================================================*/ -static void tc589_release(dev_link_t *link) +static void tc589_release(struct pcmcia_device *link) { - DEBUG(0, "3c589_release(0x%p)\n", link); - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } -static int tc589_suspend(struct pcmcia_device *p_dev) +static int tc589_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } + if (link->open) + netif_device_detach(dev); return 0; } -static int tc589_resume(struct pcmcia_device *p_dev) +static int tc589_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - tc589_reset(dev); - netif_device_attach(dev); - } + if (link->open) { + tc589_reset(dev); + netif_device_attach(dev); } return 0; @@ -587,9 +555,9 @@ static int el3_config(struct net_device *dev, struct ifmap *map) static int el3_open(struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; link->open++; @@ -848,9 +816,9 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); unsigned long flags; - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; - if (DEV_OK(link)) { + if (pcmcia_dev_present(link)) { spin_lock_irqsave(&lp->lock, flags); update_stats(dev); spin_unlock_irqrestore(&lp->lock, flags); @@ -950,11 +918,11 @@ static int el3_rx(struct net_device *dev) static void set_multicast_list(struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; kio_addr_t ioaddr = dev->base_addr; u16 opts = SetRxFilter | RxStation | RxBroadcast; - if (!(DEV_OK(link))) return; + if (!pcmcia_dev_present(link)) return; if (dev->flags & IFF_PROMISC) opts |= RxMulticast | RxProm; else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) @@ -965,12 +933,12 @@ static void set_multicast_list(struct net_device *dev) static int el3_close(struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; kio_addr_t ioaddr = dev->base_addr; DEBUG(1, "%s: shutting down ethercard.\n", dev->name); - if (DEV_OK(link)) { + if (pcmcia_dev_present(link)) { /* Turn off statistics ASAP. We update lp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -1020,7 +988,7 @@ static struct pcmcia_driver tc589_driver = { .drv = { .name = "3c589_cs", }, - .probe = tc589_attach, + .probe = tc589_probe, .remove = tc589_detach, .id_table = tc589_ids, .suspend = tc589_suspend, diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index aa5581369399..448a09488529 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "../8390.h" #include @@ -85,8 +86,8 @@ static char *version = /*====================================================================*/ -static void axnet_config(dev_link_t *link); -static void axnet_release(dev_link_t *link); +static int axnet_config(struct pcmcia_device *link); +static void axnet_release(struct pcmcia_device *link); static int axnet_open(struct net_device *dev); static int axnet_close(struct net_device *dev); static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -116,7 +117,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs *regs); /*====================================================================*/ typedef struct axnet_dev_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; caddr_t base; struct timer_list watchdog; @@ -141,10 +142,9 @@ static inline axnet_dev_t *PRIV(struct net_device *dev) ======================================================================*/ -static int axnet_attach(struct pcmcia_device *p_dev) +static int axnet_probe(struct pcmcia_device *link) { axnet_dev_t *info; - dev_link_t *link; struct net_device *dev; DEBUG(0, "axnet_attach()\n"); @@ -156,7 +156,7 @@ static int axnet_attach(struct pcmcia_device *p_dev) return -ENOMEM; info = PRIV(dev); - link = &info->link; + info->p_dev = link; link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; @@ -168,13 +168,7 @@ static int axnet_attach(struct pcmcia_device *p_dev) dev->do_ioctl = &axnet_ioctl; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - axnet_config(link); - - return 0; + return axnet_config(link); } /* axnet_attach */ /*====================================================================== @@ -186,18 +180,16 @@ static int axnet_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void axnet_detach(struct pcmcia_device *p_dev) +static void axnet_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "axnet_detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - if (link->state & DEV_CONFIG) - axnet_release(link); + axnet_release(link); free_netdev(dev); } /* axnet_detach */ @@ -208,7 +200,7 @@ static void axnet_detach(struct pcmcia_device *p_dev) ======================================================================*/ -static int get_prom(dev_link_t *link) +static int get_prom(struct pcmcia_device *link) { struct net_device *dev = link->priv; kio_addr_t ioaddr = dev->base_addr; @@ -262,7 +254,7 @@ static int get_prom(dev_link_t *link) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static int try_io_port(dev_link_t *link) +static int try_io_port(struct pcmcia_device *link) { int j, ret; if (link->io.NumPorts1 == 32) { @@ -283,25 +275,23 @@ static int try_io_port(dev_link_t *link) for (j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; link->io.BasePort2 = (j ^ 0x300) + 0x10; - ret = pcmcia_request_io(link->handle, &link->io); + ret = pcmcia_request_io(link, &link->io); if (ret == CS_SUCCESS) return ret; } return ret; } else { - return pcmcia_request_io(link->handle, &link->io); + return pcmcia_request_io(link, &link->io); } } -static void axnet_config(dev_link_t *link) +static int axnet_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; axnet_dev_t *info = PRIV(dev); tuple_t tuple; cisparse_t parse; int i, j, last_ret, last_fn; u_short buf[64]; - config_info_t conf; DEBUG(0, "axnet_config(0x%p)\n", link); @@ -310,29 +300,22 @@ static void axnet_config(dev_link_t *link) tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; /* don't trust the CIS on this; Linksys got it wrong */ link->conf.Present = 0x63; - /* Configure card */ - link->state |= DEV_CONFIG; - - /* Look up current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (last_ret == CS_SUCCESS) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_io_t *io = &(parse.cftable_entry.io); - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0 || + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0 || cfg->index == 0 || cfg->io.nwin == 0) goto next_entry; @@ -354,21 +337,21 @@ static void axnet_config(dev_link_t *link) if (last_ret == CS_SUCCESS) break; } next_entry: - last_ret = pcmcia_get_next_tuple(handle, &tuple); + last_ret = pcmcia_get_next_tuple(link, &tuple); } if (last_ret != CS_SUCCESS) { - cs_error(handle, RequestIO, last_ret); + cs_error(link, RequestIO, last_ret); goto failed; } - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); if (link->io.NumPorts2 == 8) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -405,7 +388,7 @@ static void axnet_config(dev_link_t *link) Bit 2 of CCSR is active low. */ if (i == 32) { conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 }; - pcmcia_access_configuration_register(link->handle, ®); + pcmcia_access_configuration_register(link, ®); for (i = 0; i < 32; i++) { j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); if ((j != 0) && (j != 0xffff)) break; @@ -413,13 +396,12 @@ static void axnet_config(dev_link_t *link) } info->phy_id = (i < 32) ? i : -1; - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &info->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto failed; } @@ -435,14 +417,13 @@ static void axnet_config(dev_link_t *link) } else { printk(KERN_NOTICE " No MII transceivers found!\n"); } - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: axnet_release(link); - link->state &= ~DEV_CONFIG_PENDING; - return; + return -ENODEV; } /* axnet_config */ /*====================================================================== @@ -453,45 +434,29 @@ failed: ======================================================================*/ -static void axnet_release(dev_link_t *link) +static void axnet_release(struct pcmcia_device *link) { - DEBUG(0, "axnet_release(0x%p)\n", link); - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } -static int axnet_suspend(struct pcmcia_device *p_dev) +static int axnet_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } + if (link->open) + netif_device_detach(dev); return 0; } -static int axnet_resume(struct pcmcia_device *p_dev) +static int axnet_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - axnet_reset_8390(dev); - AX88190_init(dev, 1); - netif_device_attach(dev); - } + if (link->open) { + axnet_reset_8390(dev); + AX88190_init(dev, 1); + netif_device_attach(dev); } return 0; @@ -561,11 +526,11 @@ static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value) static int axnet_open(struct net_device *dev) { axnet_dev_t *info = PRIV(dev); - dev_link_t *link = &info->link; + struct pcmcia_device *link = info->p_dev; DEBUG(2, "axnet_open('%s')\n", dev->name); - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; link->open++; @@ -587,7 +552,7 @@ static int axnet_open(struct net_device *dev) static int axnet_close(struct net_device *dev) { axnet_dev_t *info = PRIV(dev); - dev_link_t *link = &info->link; + struct pcmcia_device *link = info->p_dev; DEBUG(2, "axnet_close('%s')\n", dev->name); @@ -832,7 +797,7 @@ static struct pcmcia_driver axnet_cs_driver = { .drv = { .name = "axnet_cs", }, - .probe = axnet_attach, + .probe = axnet_probe, .remove = axnet_detach, .id_table = axnet_ids, .suspend = axnet_suspend, @@ -1595,7 +1560,7 @@ static void ei_receive(struct net_device *dev) static void ei_rx_overrun(struct net_device *dev) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -1682,17 +1647,67 @@ static struct net_device_stats *get_stats(struct net_device *dev) return &ei_local->stat; } +/* + * Form the 64 bit 8390 multicast table from the linked list of addresses + * associated with this dev structure. + */ + +static inline void make_mc_bits(u8 *bits, struct net_device *dev) +{ + struct dev_mc_list *dmi; + u32 crc; + + for (dmi=dev->mc_list; dmi; dmi=dmi->next) { + + crc = ether_crc(ETH_ALEN, dmi->dmi_addr); + /* + * The 8390 uses the 6 most significant bits of the + * CRC to index the multicast table. + */ + bits[crc>>29] |= (1<<((crc>>26)&7)); + } +} + /** * do_set_multicast_list - set/clear multicast filter * @dev: net device for which multicast filter is adjusted * - * Set or clear the multicast filter for this adaptor. May be called - * from a BH in 2.1.x. Must be called with lock held. + * Set or clear the multicast filter for this adaptor. + * Must be called with lock held. */ static void do_set_multicast_list(struct net_device *dev) { long e8390_base = dev->base_addr; + int i; + struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); + + if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { + memset(ei_local->mcfilter, 0, 8); + if (dev->mc_list) + make_mc_bits(ei_local->mcfilter, dev); + } else { + /* set to accept-all */ + memset(ei_local->mcfilter, 0xFF, 8); + } + + /* + * DP8390 manuals don't specify any magic sequence for altering + * the multicast regs on an already running card. To be safe, we + * ensure multicast mode is off prior to loading up the new hash + * table. If this proves to be not enough, we can always resort + * to stopping the NIC, loading the table and then restarting. + */ + + if (netif_running(dev)) + outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); + + outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD); + for(i = 0; i < 8; i++) + { + outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i)); + } + outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD); if(dev->flags&IFF_PROMISC) outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR); @@ -1794,12 +1809,6 @@ static void AX88190_init(struct net_device *dev, int startp) if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i]) printk(KERN_ERR "Hw. address read/write mismap %d\n",i); } - /* - * Initialize the multicast list to accept-all. If we enable multicast - * the higher levels can do the filtering. - */ - for (i = 0; i < 8; i++) - outb_p(0xff, e8390_base + EN1_MULT + i); outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 2827a48ea37c..441de824ab6b 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -118,8 +118,8 @@ MODULE_LICENSE("GPL"); /*====================================================================*/ -static void com20020_config(dev_link_t *link); -static void com20020_release(dev_link_t *link); +static int com20020_config(struct pcmcia_device *link); +static void com20020_release(struct pcmcia_device *link); static void com20020_detach(struct pcmcia_device *p_dev); @@ -138,9 +138,8 @@ typedef struct com20020_dev_t { ======================================================================*/ -static int com20020_attach(struct pcmcia_device *p_dev) +static int com20020_probe(struct pcmcia_device *p_dev) { - dev_link_t *link; com20020_dev_t *info; struct net_device *dev; struct arcnet_local *lp; @@ -148,10 +147,6 @@ static int com20020_attach(struct pcmcia_device *p_dev) DEBUG(0, "com20020_attach()\n"); /* Create new network device */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) - return -ENOMEM; - info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); if (!info) goto fail_alloc_info; @@ -161,7 +156,6 @@ static int com20020_attach(struct pcmcia_device *p_dev) goto fail_alloc_dev; memset(info, 0, sizeof(struct com20020_dev_t)); - memset(link, 0, sizeof(struct dev_link_t)); lp = dev->priv; lp->timeout = timeout; lp->backplane = backplane; @@ -172,28 +166,23 @@ static int com20020_attach(struct pcmcia_device *p_dev) /* fill in our module parameters as defaults */ dev->dev_addr[0] = node; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.NumPorts1 = 16; - link->io.IOAddrLines = 16; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.Present = PRESENT_OPTION; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.NumPorts1 = 16; + p_dev->io.IOAddrLines = 16; + p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->conf.Attributes = CONF_ENABLE_IRQ; + p_dev->conf.IntType = INT_MEMORY_AND_IO; + p_dev->conf.Present = PRESENT_OPTION; - link->irq.Instance = info->dev = dev; - link->priv = info; + p_dev->irq.Instance = info->dev = dev; + p_dev->priv = info; - link->state |= DEV_PRESENT; - com20020_config(link); - - return 0; + return com20020_config(p_dev); fail_alloc_dev: kfree(info); fail_alloc_info: - kfree(link); return -ENOMEM; } /* com20020_attach */ @@ -206,9 +195,8 @@ fail_alloc_info: ======================================================================*/ -static void com20020_detach(struct pcmcia_device *p_dev) +static void com20020_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct com20020_dev_t *info = link->priv; struct net_device *dev = info->dev; @@ -216,7 +204,7 @@ static void com20020_detach(struct pcmcia_device *p_dev) DEBUG(0, "com20020_detach(0x%p)\n", link); - if (link->dev) { + if (link->dev_node) { DEBUG(1,"unregister...\n"); unregister_netdev(dev); @@ -229,8 +217,7 @@ static void com20020_detach(struct pcmcia_device *p_dev) free_irq(dev->irq, dev); } - if (link->state & DEV_CONFIG) - com20020_release(link); + com20020_release(link); /* Unlink device structure, free bits */ DEBUG(1,"unlinking...\n"); @@ -245,8 +232,6 @@ static void com20020_detach(struct pcmcia_device *p_dev) DEBUG(1,"kfree2...\n"); kfree(info); } - DEBUG(1,"kfree3...\n"); - kfree(link); } /* com20020_detach */ @@ -261,10 +246,9 @@ static void com20020_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void com20020_config(dev_link_t *link) +static int com20020_config(struct pcmcia_device *link) { struct arcnet_local *lp; - client_handle_t handle; tuple_t tuple; cisparse_t parse; com20020_dev_t *info; @@ -273,7 +257,6 @@ static void com20020_config(dev_link_t *link) u_char buf[64]; int ioaddr; - handle = link->handle; info = link->priv; dev = info->dev; @@ -286,14 +269,11 @@ static void com20020_config(dev_link_t *link) tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; - /* Configure card */ - link->state |= DEV_CONFIG; - DEBUG(1,"arcnet: baseport1 is %Xh\n", link->io.BasePort1); i = !CS_SUCCESS; if (!link->io.BasePort1) @@ -301,13 +281,13 @@ static void com20020_config(dev_link_t *link) for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x10) { link->io.BasePort1 = ioaddr; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } } else - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i != CS_SUCCESS) { @@ -321,7 +301,7 @@ static void com20020_config(dev_link_t *link) DEBUG(1,"arcnet: request IRQ %d (%Xh/%Xh)\n", link->irq.AssignedIRQ, link->irq.IRQInfo1, link->irq.IRQInfo2); - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { DEBUG(1,"arcnet: requestIRQ failed totally!\n"); @@ -330,7 +310,7 @@ static void com20020_config(dev_link_t *link) dev->irq = link->irq.AssignedIRQ; - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); if (com20020_check(dev)) { @@ -342,15 +322,14 @@ static void com20020_config(dev_link_t *link) lp->card_name = "PCMCIA COM20020"; lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &info->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); i = com20020_found(dev, 0); /* calls register_netdev */ if (i != 0) { DEBUG(1,KERN_NOTICE "com20020_cs: com20020_found() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto failed; } @@ -358,13 +337,14 @@ static void com20020_config(dev_link_t *link) DEBUG(1,KERN_INFO "%s: port %#3lx, irq %d\n", dev->name, dev->base_addr, dev->irq); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: DEBUG(1,"com20020_config failed...\n"); com20020_release(link); + return -ENODEV; } /* com20020_config */ /*====================================================================== @@ -375,52 +355,33 @@ failed: ======================================================================*/ -static void com20020_release(dev_link_t *link) +static void com20020_release(struct pcmcia_device *link) { - - DEBUG(1,"release...\n"); - - DEBUG(0, "com20020_release(0x%p)\n", link); - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); + DEBUG(0, "com20020_release(0x%p)\n", link); + pcmcia_disable_device(link); } -static int com20020_suspend(struct pcmcia_device *p_dev) +static int com20020_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); com20020_dev_t *info = link->priv; struct net_device *dev = info->dev; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) { - netif_device_detach(dev); - } - pcmcia_release_configuration(link->handle); - } + if (link->open) + netif_device_detach(dev); return 0; } -static int com20020_resume(struct pcmcia_device *p_dev) +static int com20020_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); com20020_dev_t *info = link->priv; struct net_device *dev = info->dev; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - int ioaddr = dev->base_addr; - struct arcnet_local *lp = dev->priv; - ARCRESET; - } - } + if (link->open) { + int ioaddr = dev->base_addr; + struct arcnet_local *lp = dev->priv; + ARCRESET; + } return 0; } @@ -436,7 +397,7 @@ static struct pcmcia_driver com20020_cs_driver = { .drv = { .name = "com20020_cs", }, - .probe = com20020_attach, + .probe = com20020_probe, .remove = com20020_detach, .id_table = com20020_ids, .suspend = com20020_suspend, diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index b7ac14ba8877..09b11761cdfa 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -84,10 +84,10 @@ static char *version = DRV_NAME ".c " DRV_VERSION " 2002/03/23"; /* PCMCIA event handlers */ -static void fmvj18x_config(dev_link_t *link); -static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id); -static int fmvj18x_setup_mfc(dev_link_t *link); -static void fmvj18x_release(dev_link_t *link); +static int fmvj18x_config(struct pcmcia_device *link); +static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id); +static int fmvj18x_setup_mfc(struct pcmcia_device *link); +static void fmvj18x_release(struct pcmcia_device *link); static void fmvj18x_detach(struct pcmcia_device *p_dev); /* @@ -116,7 +116,7 @@ typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN, driver specific data structure */ typedef struct local_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct net_device_stats stats; long open_time; @@ -228,10 +228,9 @@ typedef struct local_info_t { #define BANK_1U 0x24 /* bank 1 (CONFIG_1) */ #define BANK_2U 0x28 /* bank 2 (CONFIG_1) */ -static int fmvj18x_attach(struct pcmcia_device *p_dev) +static int fmvj18x_probe(struct pcmcia_device *link) { local_info_t *lp; - dev_link_t *link; struct net_device *dev; DEBUG(0, "fmvj18x_attach()\n"); @@ -241,8 +240,8 @@ static int fmvj18x_attach(struct pcmcia_device *p_dev) if (!dev) return -ENOMEM; lp = netdev_priv(dev); - link = &lp->link; link->priv = dev; + lp->p_dev = link; /* The io structure describes IO port mapping */ link->io.NumPorts1 = 32; @@ -257,7 +256,6 @@ static int fmvj18x_attach(struct pcmcia_device *p_dev) /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; /* The FMVJ18x specific entries in the device structure. */ @@ -274,29 +272,21 @@ static int fmvj18x_attach(struct pcmcia_device *p_dev) #endif SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - fmvj18x_config(link); - - return 0; + return fmvj18x_config(link); } /* fmvj18x_attach */ /*====================================================================*/ -static void fmvj18x_detach(struct pcmcia_device *p_dev) +static void fmvj18x_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "fmvj18x_detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - if (link->state & DEV_CONFIG) - fmvj18x_release(link); + fmvj18x_release(link); free_netdev(dev); } /* fmvj18x_detach */ @@ -306,7 +296,7 @@ static void fmvj18x_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static int mfc_try_io_port(dev_link_t *link) +static int mfc_try_io_port(struct pcmcia_device *link) { int i, ret; static const kio_addr_t serial_base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; @@ -318,13 +308,13 @@ static int mfc_try_io_port(dev_link_t *link) link->io.NumPorts2 = 0; printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n"); } - ret = pcmcia_request_io(link->handle, &link->io); + ret = pcmcia_request_io(link, &link->io); if (ret == CS_SUCCESS) return ret; } return ret; } -static int ungermann_try_io_port(dev_link_t *link) +static int ungermann_try_io_port(struct pcmcia_device *link) { int ret; kio_addr_t ioaddr; @@ -334,7 +324,7 @@ static int ungermann_try_io_port(dev_link_t *link) */ for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) { link->io.BasePort1 = ioaddr; - ret = pcmcia_request_io(link->handle, &link->io); + ret = pcmcia_request_io(link, &link->io); if (ret == CS_SUCCESS) { /* calculate ConfigIndex value */ link->conf.ConfigIndex = @@ -345,9 +335,8 @@ static int ungermann_try_io_port(dev_link_t *link) return ret; /* RequestIO failed */ } -static void fmvj18x_config(dev_link_t *link) +static int fmvj18x_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; local_info_t *lp = netdev_priv(dev); tuple_t tuple; @@ -366,42 +355,34 @@ static void fmvj18x_config(dev_link_t *link) registers. */ tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = (u_char *)buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); - - /* Configure card */ - link->state |= DEV_CONFIG; + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; tuple.DesiredTuple = CISTPL_FUNCE; tuple.TupleOffset = 0; - if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) { + if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) { /* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigIndex = parse.cftable_entry.index; tuple.DesiredTuple = CISTPL_MANFID; - if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); else buf[0] = 0xffff; switch (le16_to_cpu(buf[0])) { case MANFID_TDK: cardtype = TDK; - if (le16_to_cpu(buf[1]) == PRODID_TDK_CF010) { - cs_status_t status; - pcmcia_get_status(handle, &status); - if (status.CardState & CS_EVENT_3VCARD) - link->conf.Vcc = 33; /* inserted in 3.3V slot */ - } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410 + if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410 || le16_to_cpu(buf[1]) == PRODID_TDK_NP9610 || le16_to_cpu(buf[1]) == PRODID_TDK_MN3200) { /* MultiFunction Card */ @@ -429,8 +410,8 @@ static void fmvj18x_config(dev_link_t *link) } else { /* old type card */ tuple.DesiredTuple = CISTPL_MANFID; - if (pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + if (pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); else buf[0] = 0xffff; switch (le16_to_cpu(buf[0])) { @@ -461,10 +442,10 @@ static void fmvj18x_config(dev_link_t *link) ret = ungermann_try_io_port(link); if (ret != CS_SUCCESS) goto cs_failed; } else { - CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); + CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -493,17 +474,17 @@ static void fmvj18x_config(dev_link_t *link) case CONTEC: tuple.DesiredTuple = CISTPL_FUNCE; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); if (cardtype == MBH10304) { /* MBH10304's CIS_FUNCE is corrupted */ node_id = &(tuple.TupleData[5]); card_name = "FMV-J182"; } else { while (tuple.TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID ) { - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); } node_id = &(tuple.TupleData[2]); if( cardtype == TDK ) { @@ -545,13 +526,12 @@ static void fmvj18x_config(dev_link_t *link) } lp->cardtype = cardtype; - link->dev = &lp->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &lp->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto failed; } @@ -564,19 +544,18 @@ static void fmvj18x_config(dev_link_t *link) for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); - return; + return 0; cs_failed: /* All Card Services errors end up here */ - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: fmvj18x_release(link); - link->state &= ~DEV_CONFIG_PENDING; - + return -ENODEV; } /* fmvj18x_config */ /*====================================================================*/ -static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id) +static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) { win_req_t req; memreq_t mem; @@ -587,9 +566,9 @@ static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = 0; req.Size = 0; req.AccessSpeed = 0; - i = pcmcia_request_window(&link->handle, &req, &link->win); + i = pcmcia_request_window(&link, &req, &link->win); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestWindow, i); + cs_error(link, RequestWindow, i); return -1; } @@ -623,13 +602,13 @@ static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id) iounmap(base); j = pcmcia_release_window(link->win); if (j != CS_SUCCESS) - cs_error(link->handle, ReleaseWindow, j); + cs_error(link, ReleaseWindow, j); return (i != 0x200) ? 0 : -1; } /* fmvj18x_get_hwinfo */ /*====================================================================*/ -static int fmvj18x_setup_mfc(dev_link_t *link) +static int fmvj18x_setup_mfc(struct pcmcia_device *link) { win_req_t req; memreq_t mem; @@ -642,9 +621,9 @@ static int fmvj18x_setup_mfc(dev_link_t *link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = 0; req.Size = 0; req.AccessSpeed = 0; - i = pcmcia_request_window(&link->handle, &req, &link->win); + i = pcmcia_request_window(&link, &req, &link->win); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestWindow, i); + cs_error(link, RequestWindow, i); return -1; } @@ -666,54 +645,35 @@ static int fmvj18x_setup_mfc(dev_link_t *link) iounmap(base); j = pcmcia_release_window(link->win); if (j != CS_SUCCESS) - cs_error(link->handle, ReleaseWindow, j); + cs_error(link, ReleaseWindow, j); return 0; } /*====================================================================*/ -static void fmvj18x_release(dev_link_t *link) +static void fmvj18x_release(struct pcmcia_device *link) { - - DEBUG(0, "fmvj18x_release(0x%p)\n", link); - - /* Don't bother checking to see if these succeed or not */ - pcmcia_release_window(link->win); - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + DEBUG(0, "fmvj18x_release(0x%p)\n", link); + pcmcia_disable_device(link); } -static int fmvj18x_suspend(struct pcmcia_device *p_dev) +static int fmvj18x_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } - + if (link->open) + netif_device_detach(dev); return 0; } -static int fmvj18x_resume(struct pcmcia_device *p_dev) +static int fmvj18x_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - fjn_reset(dev); - netif_device_attach(dev); - } + if (link->open) { + fjn_reset(dev); + netif_device_attach(dev); } return 0; @@ -751,7 +711,7 @@ static struct pcmcia_driver fmvj18x_cs_driver = { .drv = { .name = "fmvj18x_cs", }, - .probe = fmvj18x_attach, + .probe = fmvj18x_probe, .remove = fmvj18x_detach, .id_table = fmvj18x_ids, .suspend = fmvj18x_suspend, @@ -1148,11 +1108,11 @@ static int fjn_config(struct net_device *dev, struct ifmap *map){ static int fjn_open(struct net_device *dev) { struct local_info_t *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; DEBUG(4, "fjn_open('%s').\n", dev->name); - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; link->open++; @@ -1173,7 +1133,7 @@ static int fjn_open(struct net_device *dev) static int fjn_close(struct net_device *dev) { struct local_info_t *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; kio_addr_t ioaddr = dev->base_addr; DEBUG(4, "fjn_close('%s').\n", dev->name); diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index b9c7e39576f5..b8fe70b85641 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -105,15 +105,15 @@ MODULE_LICENSE("GPL"); /*====================================================================*/ -static void ibmtr_config(dev_link_t *link); +static int ibmtr_config(struct pcmcia_device *link); static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase); -static void ibmtr_release(dev_link_t *link); +static void ibmtr_release(struct pcmcia_device *link); static void ibmtr_detach(struct pcmcia_device *p_dev); /*====================================================================*/ typedef struct ibmtr_dev_t { - dev_link_t link; + struct pcmcia_device *p_dev; struct net_device *dev; dev_node_t node; window_handle_t sram_win_handle; @@ -138,12 +138,11 @@ static struct ethtool_ops netdev_ethtool_ops = { ======================================================================*/ -static int ibmtr_attach(struct pcmcia_device *p_dev) +static int ibmtr_attach(struct pcmcia_device *link) { ibmtr_dev_t *info; - dev_link_t *link; struct net_device *dev; - + DEBUG(0, "ibmtr_attach()\n"); /* Create new token-ring device */ @@ -156,7 +155,7 @@ static int ibmtr_attach(struct pcmcia_device *p_dev) return -ENOMEM; } - link = &info->link; + info->p_dev = link; link->priv = info; info->ti = netdev_priv(dev); @@ -167,21 +166,14 @@ static int ibmtr_attach(struct pcmcia_device *p_dev) link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = &tok_interrupt; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; link->irq.Instance = info->dev = dev; - + SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT; - ibmtr_config(link); - - return 0; + return ibmtr_config(link); } /* ibmtr_attach */ /*====================================================================== @@ -193,23 +185,22 @@ static int ibmtr_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void ibmtr_detach(struct pcmcia_device *p_dev) +static void ibmtr_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct ibmtr_dev_t *info = link->priv; struct net_device *dev = info->dev; DEBUG(0, "ibmtr_detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); { struct tok_info *ti = netdev_priv(dev); del_timer_sync(&(ti->tr_timer)); } - if (link->state & DEV_CONFIG) - ibmtr_release(link); + + ibmtr_release(link); free_netdev(dev); kfree(info); @@ -226,9 +217,8 @@ static void ibmtr_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void ibmtr_config(dev_link_t *link) +static int ibmtr_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; ibmtr_dev_t *info = link->priv; struct net_device *dev = info->dev; struct tok_info *ti = netdev_priv(dev); @@ -246,29 +236,25 @@ static void ibmtr_config(dev_link_t *link) tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; - - /* Configure card */ - link->state |= DEV_CONFIG; - link->conf.ConfigIndex = 0x61; /* Determine if this is PRIMARY or ALTERNATE. */ /* Try PRIMARY card at 0xA20-0xA23 */ link->io.BasePort1 = 0xA20; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i != CS_SUCCESS) { /* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */ link->io.BasePort1 = 0xA24; - CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); + CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); } dev->base_addr = link->io.BasePort1; - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); dev->irq = link->irq.AssignedIRQ; ti->irq = link->irq.AssignedIRQ; ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq); @@ -279,7 +265,7 @@ static void ibmtr_config(dev_link_t *link) req.Base = 0; req.Size = 0x2000; req.AccessSpeed = 250; - CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); + CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); mem.CardOffset = mmiobase; mem.Page = 0; @@ -292,7 +278,7 @@ static void ibmtr_config(dev_link_t *link) req.Base = 0; req.Size = sramsize * 1024; req.AccessSpeed = 250; - CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &info->sram_win_handle)); + CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &info->sram_win_handle)); mem.CardOffset = srambase; mem.Page = 0; @@ -302,21 +288,20 @@ static void ibmtr_config(dev_link_t *link) ti->sram_virt = ioremap(req.Base, req.Size); ti->sram_phys = req.Base; - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); /* Set up the Token-Ring Controller Configuration Register and turn on the card. Check the "Local Area Network Credit Card Adapters Technical Reference" SC30-3585 for this info. */ ibmtr_hw_setup(dev, mmiobase); - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &info->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); i = ibmtr_probe_card(dev); if (i != 0) { printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto failed; } @@ -330,12 +315,13 @@ static void ibmtr_config(dev_link_t *link) for (i = 0; i < TR_ALEN; i++) printk("%02X", dev->dev_addr[i]); printk("\n"); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: ibmtr_release(link); + return -ENODEV; } /* ibmtr_config */ /*====================================================================== @@ -346,56 +332,41 @@ failed: ======================================================================*/ -static void ibmtr_release(dev_link_t *link) +static void ibmtr_release(struct pcmcia_device *link) { - ibmtr_dev_t *info = link->priv; - struct net_device *dev = info->dev; - - DEBUG(0, "ibmtr_release(0x%p)\n", link); - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - if (link->win) { - struct tok_info *ti = netdev_priv(dev); - iounmap(ti->mmio); - pcmcia_release_window(link->win); - pcmcia_release_window(info->sram_win_handle); - } - - link->state &= ~DEV_CONFIG; -} - -static int ibmtr_suspend(struct pcmcia_device *p_dev) -{ - dev_link_t *link = dev_to_instance(p_dev); ibmtr_dev_t *info = link->priv; struct net_device *dev = info->dev; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } + DEBUG(0, "ibmtr_release(0x%p)\n", link); + + if (link->win) { + struct tok_info *ti = netdev_priv(dev); + iounmap(ti->mmio); + pcmcia_release_window(info->sram_win_handle); + } + pcmcia_disable_device(link); +} + +static int ibmtr_suspend(struct pcmcia_device *link) +{ + ibmtr_dev_t *info = link->priv; + struct net_device *dev = info->dev; + + if (link->open) + netif_device_detach(dev); return 0; } -static int ibmtr_resume(struct pcmcia_device *p_dev) +static int ibmtr_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); ibmtr_dev_t *info = link->priv; struct net_device *dev = info->dev; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - ibmtr_probe(dev); /* really? */ - netif_device_attach(dev); - } - } + if (link->open) { + ibmtr_probe(dev); /* really? */ + netif_device_attach(dev); + } return 0; } diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 787176c57fd9..4260c2128f47 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -362,7 +362,7 @@ typedef struct _mace_statistics { } mace_statistics; typedef struct _mace_private { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct net_device_stats linux_stats; /* Linux statistics counters */ mace_statistics mace_stats; /* MACE chip statistics counters */ @@ -417,8 +417,8 @@ INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); Function Prototypes ---------------------------------------------------------------------------- */ -static void nmclan_config(dev_link_t *link); -static void nmclan_release(dev_link_t *link); +static int nmclan_config(struct pcmcia_device *link); +static void nmclan_release(struct pcmcia_device *link); static void nmclan_reset(struct net_device *dev); static int mace_config(struct net_device *dev, struct ifmap *map); @@ -443,10 +443,9 @@ nmclan_attach Services. ---------------------------------------------------------------------------- */ -static int nmclan_attach(struct pcmcia_device *p_dev) +static int nmclan_probe(struct pcmcia_device *link) { mace_private *lp; - dev_link_t *link; struct net_device *dev; DEBUG(0, "nmclan_attach()\n"); @@ -457,7 +456,7 @@ static int nmclan_attach(struct pcmcia_device *p_dev) if (!dev) return -ENOMEM; lp = netdev_priv(dev); - link = &lp->link; + lp->p_dev = link; link->priv = dev; spin_lock_init(&lp->bank_lock); @@ -469,7 +468,6 @@ static int nmclan_attach(struct pcmcia_device *p_dev) link->irq.Handler = &mace_interrupt; link->irq.Instance = dev; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; @@ -489,13 +487,7 @@ static int nmclan_attach(struct pcmcia_device *p_dev) dev->watchdog_timeo = TX_TIMEOUT; #endif - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - nmclan_config(link); - - return 0; + return nmclan_config(link); } /* nmclan_attach */ /* ---------------------------------------------------------------------------- @@ -506,18 +498,16 @@ nmclan_detach when the device is released. ---------------------------------------------------------------------------- */ -static void nmclan_detach(struct pcmcia_device *p_dev) +static void nmclan_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "nmclan_detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - if (link->state & DEV_CONFIG) - nmclan_release(link); + nmclan_release(link); free_netdev(dev); } /* nmclan_detach */ @@ -661,9 +651,8 @@ nmclan_config #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void nmclan_config(dev_link_t *link) +static int nmclan_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; mace_private *lp = netdev_priv(dev); tuple_t tuple; @@ -679,17 +668,14 @@ static void nmclan_config(dev_link_t *link) tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; - /* Configure card */ - link->state |= DEV_CONFIG; - - CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -700,8 +686,8 @@ static void nmclan_config(dev_link_t *link) tuple.TupleData = buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN); /* Verify configuration by reading the MACE ID. */ @@ -716,8 +702,7 @@ static void nmclan_config(dev_link_t *link) } else { printk(KERN_NOTICE "nmclan_cs: mace id not found: %x %x should" " be 0x40 0x?9\n", sig[0], sig[1]); - link->state &= ~DEV_CONFIG_PENDING; - return; + return -ENODEV; } } @@ -730,14 +715,13 @@ static void nmclan_config(dev_link_t *link) else printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n"); - link->dev = &lp->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &lp->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); i = register_netdev(dev); if (i != 0) { printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto failed; } @@ -747,14 +731,13 @@ static void nmclan_config(dev_link_t *link) dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]); for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: - nmclan_release(link); - return; - + nmclan_release(link); + return -ENODEV; } /* nmclan_config */ /* ---------------------------------------------------------------------------- @@ -763,46 +746,29 @@ nmclan_release net device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed. ---------------------------------------------------------------------------- */ -static void nmclan_release(dev_link_t *link) +static void nmclan_release(struct pcmcia_device *link) { - - DEBUG(0, "nmclan_release(0x%p)\n", link); - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + DEBUG(0, "nmclan_release(0x%p)\n", link); + pcmcia_disable_device(link); } -static int nmclan_suspend(struct pcmcia_device *p_dev) +static int nmclan_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } - + if (link->open) + netif_device_detach(dev); return 0; } -static int nmclan_resume(struct pcmcia_device *p_dev) +static int nmclan_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - nmclan_reset(dev); - netif_device_attach(dev); - } + if (link->open) { + nmclan_reset(dev); + netif_device_attach(dev); } return 0; @@ -818,7 +784,7 @@ static void nmclan_reset(struct net_device *dev) mace_private *lp = netdev_priv(dev); #if RESET_XILINX - dev_link_t *link = &lp->link; + struct pcmcia_device *link = &lp->link; conf_reg_t reg; u_long OrigCorValue; @@ -827,7 +793,7 @@ static void nmclan_reset(struct net_device *dev) reg.Action = CS_READ; reg.Offset = CISREG_COR; reg.Value = 0; - pcmcia_access_configuration_register(link->handle, ®); + pcmcia_access_configuration_register(link, ®); OrigCorValue = reg.Value; /* Reset Xilinx */ @@ -836,12 +802,12 @@ static void nmclan_reset(struct net_device *dev) DEBUG(1, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n", OrigCorValue); reg.Value = COR_SOFT_RESET; - pcmcia_access_configuration_register(link->handle, ®); + pcmcia_access_configuration_register(link, ®); /* Need to wait for 20 ms for PCMCIA to finish reset. */ /* Restore original COR configuration index */ reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK); - pcmcia_access_configuration_register(link->handle, ®); + pcmcia_access_configuration_register(link, ®); /* Xilinx is now completely reset along with the MACE chip. */ lp->tx_free_frames=AM2150_MAX_TX_FRAMES; @@ -885,9 +851,9 @@ static int mace_open(struct net_device *dev) { kio_addr_t ioaddr = dev->base_addr; mace_private *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; link->open++; @@ -908,7 +874,7 @@ static int mace_close(struct net_device *dev) { kio_addr_t ioaddr = dev->base_addr; mace_private *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; DEBUG(2, "%s: shutting down ethercard.\n", dev->name); @@ -963,12 +929,12 @@ mace_start_xmit static void mace_tx_timeout(struct net_device *dev) { mace_private *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name); #if RESET_ON_TIMEOUT printk("resetting card\n"); - pcmcia_reset_card(link->handle, NULL); + pcmcia_reset_card(link, NULL); #else /* #if RESET_ON_TIMEOUT */ printk("NOT resetting card\n"); #endif /* #if RESET_ON_TIMEOUT */ @@ -1635,7 +1601,7 @@ static struct pcmcia_driver nmclan_cs_driver = { .drv = { .name = "nmclan_cs", }, - .probe = nmclan_attach, + .probe = nmclan_probe, .remove = nmclan_detach, .id_table = nmclan_ids, .suspend = nmclan_suspend, diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index b46e5f703efa..506e777c5f06 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -103,8 +103,8 @@ module_param_array(hw_addr, int, NULL, 0); /*====================================================================*/ static void mii_phy_probe(struct net_device *dev); -static void pcnet_config(dev_link_t *link); -static void pcnet_release(dev_link_t *link); +static int pcnet_config(struct pcmcia_device *link); +static void pcnet_release(struct pcmcia_device *link); static int pcnet_open(struct net_device *dev); static int pcnet_close(struct net_device *dev); static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -113,9 +113,9 @@ static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs); static void ei_watchdog(u_long arg); static void pcnet_reset_8390(struct net_device *dev); static int set_config(struct net_device *dev, struct ifmap *map); -static int setup_shmem_window(dev_link_t *link, int start_pg, +static int setup_shmem_window(struct pcmcia_device *link, int start_pg, int stop_pg, int cm_offset); -static int setup_dma_config(dev_link_t *link, int start_pg, +static int setup_dma_config(struct pcmcia_device *link, int start_pg, int stop_pg); static void pcnet_detach(struct pcmcia_device *p_dev); @@ -214,7 +214,7 @@ static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII }; static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10022|HAS_MII }; typedef struct pcnet_dev_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; u_int flags; void __iomem *base; @@ -240,10 +240,9 @@ static inline pcnet_dev_t *PRIV(struct net_device *dev) ======================================================================*/ -static int pcnet_probe(struct pcmcia_device *p_dev) +static int pcnet_probe(struct pcmcia_device *link) { pcnet_dev_t *info; - dev_link_t *link; struct net_device *dev; DEBUG(0, "pcnet_attach()\n"); @@ -252,7 +251,7 @@ static int pcnet_probe(struct pcmcia_device *p_dev) dev = __alloc_ei_netdev(sizeof(pcnet_dev_t)); if (!dev) return -ENOMEM; info = PRIV(dev); - link = &info->link; + info->p_dev = link; link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; @@ -265,13 +264,7 @@ static int pcnet_probe(struct pcmcia_device *p_dev) dev->stop = &pcnet_close; dev->set_config = &set_config; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - pcnet_config(link); - - return 0; + return pcnet_config(link); } /* pcnet_attach */ /*====================================================================== @@ -283,18 +276,16 @@ static int pcnet_probe(struct pcmcia_device *p_dev) ======================================================================*/ -static void pcnet_detach(struct pcmcia_device *p_dev) +static void pcnet_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "pcnet_detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - if (link->state & DEV_CONFIG) - pcnet_release(link); + pcnet_release(link); free_netdev(dev); } /* pcnet_detach */ @@ -306,7 +297,7 @@ static void pcnet_detach(struct pcmcia_device *p_dev) ======================================================================*/ -static hw_info_t *get_hwinfo(dev_link_t *link) +static hw_info_t *get_hwinfo(struct pcmcia_device *link) { struct net_device *dev = link->priv; win_req_t req; @@ -318,9 +309,9 @@ static hw_info_t *get_hwinfo(dev_link_t *link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = 0; req.Size = 0; req.AccessSpeed = 0; - i = pcmcia_request_window(&link->handle, &req, &link->win); + i = pcmcia_request_window(&link, &req, &link->win); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestWindow, i); + cs_error(link, RequestWindow, i); return NULL; } @@ -343,7 +334,7 @@ static hw_info_t *get_hwinfo(dev_link_t *link) iounmap(virt); j = pcmcia_release_window(link->win); if (j != CS_SUCCESS) - cs_error(link->handle, ReleaseWindow, j); + cs_error(link, ReleaseWindow, j); return (i < NR_INFO) ? hw_info+i : NULL; } /* get_hwinfo */ @@ -355,7 +346,7 @@ static hw_info_t *get_hwinfo(dev_link_t *link) ======================================================================*/ -static hw_info_t *get_prom(dev_link_t *link) +static hw_info_t *get_prom(struct pcmcia_device *link) { struct net_device *dev = link->priv; kio_addr_t ioaddr = dev->base_addr; @@ -409,7 +400,7 @@ static hw_info_t *get_prom(dev_link_t *link) ======================================================================*/ -static hw_info_t *get_dl10019(dev_link_t *link) +static hw_info_t *get_dl10019(struct pcmcia_device *link) { struct net_device *dev = link->priv; int i; @@ -431,7 +422,7 @@ static hw_info_t *get_dl10019(dev_link_t *link) ======================================================================*/ -static hw_info_t *get_ax88190(dev_link_t *link) +static hw_info_t *get_ax88190(struct pcmcia_device *link) { struct net_device *dev = link->priv; kio_addr_t ioaddr = dev->base_addr; @@ -464,7 +455,7 @@ static hw_info_t *get_ax88190(dev_link_t *link) ======================================================================*/ -static hw_info_t *get_hwired(dev_link_t *link) +static hw_info_t *get_hwired(struct pcmcia_device *link) { struct net_device *dev = link->priv; int i; @@ -491,7 +482,7 @@ static hw_info_t *get_hwired(dev_link_t *link) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static int try_io_port(dev_link_t *link) +static int try_io_port(struct pcmcia_device *link) { int j, ret; if (link->io.NumPorts1 == 32) { @@ -512,18 +503,17 @@ static int try_io_port(dev_link_t *link) for (j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; link->io.BasePort2 = (j ^ 0x300) + 0x10; - ret = pcmcia_request_io(link->handle, &link->io); + ret = pcmcia_request_io(link, &link->io); if (ret == CS_SUCCESS) return ret; } return ret; } else { - return pcmcia_request_io(link->handle, &link->io); + return pcmcia_request_io(link, &link->io); } } -static void pcnet_config(dev_link_t *link) +static int pcnet_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; pcnet_dev_t *info = PRIV(dev); tuple_t tuple; @@ -531,7 +521,6 @@ static void pcnet_config(dev_link_t *link) int i, last_ret, last_fn, start_pg, stop_pg, cm_offset; int manfid = 0, prodid = 0, has_shmem = 0; u_short buf[64]; - config_info_t conf; hw_info_t *hw_info; DEBUG(0, "pcnet_config(0x%p)\n", link); @@ -541,36 +530,29 @@ static void pcnet_config(dev_link_t *link) tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - - /* Look up current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; - tuple.DesiredTuple = CISTPL_MANFID; tuple.Attributes = TUPLE_RETURN_COMMON; - if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && - (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) { + if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && + (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) { manfid = le16_to_cpu(buf[0]); prodid = le16_to_cpu(buf[1]); } tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (last_ret == CS_SUCCESS) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_io_t *io = &(parse.cftable_entry.io); - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0 || + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0 || cfg->index == 0 || cfg->io.nwin == 0) goto next_entry; @@ -594,14 +576,14 @@ static void pcnet_config(dev_link_t *link) if (last_ret == CS_SUCCESS) break; } next_entry: - last_ret = pcmcia_get_next_tuple(handle, &tuple); + last_ret = pcmcia_get_next_tuple(link, &tuple); } if (last_ret != CS_SUCCESS) { - cs_error(handle, RequestIO, last_ret); + cs_error(link, RequestIO, last_ret); goto failed; } - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); if (link->io.NumPorts2 == 8) { link->conf.Attributes |= CONF_ENABLE_SPKR; @@ -611,7 +593,7 @@ static void pcnet_config(dev_link_t *link) (prodid == PRODID_IBM_HOME_AND_AWAY)) link->conf.ConfigIndex |= 0x10; - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; if (info->flags & HAS_MISC_REG) { @@ -679,9 +661,8 @@ static void pcnet_config(dev_link_t *link) info->eth_phy = 0; } - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &info->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = ei_poll; @@ -689,7 +670,7 @@ static void pcnet_config(dev_link_t *link) if (register_netdev(dev) != 0) { printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto failed; } @@ -712,14 +693,13 @@ static void pcnet_config(dev_link_t *link) printk(" hw_addr "); for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: pcnet_release(link); - link->state &= ~DEV_CONFIG_PENDING; - return; + return -ENODEV; } /* pcnet_config */ /*====================================================================== @@ -730,21 +710,16 @@ failed: ======================================================================*/ -static void pcnet_release(dev_link_t *link) +static void pcnet_release(struct pcmcia_device *link) { - pcnet_dev_t *info = PRIV(link->priv); + pcnet_dev_t *info = PRIV(link->priv); - DEBUG(0, "pcnet_release(0x%p)\n", link); + DEBUG(0, "pcnet_release(0x%p)\n", link); - if (info->flags & USE_SHMEM) { - iounmap(info->base); - pcmcia_release_window(link->win); - } - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); + if (info->flags & USE_SHMEM) + iounmap(info->base); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } /*====================================================================== @@ -756,34 +731,24 @@ static void pcnet_release(dev_link_t *link) ======================================================================*/ -static int pcnet_suspend(struct pcmcia_device *p_dev) +static int pcnet_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } + if (link->open) + netif_device_detach(dev); return 0; } -static int pcnet_resume(struct pcmcia_device *p_dev) +static int pcnet_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - pcnet_reset_8390(dev); - NS8390_init(dev, 1); - netif_device_attach(dev); - } + if (link->open) { + pcnet_reset_8390(dev); + NS8390_init(dev, 1); + netif_device_attach(dev); } return 0; @@ -1023,11 +988,11 @@ static void mii_phy_probe(struct net_device *dev) static int pcnet_open(struct net_device *dev) { pcnet_dev_t *info = PRIV(dev); - dev_link_t *link = &info->link; - + struct pcmcia_device *link = info->p_dev; + DEBUG(2, "pcnet_open('%s')\n", dev->name); - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; link->open++; @@ -1051,7 +1016,7 @@ static int pcnet_open(struct net_device *dev) static int pcnet_close(struct net_device *dev) { pcnet_dev_t *info = PRIV(dev); - dev_link_t *link = &info->link; + struct pcmcia_device *link = info->p_dev; DEBUG(2, "pcnet_close('%s')\n", dev->name); @@ -1429,7 +1394,7 @@ static void dma_block_output(struct net_device *dev, int count, /*====================================================================*/ -static int setup_dma_config(dev_link_t *link, int start_pg, +static int setup_dma_config(struct pcmcia_device *link, int start_pg, int stop_pg) { struct net_device *dev = link->priv; @@ -1532,7 +1497,7 @@ static void shmem_block_output(struct net_device *dev, int count, /*====================================================================*/ -static int setup_shmem_window(dev_link_t *link, int start_pg, +static int setup_shmem_window(struct pcmcia_device *link, int start_pg, int stop_pg, int cm_offset) { struct net_device *dev = link->priv; @@ -1554,7 +1519,7 @@ static int setup_shmem_window(dev_link_t *link, int start_pg, req.Attributes |= WIN_USE_WAIT; req.Base = 0; req.Size = window_size; req.AccessSpeed = mem_speed; - CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); + CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); mem.CardOffset = (start_pg << 8) + cm_offset; offset = mem.CardOffset % window_size; @@ -1595,7 +1560,7 @@ static int setup_shmem_window(dev_link_t *link, int start_pg, return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: return 1; } diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 8839c4faafd6..e74bf5014ef6 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -103,7 +104,7 @@ static const char *version = #define MEMORY_WAIT_TIME 8 struct smc_private { - dev_link_t link; + struct pcmcia_device *p_dev; spinlock_t lock; u_short manfid; u_short cardid; @@ -278,8 +279,8 @@ enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002, /*====================================================================*/ static void smc91c92_detach(struct pcmcia_device *p_dev); -static void smc91c92_config(dev_link_t *link); -static void smc91c92_release(dev_link_t *link); +static int smc91c92_config(struct pcmcia_device *link); +static void smc91c92_release(struct pcmcia_device *link); static int smc_open(struct net_device *dev); static int smc_close(struct net_device *dev); @@ -308,10 +309,9 @@ static struct ethtool_ops ethtool_ops; ======================================================================*/ -static int smc91c92_attach(struct pcmcia_device *p_dev) +static int smc91c92_probe(struct pcmcia_device *link) { struct smc_private *smc; - dev_link_t *link; struct net_device *dev; DEBUG(0, "smc91c92_attach()\n"); @@ -321,7 +321,7 @@ static int smc91c92_attach(struct pcmcia_device *p_dev) if (!dev) return -ENOMEM; smc = netdev_priv(dev); - link = &smc->link; + smc->p_dev = link; link->priv = dev; spin_lock_init(&smc->lock); @@ -333,7 +333,6 @@ static int smc91c92_attach(struct pcmcia_device *p_dev) link->irq.Handler = &smc_interrupt; link->irq.Instance = dev; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; /* The SMC91c92-specific entries in the device structure. */ @@ -357,13 +356,7 @@ static int smc91c92_attach(struct pcmcia_device *p_dev) smc->mii_if.phy_id_mask = 0x1f; smc->mii_if.reg_num_mask = 0x1f; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - smc91c92_config(link); - - return 0; + return smc91c92_config(link); } /* smc91c92_attach */ /*====================================================================== @@ -375,18 +368,16 @@ static int smc91c92_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void smc91c92_detach(struct pcmcia_device *p_dev) +static void smc91c92_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "smc91c92_detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - if (link->state & DEV_CONFIG) - smc91c92_release(link); + smc91c92_release(link); free_netdev(dev); } /* smc91c92_detach */ @@ -414,7 +405,7 @@ static int cvt_ascii_address(struct net_device *dev, char *s) /*====================================================================*/ -static int first_tuple(client_handle_t handle, tuple_t *tuple, +static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i; @@ -425,7 +416,7 @@ static int first_tuple(client_handle_t handle, tuple_t *tuple, return pcmcia_parse_tuple(handle, tuple, parse); } -static int next_tuple(client_handle_t handle, tuple_t *tuple, +static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int i; @@ -447,7 +438,7 @@ static int next_tuple(client_handle_t handle, tuple_t *tuple, ======================================================================*/ -static int mhz_3288_power(dev_link_t *link) +static int mhz_3288_power(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); @@ -469,7 +460,7 @@ static int mhz_3288_power(dev_link_t *link) return 0; } -static int mhz_mfc_config(dev_link_t *link) +static int mhz_mfc_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); @@ -504,7 +495,7 @@ static int mhz_mfc_config(dev_link_t *link) tuple->TupleDataMax = 255; tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; - i = first_tuple(link->handle, tuple, parse); + i = first_tuple(link, tuple, parse); /* The Megahertz combo cards have modem-like CIS entries, so we have to explicitly try a bunch of port combinations. */ while (i == CS_SUCCESS) { @@ -513,11 +504,11 @@ static int mhz_mfc_config(dev_link_t *link) for (k = 0; k < 0x400; k += 0x10) { if (k & 0x80) continue; link->io.BasePort1 = k ^ 0x300; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } if (i == CS_SUCCESS) break; - i = next_tuple(link->handle, tuple, parse); + i = next_tuple(link, tuple, parse); } if (i != CS_SUCCESS) goto free_cfg_mem; @@ -527,7 +518,7 @@ static int mhz_mfc_config(dev_link_t *link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = 0; - i = pcmcia_request_window(&link->handle, &req, &link->win); + i = pcmcia_request_window(&link, &req, &link->win); if (i != CS_SUCCESS) goto free_cfg_mem; smc->base = ioremap(req.Base, req.Size); @@ -546,9 +537,8 @@ free_cfg_mem: return i; } -static int mhz_setup(dev_link_t *link) +static int mhz_setup(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; struct smc_cfg_mem *cfg_mem; tuple_t *tuple; @@ -571,13 +561,13 @@ static int mhz_setup(dev_link_t *link) /* Read the station address from the CIS. It is stored as the last (fourth) string in the Version 1 Version/ID tuple. */ tuple->DesiredTuple = CISTPL_VERS_1; - if (first_tuple(handle, tuple, parse) != CS_SUCCESS) { + if (first_tuple(link, tuple, parse) != CS_SUCCESS) { rc = -1; goto free_cfg_mem; } /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ - if (next_tuple(handle, tuple, parse) != CS_SUCCESS) - first_tuple(handle, tuple, parse); + if (next_tuple(link, tuple, parse) != CS_SUCCESS) + first_tuple(link, tuple, parse); if (parse->version_1.ns > 3) { station_addr = parse->version_1.str + parse->version_1.ofs[3]; if (cvt_ascii_address(dev, station_addr) == 0) { @@ -588,11 +578,11 @@ static int mhz_setup(dev_link_t *link) /* Another possibility: for the EM3288, in a special tuple */ tuple->DesiredTuple = 0x81; - if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) { + if (pcmcia_get_first_tuple(link, tuple) != CS_SUCCESS) { rc = -1; goto free_cfg_mem; } - if (pcmcia_get_tuple_data(handle, tuple) != CS_SUCCESS) { + if (pcmcia_get_tuple_data(link, tuple) != CS_SUCCESS) { rc = -1; goto free_cfg_mem; } @@ -616,7 +606,7 @@ free_cfg_mem: ======================================================================*/ -static void mot_config(dev_link_t *link) +static void mot_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); @@ -637,7 +627,7 @@ static void mot_config(dev_link_t *link) mdelay(100); } -static int mot_setup(dev_link_t *link) +static int mot_setup(struct pcmcia_device *link) { struct net_device *dev = link->priv; kio_addr_t ioaddr = dev->base_addr; @@ -671,7 +661,7 @@ static int mot_setup(dev_link_t *link) /*====================================================================*/ -static int smc_config(dev_link_t *link) +static int smc_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct smc_cfg_mem *cfg_mem; @@ -696,16 +686,16 @@ static int smc_config(dev_link_t *link) tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; link->io.NumPorts1 = 16; - i = first_tuple(link->handle, tuple, parse); + i = first_tuple(link, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if (i == CS_SUCCESS) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } - i = next_tuple(link->handle, tuple, parse); + i = next_tuple(link, tuple, parse); } if (i == CS_SUCCESS) dev->base_addr = link->io.BasePort1; @@ -714,9 +704,8 @@ static int smc_config(dev_link_t *link) return i; } -static int smc_setup(dev_link_t *link) +static int smc_setup(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; struct smc_cfg_mem *cfg_mem; tuple_t *tuple; @@ -739,11 +728,11 @@ static int smc_setup(dev_link_t *link) /* Check for a LAN function extension tuple */ tuple->DesiredTuple = CISTPL_FUNCE; - i = first_tuple(handle, tuple, parse); + i = first_tuple(link, tuple, parse); while (i == CS_SUCCESS) { if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID) break; - i = next_tuple(handle, tuple, parse); + i = next_tuple(link, tuple, parse); } if (i == CS_SUCCESS) { node_id = (cistpl_lan_node_id_t *)parse->funce.data; @@ -756,7 +745,7 @@ static int smc_setup(dev_link_t *link) } /* Try the third string in the Version 1 Version/ID tuple. */ tuple->DesiredTuple = CISTPL_VERS_1; - if (first_tuple(handle, tuple, parse) != CS_SUCCESS) { + if (first_tuple(link, tuple, parse) != CS_SUCCESS) { rc = -1; goto free_cfg_mem; } @@ -774,7 +763,7 @@ free_cfg_mem: /*====================================================================*/ -static int osi_config(dev_link_t *link) +static int osi_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; static const kio_addr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; @@ -794,22 +783,21 @@ static int osi_config(dev_link_t *link) for (i = j = 0; j < 4; j++) { link->io.BasePort2 = com[j]; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { /* Fallback: turn off hard decode */ link->conf.ConfigIndex = 0x03; link->io.NumPorts2 = 0; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); } dev->base_addr = link->io.BasePort1 + 0x10; return i; } -static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid) +static int osi_setup(struct pcmcia_device *link, u_short manfid, u_short cardid) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; struct smc_cfg_mem *cfg_mem; tuple_t *tuple; @@ -830,12 +818,12 @@ static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid) /* Read the station address from tuple 0x90, subtuple 0x04 */ tuple->DesiredTuple = 0x90; - i = pcmcia_get_first_tuple(handle, tuple); + i = pcmcia_get_first_tuple(link, tuple); while (i == CS_SUCCESS) { - i = pcmcia_get_tuple_data(handle, tuple); + i = pcmcia_get_tuple_data(link, tuple); if ((i != CS_SUCCESS) || (buf[0] == 0x04)) break; - i = pcmcia_get_next_tuple(handle, tuple); + i = pcmcia_get_next_tuple(link, tuple); } if (i != CS_SUCCESS) { rc = -1; @@ -868,57 +856,47 @@ free_cfg_mem: return rc; } -static int smc91c92_suspend(struct pcmcia_device *p_dev) +static int smc91c92_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } + if (link->open) + netif_device_detach(dev); return 0; } -static int smc91c92_resume(struct pcmcia_device *p_dev) +static int smc91c92_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); int i; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if ((smc->manfid == MANFID_MEGAHERTZ) && - (smc->cardid == PRODID_MEGAHERTZ_EM3288)) - mhz_3288_power(link); - pcmcia_request_configuration(link->handle, &link->conf); - if (smc->manfid == MANFID_MOTOROLA) - mot_config(link); - if ((smc->manfid == MANFID_OSITECH) && - (smc->cardid != PRODID_OSITECH_SEVEN)) { - /* Power up the card and enable interrupts */ - set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); - set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); - } - if (((smc->manfid == MANFID_OSITECH) && - (smc->cardid == PRODID_OSITECH_SEVEN)) || - ((smc->manfid == MANFID_PSION) && - (smc->cardid == PRODID_PSION_NET100))) { - /* Download the Seven of Diamonds firmware */ - for (i = 0; i < sizeof(__Xilinx7OD); i++) { - outb(__Xilinx7OD[i], link->io.BasePort1+2); - udelay(50); - } - } - if (link->open) { - smc_reset(dev); - netif_device_attach(dev); + if ((smc->manfid == MANFID_MEGAHERTZ) && + (smc->cardid == PRODID_MEGAHERTZ_EM3288)) + mhz_3288_power(link); + if (smc->manfid == MANFID_MOTOROLA) + mot_config(link); + if ((smc->manfid == MANFID_OSITECH) && + (smc->cardid != PRODID_OSITECH_SEVEN)) { + /* Power up the card and enable interrupts */ + set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); + set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); + } + if (((smc->manfid == MANFID_OSITECH) && + (smc->cardid == PRODID_OSITECH_SEVEN)) || + ((smc->manfid == MANFID_PSION) && + (smc->cardid == PRODID_PSION_NET100))) { + /* Download the Seven of Diamonds firmware */ + for (i = 0; i < sizeof(__Xilinx7OD); i++) { + outb(__Xilinx7OD[i], link->io.BasePort1+2); + udelay(50); } } + if (link->open) { + smc_reset(dev); + netif_device_attach(dev); + } return 0; } @@ -931,7 +909,7 @@ static int smc91c92_resume(struct pcmcia_device *p_dev) ======================================================================*/ -static int check_sig(dev_link_t *link) +static int check_sig(struct pcmcia_device *link) { struct net_device *dev = link->priv; kio_addr_t ioaddr = dev->base_addr; @@ -964,13 +942,15 @@ static int check_sig(dev_link_t *link) } if (width) { - printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n"); - smc91c92_suspend(link->handle); - pcmcia_release_io(link->handle, &link->io); - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - pcmcia_request_io(link->handle, &link->io); - smc91c92_resume(link->handle); - return check_sig(link); + modconf_t mod = { + .Attributes = CONF_IO_CHANGE_WIDTH, + }; + printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n"); + + smc91c92_suspend(link); + pcmcia_modify_configuration(link, &mod); + smc91c92_resume(link); + return check_sig(link); } return -ENODEV; } @@ -984,11 +964,10 @@ static int check_sig(dev_link_t *link) ======================================================================*/ #define CS_EXIT_TEST(ret, svc, label) \ -if (ret != CS_SUCCESS) { cs_error(link->handle, svc, ret); goto label; } +if (ret != CS_SUCCESS) { cs_error(link, svc, ret); goto label; } -static void smc91c92_config(dev_link_t *link) +static int smc91c92_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; struct smc_private *smc = netdev_priv(dev); struct smc_cfg_mem *cfg_mem; @@ -1015,21 +994,18 @@ static void smc91c92_config(dev_link_t *link) tuple->TupleDataMax = 64; tuple->DesiredTuple = CISTPL_CONFIG; - i = first_tuple(handle, tuple, parse); + i = first_tuple(link, tuple, parse); CS_EXIT_TEST(i, ParseTuple, config_failed); link->conf.ConfigBase = parse->config.base; link->conf.Present = parse->config.rmask[0]; tuple->DesiredTuple = CISTPL_MANFID; tuple->Attributes = TUPLE_RETURN_COMMON; - if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { + if (first_tuple(link, tuple, parse) == CS_SUCCESS) { smc->manfid = parse->manfid.manf; smc->cardid = parse->manfid.card; } - /* Configure card */ - link->state |= DEV_CONFIG; - if ((smc->manfid == MANFID_OSITECH) && (smc->cardid != PRODID_OSITECH_SEVEN)) { i = osi_config(link); @@ -1043,9 +1019,9 @@ static void smc91c92_config(dev_link_t *link) } CS_EXIT_TEST(i, RequestIO, config_failed); - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); CS_EXIT_TEST(i, RequestIRQ, config_failed); - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); CS_EXIT_TEST(i, RequestConfiguration, config_failed); if (smc->manfid == MANFID_MOTOROLA) @@ -1124,13 +1100,12 @@ static void smc91c92_config(dev_link_t *link) SMC_SELECT_BANK(0); } - link->dev = &smc->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &smc->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); if (register_netdev(dev) != 0) { printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto config_undo; } @@ -1160,15 +1135,14 @@ static void smc91c92_config(dev_link_t *link) } } kfree(cfg_mem); - return; + return 0; config_undo: unregister_netdev(dev); config_failed: /* CS_EXIT_TEST() calls jump to here... */ smc91c92_release(link); - link->state &= ~DEV_CONFIG_PENDING; kfree(cfg_mem); - + return -ENODEV; } /* smc91c92_config */ /*====================================================================== @@ -1179,22 +1153,15 @@ config_failed: /* CS_EXIT_TEST() calls jump to here... */ ======================================================================*/ -static void smc91c92_release(dev_link_t *link) +static void smc91c92_release(struct pcmcia_device *link) { - - DEBUG(0, "smc91c92_release(0x%p)\n", link); - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - if (link->win) { - struct net_device *dev = link->priv; - struct smc_private *smc = netdev_priv(dev); - iounmap(smc->base); - pcmcia_release_window(link->win); - } - - link->state &= ~DEV_CONFIG; + DEBUG(0, "smc91c92_release(0x%p)\n", link); + if (link->win) { + struct net_device *dev = link->priv; + struct smc_private *smc = netdev_priv(dev); + iounmap(smc->base); + } + pcmcia_disable_device(link); } /*====================================================================== @@ -1283,7 +1250,7 @@ static void smc_dump(struct net_device *dev) static int smc_open(struct net_device *dev) { struct smc_private *smc = netdev_priv(dev); - dev_link_t *link = &smc->link; + struct pcmcia_device *link = smc->p_dev; #ifdef PCMCIA_DEBUG DEBUG(0, "%s: smc_open(%p), ID/Window %4.4x.\n", @@ -1292,7 +1259,7 @@ static int smc_open(struct net_device *dev) #endif /* Check that the PCMCIA card is still here. */ - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; /* Physical device present signature. */ if (check_sig(link) < 0) { @@ -1320,7 +1287,7 @@ static int smc_open(struct net_device *dev) static int smc_close(struct net_device *dev) { struct smc_private *smc = netdev_priv(dev); - dev_link_t *link = &smc->link; + struct pcmcia_device *link = smc->p_dev; kio_addr_t ioaddr = dev->base_addr; DEBUG(0, "%s: smc_close(), status %4.4x.\n", @@ -2311,7 +2278,7 @@ static struct pcmcia_driver smc91c92_cs_driver = { .drv = { .name = "smc91c92_cs", }, - .probe = smc91c92_attach, + .probe = smc91c92_probe, .remove = smc91c92_detach, .id_table = smc91c92_ids, .suspend = smc91c92_suspend, diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index eed496803fe4..71f45056a70c 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -289,9 +289,9 @@ static void mii_wr(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg, * and ejection events. They are invoked from the event handler. */ -static int has_ce2_string(dev_link_t * link); -static void xirc2ps_config(dev_link_t * link); -static void xirc2ps_release(dev_link_t * link); +static int has_ce2_string(struct pcmcia_device * link); +static int xirc2ps_config(struct pcmcia_device * link); +static void xirc2ps_release(struct pcmcia_device * link); /**************** * The attach() and detach() entry points are used to create and destroy @@ -313,10 +313,10 @@ static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs /**************** * A linked list of "instances" of the device. Each actual * PCMCIA card corresponds to one device instance, and is described - * by one dev_link_t structure (defined in ds.h). + * by one struct pcmcia_device structure (defined in ds.h). * * You may not want to use a linked list for this -- for example, the - * memory card driver uses an array of dev_link_t pointers, where minor + * memory card driver uses an array of struct pcmcia_device pointers, where minor * device numbers are used to derive the corresponding array index. */ @@ -326,13 +326,13 @@ static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs * example, ethernet cards, modems). In other cases, there may be * many actual or logical devices (SCSI adapters, memory cards with * multiple partitions). The dev_node_t structures need to be kept - * in a linked list starting at the 'dev' field of a dev_link_t + * in a linked list starting at the 'dev' field of a struct pcmcia_device * structure. We allocate them in the card's private data structure, * because they generally can't be allocated dynamically. */ typedef struct local_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct net_device_stats stats; int card_type; @@ -355,7 +355,7 @@ static void do_tx_timeout(struct net_device *dev); static struct net_device_stats *do_get_stats(struct net_device *dev); static void set_addresses(struct net_device *dev); static void set_multicast_list(struct net_device *dev); -static int set_card_type(dev_link_t *link, const void *s); +static int set_card_type(struct pcmcia_device *link, const void *s); static int do_config(struct net_device *dev, struct ifmap *map); static int do_open(struct net_device *dev); static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -368,7 +368,7 @@ static int do_stop(struct net_device *dev); /*=============== Helper functions =========================*/ static int -first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int err; @@ -379,7 +379,7 @@ first_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) } static int -next_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse) { int err; @@ -553,9 +553,8 @@ mii_wr(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg, unsigned data, int len) */ static int -xirc2ps_attach(struct pcmcia_device *p_dev) +xirc2ps_probe(struct pcmcia_device *link) { - dev_link_t *link; struct net_device *dev; local_info_t *local; @@ -566,12 +565,11 @@ xirc2ps_attach(struct pcmcia_device *p_dev) if (!dev) return -ENOMEM; local = netdev_priv(dev); - link = &local->link; + local->p_dev = link; link->priv = dev; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; @@ -593,13 +591,7 @@ xirc2ps_attach(struct pcmcia_device *p_dev) dev->watchdog_timeo = TX_TIMEOUT; #endif - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - xirc2ps_config(link); - - return 0; + return xirc2ps_config(link); } /* xirc2ps_attach */ /**************** @@ -610,18 +602,16 @@ xirc2ps_attach(struct pcmcia_device *p_dev) */ static void -xirc2ps_detach(struct pcmcia_device *p_dev) +xirc2ps_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - if (link->state & DEV_CONFIG) - xirc2ps_release(link); + xirc2ps_release(link); free_netdev(dev); } /* xirc2ps_detach */ @@ -645,7 +635,7 @@ xirc2ps_detach(struct pcmcia_device *p_dev) * */ static int -set_card_type(dev_link_t *link, const void *s) +set_card_type(struct pcmcia_device *link, const void *s) { struct net_device *dev = link->priv; local_info_t *local = netdev_priv(dev); @@ -714,9 +704,8 @@ set_card_type(dev_link_t *link, const void *s) * Returns: true if this is a CE2 */ static int -has_ce2_string(dev_link_t * link) +has_ce2_string(struct pcmcia_device * link) { - client_handle_t handle = link->handle; tuple_t tuple; cisparse_t parse; u_char buf[256]; @@ -726,7 +715,7 @@ has_ce2_string(dev_link_t * link) tuple.TupleDataMax = 254; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_VERS_1; - if (!first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 2) { + if (!first_tuple(link, &tuple, &parse) && parse.version_1.ns > 2) { if (strstr(parse.version_1.str + parse.version_1.ofs[2], "CE2")) return 1; } @@ -738,10 +727,9 @@ has_ce2_string(dev_link_t * link) * is received, to configure the PCMCIA socket, and to make the * ethernet device available to the system. */ -static void -xirc2ps_config(dev_link_t * link) +static int +xirc2ps_config(struct pcmcia_device * link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; local_info_t *local = netdev_priv(dev); tuple_t tuple; @@ -767,7 +755,7 @@ xirc2ps_config(dev_link_t * link) /* Is this a valid card */ tuple.DesiredTuple = CISTPL_MANFID; - if ((err=first_tuple(handle, &tuple, &parse))) { + if ((err=first_tuple(link, &tuple, &parse))) { printk(KNOT_XIRC "manfid not found in CIS\n"); goto failure; } @@ -803,15 +791,15 @@ xirc2ps_config(dev_link_t * link) /* get configuration stuff */ tuple.DesiredTuple = CISTPL_CONFIG; - if ((err=first_tuple(handle, &tuple, &parse))) + if ((err=first_tuple(link, &tuple, &parse))) goto cis_error; link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* get the ethernet address from the CIS */ tuple.DesiredTuple = CISTPL_FUNCE; - for (err = first_tuple(handle, &tuple, &parse); !err; - err = next_tuple(handle, &tuple, &parse)) { + for (err = first_tuple(link, &tuple, &parse); !err; + err = next_tuple(link, &tuple, &parse)) { /* Once I saw two CISTPL_FUNCE_LAN_NODE_ID entries: * the first one with a length of zero the second correct - * so I skip all entries with length 0 */ @@ -821,8 +809,8 @@ xirc2ps_config(dev_link_t * link) } if (err) { /* not found: try to get the node-id from tuple 0x89 */ tuple.DesiredTuple = 0x89; /* data layout looks like tuple 0x22 */ - if ((err = pcmcia_get_first_tuple(handle, &tuple)) == 0 && - (err = pcmcia_get_tuple_data(handle, &tuple)) == 0) { + if ((err = pcmcia_get_first_tuple(link, &tuple)) == 0 && + (err = pcmcia_get_tuple_data(link, &tuple)) == 0) { if (tuple.TupleDataLen == 8 && *buf == CISTPL_FUNCE_LAN_NODE_ID) memcpy(&parse, buf, 8); else @@ -831,8 +819,8 @@ xirc2ps_config(dev_link_t * link) } if (err) { /* another try (James Lehmer's CE2 version 4.1)*/ tuple.DesiredTuple = CISTPL_FUNCE; - for (err = first_tuple(handle, &tuple, &parse); !err; - err = next_tuple(handle, &tuple, &parse)) { + for (err = first_tuple(link, &tuple, &parse); !err; + err = next_tuple(link, &tuple, &parse)) { if (parse.funce.type == 0x02 && parse.funce.data[0] == 1 && parse.funce.data[1] == 6 && tuple.TupleDataLen == 13) { buf[1] = 4; @@ -853,9 +841,6 @@ xirc2ps_config(dev_link_t * link) for (i=0; i < 6; i++) dev->dev_addr[i] = node_id->id[i]; - /* Configure card */ - link->state |= DEV_CONFIG; - link->io.IOAddrLines =10; link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; link->irq.Attributes = IRQ_HANDLE_PRESENT; @@ -875,14 +860,14 @@ xirc2ps_config(dev_link_t * link) * Ethernet port */ link->io.NumPorts1 = 16; /* no Mako stuff anymore */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - for (err = first_tuple(handle, &tuple, &parse); !err; - err = next_tuple(handle, &tuple, &parse)) { + for (err = first_tuple(link, &tuple, &parse); !err; + err = next_tuple(link, &tuple, &parse)) { if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) { for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { link->conf.ConfigIndex = cf->index ; link->io.BasePort2 = cf->io.win[0].base; link->io.BasePort1 = ioaddr; - if (!(err=pcmcia_request_io(link->handle, &link->io))) + if (!(err=pcmcia_request_io(link, &link->io))) goto port_found; } } @@ -896,15 +881,15 @@ xirc2ps_config(dev_link_t * link) */ for (pass=0; pass < 2; pass++) { tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - for (err = first_tuple(handle, &tuple, &parse); !err; - err = next_tuple(handle, &tuple, &parse)){ + for (err = first_tuple(link, &tuple, &parse); !err; + err = next_tuple(link, &tuple, &parse)){ if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8){ link->conf.ConfigIndex = cf->index ; link->io.BasePort2 = cf->io.win[0].base; link->io.BasePort1 = link->io.BasePort2 + (pass ? (cf->index & 0x20 ? -24:8) : (cf->index & 0x20 ? 8:-24)); - if (!(err=pcmcia_request_io(link->handle, &link->io))) + if (!(err=pcmcia_request_io(link, &link->io))) goto port_found; } } @@ -919,12 +904,12 @@ xirc2ps_config(dev_link_t * link) link->io.NumPorts1 = 16; for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) { link->io.BasePort1 = ioaddr; - if (!(err=pcmcia_request_io(link->handle, &link->io))) + if (!(err=pcmcia_request_io(link, &link->io))) goto port_found; } link->io.BasePort1 = 0; /* let CS decide */ - if ((err=pcmcia_request_io(link->handle, &link->io))) { - cs_error(link->handle, RequestIO, err); + if ((err=pcmcia_request_io(link, &link->io))) { + cs_error(link, RequestIO, err); goto config_error; } } @@ -936,8 +921,8 @@ xirc2ps_config(dev_link_t * link) * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ - if ((err=pcmcia_request_irq(link->handle, &link->irq))) { - cs_error(link->handle, RequestIRQ, err); + if ((err=pcmcia_request_irq(link, &link->irq))) { + cs_error(link, RequestIRQ, err); goto config_error; } @@ -945,8 +930,8 @@ xirc2ps_config(dev_link_t * link) * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping. */ - if ((err=pcmcia_request_configuration(link->handle, &link->conf))) { - cs_error(link->handle, RequestConfiguration, err); + if ((err=pcmcia_request_configuration(link, &link->conf))) { + cs_error(link, RequestConfiguration, err); goto config_error; } @@ -963,15 +948,15 @@ xirc2ps_config(dev_link_t * link) reg.Action = CS_WRITE; reg.Offset = CISREG_IOBASE_0; reg.Value = link->io.BasePort2 & 0xff; - if ((err = pcmcia_access_configuration_register(link->handle, ®))) { - cs_error(link->handle, AccessConfigurationRegister, err); + if ((err = pcmcia_access_configuration_register(link, ®))) { + cs_error(link, AccessConfigurationRegister, err); goto config_error; } reg.Action = CS_WRITE; reg.Offset = CISREG_IOBASE_1; reg.Value = (link->io.BasePort2 >> 8) & 0xff; - if ((err = pcmcia_access_configuration_register(link->handle, ®))) { - cs_error(link->handle, AccessConfigurationRegister, err); + if ((err = pcmcia_access_configuration_register(link, ®))) { + cs_error(link, AccessConfigurationRegister, err); goto config_error; } @@ -982,15 +967,15 @@ xirc2ps_config(dev_link_t * link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = 0; - if ((err = pcmcia_request_window(&link->handle, &req, &link->win))) { - cs_error(link->handle, RequestWindow, err); + if ((err = pcmcia_request_window(&link, &req, &link->win))) { + cs_error(link, RequestWindow, err); goto config_error; } local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800; mem.CardOffset = 0x0; mem.Page = 0; if ((err = pcmcia_map_mem_page(link->win, &mem))) { - cs_error(link->handle, MapMemPage, err); + cs_error(link, MapMemPage, err); goto config_error; } @@ -1050,13 +1035,12 @@ xirc2ps_config(dev_link_t * link) if (local->dingo) do_reset(dev, 1); /* a kludge to make the cem56 work */ - link->dev = &local->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &local->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); if ((err=register_netdev(dev))) { printk(KNOT_XIRC "register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto config_error; } @@ -1069,17 +1053,16 @@ xirc2ps_config(dev_link_t * link) printk("%c%02X", i?':':' ', dev->dev_addr[i]); printk("\n"); - return; + return 0; config_error: - link->state &= ~DEV_CONFIG_PENDING; xirc2ps_release(link); - return; + return -ENODEV; cis_error: printk(KNOT_XIRC "unable to parse CIS\n"); failure: - link->state &= ~DEV_CONFIG_PENDING; + return -ENODEV; } /* xirc2ps_config */ /**************** @@ -1088,57 +1071,41 @@ xirc2ps_config(dev_link_t * link) * still open, this will be postponed until it is closed. */ static void -xirc2ps_release(dev_link_t *link) +xirc2ps_release(struct pcmcia_device *link) { + DEBUG(0, "release(0x%p)\n", link); - DEBUG(0, "release(0x%p)\n", link); - - if (link->win) { - struct net_device *dev = link->priv; - local_info_t *local = netdev_priv(dev); - if (local->dingo) - iounmap(local->dingo_ccr - 0x0800); - pcmcia_release_window(link->win); - } - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; - + if (link->win) { + struct net_device *dev = link->priv; + local_info_t *local = netdev_priv(dev); + if (local->dingo) + iounmap(local->dingo_ccr - 0x0800); + } + pcmcia_disable_device(link); } /* xirc2ps_release */ /*====================================================================*/ -static int xirc2ps_suspend(struct pcmcia_device *p_dev) +static int xirc2ps_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) { - netif_device_detach(dev); - do_powerdown(dev); - } - pcmcia_release_configuration(link->handle); + if (link->open) { + netif_device_detach(dev); + do_powerdown(dev); } return 0; } -static int xirc2ps_resume(struct pcmcia_device *p_dev) +static int xirc2ps_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - do_reset(dev,1); - netif_device_attach(dev); - } + if (link->open) { + do_reset(dev,1); + netif_device_attach(dev); } return 0; @@ -1552,13 +1519,13 @@ static int do_open(struct net_device *dev) { local_info_t *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; DEBUG(0, "do_open(%p)\n", dev); /* Check that the PCMCIA card is still here. */ /* Physical device present signature. */ - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; /* okay */ @@ -1882,7 +1849,7 @@ do_stop(struct net_device *dev) { kio_addr_t ioaddr = dev->base_addr; local_info_t *lp = netdev_priv(dev); - dev_link_t *link = &lp->link; + struct pcmcia_device *link = lp->p_dev; DEBUG(0, "do_stop(%p)\n", dev); @@ -1935,7 +1902,7 @@ static struct pcmcia_driver xirc2ps_cs_driver = { .drv = { .name = "xirc2ps_cs", }, - .probe = xirc2ps_attach, + .probe = xirc2ps_probe, .remove = xirc2ps_detach, .id_table = xirc2ps_ids, .suspend = xirc2ps_suspend, @@ -1973,7 +1940,7 @@ static int __init setup_xirc2ps_cs(char *str) MAYBE_SET(lockup_hack, 6); #undef MAYBE_SET - return 0; + return 1; } __setup("xirc2ps_cs=", setup_xirc2ps_cs); diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 9595f74da93f..07c31f19c6ba 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1167,8 +1167,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) * station address PROM at the base address and programmed into the * "Physical Address Registers" CSR12-14. * As a precautionary measure, we read the PROM values and complain if - * they disagree with the CSRs. Either way, we use the CSR values, and - * double check that they are valid. + * they disagree with the CSRs. If they miscompare, and the PROM addr + * is valid, then the PROM addr is used. */ for (i = 0; i < 3; i++) { unsigned int val; diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 35dbf05c7f06..a70c2b0cc104 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -78,6 +78,8 @@ static const struct pci_device_id skge_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) }, diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 68f9c206a620..67b0eab16589 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -99,8 +99,6 @@ MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, @@ -579,8 +577,8 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) reg = gma_read16(hw, port, GM_PHY_ADDR); gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); - for (i = 0; i < GM_MIB_CNT_SIZE; i++) - gma_read16(hw, port, GM_MIB_CNT_BASE + 8 * i); + for (i = GM_MIB_CNT_BASE; i <= GM_MIB_CNT_END; i += 4) + gma_read16(hw, port, i); gma_write16(hw, port, GM_PHY_ADDR, reg); /* transmit control */ diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 62532b4e45c5..89dd18cd12f0 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1375,7 +1375,7 @@ enum { GM_PHY_ADDR = 0x0088, /* 16 bit r/w GPHY Address Register */ /* MIB Counters */ GM_MIB_CNT_BASE = 0x0100, /* Base Address of MIB Counters */ - GM_MIB_CNT_SIZE = 256, + GM_MIB_CNT_END = 0x025C, /* Last MIB counter */ }; diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 1f5975a61e1f..43f5e86fc559 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1442,7 +1442,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_GRFAFLLINT: /* fallthrough */ case SPIDER_NET_GRMFLLINT: if (netif_msg_intr(card) && net_ratelimit()) - pr_err("Spider RX RAM full, incoming packets " + pr_debug("Spider RX RAM full, incoming packets " "might be discarded!\n"); spider_net_rx_irq_off(card); tasklet_schedule(&card->rxram_full_tl); @@ -2086,7 +2086,7 @@ spider_net_setup_netdev(struct spider_net_card *card) spider_net_setup_netdev_ops(netdev); - netdev->features = 0; + netdev->features = NETIF_F_HW_CSUM; /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | * NETIF_F_HW_VLAN_FILTER */ diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 35b18057fbdd..9b7805be21da 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -335,7 +335,7 @@ do { \ /* These identify the driver base version and may not be removed. */ -static char version[] __devinitdata = +static const char version[] __devinitdata = KERN_INFO "starfire.c:v1.03 7/26/2000 Written by Donald Becker \n" KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n"; @@ -2122,8 +2122,7 @@ static void __devexit starfire_remove_one (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct netdev_private *np = netdev_priv(dev); - if (!dev) - BUG(); + BUG_ON(!dev); unregister_netdev(dev); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b5473325bff4..73e271e59c6a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.54" -#define DRV_MODULE_RELDATE "Mar 23, 2006" +#define DRV_MODULE_VERSION "3.56" +#define DRV_MODULE_RELDATE "Apr 1, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -497,33 +497,40 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) unsigned long flags; spin_lock_irqsave(&tp->indirect_lock, flags); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); - /* Always leave this as zero. */ - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + } else { + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); + tw32_f(TG3PCI_MEM_WIN_DATA, val); + + /* Always leave this as zero. */ + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); + } spin_unlock_irqrestore(&tp->indirect_lock, flags); } -static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val) -{ - /* If no workaround is needed, write to mem space directly */ - if (tp->write32 != tg3_write_indirect_reg32) - tw32(NIC_SRAM_WIN_BASE + off, val); - else - tg3_write_mem(tp, off, val); -} - static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) { unsigned long flags; spin_lock_irqsave(&tp->indirect_lock, flags); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); - pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); - /* Always leave this as zero. */ - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + } else { + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); + *val = tr32(TG3PCI_MEM_WIN_DATA); + + /* Always leave this as zero. */ + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); + } spin_unlock_irqrestore(&tp->indirect_lock, flags); } @@ -1367,12 +1374,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } + tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); + /* Finally, set the new power state. */ pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); udelay(100); /* Delay after power state change */ - tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); - return 0; } @@ -2959,9 +2966,7 @@ static void tg3_tx(struct tg3 *tp) struct sk_buff *skb = ri->skb; int i; - if (unlikely(skb == NULL)) - BUG(); - + BUG_ON(skb == NULL); pci_unmap_single(tp->pdev, pci_unmap_addr(ri, mapping), skb_headlen(skb), @@ -2972,12 +2977,10 @@ static void tg3_tx(struct tg3 *tp) sw_idx = NEXT_TX(sw_idx); for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - if (unlikely(sw_idx == hw_idx)) - BUG(); + BUG_ON(sw_idx == hw_idx); ri = &tp->tx_buffers[sw_idx]; - if (unlikely(ri->skb != NULL)) - BUG(); + BUG_ON(ri->skb != NULL); pci_unmap_page(tp->pdev, pci_unmap_addr(ri, mapping), @@ -3600,7 +3603,7 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, int len) { #if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64) - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) return (((u64) mapping + len) > DMA_40BIT_MASK); return 0; #else @@ -4928,9 +4931,8 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset) { int i; - if (offset == TX_CPU_BASE && - (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) - BUG(); + BUG_ON(offset == TX_CPU_BASE && + (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)); if (offset == RX_CPU_BASE) { for (i = 0; i < 10000; i++) { @@ -5833,10 +5835,14 @@ static int tg3_reset_hw(struct tg3 *tp) GRC_MODE_NO_TX_PHDR_CSUM | GRC_MODE_NO_RX_PHDR_CSUM); tp->grc_mode |= GRC_MODE_HOST_SENDBDS; - if (tp->tg3_flags & TG3_FLAG_NO_TX_PSEUDO_CSUM) - tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; - if (tp->tg3_flags & TG3_FLAG_NO_RX_PSEUDO_CSUM) - tp->grc_mode |= GRC_MODE_NO_RX_PHDR_CSUM; + + /* Pseudo-header checksum is done by hardware logic and not + * the offload processers, so make the chip do the pseudo- + * header checksums on receive. For transmit it is more + * convenient to do the pseudo-header checksum in software + * as Linux does that on transmit for us in all cases. + */ + tp->grc_mode |= GRC_MODE_NO_TX_PHDR_CSUM; tw32(GRC_MODE, tp->grc_mode | @@ -6461,6 +6467,9 @@ static void tg3_timer(unsigned long __opaque) { struct tg3 *tp = (struct tg3 *) __opaque; + if (tp->irq_sync) + goto restart_timer; + spin_lock(&tp->lock); if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { @@ -6537,11 +6546,11 @@ static void tg3_timer(unsigned long __opaque) if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { u32 val; - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX, - FWCMD_NICDRV_ALIVE2); - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, + FWCMD_NICDRV_ALIVE2); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); /* 5 seconds timeout */ - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); val = tr32(GRC_RX_CPU_EVENT); val |= (1 << 14); tw32(GRC_RX_CPU_EVENT, val); @@ -6551,6 +6560,7 @@ static void tg3_timer(unsigned long __opaque) spin_unlock(&tp->lock); +restart_timer: tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); } @@ -8035,9 +8045,13 @@ static int tg3_test_nvram(struct tg3 *tp) for (i = 0; i < size; i++) csum8 += buf8[i]; - if (csum8 == 0) - return 0; - return -EIO; + if (csum8 == 0) { + err = 0; + goto out; + } + + err = -EIO; + goto out; } /* Bootstrap checksum at offset 0x10 */ @@ -8399,8 +8413,11 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) } mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII; - if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) + if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { mac_mode &= ~MAC_MODE_LINK_POLARITY; + tg3_writephy(tp, MII_TG3_EXT_CTRL, + MII_TG3_EXT_CTRL_LNK3_LED_MODE); + } tw32(MAC_MODE, mac_mode); } else @@ -9529,8 +9546,11 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->led_ctrl = LED_CTRL_MODE_PHY_1; /* Do not even try poking around in here on Sun parts. */ - if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { + /* All SUN chips are built-in LOMs. */ + tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; return; + } tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { @@ -9628,9 +9648,7 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL) tp->led_ctrl = LED_CTRL_MODE_PHY_2; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) && - (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)) + if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) { @@ -10255,6 +10273,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); } + if (tp->write32 == tg3_write_indirect_reg32 || + ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) && + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) || + (tp->tg3_flags2 & TG3_FLG2_SUN_570X)) + tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG; + /* Get eeprom hw config before calling tg3_set_power_state(). * In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be * determined before calling tg3_set_power_state() so that @@ -10297,15 +10322,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; - /* Pseudo-header checksum is done by hardware logic and not - * the offload processers, so make the chip do the pseudo- - * header checksums on receive. For transmit it is more - * convenient to do the pseudo-header checksum in software - * as Linux does that on transmit for us in all cases. - */ - tp->tg3_flags |= TG3_FLAG_NO_TX_PSEUDO_CSUM; - tp->tg3_flags &= ~TG3_FLAG_NO_RX_PSEUDO_CSUM; - /* Derive initial jumbo mode from MTU assigned in * ether_setup() via the alloc_etherdev() call */ @@ -10531,6 +10547,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) { struct net_device *dev = tp->dev; u32 hi, lo, mac_offset; + int addr_ok = 0; #ifdef CONFIG_SPARC64 if (!tg3_get_macaddr_sparc(tp)) @@ -10560,29 +10577,34 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) dev->dev_addr[3] = (lo >> 16) & 0xff; dev->dev_addr[4] = (lo >> 8) & 0xff; dev->dev_addr[5] = (lo >> 0) & 0xff; - } - /* Next, try NVRAM. */ - else if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) && - !tg3_nvram_read(tp, mac_offset + 0, &hi) && - !tg3_nvram_read(tp, mac_offset + 4, &lo)) { - dev->dev_addr[0] = ((hi >> 16) & 0xff); - dev->dev_addr[1] = ((hi >> 24) & 0xff); - dev->dev_addr[2] = ((lo >> 0) & 0xff); - dev->dev_addr[3] = ((lo >> 8) & 0xff); - dev->dev_addr[4] = ((lo >> 16) & 0xff); - dev->dev_addr[5] = ((lo >> 24) & 0xff); - } - /* Finally just fetch it out of the MAC control regs. */ - else { - hi = tr32(MAC_ADDR_0_HIGH); - lo = tr32(MAC_ADDR_0_LOW); - dev->dev_addr[5] = lo & 0xff; - dev->dev_addr[4] = (lo >> 8) & 0xff; - dev->dev_addr[3] = (lo >> 16) & 0xff; - dev->dev_addr[2] = (lo >> 24) & 0xff; - dev->dev_addr[1] = hi & 0xff; - dev->dev_addr[0] = (hi >> 8) & 0xff; + /* Some old bootcode may report a 0 MAC address in SRAM */ + addr_ok = is_valid_ether_addr(&dev->dev_addr[0]); + } + if (!addr_ok) { + /* Next, try NVRAM. */ + if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) && + !tg3_nvram_read(tp, mac_offset + 0, &hi) && + !tg3_nvram_read(tp, mac_offset + 4, &lo)) { + dev->dev_addr[0] = ((hi >> 16) & 0xff); + dev->dev_addr[1] = ((hi >> 24) & 0xff); + dev->dev_addr[2] = ((lo >> 0) & 0xff); + dev->dev_addr[3] = ((lo >> 8) & 0xff); + dev->dev_addr[4] = ((lo >> 16) & 0xff); + dev->dev_addr[5] = ((lo >> 24) & 0xff); + } + /* Finally just fetch it out of the MAC control regs. */ + else { + hi = tr32(MAC_ADDR_0_HIGH); + lo = tr32(MAC_ADDR_0_LOW); + + dev->dev_addr[5] = lo & 0xff; + dev->dev_addr[4] = (lo >> 8) & 0xff; + dev->dev_addr[3] = (lo >> 16) & 0xff; + dev->dev_addr[2] = (lo >> 24) & 0xff; + dev->dev_addr[1] = hi & 0xff; + dev->dev_addr[0] = (hi >> 8) & 0xff; + } } if (!is_valid_ether_addr(&dev->dev_addr[0])) { diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index c43cc3264202..8c8b987d1250 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2171,8 +2171,7 @@ struct tg3 { #define TG3_FLAG_PCIX_MODE 0x00020000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_32BIT 0x00080000 -#define TG3_FLAG_NO_TX_PSEUDO_CSUM 0x00100000 -#define TG3_FLAG_NO_RX_PSEUDO_CSUM 0x00200000 +#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000 #define TG3_FLAG_SERDES_WOL_CAP 0x00400000 #define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000 #define TG3_FLAG_10_100_ONLY 0x01000000 diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig index e4cfc80b283b..99c4c1922f19 100644 --- a/drivers/net/tokenring/Kconfig +++ b/drivers/net/tokenring/Kconfig @@ -3,7 +3,7 @@ # menu "Token Ring devices" - depends on NETDEVICES + depends on NETDEVICES && !UML # So far, we only have PCI, ISA, and MCA token ring devices config TR diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 9345e68c451e..649d8ea354f5 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -438,8 +438,7 @@ static void __devexit abyss_detach (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - if (!dev) - BUG(); + BUG_ON(!dev); unregister_netdev(dev); release_region(dev->base_addr-0x10, ABYSS_IO_EXTENT); free_irq(dev->irq, dev); diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 3a25d191ea4a..19e6f4dfd69c 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -735,8 +735,7 @@ static int __devexit madgemc_remove(struct device *device) struct net_local *tp; struct card_info *card; - if (!dev) - BUG(); + BUG_ON(!dev); tp = dev->priv; card = tp->tmspriv; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index d1a86a080a65..f56094102042 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -4160,7 +4160,7 @@ get_hw_addr(struct net_device *dev) ** If the address starts with 00 a0, we have to bit-reverse ** each byte of the address. */ - if ( (_machine & _MACH_Pmac) && + if ( machine_is(powermac) && (dev->dev_addr[0] == 0) && (dev->dev_addr[1] == 0xa0) ) { diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index c1ce87a5f8d3..d9258d42090c 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -134,7 +134,7 @@ static const int multicast_filter_limit = 32; #include "typhoon.h" #include "typhoon-firmware.h" -static char version[] __devinitdata = +static const char version[] __devinitdata = "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("David Dillow "); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 241871589283..6a23964c1317 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -469,7 +469,7 @@ struct rhine_private { struct sk_buff *tx_skbuff[TX_RING_SIZE]; dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; - /* Tx bounce buffers */ + /* Tx bounce buffers (Rhine-I only) */ unsigned char *tx_buf[TX_RING_SIZE]; unsigned char *tx_bufs; dma_addr_t tx_bufs_dma; @@ -1043,7 +1043,8 @@ static void alloc_tbufs(struct net_device* dev) rp->tx_ring[i].desc_length = cpu_to_le32(TXDESC); next += sizeof(struct tx_desc); rp->tx_ring[i].next_desc = cpu_to_le32(next); - rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ]; + if (rp->quirks & rqRhineI) + rp->tx_buf[i] = &rp->tx_bufs[i * PKT_BUF_SZ]; } rp->tx_ring[i-1].next_desc = cpu_to_le32(rp->tx_ring_dma); @@ -1085,6 +1086,25 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) else iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex, ioaddr + ChipCmd1); + if (debug > 1) + printk(KERN_INFO "%s: force_media %d, carrier %d\n", dev->name, + rp->mii_if.force_media, netif_carrier_ok(dev)); +} + +/* Called after status of force_media possibly changed */ +static void rhine_set_carrier(struct mii_if_info *mii) +{ + if (mii->force_media) { + /* autoneg is off: Link is always assumed to be up */ + if (!netif_carrier_ok(mii->dev)) + netif_carrier_on(mii->dev); + } + else /* Let MMI library update carrier status */ + rhine_check_media(mii->dev, 0); + if (debug > 1) + printk(KERN_INFO "%s: force_media %d, carrier %d\n", + mii->dev->name, mii->force_media, + netif_carrier_ok(mii->dev)); } static void rhine_check_media_task(struct net_device *dev) @@ -1782,6 +1802,7 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) spin_lock_irq(&rp->lock); rc = mii_ethtool_sset(&rp->mii_if, cmd); spin_unlock_irq(&rp->lock); + rhine_set_carrier(&rp->mii_if); return rc; } @@ -1869,6 +1890,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_lock_irq(&rp->lock); rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL); spin_unlock_irq(&rp->lock); + rhine_set_carrier(&rp->mii_if); return rc; } diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 883cf7da10fc..b5328b0ff927 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -410,103 +410,6 @@ config WAN_ROUTER_DRIVERS If unsure, say N. -config VENDOR_SANGOMA - tristate "Sangoma WANPIPE(tm) multiprotocol cards" - depends on WAN_ROUTER_DRIVERS && WAN_ROUTER && (PCI || ISA) && BROKEN - ---help--- - Driver for S514-PCI/ISA Synchronous Data Link Adapters (SDLA). - - WANPIPE from Sangoma Technologies Inc. - is a family of intelligent multiprotocol WAN adapters with data - transfer rates up to 4Mbps. Cards support: - - - X.25, Frame Relay, PPP, Cisco HDLC protocols. - - - API for protocols like HDLC (LAPB), HDLC Streaming, X.25, - Frame Relay and BiSync. - - - Ethernet Bridging over Frame Relay protocol. - - - MULTILINK PPP - - - Async PPP (Modem Dialup) - - The next questions will ask you about the protocols you want - the driver to support. - - If you have one or more of these cards, say M to this option; - and read . - - To compile this driver as a module, choose M here: the - module will be called wanpipe. - -config WANPIPE_CHDLC - bool "WANPIPE Cisco HDLC support" - depends on VENDOR_SANGOMA - ---help--- - Connect a WANPIPE card to a leased line using the Cisco HDLC. - - - Supports Dual Port Cisco HDLC on the S514-PCI/S508-ISA cards - which allows user to build applications using the HDLC streaming API. - - - CHDLC Streaming MULTILINK PPP that can bind multiple WANPIPE T1 - cards into a single logical channel. - - Say Y and the Cisco HDLC support, HDLC streaming API and - MULTILINK PPP will be included in the driver. - -config WANPIPE_FR - bool "WANPIPE Frame Relay support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to a Frame Relay network, or use Frame Relay - API to develop custom applications. - - Contains the Ethernet Bridging over Frame Relay feature, where - a WANPIPE frame relay link can be directly connected to the Linux - kernel bridge. The Frame Relay option is supported on S514-PCI - and S508-ISA cards. - - Say Y and the Frame Relay support will be included in the driver. - -config WANPIPE_X25 - bool "WANPIPE X.25 support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to an X.25 network. - - Includes the X.25 API support for custom applications over the - X.25 protocol. The X.25 option is supported on S514-PCI and - S508-ISA cards. - - Say Y and the X.25 support will be included in the driver. - -config WANPIPE_PPP - bool "WANPIPE PPP support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to a leased line using Point-to-Point - Protocol (PPP). - - The PPP option is supported on S514-PCI/S508-ISA cards. - - Say Y and the PPP support will be included in the driver. - -config WANPIPE_MULTPPP - bool "WANPIPE Multi-Port PPP support" - depends on VENDOR_SANGOMA - help - Connect a WANPIPE card to a leased line using Point-to-Point - Protocol (PPP). - - Uses in-kernel SyncPPP protocol over the Sangoma HDLC Streaming - adapter. In this case each Sangoma adapter port can support an - independent PPP connection. For example, a single Quad-Port PCI - adapter can support up to four independent PPP links. The PPP - option is supported on S514-PCI/S508-ISA cards. - - Say Y and the Multi-Port PPP support will be included in the driver. - config CYCLADES_SYNC tristate "Cyclom 2X(tm) cards (EXPERIMENTAL)" depends on WAN_ROUTER_DRIVERS && (PCI || ISA) diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index ce6c56b903e7..823c6d5ab90d 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -5,14 +5,6 @@ # Rewritten to use lists instead of if-statements. # -wanpipe-y := sdlamain.o sdla_ft1.o -wanpipe-$(CONFIG_WANPIPE_X25) += sdla_x25.o -wanpipe-$(CONFIG_WANPIPE_FR) += sdla_fr.o -wanpipe-$(CONFIG_WANPIPE_CHDLC) += sdla_chdlc.o -wanpipe-$(CONFIG_WANPIPE_PPP) += sdla_ppp.o -wanpipe-$(CONFIG_WANPIPE_MULTPPP) += wanpipe_multppp.o -wanpipe-objs := $(wanpipe-y) - cyclomx-y := cycx_main.o cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o cyclomx-objs := $(cyclomx-y) @@ -43,11 +35,6 @@ obj-$(CONFIG_LANMEDIA) += lmc/ obj-$(CONFIG_DLCI) += dlci.o obj-$(CONFIG_SDLA) += sdla.o -ifeq ($(CONFIG_WANPIPE_MULTPPP),y) - obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o syncppp.o -else - obj-$(CONFIG_VENDOR_SANGOMA) += sdladrv.o wanpipe.o -endif obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o obj-$(CONFIG_LAPBETHER) += lapbether.o obj-$(CONFIG_SBNI) += sbni.o diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c deleted file mode 100644 index 496d29237e92..000000000000 --- a/drivers/net/wan/sdla_chdlc.c +++ /dev/null @@ -1,4428 +0,0 @@ -/***************************************************************************** -* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. -* -* Authors: Nenad Corbic -* Gideon Hack -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* 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. -* ============================================================================ -* Feb 28, 2001 Nenad Corbic Updated if_tx_timeout() routine for -* 2.4.X kernels. -* Jan 25, 2001 Nenad Corbic Added a TTY Sync serial driver over the -* HDLC streaming protocol -* Added a TTY Async serial driver over the -* Async protocol. -* Dec 15, 2000 Nenad Corbic Updated for 2.4.X Kernel support -* Nov 13, 2000 Nenad Corbic Added true interface type encoding option. -* Tcpdump doesn't support CHDLC inteface -* types, to fix this "true type" option will set -* the interface type to RAW IP mode. -* Nov 07, 2000 Nenad Corbic Added security features for UDP debugging: -* Deny all and specify allowed requests. -* Jun 20, 2000 Nenad Corbic Fixed the API IP ERROR bug. Caused by the -* latest update. -* May 09, 2000 Nenad Corbic Option to bring down an interface -* upon disconnect. -* Mar 23, 2000 Nenad Corbic Improved task queue, bh handling. -* Mar 16, 2000 Nenad Corbic Fixed the SLARP Dynamic IP addressing. -* Mar 06, 2000 Nenad Corbic Bug Fix: corrupted mbox recovery. -* Feb 10, 2000 Gideon Hack Added ASYNC support. -* Feb 09, 2000 Nenad Corbic Fixed two shutdown bugs in update() and -* if_stats() functions. -* Jan 24, 2000 Nenad Corbic Fixed a startup wanpipe state racing, -* condition between if_open and isr. -* Jan 10, 2000 Nenad Corbic Added new socket API support. -* Dev 15, 1999 Nenad Corbic Fixed up header files for 2.0.X kernels -* Nov 20, 1999 Nenad Corbic Fixed zero length API bug. -* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. -* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing -* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). -* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. -* Aug 07, 1998 David Fong Initial version. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ - - -#include -#include -#include - -#include /* sockaddr_in */ -#include -#include -#include /* htons(), etc. */ -#include -#include - -#include /* CHDLC firmware API definitions */ -#include /* CHDLC (async) API definitions */ - -#include /* Socket Driver common area */ -#include - -/* TTY Includes */ -#include -#include -#include - - -/****** Defines & Macros ****************************************************/ - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x01 -#define TMR_INT_ENABLED_UPDATE 0x02 -#define TMR_INT_ENABLED_CONFIG 0x10 - -#define MAX_IP_ERRORS 10 - -#define TTY_CHDLC_MAX_MTU 2000 -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) -#define MAX_BH_BUFF 10 - -//#define PRINT_DEBUG -#ifdef PRINT_DEBUG -#define dbg_printk(format, a...) printk(format, ## a) -#else -#define dbg_printk(format, a...) -#endif - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - wanpipe_common_t common; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - u32 ip_local; - u32 ip_remote; - u32 ip_local_tmp; - u32 ip_remote_tmp; - u8 ip_error; - u8 config_chdlc; - u8 config_chdlc_timeout; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - - bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ - unsigned long tq_working; - volatile int bh_write; - volatile int bh_read; - atomic_t bh_buff_used; - - unsigned char interface_down; - - /* Polling work queue entry. Each interface - * has its own work queue entry, which is used - * to defer events from the interrupt */ - struct work_struct poll_work; - struct timer_list poll_delay_timer; - - u8 gateway; - u8 true_if_encoding; - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -/* variable for tracking how many interfaces to open for WANPIPE on the - two ports */ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); - -/* Network device interface */ -static int if_init(struct net_device* dev); -static int if_open(struct net_device* dev); -static int if_close(struct net_device* dev); -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, - unsigned len); - -static int if_rebuild_hdr (struct sk_buff *skb); -static struct net_device_stats* if_stats(struct net_device* dev); - -static int if_send(struct sk_buff* skb, struct net_device* dev); - -/* CHDLC Firmware interface functions */ -static int chdlc_configure (sdla_t* card, void* data); -static int chdlc_comm_enable (sdla_t* card); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); -static int chdlc_send (sdla_t* card, void* data, unsigned len); -static int chdlc_read_comm_err_stats (sdla_t* card); -static int chdlc_read_op_stats (sdla_t* card); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); - - -static int chdlc_disable_comm_shutdown (sdla_t *card); -static void if_tx_timeout(struct net_device *dev); - -/* Miscellaneous CHDLC Functions */ -static int set_chdlc_config (sdla_t* card); -static void init_chdlc_tx_rx_buff( sdla_t* card); -static int process_chdlc_exception(sdla_t *card); -static int process_global_exception(sdla_t *card); -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area); -static int configure_ip (sdla_t* card); -static int unconfigure_ip (sdla_t* card); -static void process_route(sdla_t *card); -static void port_set_state (sdla_t *card, int); -static int config_chdlc (sdla_t *card); -static void disable_comm (sdla_t *card); - -static void trigger_chdlc_poll(struct net_device *dev); -static void chdlc_poll(struct net_device *dev); -static void chdlc_poll_delay (unsigned long dev_ptr); - - -/* Miscellaneous asynchronous interface Functions */ -static int set_asy_config (sdla_t* card); -static int asy_comm_enable (sdla_t* card); - -/* Interrupt handlers */ -static void wpc_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void timer_intr(sdla_t *); - -/* Bottom half handlers */ -static void chdlc_work(struct net_device *dev); -static int chdlc_work_cleanup(struct net_device *dev); -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); - -/* Miscellaneous functions */ -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, - struct sk_buff *skb); -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static int intr_test( sdla_t* card); -static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static unsigned short calc_checksum (char *, int); -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); - - -static int Intr_test_counter; - -/* TTY Global Definitions */ - -#define NR_PORTS 4 -#define WAN_TTY_MAJOR 226 -#define WAN_TTY_MINOR 0 - -#define WAN_CARD(port) (tty_card_map[port]) -#define MIN_PORT 0 -#define MAX_PORT NR_PORTS-1 - -#define CRC_LENGTH 2 - -static int wanpipe_tty_init(sdla_t *card); -static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int); -static void wanpipe_tty_trigger_poll(sdla_t *card); - -static struct tty_driver serial_driver; -static int tty_init_cnt=0; - -static struct serial_state rs_table[NR_PORTS]; - -static char tty_driver_mode=WANOPT_TTY_SYNC; - -static char *opt_decode[] = {"NONE","CRTSCTS","XONXOFF-RX", - "CRTSCTS XONXOFF-RX","XONXOFF-TX", - "CRTSCTS XONXOFF-TX","CRTSCTS XONXOFF"}; -static char *p_decode[] = {"NONE","ODD","EVEN"}; - -static void* tty_card_map[NR_PORTS] = {NULL,NULL,NULL,NULL}; - - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpc_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - unsigned long max_permitted_baud = 0; - SHARED_MEMORY_INFO_STRUCT *flags; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_CHDLC) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Find out which Port to use */ - if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ - if (card->next){ - - if (conf->comm_port != card->next->u.c.comm_port){ - card->u.c.comm_port = conf->comm_port; - }else{ - printk(KERN_INFO "%s: ERROR - %s port used!\n", - card->wandev.name, PORT(conf->comm_port)); - return -EINVAL; - } - }else{ - card->u.c.comm_port = conf->comm_port; - } - }else{ - printk(KERN_INFO "%s: ERROR - Invalid Port Selected!\n", - card->wandev.name); - return -EINVAL; - } - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + - SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; - } - }else{ - /* for a S514 adapter, set a pointer to the actual mailbox in the */ - /* allocated virtual memory area */ - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - }else{ - card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; - } - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if ((jiffies - timeout) > 1*HZ) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n", - card->devname, u.str); - - card->isr = &wpc_isr; - card->poll = NULL; - card->exec = NULL; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = NULL; - card->wandev.udp_port = conf->udp_port; - card->disable_comm = &disable_comm; - card->wandev.new_if_cnt = 0; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = conf->ttl; - card->wandev.interface = conf->interface; - - if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& - card->hw.type != SDLA_S514){ - printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", - card->devname, PORT(card->u.c.comm_port)); - return -EIO; - } - - card->wandev.clocking = conf->clocking; - - port_num = card->u.c.comm_port; - - /* in API mode, we can configure for "receive only" buffering */ - if(card->hw.type == SDLA_S514) { - card->u.c.receive_only = conf->receive_only; - if(conf->receive_only) { - printk(KERN_INFO - "%s: Configured for 'receive only' mode\n", - card->devname); - } - } - - /* Setup Port Bps */ - - if(card->wandev.clocking) { - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - /* For Primary Port 0 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - PRI_MAX_BAUD_RATE_S514 : - PRI_MAX_BAUD_RATE_S508; - - }else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - SEC_MAX_BAUD_RATE_S514 : - SEC_MAX_BAUD_RATE_S508; - } - - if(conf->bps > max_permitted_baud) { - conf->bps = max_permitted_baud; - printk(KERN_INFO "%s: Baud too high!\n", - card->wandev.name); - printk(KERN_INFO "%s: Baud rate set to %lu bps\n", - card->wandev.name, max_permitted_baud); - } - card->wandev.bps = conf->bps; - }else{ - card->wandev.bps = 0; - } - - /* Setup the Port MTU */ - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - - /* For Primary Port 0 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - if(card->hw.type != SDLA_S514) - enable_irq(card->hw.irq); - - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - flags = card->u.c.flags; - - /* This is for the ports link state */ - card->wandev.state = WAN_DUALPORT; - card->u.c.state = WAN_DISCONNECTED; - - - if (!card->wandev.piggyback){ - int err; - - /* Perform interrupt testing */ - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_INFO "%s: Interrupt test failed (%i)\n", - card->devname, Intr_test_counter); - printk(KERN_INFO "%s: Please choose another interrupt\n", - card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt test passed (%i)\n", - card->devname, Intr_test_counter); - card->configured = 1; - } - - if ((card->tty_opt=conf->tty) == WANOPT_YES){ - int err; - card->tty_minor = conf->tty_minor; - - /* On ASYNC connections internal clocking - * is mandatory */ - if ((card->u.c.async_mode = conf->tty_mode)){ - card->wandev.clocking = 1; - } - err=wanpipe_tty_init(card); - if (err){ - return err; - } - }else{ - - - if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: " - "Failed to set interrupt triggers!\n", - card->devname); - return -EIO; - } - - /* Mask the Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - } - - /* If we are using CHDLC in backup mode, this flag will - * indicate not to look for IP addresses in config_chdlc()*/ - card->u.c.backup = conf->backup; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics - * This procedure is called when updating the PROC file system and returns - * various communications statistics. These statistics are accumulated from 3 - * different locations: - * 1) The 'if_stats' recorded for the device. - * 2) Communication error statistics on the adapter. - * 3) CHDLC operational statistics on the adapter. - * The board level statistics are read during a timer interrupt. Note that we - * read the error and operational statistics during consecitive timer ticks so - * as to minimize the time that we are inside the interrupt handler. - * - */ -static int update(struct wan_device* wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile chdlc_private_area_t* chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags; - unsigned long timeout; - - /* sanity checks */ - if((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if(wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* more sanity checks */ - if(!card->u.c.flags) - return -ENODEV; - - if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) - return -EAGAIN; - - if((dev=card->wandev.dev) == NULL) - return -ENODEV; - - if((chdlc_priv_area=dev->priv) == NULL) - return -ENODEV; - - flags = card->u.c.flags; - if(chdlc_priv_area->update_comms_stats){ - return -EAGAIN; - } - - /* we will need 2 timer interrupts to complete the */ - /* reading of the statistics */ - chdlc_priv_area->update_comms_stats = 2; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies; - for(;;) { - if(chdlc_priv_area->update_comms_stats == 0) - break; - if ((jiffies - timeout) > (1 * HZ)){ - chdlc_priv_area->update_comms_stats = 0; - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - - return 0; -} - - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - chdlc_private_area_t* chdlc_priv_area; - - - printk(KERN_INFO "%s: Configuring Interface: %s\n", - card->devname, conf->name); - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: Invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); - - if(chdlc_priv_area == NULL) - return -ENOMEM; - - memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); - - chdlc_priv_area->card = card; - chdlc_priv_area->common.sk = NULL; - chdlc_priv_area->common.func = NULL; - - /* initialize data */ - strcpy(card->u.c.if_name, conf->name); - - if(card->wandev.new_if_cnt > 0) { - kfree(chdlc_priv_area); - return -EEXIST; - } - - card->wandev.new_if_cnt++; - - chdlc_priv_area->TracingEnabled = 0; - chdlc_priv_area->route_status = NO_ROUTE; - chdlc_priv_area->route_removed = 0; - - card->u.c.async_mode = conf->async_mode; - - /* setup for asynchronous mode */ - if(conf->async_mode) { - printk(KERN_INFO "%s: Configuring for asynchronous mode\n", - wandev->name); - - if(card->u.c.comm_port == WANOPT_PRI) { - printk(KERN_INFO - "%s:Asynchronous mode on secondary port only\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - if(strcmp(conf->usedby, "WANPIPE") == 0) { - printk(KERN_INFO - "%s: Running in WANIPE Async Mode\n", wandev->name); - card->u.c.usedby = WANPIPE; - }else{ - card->u.c.usedby = API; - } - - if(!card->wandev.clocking) { - printk(KERN_INFO - "%s: Asynch. clocking must be 'Internal'\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - if((card->wandev.bps < MIN_ASY_BAUD_RATE) || - (card->wandev.bps > MAX_ASY_BAUD_RATE)) { - printk(KERN_INFO "%s: Selected baud rate is invalid.\n", - wandev->name); - printk(KERN_INFO "Must be between %u and %u bps.\n", - MIN_ASY_BAUD_RATE, MAX_ASY_BAUD_RATE); - kfree(chdlc_priv_area); - return -EINVAL; - } - - card->u.c.api_options = 0; - if (conf->asy_data_trans == WANOPT_YES) { - card->u.c.api_options |= ASY_RX_DATA_TRANSPARENT; - } - - card->u.c.protocol_options = 0; - if (conf->rts_hs_for_receive == WANOPT_YES) { - card->u.c.protocol_options |= ASY_RTS_HS_FOR_RX; - } - if (conf->xon_xoff_hs_for_receive == WANOPT_YES) { - card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_RX; - } - if (conf->xon_xoff_hs_for_transmit == WANOPT_YES) { - card->u.c.protocol_options |= ASY_XON_XOFF_HS_FOR_TX; - } - if (conf->dcd_hs_for_transmit == WANOPT_YES) { - card->u.c.protocol_options |= ASY_DCD_HS_FOR_TX; - } - if (conf->cts_hs_for_transmit == WANOPT_YES) { - card->u.c.protocol_options |= ASY_CTS_HS_FOR_TX; - } - - card->u.c.tx_bits_per_char = conf->tx_bits_per_char; - card->u.c.rx_bits_per_char = conf->rx_bits_per_char; - card->u.c.stop_bits = conf->stop_bits; - card->u.c.parity = conf->parity; - card->u.c.break_timer = conf->break_timer; - card->u.c.inter_char_timer = conf->inter_char_timer; - card->u.c.rx_complete_length = conf->rx_complete_length; - card->u.c.xon_char = conf->xon_char; - - } else { /* setup for synchronous mode */ - - card->u.c.protocol_options = 0; - if (conf->ignore_dcd == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; - } - if (conf->ignore_cts == WANOPT_YES){ - card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; - } - - if (conf->ignore_keepalive == WANOPT_YES) { - card->u.c.protocol_options |= - IGNORE_KPALV_FOR_LINK_STAT; - card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; - card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; - card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; - - } else { /* Do not ignore keepalives */ - card->u.c.kpalv_tx = - ((conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) - >= 0) ? - min_t(unsigned int, conf->keepalive_tx_tmr,MAX_Tx_KPALV_TIMER) : - DEFAULT_Tx_KPALV_TIMER; - - card->u.c.kpalv_rx = - ((conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) - >= 0) ? - min_t(unsigned int, conf->keepalive_rx_tmr,MAX_Rx_KPALV_TIMER) : - DEFAULT_Rx_KPALV_TIMER; - - card->u.c.kpalv_err = - ((conf->keepalive_err_margin-MIN_KPALV_ERR_TOL) - >= 0) ? - min_t(unsigned int, conf->keepalive_err_margin, - MAX_KPALV_ERR_TOL) : - DEFAULT_KPALV_ERR_TOL; - } - - /* Setup slarp timer to control delay between slarps */ - card->u.c.slarp_timer = - ((conf->slarp_timer - MIN_SLARP_REQ_TIMER) >= 0) ? - min_t(unsigned int, conf->slarp_timer, MAX_SLARP_REQ_TIMER) : - DEFAULT_SLARP_REQ_TIMER; - - if (conf->hdlc_streaming == WANOPT_YES) { - printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", - wandev->name); - card->u.c.protocol_options = HDLC_STREAMING_MODE; - } - - if ((chdlc_priv_area->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ - printk(KERN_INFO - "%s: Enabling, true interface type encoding.\n", - card->devname); - } - - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if( strcmp(conf->usedby, "WANPIPE") == 0) { - - printk(KERN_INFO "%s: Running in WANPIPE mode!\n", - wandev->name); - card->u.c.usedby = WANPIPE; - - /* Option to bring down the interface when - * the link goes down */ - if (conf->if_down){ - set_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down); - printk(KERN_INFO - "%s: Dynamic interface configuration enabled\n", - card->devname); - } - - } else if( strcmp(conf->usedby, "API") == 0) { - card->u.c.usedby = API; - printk(KERN_INFO "%s: Running in API mode !\n", - wandev->name); - } - } - - /* Tells us that if this interface is a - * gateway or not */ - if ((chdlc_priv_area->gateway = conf->gateway) == WANOPT_YES){ - printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", - card->devname,card->u.c.if_name); - } - - /* Get Multicast Information */ - chdlc_priv_area->mc = conf->mc; - - /* prepare network device data space for registration */ - strcpy(dev->name,card->u.c.if_name); - - dev->init = &if_init; - dev->priv = chdlc_priv_area; - - /* Initialize the polling work routine */ - INIT_WORK(&chdlc_priv_area->poll_work, (void*)(void*)chdlc_poll, dev); - - /* Initialize the polling delay timer */ - init_timer(&chdlc_priv_area->poll_delay_timer); - chdlc_priv_area->poll_delay_timer.data = (unsigned long)dev; - chdlc_priv_area->poll_delay_timer.function = chdlc_poll_delay; - - printk(KERN_INFO "\n"); - - return 0; -} - - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct wan_device* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Initialize media-specific parameters */ - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - /* Enable Mulitcasting if user selected */ - if (chdlc_priv_area->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } - - if (chdlc_priv_area->true_if_encoding){ - dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */ - }else{ - dev->type = ARPHRD_PPP; - } - - dev->mtu = card->wandev.mtu; - /* for API usage, add the API header size to the requested MTU size */ - if(card->u.c.usedby == API) { - dev->mtu += sizeof(api_tx_hdr_t); - } - - dev->hard_header_len = CHDLC_HDR_LEN; - - /* Initialize hardware parameters */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length - * If too low packets will not be retransmitted - * by stack. - */ - dev->tx_queue_len = 100; - SET_MODULE_OWNER(dev); - - return 0; -} - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct timeval tv; - int err = 0; - - /* Only one open per interface is allowed */ - - if (netif_running(dev)) - return -EBUSY; - - /* Initialize the work queue entry */ - chdlc_priv_area->tq_working=0; - - INIT_WORK(&chdlc_priv_area->common.wanpipe_work, - (void *)(void *)chdlc_work, dev); - - /* Allocate and initialize BH circular buffer */ - /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ - chdlc_priv_area->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); - memset(chdlc_priv_area->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); - atomic_set(&chdlc_priv_area->bh_buff_used, 0); - - do_gettimeofday(&tv); - chdlc_priv_area->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - wanpipe_open(card); - - /* TTY is configured during wanpipe_set_termios - * call, not here */ - if (card->tty_opt) - return err; - - set_bit(0,&chdlc_priv_area->config_chdlc); - chdlc_priv_area->config_chdlc_timeout=jiffies; - - /* Start the CHDLC configuration after 1sec delay. - * This will give the interface initilization time - * to finish its configuration */ - mod_timer(&chdlc_priv_area->poll_delay_timer, jiffies + HZ); - return err; -} - -/*============================================================================ - * Close network interface. - * o if this is the last close, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - - if (chdlc_priv_area->bh_head){ - int i; - struct sk_buff *skb; - - for (i=0; i<(MAX_BH_BUFF+1); i++){ - skb = ((bh_data_t *)&chdlc_priv_area->bh_head[i])->skb; - if (skb != NULL){ - dev_kfree_skb_any(skb); - } - } - kfree(chdlc_priv_area->bh_head); - chdlc_priv_area->bh_head=NULL; - } - - netif_stop_queue(dev); - wanpipe_close(card); - del_timer(&chdlc_priv_area->poll_delay_timer); - return 0; -} - -static void disable_comm (sdla_t *card) -{ - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - if (card->u.c.comm_enabled){ - chdlc_disable_comm_shutdown (card); - }else{ - flags->interrupt_info_struct.interrupt_permission = 0; - } - - if (!tty_init_cnt) - return; - - if (card->tty_opt){ - struct serial_state * state; - if (!(--tty_init_cnt)){ - int e1; - serial_driver.refcount=0; - - if ((e1 = tty_unregister_driver(&serial_driver))) - printk("SERIAL: failed to unregister serial driver (%d)\n", - e1); - printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", - card->devname,WAN_TTY_MAJOR); - } - card->tty=NULL; - tty_card_map[card->tty_minor]=NULL; - state = &rs_table[card->tty_minor]; - memset(state, 0, sizeof(*state)); - } - return; -} - - -/*============================================================================ - * Build media header. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If packet type is not - * supported, set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, - unsigned len) -{ - skb->protocol = htons(type); - - return CHDLC_HDR_LEN; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - netif_wake_queue (dev); -} - - - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ -static int if_rebuild_hdr (struct sk_buff *skb) -{ - return 1; -} - - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - int udp_type = 0; - unsigned long smp_flags; - int err=0; - - netif_stop_queue(dev); - - if (skb == NULL){ - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - - netif_wake_queue(dev); - return 0; - } - - if (ntohs(skb->protocol) != htons(PVC_PROT)){ - - /* check the udp packet type */ - - udp_type = udp_pkt_type(skb, card); - - if (udp_type == UDP_CPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - chdlc_priv_area)){ - chdlc_int->interrupt_permission |= - APP_INT_ON_TIMER; - } - netif_start_queue(dev); - return 0; - } - - /* check to see if the source IP address is a broadcast or */ - /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)){ - ++card->wandev.stats.tx_dropped; - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_exit_crit; - } - - if(card->u.c.state != WAN_CONNECTED){ - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - - }else if(!skb->protocol){ - ++card->wandev.stats.tx_errors; - netif_start_queue(dev); - - }else { - void* data = skb->data; - unsigned len = skb->len; - unsigned char attr; - - /* If it's an API packet pull off the API - * header. Also check that the packet size - * is larger than the API header - */ - if (card->u.c.usedby == API){ - api_tx_hdr_t* api_tx_hdr; - - /* discard the frame if we are configured for */ - /* 'receive only' mode or if there is no data */ - if (card->u.c.receive_only || - (len <= sizeof(api_tx_hdr_t))) { - - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_exit_crit; - } - - api_tx_hdr = (api_tx_hdr_t *)data; - attr = api_tx_hdr->attr; - data += sizeof(api_tx_hdr_t); - len -= sizeof(api_tx_hdr_t); - } - - if(chdlc_send(card, data, len)) { - netif_stop_queue(dev); - }else{ - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += len; - - netif_start_queue(dev); - - dev->trans_start = jiffies; - } - } - -if_send_exit_crit: - - if (!(err=netif_queue_stopped(dev))) { - dev_kfree_skb_any(skb); - }else{ - chdlc_priv_area->tick_counter = jiffies; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================ - * Check to see if the packet to be transmitted contains a broadcast or - * multicast source IP address. - */ - -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb) -{ - u32 src_ip_addr; - u32 broadcast_ip_addr = 0; - struct in_device *in_dev; - - /* read the IP source address from the outgoing packet */ - src_ip_addr = *(u32 *)(skb->data + 12); - - /* read the IP broadcast address for the device */ - in_dev = dev->ip_ptr; - if(in_dev != NULL) { - struct in_ifaddr *ifa= in_dev->ifa_list; - if(ifa != NULL) - broadcast_ip_addr = ifa->ifa_broadcast; - else - return 0; - } - - /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { - printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", - card->devname); - return 1; - } - - /* check if the IP Source Address is a Multicast address */ - if((ntohl(src_ip_addr) >= 0xE0000001) && - (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", - card->devname); - return 1; - } - - return 0; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* fill in UDP reply */ - c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - c_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = c_udp_pkt->udp_pkt.udp_src_port; - c_udp_pkt->udp_pkt.udp_src_port = - c_udp_pkt->udp_pkt.udp_dst_port; - c_udp_pkt->udp_pkt.udp_dst_port = temp; - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - - /* calculate UDP checksum */ - c_udp_pkt->udp_pkt.udp_checksum = 0; - c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - c_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = c_udp_pkt->ip_pkt.ip_src_address; - c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; - c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - c_udp_pkt->ip_pkt.hdr_checksum = 0; - c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); - - return len; - -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats* if_stats(struct net_device* dev) -{ - sdla_t *my_card; - chdlc_private_area_t* chdlc_priv_area; - - if ((chdlc_priv_area=dev->priv) == NULL) - return NULL; - - my_card = chdlc_priv_area->card; - return &my_card->wandev.stats; -} - - -/****** Cisco HDLC Firmware Interface Functions *******************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*----------------------------------------------------------------------------- - * Configure CHDLC firmware. - */ -static int chdlc_configure (sdla_t* card, void* data) -{ - int err; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); - - mailbox->buffer_length = data_length; - memcpy(mailbox->data, data, data_length); - mailbox->command = SET_CHDLC_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) chdlc_error (card, err, mailbox); - - return err; -} - - -/*============================================================================ - * Set interrupt mode -- HDLC Version. - */ - -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - int_data->CHDLC_interrupt_triggers = mode; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - return err; -} - - -/*=========================================================== - * chdlc_disable_comm_shutdown - * - * Shutdown() disables the communications. We must - * have a sparate functions, because we must not - * call chdlc_error() hander since the private - * area has already been replaced */ - -static int chdlc_disable_comm_shutdown (sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - /* Disable Interrutps */ - int_data->CHDLC_interrupt_triggers = 0; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - /* Disable Communications */ - - if (card->u.c.async_mode) { - mb->command = DISABLE_ASY_COMMUNICATIONS; - }else{ - mb->command = DISABLE_CHDLC_COMMUNICATIONS; - } - - mb->buffer_length = 0; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - card->u.c.comm_enabled = 0; - - return 0; -} - -/*============================================================================ - * Enable communications. - */ - -static int chdlc_comm_enable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card, err, mb); - else - card->u.c.comm_enabled = 1; - - return err; -} - -/*============================================================================ - * Read communication error statistics. - */ -static int chdlc_read_comm_err_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_COMMS_ERROR_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Read CHDLC operational statistics. - */ -static int chdlc_read_op_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_OPERATIONAL_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Update communications error and general packet statistics. - */ -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - COMMS_ERROR_STATS_STRUCT* err_stats; - CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; - - /* on the first timer interrupt, read the comms error statistics */ - if(chdlc_priv_area->update_comms_stats == 2) { - if(chdlc_read_comm_err_stats(card)) - return 1; - err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_over_errors = - err_stats->Rx_overrun_err_count; - card->wandev.stats.rx_crc_errors = - err_stats->CRC_err_count; - card->wandev.stats.rx_frame_errors = - err_stats->Rx_abort_count; - card->wandev.stats.rx_fifo_errors = - err_stats->Rx_dis_pri_bfrs_full_count; - card->wandev.stats.rx_missed_errors = - card->wandev.stats.rx_fifo_errors; - card->wandev.stats.tx_aborted_errors = - err_stats->sec_Tx_abort_count; - } - - /* on the second timer interrupt, read the operational statistics */ - else { - if(chdlc_read_op_stats(card)) - return 1; - op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_length_errors = - (op_stats->Rx_Data_discard_short_count + - op_stats->Rx_Data_discard_long_count); - } - - return 0; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ -static int chdlc_send (sdla_t* card, void* data, unsigned len) -{ - CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; - - if (txbuf->opp_flag) - return 1; - - sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); - - txbuf->frame_length = len; - txbuf->opp_flag = 1; /* start transmission */ - - /* Update transmit buffer control fields */ - card->u.c.txbuf = ++txbuf; - - if ((void*)txbuf > card->u.c.txbuf_last) - card->u.c.txbuf = card->u.c.txbuf_base; - - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) -{ - unsigned cmd = mb->command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_INFO "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - case S514_BOTH_PORTS_SAME_CLK_MODE: - if(cmd == SET_CHDLC_CONFIGURATION) { - printk(KERN_INFO - "%s: Configure both ports for the same clock source\n", - card->devname); - break; - } - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - } - - return 0; -} - - -/********** Bottom Half Handlers ********************************************/ - -/* NOTE: There is no API, BH support for Kernels lower than 2.2.X. - * DO NOT INSERT ANY CODE HERE, NOTICE THE - * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE - * DOING */ - -static void chdlc_work(struct net_device * dev) -{ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - struct sk_buff *skb; - - if (atomic_read(&chan->bh_buff_used) == 0){ - clear_bit(0, &chan->tq_working); - return; - } - - while (atomic_read(&chan->bh_buff_used)){ - - skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; - - if (skb != NULL){ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - ++card->wandev.stats.rx_dropped; - dev_kfree_skb_any(skb); - chdlc_work_cleanup(dev); - continue; - } - - if (chan->common.func(skb,dev,chan->common.sk) != 0){ - /* Sock full cannot send, queue us for another - * try */ - atomic_set(&chan->common.receive_block,1); - return; - }else{ - chdlc_work_cleanup(dev); - } - }else{ - chdlc_work_cleanup(dev); - } - } - clear_bit(0, &chan->tq_working); - - return; -} - -static int chdlc_work_cleanup(struct net_device *dev) -{ - chdlc_private_area_t* chan = dev->priv; - - ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; - - if (chan->bh_read == MAX_BH_BUFF){ - chan->bh_read=0; - }else{ - ++chan->bh_read; - } - - atomic_dec(&chan->bh_buff_used); - return 0; -} - - - -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) -{ - /* Check for full */ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ - ++card->wandev.stats.rx_dropped; - dev_kfree_skb_any(skb); - return 1; - } - - ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; - - if (chan->bh_write == MAX_BH_BUFF){ - chan->bh_write=0; - }else{ - ++chan->bh_write; - } - - atomic_inc(&chan->bh_buff_used); - - return 0; -} - -/* END OF API BH Support */ - - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * Cisco HDLC interrupt service routine. - */ -static void wpc_isr (sdla_t* card) -{ - struct net_device* dev; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - int i; - sdla_t *my_card; - - - /* Check for which port the interrupt has been generated - * Since Secondary Port is piggybacking on the Primary - * the check must be done here. - */ - - flags = card->u.c.flags; - if (!flags->interrupt_info_struct.interrupt_type){ - /* Check for a second port (piggybacking) */ - if ((my_card = card->next)){ - flags = my_card->u.c.flags; - if (flags->interrupt_info_struct.interrupt_type){ - card = my_card; - card->isr(card); - return; - } - } - } - - flags = card->u.c.flags; - card->in_isr = 1; - dev = card->wandev.dev; - - /* If we get an interrupt with no network device, stop the interrupts - * and issue an error */ - if (!card->tty_opt && !dev && - flags->interrupt_info_struct.interrupt_type != - COMMAND_COMPLETE_APP_INT_PEND){ - - goto isr_done; - } - - /* if critical due to peripheral operations - * ie. update() or getstats() then reset the interrupt and - * wait for the board to retrigger. - */ - if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - printk(KERN_INFO "ISR CRIT TO PERI\n"); - goto isr_done; - } - - /* On a 508 Card, if critical due to if_send - * Major Error !!! */ - if(card->hw.type != SDLA_S514) { - if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: %lx\n", - card->devname, card->wandev.critical); - card->in_isr = 0; - flags->interrupt_info_struct.interrupt_type = 0; - return; - } - } - - switch(flags->interrupt_info_struct.interrupt_type) { - - case RX_APP_INT_PEND: /* 0x01: receive interrupt */ - rx_intr(card); - break; - - case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TX_FRAME; - - if (card->tty_opt){ - wanpipe_tty_trigger_poll(card); - break; - } - - if (dev && netif_queue_stopped(dev)){ - if (card->u.c.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - break; - - case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ - ++ Intr_test_counter; - break; - - case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ - process_chdlc_exception(card); - break; - - case GLOBAL_EXCEP_COND_APP_INT_PEND: - process_global_exception(card); - break; - - case TIMER_APP_INT_PEND: - timer_intr(card); - break; - - default: - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, - flags->interrupt_info_struct.interrupt_type); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - break; - } - -isr_done: - - card->in_isr = 0; - flags->interrupt_info_struct.interrupt_type = 0; - return; -} - -/*============================================================================ - * Receive interrupt handler. - */ -static void rx_intr (sdla_t* card) -{ - struct net_device *dev; - chdlc_private_area_t *chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; - struct sk_buff *skb; - unsigned len; - unsigned addr = rxbuf->ptr_data_bfr; - void *buf; - int i,udp_type; - - if (rxbuf->opp_flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)rxbuf, rxbuf->opp_flag); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it measn that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - chdlc_set_intr_mode(card,0); - return; - } - - len = rxbuf->frame_length; - - if (card->tty_opt){ - - if (rxbuf->error_flag){ - goto rx_exit; - } - - if (len <= CRC_LENGTH){ - goto rx_exit; - } - - if (!card->u.c.async_mode){ - len -= CRC_LENGTH; - } - - wanpipe_tty_receive(card,addr,len); - goto rx_exit; - } - - dev = card->wandev.dev; - - if (!dev){ - goto rx_exit; - } - - if (!netif_running(dev)) - goto rx_exit; - - chdlc_priv_area = dev->priv; - - - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - - if (skb == NULL) { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++card->wandev.stats.rx_dropped; - goto rx_exit; - } - - /* Copy data to the socket buffer */ - if((addr + len) > card->u.c.rx_top + 1) { - unsigned tmp = card->u.c.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.c.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - - skb->protocol = htons(ETH_P_IP); - - card->wandev.stats.rx_packets ++; - card->wandev.stats.rx_bytes += skb->len; - udp_type = udp_pkt_type( skb, card ); - - if(udp_type == UDP_CPIPE_TYPE) { - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, - card, skb, dev, chdlc_priv_area)) { - flags->interrupt_info_struct. - interrupt_permission |= - APP_INT_ON_TIMER; - } - } else if(card->u.c.usedby == API) { - - api_rx_hdr_t* api_rx_hdr; - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->error_flag = rxbuf->error_flag; - api_rx_hdr->time_stamp = rxbuf->time_stamp; - - skb->protocol = htons(PVC_PROT); - skb->mac.raw = skb->data; - skb->dev = dev; - skb->pkt_type = WAN_PACKET_DATA; - - bh_enqueue(dev, skb); - - if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)) - wanpipe_queue_work(&chdlc_priv_area->common.wanpipe_work); - }else{ - /* FIXME: we should check to see if the received packet is a - multicast packet so that we can increment the multicast - statistic - ++ chdlc_priv_area->if_stats.multicast; - */ - /* Pass it up the protocol stack */ - - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - dev->last_rx = jiffies; - } - -rx_exit: - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->opp_flag = 0x00; - card->u.c.rxmb = ++ rxbuf; - if((void*)rxbuf > card->u.c.rxbuf_last){ - card->u.c.rxmb = card->u.c.rxbuf_base; - } -} - -/*============================================================================ - * Timer interrupt handler. - * The timer interrupt is used for two purposes: - * 1) Processing udp calls from 'cpipemon'. - * 2) Reading board-level statistics for updating the proc file system. - */ -void timer_intr(sdla_t *card) -{ - struct net_device* dev; - chdlc_private_area_t* chdlc_priv_area = NULL; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - - if ((dev = card->wandev.dev)==NULL){ - flags = card->u.c.flags; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - return; - } - - chdlc_priv_area = dev->priv; - - if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { - if (!config_chdlc(card)){ - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; - } - } - - /* process a udp call if pending */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { - process_udp_mgmt_pkt(card, dev, - chdlc_priv_area); - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; - } - - /* read the communications statistics if required */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { - update_comms_stats(card, chdlc_priv_area); - if(!(-- chdlc_priv_area->update_comms_stats)) { - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - } - } - - /* only disable the timer interrupt if there are no udp or statistic */ - /* updates pending */ - if(!chdlc_priv_area->timer_int_enabled) { - flags = card->u.c.flags; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - } -} - -/*------------------------------------------------------------------------------ - Miscellaneous Functions - - set_chdlc_config() used to set configuration options on the board -------------------------------------------------------------------------------*/ - -static int set_chdlc_config(sdla_t* card) -{ - CHDLC_CONFIGURATION_STRUCT cfg; - - memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); - - if(card->wandev.clocking){ - cfg.baud_rate = card->wandev.bps; - } - - cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? - INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; - - cfg.modem_config_options = 0; - cfg.modem_status_timer = 100; - - cfg.CHDLC_protocol_options = card->u.c.protocol_options; - - if (card->tty_opt){ - cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; - } - - cfg.percent_data_buffer_for_Tx = (card->u.c.receive_only) ? 0 : 50; - cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | - CHDLC_RX_DATA_BYTE_COUNT_STAT); - - if (card->tty_opt){ - card->wandev.mtu = TTY_CHDLC_MAX_MTU; - } - cfg.max_CHDLC_data_field_length = card->wandev.mtu; - cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; - cfg.receive_keepalive_timer = card->u.c.kpalv_rx; - cfg.keepalive_error_tolerance = card->u.c.kpalv_err; - cfg.SLARP_request_timer = card->u.c.slarp_timer; - - if (cfg.SLARP_request_timer) { - cfg.IP_address = 0; - cfg.IP_netmask = 0; - - }else if (card->wandev.dev){ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - - struct in_device *in_dev = dev->ip_ptr; - - if(in_dev != NULL) { - struct in_ifaddr *ifa = in_dev->ifa_list; - - if (ifa != NULL ) { - cfg.IP_address = ntohl(ifa->ifa_local); - cfg.IP_netmask = ntohl(ifa->ifa_mask); - chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); - chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); - } - } - - /* FIXME: We must re-think this message in next release - if((cfg.IP_address & 0x000000FF) > 2) { - printk(KERN_WARNING "\n"); - printk(KERN_WARNING " WARNING:%s configured with an\n", - card->devname); - printk(KERN_WARNING " invalid local IP address.\n"); - printk(KERN_WARNING " Slarp pragmatics will fail.\n"); - printk(KERN_WARNING " IP address should be of the\n"); - printk(KERN_WARNING " format A.B.C.1 or A.B.C.2.\n"); - } - */ - } - - return chdlc_configure(card, &cfg); -} - - -/*----------------------------------------------------------------------------- - set_asy_config() used to set asynchronous configuration options on the board -------------------------------------------------------------------------------*/ - -static int set_asy_config(sdla_t* card) -{ - - ASY_CONFIGURATION_STRUCT cfg; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int err; - - memset(&cfg, 0, sizeof(ASY_CONFIGURATION_STRUCT)); - - if(card->wandev.clocking) - cfg.baud_rate = card->wandev.bps; - - cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? - INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; - - cfg.modem_config_options = 0; - cfg.asy_API_options = card->u.c.api_options; - cfg.asy_protocol_options = card->u.c.protocol_options; - cfg.Tx_bits_per_char = card->u.c.tx_bits_per_char; - cfg.Rx_bits_per_char = card->u.c.rx_bits_per_char; - cfg.stop_bits = card->u.c.stop_bits; - cfg.parity = card->u.c.parity; - cfg.break_timer = card->u.c.break_timer; - cfg.asy_Rx_inter_char_timer = card->u.c.inter_char_timer; - cfg.asy_Rx_complete_length = card->u.c.rx_complete_length; - cfg.XON_char = card->u.c.xon_char; - cfg.XOFF_char = card->u.c.xoff_char; - cfg.asy_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | - CHDLC_RX_DATA_BYTE_COUNT_STAT); - - mailbox->buffer_length = sizeof(ASY_CONFIGURATION_STRUCT); - memcpy(mailbox->data, &cfg, mailbox->buffer_length); - mailbox->command = SET_ASY_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mailbox); - return err; -} - -/*============================================================================ - * Enable asynchronous communications. - */ - -static int asy_comm_enable (sdla_t* card) -{ - - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_ASY_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK && card->wandev.dev) - chdlc_error(card, err, mb); - - if (!err) - card->u.c.comm_enabled = 1; - - return err; -} - -/*============================================================================ - * Process global exception condition - */ -static int process_global_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mbox = card->mbox; - int err; - - mbox->buffer_length = 0; - mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; - err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; - - if(err != CMD_TIMEOUT ){ - - switch(mbox->return_code) { - - case EXCEP_MODEM_STATUS_CHANGE: - - printk(KERN_INFO "%s: Modem status change\n", - card->devname); - - switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { - case (DCD_HIGH): - printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); - break; - case (CTS_HIGH): - printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); - break; - case ((DCD_HIGH | CTS_HIGH)): - printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); - break; - default: - printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); - break; - } - break; - - case EXCEP_TRC_DISABLED: - printk(KERN_INFO "%s: Line trace disabled\n", - card->devname); - break; - - case EXCEP_IRQ_TIMEOUT: - printk(KERN_INFO "%s: IRQ timeout occurred\n", - card->devname); - break; - - case 0x17: - if (card->tty_opt){ - if (card->tty && card->tty_open){ - printk(KERN_INFO - "%s: Modem Hangup Exception: Hanging Up!\n", - card->devname); - tty_hangup(card->tty); - } - break; - } - - /* If TTY is not used just drop throught */ - - default: - printk(KERN_INFO "%s: Global exception %x\n", - card->devname, mbox->return_code); - break; - } - } - return 0; -} - - -/*============================================================================ - * Process chdlc exception condition - */ -static int process_chdlc_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_EXCEPTION_CONDITION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if(err != CMD_TIMEOUT) { - - switch (err) { - - case EXCEP_LINK_ACTIVE: - port_set_state(card, WAN_CONNECTED); - trigger_chdlc_poll(card->wandev.dev); - break; - - case EXCEP_LINK_INACTIVE_MODEM: - port_set_state(card, WAN_DISCONNECTED); - unconfigure_ip(card); - trigger_chdlc_poll(card->wandev.dev); - break; - - case EXCEP_LINK_INACTIVE_KPALV: - port_set_state(card, WAN_DISCONNECTED); - printk(KERN_INFO "%s: Keepalive timer expired.\n", - card->devname); - unconfigure_ip(card); - trigger_chdlc_poll(card->wandev.dev); - break; - - case EXCEP_IP_ADDRESS_DISCOVERED: - if (configure_ip(card)) - return -1; - break; - - case EXCEP_LOOPBACK_CONDITION: - printk(KERN_INFO "%s: Loopback Condition Detected.\n", - card->devname); - break; - - case NO_CHDLC_EXCEP_COND_TO_REPORT: - printk(KERN_INFO "%s: No exceptions reported.\n", - card->devname); - break; - } - - } - return 0; -} - - -/*============================================================================ - * Configure IP from SLARP negotiation - * This adds dynamic routes when SLARP has provided valid addresses - */ - -static int configure_ip (sdla_t* card) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area; - char err; - - if (!dev) - return 0; - - chdlc_priv_area = dev->priv; - - - /* set to discover */ - if(card->u.c.slarp_timer != 0x00) { - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_CONFIGURATION_STRUCT *cfg; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - return -1; - } - - cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; - chdlc_priv_area->IP_address = cfg->IP_address; - chdlc_priv_area->IP_netmask = cfg->IP_netmask; - - /* Set flag to add route */ - chdlc_priv_area->route_status = ADD_ROUTE; - - /* The idea here is to add the route in the poll routine. - This way, we aren't in interrupt context when adding routes */ - trigger_chdlc_poll(dev); - } - - return 0; -} - - -/*============================================================================ - * Un-Configure IP negotiated by SLARP - * This removes dynamic routes when the link becomes inactive. - */ - -static int unconfigure_ip (sdla_t* card) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area; - - if (!dev) - return 0; - - chdlc_priv_area= dev->priv; - - if (chdlc_priv_area->route_status == ROUTE_ADDED) { - - /* Note: If this function is called, the - * port state has been DISCONNECTED. This state - * change will trigger a poll_disconnected - * function, that will check for this condition. - */ - chdlc_priv_area->route_status = REMOVE_ROUTE; - - } - return 0; -} - -/*============================================================================ - * Routine to add/remove routes - * Called like a polling routine when Routes are flagged to be added/removed. - */ - -static void process_route (sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - unsigned char port_num; - chdlc_private_area_t *chdlc_priv_area = NULL; - u32 local_IP_addr = 0; - u32 remote_IP_addr = 0; - u32 IP_netmask, IP_addr; - int err = 0; - struct in_device *in_dev; - mm_segment_t fs; - struct ifreq if_info; - struct sockaddr_in *if_data1, *if_data2; - - chdlc_priv_area = dev->priv; - port_num = card->u.c.comm_port; - - /* Bug Fix Mar 16 2000 - * AND the IP address to the Mask before checking - * the last two bits. */ - - if((chdlc_priv_area->route_status == ADD_ROUTE) && - ((chdlc_priv_area->IP_address & ~chdlc_priv_area->IP_netmask) > 2)) { - - printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname); - - if(card->u.c.slarp_timer) { - u32 addr_net = htonl(chdlc_priv_area->IP_address); - - printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u received\n", - card->devname, - NIPQUAD(addr_net)); - printk(KERN_INFO "%s: from remote station.\n", - card->devname); - - }else{ - u32 addr_net = htonl(chdlc_priv_area->IP_address); - - printk(KERN_INFO "%s: Bad IP address %u.%u.%u.%u issued\n", - card->devname, - NIPQUAD(addr_net)); - printk(KERN_INFO "%s: to remote station. Local\n", - card->devname); - printk(KERN_INFO "%s: IP address must be A.B.C.1\n", - card->devname); - printk(KERN_INFO "%s: or A.B.C.2.\n",card->devname); - } - - /* remove the route due to the IP address error condition */ - chdlc_priv_area->route_status = REMOVE_ROUTE; - err = 1; - } - - /* If we are removing a route with bad IP addressing, then use the */ - /* locally configured IP addresses */ - if((chdlc_priv_area->route_status == REMOVE_ROUTE) && err) { - - /* do not remove a bad route that has already been removed */ - if(chdlc_priv_area->route_removed) { - return; - } - - in_dev = dev->ip_ptr; - - if(in_dev != NULL) { - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa != NULL ) { - local_IP_addr = ifa->ifa_local; - IP_netmask = ifa->ifa_mask; - } - } - }else{ - /* According to Cisco HDLC, if the point-to-point address is - A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa. - */ - IP_netmask = ntohl(chdlc_priv_area->IP_netmask); - remote_IP_addr = ntohl(chdlc_priv_area->IP_address); - - - /* If Netmask is 255.255.255.255 the local address - * calculation will fail. Default it back to 255.255.255.0 */ - if (IP_netmask == 0xffffffff) - IP_netmask &= 0x00ffffff; - - /* Bug Fix Mar 16 2000 - * AND the Remote IP address with IP netmask, instead - * of static netmask of 255.255.255.0 */ - local_IP_addr = (remote_IP_addr & IP_netmask) + - (~remote_IP_addr & ntohl(0x0003)); - - if(!card->u.c.slarp_timer) { - IP_addr = local_IP_addr; - local_IP_addr = remote_IP_addr; - remote_IP_addr = IP_addr; - } - } - - fs = get_fs(); /* Save file system */ - set_fs(get_ds()); /* Get user space block */ - - /* Setup a structure for adding/removing routes */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - switch (chdlc_priv_area->route_status) { - - case ADD_ROUTE: - - if(!card->u.c.slarp_timer) { - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = remote_IP_addr; - if_data2->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); - } else { - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = local_IP_addr; - if_data1->sin_family = AF_INET; - if(!(err = devinet_ioctl(SIOCSIFADDR, &if_info))){ - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = remote_IP_addr; - if_data2->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); - } - } - - if(err) { - printk(KERN_INFO "%s: Add route %u.%u.%u.%u failed (%d)\n", - card->devname, NIPQUAD(remote_IP_addr), err); - } else { - ((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED; - printk(KERN_INFO "%s: Dynamic route added.\n", - card->devname); - printk(KERN_INFO "%s: Local IP addr : %u.%u.%u.%u\n", - card->devname, NIPQUAD(local_IP_addr)); - printk(KERN_INFO "%s: Remote IP addr: %u.%u.%u.%u\n", - card->devname, NIPQUAD(remote_IP_addr)); - chdlc_priv_area->route_removed = 0; - } - break; - - - case REMOVE_ROUTE: - - /* Change the local ip address of the interface to 0. - * This will also delete the destination route. - */ - if(!card->u.c.slarp_timer) { - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = 0; - if_data2->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); - } else { - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = 0; - if_data1->sin_family = AF_INET; - err = devinet_ioctl(SIOCSIFADDR,&if_info); - - } - if(err) { - printk(KERN_INFO - "%s: Remove route %u.%u.%u.%u failed, (err %d)\n", - card->devname, NIPQUAD(remote_IP_addr), - err); - } else { - ((chdlc_private_area_t *)dev->priv)->route_status = - NO_ROUTE; - printk(KERN_INFO "%s: Dynamic route removed: %u.%u.%u.%u\n", - card->devname, NIPQUAD(local_IP_addr)); - chdlc_priv_area->route_removed = 1; - } - break; - } - - set_fs(fs); /* Restore file system */ - -} - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area) -{ - int udp_pkt_stored = 0; - - if(!chdlc_priv_area->udp_pkt_lgth && - (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { - chdlc_priv_area->udp_pkt_lgth = skb->len; - chdlc_priv_area->udp_pkt_src = udp_pkt_src; - memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; - udp_pkt_stored = 1; - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - -/*============================================================================= - * Process UDP management packet. - */ - -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area ) -{ - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short buffer_length, real_len; - unsigned long data_ptr; - unsigned data_length; - int udp_mgmt_req_valid = 1; - CHDLC_MAILBOX_STRUCT *mb = card->mbox; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - chdlc_udp_pkt_t *chdlc_udp_pkt; - struct timeval tv; - int err; - char ut_char; - - chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ - - /* Only these commands are support for remote debugging. - * All others are not */ - switch(chdlc_udp_pkt->cblock.command) { - - case READ_GLOBAL_STATISTICS: - case READ_MODEM_STATUS: - case READ_CHDLC_LINK_STATUS: - case CPIPE_ROUTER_UP_TIME: - case READ_COMMS_ERROR_STATS: - case READ_CHDLC_OPERATIONAL_STATS: - - /* These two commands are executed for - * each request */ - case READ_CHDLC_CONFIGURATION: - case READ_CHDLC_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - - /* set length to 0 */ - chdlc_udp_pkt->cblock.buffer_length = 0; - - /* set return code */ - chdlc_udp_pkt->cblock.return_code = 0xCD; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,chdlc_udp_pkt->cblock.command); - } - - } else { - unsigned long trace_status_cfg_addr = 0; - TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; - TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; - - switch(chdlc_udp_pkt->cblock.command) { - - case CPIPE_ENABLE_TRACING: - if (!chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_ACTIVE; - /* Trace delay mode is not used because it slows - down transfer and results in a standoff situation - when there is a lot of data */ - - /* Configure the Trace based on user inputs */ - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= - chdlc_udp_pkt->data[0]; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_deactivation_timer = 4000; - - - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - card->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - /* Get the base address of the trace element list */ - mb->buffer_length = 0; - mb->command = READ_TRACE_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) - mb->data) -> ptr_trace_stat_el_cfg_struct; - - sdla_peek(&card->hw, trace_status_cfg_addr, - &trace_cfg_struct, sizeof(trace_cfg_struct)); - - chdlc_priv_area->start_trace_addr = trace_cfg_struct. - base_addr_trace_status_elements; - - chdlc_priv_area->number_trace_elements = - trace_cfg_struct.number_trace_status_elements; - - chdlc_priv_area->end_trace_addr = (unsigned long) - ((TRACE_STATUS_ELEMENT_STRUCT *) - chdlc_priv_area->start_trace_addr + - (chdlc_priv_area->number_trace_elements - 1)); - - chdlc_priv_area->base_addr_trace_buffer = - trace_cfg_struct.base_addr_trace_buffer; - - chdlc_priv_area->end_addr_trace_buffer = - trace_cfg_struct.end_addr_trace_buffer; - - chdlc_priv_area->curr_trace_addr = - trace_cfg_struct.next_trace_element_to_use; - - chdlc_priv_area->available_buffer_space = 2000 - - sizeof(ip_pkt_t) - - sizeof(udp_pkt_t) - - sizeof(wp_mgmt_t) - - sizeof(cblock_t) - - sizeof(trace_info_t); - } - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - chdlc_priv_area->TracingEnabled = 1; - break; - - - case CPIPE_DISABLE_TRACING: - if (chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_INACTIVE; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - } - - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - break; - - - case CPIPE_GET_TRACE_INFO: - - if (!chdlc_priv_area->TracingEnabled) { - chdlc_udp_pkt->cblock.return_code = 1; - mb->buffer_length = 0; - break; - } - - chdlc_udp_pkt->trace_info.ismoredata = 0x00; - buffer_length = 0; /* offset of packet already occupied */ - - for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ - - trace_pkt_t *trace_pkt = (trace_pkt_t *) - &chdlc_udp_pkt->data[buffer_length]; - - sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, - (unsigned char *)&trace_element_struct, - sizeof(TRACE_STATUS_ELEMENT_STRUCT)); - - if (trace_element_struct.opp_flag == 0x00) { - break; - } - - /* get pointer to real data */ - data_ptr = trace_element_struct.ptr_data_bfr; - - /* See if there is actual data on the trace buffer */ - if (data_ptr){ - data_length = trace_element_struct.trace_length; - }else{ - data_length = 0; - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - - if( (chdlc_priv_area->available_buffer_space - buffer_length) - < ( sizeof(trace_pkt_t) + data_length) ) { - - /* indicate there are more frames on board & exit */ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - break; - } - - trace_pkt->status = trace_element_struct.trace_type; - - trace_pkt->time_stamp = - trace_element_struct.trace_time_stamp; - - trace_pkt->real_length = - trace_element_struct.trace_length; - - /* see if we can fit the frame into the user buffer */ - real_len = trace_pkt->real_length; - - if (data_ptr == 0) { - trace_pkt->data_avail = 0x00; - } else { - unsigned tmp = 0; - - /* get the data from circular buffer - must check for end of buffer */ - trace_pkt->data_avail = 0x01; - - if ((data_ptr + real_len) > - chdlc_priv_area->end_addr_trace_buffer + 1){ - - tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; - sdla_peek(&card->hw, data_ptr, - trace_pkt->data,tmp); - data_ptr = chdlc_priv_area->base_addr_trace_buffer; - } - - sdla_peek(&card->hw, data_ptr, - &trace_pkt->data[tmp], real_len - tmp); - } - - /* zero the opp flag to show we got the frame */ - ut_char = 0x00; - sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); - - /* now move onto the next frame */ - chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); - - /* check if we went over the last address */ - if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { - chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; - } - - if(trace_pkt->data_avail == 0x01) { - buffer_length += real_len - 1; - } - - /* for the header */ - buffer_length += sizeof(trace_pkt_t); - - } /* For Loop */ - - if (frames == chdlc_priv_area->number_trace_elements){ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - chdlc_udp_pkt->trace_info.num_frames = frames; - - mb->buffer_length = buffer_length; - chdlc_udp_pkt->cblock.buffer_length = buffer_length; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - - break; - - - case CPIPE_FT1_READ_STATUS: - ((unsigned char *)chdlc_udp_pkt->data )[0] = - flags->FT1_info_struct.parallel_port_A_input; - - ((unsigned char *)chdlc_udp_pkt->data )[1] = - flags->FT1_info_struct.parallel_port_B_input; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - chdlc_udp_pkt->cblock.buffer_length = 2; - mb->buffer_length = 2; - break; - - case CPIPE_ROUTER_UP_TIME: - do_gettimeofday( &tv ); - chdlc_priv_area->router_up_time = tv.tv_sec - - chdlc_priv_area->router_start_time; - *(unsigned long *)&chdlc_udp_pkt->data = - chdlc_priv_area->router_up_time; - mb->buffer_length = sizeof(unsigned long); - chdlc_udp_pkt->cblock.buffer_length = sizeof(unsigned long); - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - break; - - case FT1_MONITOR_STATUS_CTRL: - /* Enable FT1 MONITOR STATUS */ - if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || - (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { - - if( rCount++ != 0 ) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( chdlc_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - goto dflt_1; - - default: -dflt_1: - /* it's a board command */ - mb->command = chdlc_udp_pkt->cblock.command; - mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; - if (mb->buffer_length) { - memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> - data, mb->buffer_length); - } - /* run the command on the board */ - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - break; - } - - /* copy the result back to our buffer */ - memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); - - if (mb->buffer_length) { - memcpy(&chdlc_udp_pkt->data, &mb->data, - mb->buffer_length); - } - - } /* end of switch */ - } /* end of else */ - - /* Fill UDP TTL */ - chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - - len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); - - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){ - - /* Must check if we interrupted if_send() routine. The - * tx buffers might be used. If so drop the packet */ - if (!test_bit(SEND_CRIT,&card->wandev.critical)) { - - if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { - ++ card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += len; - } - } - } else { - - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - /* copy data into new_skb */ - - buf = skb_put(new_skb, len); - memcpy(buf, chdlc_priv_area->udp_pkt_data, len); - - /* Decapsulate pkt and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - dev->last_rx = jiffies; - } else { - - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - } - - chdlc_priv_area->udp_pkt_lgth = 0; - - return 0; -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ - -static void init_chdlc_tx_rx_buff( sdla_t* card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; - CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; - char err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - if (card->wandev.dev){ - chdlc_error(card,err,mb); - } - return; - } - - if(card->hw.type == SDLA_S514) { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct)); - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - tx_config->base_addr_Tx_status_elements); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *) - card->u.c.txbuf_base + - (tx_config->number_Tx_status_elements - 1); - - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - rx_config->base_addr_Rx_status_elements); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *) - card->u.c.rxbuf_base + - (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - tx_config->next_Tx_status_element_to_use); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - rx_config->next_Rx_status_element_to_use); - } - else { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base - + (tx_config->number_Tx_status_elements - 1); - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base - + (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); - } - - /* Setup Actual Buffer Start and end addresses */ - card->u.c.rx_base = rx_config->base_addr_Rx_buffer; - card->u.c.rx_top = rx_config->end_addr_Rx_buffer; - -} - -/*============================================================================= - * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ -static int intr_test( sdla_t* card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err,i; - - Intr_test_counter = 0; - - err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); - - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != CMD_OK) - chdlc_error(card, err, mb); - } - } - else { - return err; - } - - err = chdlc_set_intr_mode(card, 0); - - if (err != CMD_OK) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. CPIPEAB ? - */ -static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) -{ - chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; - -#ifdef _WAN_UDP_DEBUG - printk(KERN_INFO "SIG %s = %s\n\ - UPP %x = %x\n\ - PRT %x = %x\n\ - REQ %i = %i\n\ - 36 th = %x 37th = %x\n", - chdlc_udp_pkt->wp_mgmt.signature, - UDPMGMT_SIGNATURE, - chdlc_udp_pkt->udp_pkt.udp_dst_port, - ntohs(card->wandev.udp_port), - chdlc_udp_pkt->ip_pkt.protocol, - UDPMGMT_UDP_PROTOCOL, - chdlc_udp_pkt->wp_mgmt.request_reply, - UDPMGMT_REQUEST, - skb->data[36], skb->data[37]); -#endif - - if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && - (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && - (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { - - return UDP_CPIPE_TYPE; - - }else{ - return UDP_INVALID_TYPE; - } -} - -/*============================================================================ - * Set PORT state. - */ -static void port_set_state (sdla_t *card, int state) -{ - if (card->u.c.state != state) - { - switch (state) - { - case WAN_CONNECTED: - printk (KERN_INFO "%s: Link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: Link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: Link disconnected!\n", - card->devname); - break; - } - - card->wandev.state = card->u.c.state = state; - if (card->wandev.dev){ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - chdlc_priv_area->common.state = state; - } - } -} - -/*=========================================================================== - * config_chdlc - * - * Configure the chdlc protocol and enable communications. - * - * The if_open() function binds this function to the poll routine. - * Therefore, this function will run every time the chdlc interface - * is brought up. We cannot run this function from the if_open - * because if_open does not have access to the remote IP address. - * - * If the communications are not enabled, proceed to configure - * the card and enable communications. - * - * If the communications are enabled, it means that the interface - * was shutdown by ether the user or driver. In this case, we - * have to check that the IP addresses have not changed. If - * the IP addresses have changed, we have to reconfigure the firmware - * and update the changed IP addresses. Otherwise, just exit. - * - */ - -static int config_chdlc (sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - if (card->u.c.comm_enabled){ - - /* Jun 20. 2000: NC - * IP addresses are not used in the API mode */ - - if ((chdlc_priv_area->ip_local_tmp != chdlc_priv_area->ip_local || - chdlc_priv_area->ip_remote_tmp != chdlc_priv_area->ip_remote) && - card->u.c.usedby == WANPIPE) { - - /* The IP addersses have changed, we must - * stop the communications and reconfigure - * the card. Reason: the firmware must know - * the local and remote IP addresses. */ - disable_comm(card); - port_set_state(card, WAN_DISCONNECTED); - printk(KERN_INFO - "%s: IP addresses changed!\n", - card->devname); - printk(KERN_INFO - "%s: Restarting communications ...\n", - card->devname); - }else{ - /* IP addresses are the same and the link is up, - * we don't have to do anything here. Therefore, exit */ - return 0; - } - } - - chdlc_priv_area->ip_local = chdlc_priv_area->ip_local_tmp; - chdlc_priv_area->ip_remote = chdlc_priv_area->ip_remote_tmp; - - - /* Setup the Board for asynchronous mode */ - if (card->u.c.async_mode){ - - if (set_asy_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", - card->devname); - return 0; - } - }else{ - /* Setup the Board for CHDLC */ - if (set_chdlc_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC configuration!\n", - card->devname); - return 0; - } - } - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return 0; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - /* In TTY mode, receive interrupt will be enabled during - * wanpipe_tty_open() operation */ - if (card->tty_opt){ - flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_RX_FRAME; - } - - /* Enable communications */ - if (card->u.c.async_mode){ - if (asy_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable async commnunication!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return 0; - } - }else{ - if (chdlc_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return 0; - } - } - - /* Initialize Rx/Tx buffer control fields */ - init_chdlc_tx_rx_buff(card); - port_set_state(card, WAN_CONNECTING); - return 0; -} - - -/*============================================================ - * chdlc_poll - * - * Rationale: - * We cannot manipulate the routing tables, or - * ip addresses withing the interrupt. Therefore - * we must perform such actons outside an interrupt - * at a later time. - * - * Description: - * CHDLC polling routine, responsible for - * shutting down interfaces upon disconnect - * and adding/removing routes. - * - * Usage: - * This function is executed for each CHDLC - * interface through a tq_schedule bottom half. - * - * trigger_chdlc_poll() function is used to kick - * the chldc_poll routine. - */ - -static void chdlc_poll(struct net_device *dev) -{ - chdlc_private_area_t *chdlc_priv_area; - sdla_t *card; - u8 check_gateway=0; - SHARED_MEMORY_INFO_STRUCT* flags; - - - if (!dev || (chdlc_priv_area=dev->priv) == NULL) - return; - - card = chdlc_priv_area->card; - flags = card->u.c.flags; - - /* (Re)Configuraiton is in progress, stop what you are - * doing and get out */ - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - clear_bit(POLL_CRIT,&card->wandev.critical); - return; - } - - /* if_open() function has triggered the polling routine - * to determine the configured IP addresses. Once the - * addresses are found, trigger the chdlc configuration */ - if (test_bit(0,&chdlc_priv_area->config_chdlc)){ - - chdlc_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); - chdlc_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); - - /* Jun 20. 2000 Bug Fix - * Only perform this check in WANPIPE mode, since - * IP addresses are not used in the API mode. */ - - if (chdlc_priv_area->ip_local_tmp == chdlc_priv_area->ip_remote_tmp && - card->u.c.slarp_timer == 0x00 && - !card->u.c.backup && - card->u.c.usedby == WANPIPE){ - - if (++chdlc_priv_area->ip_error > MAX_IP_ERRORS){ - printk(KERN_INFO "\n%s: --- WARNING ---\n", - card->devname); - printk(KERN_INFO - "%s: The local IP address is the same as the\n", - card->devname); - printk(KERN_INFO - "%s: Point-to-Point IP address.\n", - card->devname); - printk(KERN_INFO "%s: --- WARNING ---\n\n", - card->devname); - }else{ - clear_bit(POLL_CRIT,&card->wandev.critical); - chdlc_priv_area->poll_delay_timer.expires = jiffies+HZ; - add_timer(&chdlc_priv_area->poll_delay_timer); - return; - } - } - - clear_bit(0,&chdlc_priv_area->config_chdlc); - clear_bit(POLL_CRIT,&card->wandev.critical); - - chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - return; - } - /* Dynamic interface implementation, as well as dynamic - * routing. */ - - switch (card->u.c.state){ - - case WAN_DISCONNECTED: - - /* If the dynamic interface configuration is on, and interface - * is up, then bring down the netowrk interface */ - - if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && - !test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && - card->wandev.dev->flags & IFF_UP){ - - printk(KERN_INFO "%s: Interface %s down.\n", - card->devname,card->wandev.dev->name); - change_dev_flags(card->wandev.dev,(card->wandev.dev->flags&~IFF_UP)); - set_bit(DEV_DOWN,&chdlc_priv_area->interface_down); - chdlc_priv_area->route_status = NO_ROUTE; - - }else{ - /* We need to check if the local IP address is - * zero. If it is, we shouldn't try to remove it. - */ - - if (card->wandev.dev->flags & IFF_UP && - get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && - chdlc_priv_area->route_status != NO_ROUTE && - card->u.c.slarp_timer){ - - process_route(card); - } - } - break; - - case WAN_CONNECTED: - - /* In SMP machine this code can execute before the interface - * comes up. In this case, we must make sure that we do not - * try to bring up the interface before dev_open() is finished */ - - - /* DEV_DOWN will be set only when we bring down the interface - * for the very first time. This way we know that it was us - * that brought the interface down */ - - if (test_bit(DYN_OPT_ON,&chdlc_priv_area->interface_down) && - test_bit(DEV_DOWN, &chdlc_priv_area->interface_down) && - !(card->wandev.dev->flags & IFF_UP)){ - - printk(KERN_INFO "%s: Interface %s up.\n", - card->devname,card->wandev.dev->name); - change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); - clear_bit(DEV_DOWN,&chdlc_priv_area->interface_down); - check_gateway=1; - } - - if (chdlc_priv_area->route_status == ADD_ROUTE && - card->u.c.slarp_timer){ - - process_route(card); - check_gateway=1; - } - - if (chdlc_priv_area->gateway && check_gateway) - add_gateway(card,dev); - - break; - } - - clear_bit(POLL_CRIT,&card->wandev.critical); -} - -/*============================================================ - * trigger_chdlc_poll - * - * Description: - * Add a chdlc_poll() work entry into the keventd work queue - * for a specific dlci/interface. This will kick - * the fr_poll() routine at a later time. - * - * Usage: - * Interrupts use this to defer a taks to - * a polling routine. - * - */ -static void trigger_chdlc_poll(struct net_device *dev) -{ - chdlc_private_area_t *chdlc_priv_area; - sdla_t *card; - - if (!dev) - return; - - if ((chdlc_priv_area = dev->priv)==NULL) - return; - - card = chdlc_priv_area->card; - - if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ - return; - } - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - return; - } - schedule_work(&chdlc_priv_area->poll_work); -} - - -static void chdlc_poll_delay (unsigned long dev_ptr) -{ - struct net_device *dev = (struct net_device *)dev_ptr; - trigger_chdlc_poll(dev); -} - - -void s508_lock (sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); - if (card->next){ - spin_lock(&card->next->wandev.lock); - } -} - -void s508_unlock (sdla_t *card, unsigned long *smp_flags) -{ - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - -//*********** TTY SECTION **************** - -static void wanpipe_tty_trigger_tx_irq(sdla_t *card) -{ - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; -} - -static void wanpipe_tty_trigger_poll(sdla_t *card) -{ - schedule_work(&card->tty_work); -} - -static void tty_poll_work (void* data) -{ - sdla_t *card = (sdla_t*)data; - struct tty_struct *tty; - - if ((tty=card->tty)==NULL) - return; - - tty_wakeup(tty); -#if defined(SERIAL_HAVE_POLL_WAIT) - wake_up_interruptible(&tty->poll_wait); -#endif - return; -} - -static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp) -{ - sdla_t *card; - unsigned long smp_flags; - - if (!tty || !tty->driver_data){ - return; - } - - card = (sdla_t*)tty->driver_data; - - if (!card) - return; - - printk(KERN_INFO "%s: Closing TTY Driver!\n", - card->devname); - - /* Sanity Check */ - if (!card->tty_open) - return; - - wanpipe_close(card); - if (--card->tty_open == 0){ - - lock_adapter_irq(&card->wandev.lock,&smp_flags); - card->tty=NULL; - chdlc_disable_comm_shutdown(card); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - - kfree(card->tty_buf); - card->tty_buf = NULL; - kfree(card->tty_rx); - card->tty_rx = NULL; - } - return; -} -static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp) -{ - unsigned long smp_flags; - sdla_t *card; - - if (!tty){ - return -ENODEV; - } - - if (!tty->driver_data){ - int port; - port = tty->index; - if ((port < 0) || (port >= NR_PORTS)) - return -ENODEV; - - tty->driver_data = WAN_CARD(port); - if (!tty->driver_data) - return -ENODEV; - } - - card = (sdla_t*)tty->driver_data; - - if (!card){ - lock_adapter_irq(&card->wandev.lock,&smp_flags); - card->tty=NULL; - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - return -ENODEV; - } - - printk(KERN_INFO "%s: Opening TTY Driver!\n", - card->devname); - - if (card->tty_open == 0){ - lock_adapter_irq(&card->wandev.lock,&smp_flags); - card->tty=tty; - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - - if (!card->tty_buf){ - card->tty_buf = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); - if (!card->tty_buf){ - card->tty_buf=NULL; - card->tty=NULL; - return -ENOMEM; - } - } - - if (!card->tty_rx){ - card->tty_rx = kmalloc(TTY_CHDLC_MAX_MTU, GFP_KERNEL); - if (!card->tty_rx){ - /* Free the buffer above */ - kfree(card->tty_buf); - card->tty_buf=NULL; - card->tty=NULL; - return -ENOMEM; - } - } - } - - ++card->tty_open; - wanpipe_open(card); - return 0; -} - -static int wanpipe_tty_write(struct tty_struct * tty, const unsigned char *buf, int count) -{ - unsigned long smp_flags=0; - sdla_t *card=NULL; - - if (!tty){ - dbg_printk(KERN_INFO "NO TTY in Write\n"); - return -ENODEV; - } - - card = (sdla_t *)tty->driver_data; - - if (!card){ - dbg_printk(KERN_INFO "No Card in TTY Write\n"); - return -ENODEV; - } - - if (count > card->wandev.mtu){ - dbg_printk(KERN_INFO "Frame too big in Write %i Max: %i\n", - count,card->wandev.mtu); - return -EINVAL; - } - - if (card->wandev.state != WAN_CONNECTED){ - dbg_printk(KERN_INFO "Card not connected in TTY Write\n"); - return -EINVAL; - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ - printk(KERN_INFO "%s: Critical in TTY Write\n", - card->devname); - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - - return -EINVAL; - } - - if (chdlc_send(card,(void*)buf,count)){ - dbg_printk(KERN_INFO "%s: Failed to send, retry later: kernel!\n", - card->devname); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - - wanpipe_tty_trigger_tx_irq(card); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - return 0; - } - dbg_printk(KERN_INFO "%s: Packet sent OK: %i\n",card->devname,count); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - - return count; -} - -static void wanpipe_tty_receive(sdla_t *card, unsigned addr, unsigned int len) -{ - unsigned offset=0; - unsigned olen=len; - char fp=0; - struct tty_struct *tty; - int i; - struct tty_ldisc *ld; - - if (!card->tty_open){ - dbg_printk(KERN_INFO "%s: TTY not open during receive\n", - card->devname); - return; - } - - if ((tty=card->tty) == NULL){ - dbg_printk(KERN_INFO "%s: No TTY on receive\n", - card->devname); - return; - } - - if (!tty->driver_data){ - dbg_printk(KERN_INFO "%s: No Driver Data, or Flip on receive\n", - card->devname); - return; - } - - - if (card->u.c.async_mode){ - if ((tty->flip.count+len) >= TTY_FLIPBUF_SIZE){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Received packet size too big: %i bytes, Max: %i!\n", - card->devname,len,TTY_FLIPBUF_SIZE); - } - return; - } - - - if((addr + len) > card->u.c.rx_top + 1) { - offset = card->u.c.rx_top - addr + 1; - - sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, offset); - - addr = card->u.c.rx_base; - len -= offset; - - tty->flip.char_buf_ptr+=offset; - tty->flip.count+=offset; - for (i=0;iflip.flag_buf_ptr = 0; - tty->flip.flag_buf_ptr++; - } - } - - sdla_peek(&card->hw, addr, tty->flip.char_buf_ptr, len); - - tty->flip.char_buf_ptr+=len; - card->tty->flip.count+=len; - for (i=0;iflip.flag_buf_ptr = 0; - tty->flip.flag_buf_ptr++; - } - - tty->low_latency=1; - tty_flip_buffer_push(tty); - }else{ - if (!card->tty_rx){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Receive sync buffer not available!\n", - card->devname); - } - return; - } - - if (len > TTY_CHDLC_MAX_MTU){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Received packet size too big: %i bytes, Max: %i!\n", - card->devname,len,TTY_FLIPBUF_SIZE); - } - return; - } - - - if((addr + len) > card->u.c.rx_top + 1) { - offset = card->u.c.rx_top - addr + 1; - - sdla_peek(&card->hw, addr, card->tty_rx, offset); - - addr = card->u.c.rx_base; - len -= offset; - } - sdla_peek(&card->hw, addr, card->tty_rx+offset, len); - ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->receive_buf) - ld->receive_buf(tty,card->tty_rx,&fp,olen); - tty_ldisc_deref(ld); - }else{ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: NO TTY Sync line discipline!\n", - card->devname); - } - } - } - - dbg_printk(KERN_INFO "%s: Received Data %i\n",card->devname,olen); - return; -} - -#if 0 -static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - return -ENOIOCTLCMD; -} -#endif - -static void wanpipe_tty_stop(struct tty_struct *tty) -{ - return; -} - -static void wanpipe_tty_start(struct tty_struct *tty) -{ - return; -} - -static int config_tty (sdla_t *card) -{ - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - /* Setup the Board for asynchronous mode */ - if (card->u.c.async_mode){ - - if (set_asy_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC Async configuration!\n", - card->devname); - return -EINVAL; - } - }else{ - /* Setup the Board for CHDLC */ - if (set_chdlc_config(card)) { - printk (KERN_INFO "%s: Failed CHDLC configuration!\n", - card->devname); - return -EINVAL; - } - } - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return -EINVAL; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - - /* Enable communications */ - if (card->u.c.async_mode){ - if (asy_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable async commnunication!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return -EINVAL; - } - }else{ - if (chdlc_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return -EINVAL; - } - } - - /* Initialize Rx/Tx buffer control fields */ - init_chdlc_tx_rx_buff(card); - port_set_state(card, WAN_CONNECTING); - return 0; -} - - -static int change_speed(sdla_t *card, struct tty_struct *tty, - struct termios *old_termios) -{ - int baud, ret=0; - unsigned cflag; - int dbits,sbits,parity,handshaking; - - cflag = tty->termios->c_cflag; - - /* There is always one stop bit */ - sbits=WANOPT_ONE; - - /* Parity is defaulted to NONE */ - parity = WANOPT_NONE; - - handshaking=0; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: dbits = 5; break; - case CS6: dbits = 6; break; - case CS7: dbits = 7; break; - case CS8: dbits = 8; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: dbits = 8; break; - } - - /* One more stop bit should be supported, thus increment - * the number of stop bits Max=2 */ - if (cflag & CSTOPB) { - sbits = WANOPT_TWO; - } - if (cflag & PARENB) { - parity = WANOPT_EVEN; - } - if (cflag & PARODD){ - parity = WANOPT_ODD; - } - - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(tty); - - if (!baud) - baud = 9600; /* B0 transition handled in rs_set_termios */ - - if (cflag & CRTSCTS) { - handshaking|=ASY_RTS_HS_FOR_RX; - } - - if (I_IGNPAR(tty)) - parity = WANOPT_NONE; - - if (I_IXOFF(tty)){ - handshaking|=ASY_XON_XOFF_HS_FOR_RX; - handshaking|=ASY_XON_XOFF_HS_FOR_TX; - } - - if (I_IXON(tty)){ - handshaking|=ASY_XON_XOFF_HS_FOR_RX; - handshaking|=ASY_XON_XOFF_HS_FOR_TX; - } - - if (card->u.c.async_mode){ - if (card->wandev.bps != baud) - ret=1; - card->wandev.bps = baud; - } - - if (card->u.c.async_mode){ - if (card->u.c.protocol_options != handshaking) - ret=1; - card->u.c.protocol_options = handshaking; - - if (card->u.c.tx_bits_per_char != dbits) - ret=1; - card->u.c.tx_bits_per_char = dbits; - - if (card->u.c.rx_bits_per_char != dbits) - ret=1; - card->u.c.rx_bits_per_char = dbits; - - if (card->u.c.stop_bits != sbits) - ret=1; - card->u.c.stop_bits = sbits; - - if (card->u.c.parity != parity) - ret=1; - card->u.c.parity = parity; - - card->u.c.break_timer = 50; - card->u.c.inter_char_timer = 10; - card->u.c.rx_complete_length = 100; - card->u.c.xon_char = 0xFE; - }else{ - card->u.c.protocol_options = HDLC_STREAMING_MODE; - } - - return ret; -} - - -static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios) -{ - sdla_t *card; - int err=1; - - if (!tty){ - return; - } - - card = (sdla_t *)tty->driver_data; - - if (!card) - return; - - if (change_speed(card, tty, old_termios) || !card->u.c.comm_enabled){ - unsigned long smp_flags; - - if (card->u.c.comm_enabled){ - lock_adapter_irq(&card->wandev.lock,&smp_flags); - chdlc_disable_comm_shutdown(card); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - } - lock_adapter_irq(&card->wandev.lock,&smp_flags); - err = config_tty(card); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - if (card->u.c.async_mode){ - printk(KERN_INFO "%s: TTY Async Configuration:\n" - " Baud =%i\n" - " Handshaking =%s\n" - " Tx Dbits =%i\n" - " Rx Dbits =%i\n" - " Parity =%s\n" - " Stop Bits =%i\n", - card->devname, - card->wandev.bps, - opt_decode[card->u.c.protocol_options], - card->u.c.tx_bits_per_char, - card->u.c.rx_bits_per_char, - p_decode[card->u.c.parity] , - card->u.c.stop_bits); - }else{ - printk(KERN_INFO "%s: TTY Sync Configuration:\n" - " Baud =%i\n" - " Protocol =HDLC_STREAMING\n", - card->devname,card->wandev.bps); - } - if (!err){ - port_set_state(card,WAN_CONNECTED); - }else{ - port_set_state(card,WAN_DISCONNECTED); - } - } - return; -} - -static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch) -{ - sdla_t *card; - unsigned long smp_flags=0; - - if (!tty){ - return; - } - - card = (sdla_t *)tty->driver_data; - - if (!card) - return; - - if (card->wandev.state != WAN_CONNECTED) - return; - - if(card->hw.type != SDLA_S514) - s508_lock(card,&smp_flags); - - if (test_and_set_bit(SEND_CRIT,(void*)&card->wandev.critical)){ - - wanpipe_tty_trigger_tx_irq(card); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - return; - } - - if (chdlc_send(card,(void*)&ch,1)){ - wanpipe_tty_trigger_tx_irq(card); - dbg_printk("%s: Failed to TX char!\n",card->devname); - } - - dbg_printk("%s: Char TX OK\n",card->devname); - - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - s508_unlock(card,&smp_flags); - - return; -} - -static void wanpipe_tty_flush_chars(struct tty_struct *tty) -{ - return; -} - -static void wanpipe_tty_flush_buffer(struct tty_struct *tty) -{ - if (!tty) - return; - -#if defined(SERIAL_HAVE_POLL_WAIT) - wake_up_interruptible(&tty->poll_wait); -#endif - tty_wakeup(tty); - return; -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch) -{ - return; -} - - -static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty) -{ - return 0; -} - - -static int wanpipe_tty_write_room(struct tty_struct *tty) -{ - sdla_t *card; - - printk(KERN_INFO "TTY Write Room\n"); - - if (!tty){ - return 0; - } - - card = (sdla_t *)tty->driver_data; - if (!card) - return 0; - - if (card->wandev.state != WAN_CONNECTED) - return 0; - - return SEC_MAX_NO_DATA_BYTES_IN_FRAME; -} - - -static int set_modem_status(sdla_t *card, unsigned char data) -{ - CHDLC_MAILBOX_STRUCT *mb = card->mbox; - int err; - - mb->buffer_length=1; - mb->command=SET_MODEM_STATUS; - mb->data[0]=data; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - - return err; -} - -static void wanpipe_tty_hangup(struct tty_struct *tty) -{ - sdla_t *card; - unsigned long smp_flags; - - printk(KERN_INFO "TTY Hangup!\n"); - - if (!tty){ - return; - } - - card = (sdla_t *)tty->driver_data; - if (!card) - return; - - lock_adapter_irq(&card->wandev.lock,&smp_flags); - set_modem_status(card,0); - unlock_adapter_irq(&card->wandev.lock,&smp_flags); - return; -} - -static void wanpipe_tty_break(struct tty_struct *tty, int break_state) -{ - return; -} - -static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout) -{ - return; -} - -static void wanpipe_tty_throttle(struct tty_struct * tty) -{ - return; -} - -static void wanpipe_tty_unthrottle(struct tty_struct * tty) -{ - return; -} - -int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - return 0; -} - -/* - * The serial driver boot-time initialization code! - */ -int wanpipe_tty_init(sdla_t *card) -{ - struct serial_state * state; - - /* Initialize the tty_driver structure */ - - if (card->tty_minor < 0 || card->tty_minor > NR_PORTS){ - printk(KERN_INFO "%s: Illegal Minor TTY number (0-4): %i\n", - card->devname,card->tty_minor); - return -EINVAL; - } - - if (WAN_CARD(card->tty_minor)){ - printk(KERN_INFO "%s: TTY Minor %i, already in use\n", - card->devname,card->tty_minor); - return -EBUSY; - } - - if (tty_init_cnt==0){ - - printk(KERN_INFO "%s: TTY %s Driver Init: Major %i, Minor Range %i-%i\n", - card->devname, - card->u.c.async_mode ? "ASYNC" : "SYNC", - WAN_TTY_MAJOR,MIN_PORT,MAX_PORT); - - tty_driver_mode = card->u.c.async_mode; - - memset(&serial_driver, 0, sizeof(struct tty_driver)); - serial_driver.magic = TTY_DRIVER_MAGIC; - serial_driver.owner = THIS_MODULE; - serial_driver.driver_name = "wanpipe_tty"; - serial_driver.name = "ttyW"; - serial_driver.major = WAN_TTY_MAJOR; - serial_driver.minor_start = WAN_TTY_MINOR; - serial_driver.num = NR_PORTS; - serial_driver.type = TTY_DRIVER_TYPE_SERIAL; - serial_driver.subtype = SERIAL_TYPE_NORMAL; - - serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver.flags = TTY_DRIVER_REAL_RAW; - - serial_driver.refcount = 1; /* !@!@^#^&!! */ - - serial_driver.open = wanpipe_tty_open; - serial_driver.close = wanpipe_tty_close; - serial_driver.write = wanpipe_tty_write; - - serial_driver.put_char = wanpipe_tty_put_char; - serial_driver.flush_chars = wanpipe_tty_flush_chars; - serial_driver.write_room = wanpipe_tty_write_room; - serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer; - serial_driver.flush_buffer = wanpipe_tty_flush_buffer; - //serial_driver.ioctl = wanpipe_tty_ioctl; - serial_driver.throttle = wanpipe_tty_throttle; - serial_driver.unthrottle = wanpipe_tty_unthrottle; - serial_driver.send_xchar = wanpipe_tty_send_xchar; - serial_driver.set_termios = wanpipe_tty_set_termios; - serial_driver.stop = wanpipe_tty_stop; - serial_driver.start = wanpipe_tty_start; - serial_driver.hangup = wanpipe_tty_hangup; - serial_driver.break_ctl = wanpipe_tty_break; - serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent; - serial_driver.read_proc = wanpipe_tty_read_proc; - - if (tty_register_driver(&serial_driver)){ - printk(KERN_INFO "%s: Failed to register serial driver!\n", - card->devname); - } - } - - - /* The subsequent ports must comply to the initial configuration */ - if (tty_driver_mode != card->u.c.async_mode){ - printk(KERN_INFO "%s: Error: TTY Driver operation mode mismatch!\n", - card->devname); - printk(KERN_INFO "%s: The TTY driver is configured for %s!\n", - card->devname, tty_driver_mode ? "ASYNC" : "SYNC"); - return -EINVAL; - } - - tty_init_cnt++; - - printk(KERN_INFO "%s: Initializing TTY %s Driver Minor %i\n", - card->devname, - tty_driver_mode ? "ASYNC" : "SYNC", - card->tty_minor); - - tty_card_map[card->tty_minor] = card; - state = &rs_table[card->tty_minor]; - - state->magic = SSTATE_MAGIC; - state->line = 0; - state->type = PORT_UNKNOWN; - state->custom_divisor = 0; - state->close_delay = 5*HZ/10; - state->closing_wait = 30*HZ; - state->icount.cts = state->icount.dsr = - state->icount.rng = state->icount.dcd = 0; - state->icount.rx = state->icount.tx = 0; - state->icount.frame = state->icount.parity = 0; - state->icount.overrun = state->icount.brk = 0; - state->irq = card->wandev.irq; - - INIT_WORK(&card->tty_work, tty_poll_work, (void*)card); - return 0; -} - - -MODULE_LICENSE("GPL"); - -/****** End ****************************************************************/ diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c deleted file mode 100644 index 7f1ce9d4333e..000000000000 --- a/drivers/net/wan/sdla_fr.c +++ /dev/null @@ -1,5061 +0,0 @@ -/***************************************************************************** -* sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. -* -* Author(s): Nenad Corbic -* Gideon Hack -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* 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. -* ============================================================================ -* Nov 23, 2000 Nenad Corbic o Added support for 2.4.X kernels -* Nov 15, 2000 David Rokavarg -* Nenad Corbic o Added frame relay bridging support. -* Original code from Mark Wells and Kristian Hoffmann has -* been integrated into the frame relay driver. -* Nov 13, 2000 Nenad Corbic o Added true interface type encoding option. -* Tcpdump doesn't support Frame Relay inteface -* types, to fix this true type option will set -* the interface type to RAW IP mode. -* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: -* Deny all and specify allowed requests. -* Nov 06, 2000 Nenad Corbic o Wanpipe interfaces conform to raw packet interfaces. -* Moved the if_header into the if_send() routine. -* The if_header() was breaking the libpcap -* support. i.e. support for tcpdump, ethereal ... -* Oct 12. 2000 Nenad Corbic o Added error message in fr_configure -* Jul 31, 2000 Nenad Corbic o Fixed the Router UP Time. -* Apr 28, 2000 Nenad Corbic o Added the option to shutdown an interface -* when the channel gets disconnected. -* Apr 28, 2000 Nenad Corbic o Added M.Grants patch: disallow duplicate -* interface setups. -* Apr 25, 2000 Nenad Corbic o Added M.Grants patch: dynamically add/remove -* new dlcis/interfaces. -* Mar 23, 2000 Nenad Corbic o Improved task queue, bh handling. -* Mar 16, 2000 Nenad Corbic o Added Inverse ARP support -* Mar 13, 2000 Nenad Corbic o Added new socket API support. -* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. -* Feb 24, 2000 Nenad Corbic o Fixed up FT1 UDP debugging problem. -* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels -* -* Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function -* o Removed the ARP support. This has to be done -* in the next version. -* o Only a Node can implement NO signalling. -* Initialize DLCI during if_open() if NO -* signalling. -* o Took out IPX support, implement in next -* version -* Sep 29, 1999 Nenad Corbic o Added SMP support and changed the update -* function to use timer interrupt. -* o Fixed the CIR bug: Set the value of BC -* to CIR when the CIR is enabled. -* o Updated comments, statistics and tracing. -* Jun 02, 1999 Gideon Hack o Updated for S514 support. -* Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. -* Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI -* status is received through an event interrupt. -* Jul 08, 1998 David Fong o Added inverse ARP support. -* Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. -* Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. -* Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) -* Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. -* Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards -* o Added Cli() to protect enabling of interrupts -* while polling is called. -* Nov 24, 1997 Jaspreet Singh o Added counters to avoid enabling of interrupts -* when they have been disabled by another -* interface or routine (eg. wpf_poll). -* Nov 06, 1997 Jaspreet Singh o Added INTR_TEST_MODE to avoid polling -* routine disable interrupts during interrupt -* testing. -* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. -* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow -* control by avoiding RACE conditions. The -* cli() and restore_flags() are taken out. -* The fr_channel structure is appended for -* Driver Statistics. -* Oct 15, 1997 Farhan Thawar o updated if_send() and receive for IPX -* Aug 29, 1997 Farhan Thawar o Removed most of the cli() and sti() -* o Abstracted the UDP management stuff -* o Now use tbusy and critical more intelligently -* Jul 21, 1997 Jaspreet Singh o Can configure T391, T392, N391, N392 & N393 -* through router.conf. -* o Protected calls to sdla_peek() by adDing -* save_flags(), cli() and restore_flags(). -* o Added error message for Inactive DLCIs in -* fr_event() and update_chan_state(). -* o Fixed freeing up of buffers using kfree() -* when packets are received. -* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets -* o Added ability to discard multicast and -* broadcast source addressed packets -* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities -* New case (0x44) statement in if_send routine -* Added a global variable rCount to keep track -* of FT1 status enabled on the board. -* May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem -* With multiple boards a problem was seen where -* the second board always stopped transmitting -* packet after running for a while. The code -* got into a stage where the interrupts were -* disabled and dev->tbusy was set to 1. -* This caused the If_send() routine to get into -* the if clause for it(0,dev->tbusy) -* forever. -* The code got into this stage due to an -* interrupt occurring within the if clause for -* set_bit(0,dev->tbusy). Since an interrupt -* disables furhter transmit interrupt and -* makes dev->tbusy = 0, this effect was undone -* by making dev->tbusy = 1 in the if clause. -* The Fix checks to see if Transmit interrupts -* are disabled then do not make dev->tbusy = 1 -* Introduced a global variable: int_occur and -* added tx_int_enabled in the wan_device -* structure. -* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple -* boards. -* -* Apr 25, 1997 Farhan Thawar o added UDP Management stuff -* o fixed bug in if_send() and tx_intr() to -* sleep and wakeup all devices -* Mar 11, 1997 Farhan Thawar Version 3.1.1 -* o fixed (+1) bug in fr508_rx_intr() -* o changed if_send() to return 0 if -* wandev.critical() is true -* o free socket buffer in if_send() if -* returning 0 -* o added tx_intr() routine -* Jan 30, 1997 Gene Kozin Version 3.1.0 -* o implemented exec() entry point -* o fixed a bug causing driver configured as -* a FR switch to be stuck in WAN_ -* mode -* Jan 02, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include -#include /* ARPHRD_* defines */ -#include /* htons(), etc. */ -#include /* for inb(), outb(), etc. */ -#include /* for do_gettimeofday */ -#include /* sockaddr_in */ -#include /* time_after() macro */ -#include - -#include -#include - -#include /* Wanpipe Socket */ -#include - -#include /* frame relay firmware API definitions */ - -#include -#include -#include - -#include /* Dynamic Route Creation */ -#include /* eth_type_trans() used for bridging */ -#include - -/****** Defines & Macros ****************************************************/ - -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ - -#define FR_HEADER_LEN 8 /* max encapsulation header size */ -#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ - -/* Q.922 frame types */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF - -/* DLCI configured or not */ -#define DLCI_NOT_CONFIGURED 0x00 -#define DLCI_CONFIG_PENDING 0x01 -#define DLCI_CONFIGURED 0x02 - -/* CIR enabled or not */ -#define CIR_ENABLED 0x00 -#define CIR_DISABLED 0x01 - -#define FRAME_RELAY_API 1 -#define MAX_BH_BUFF 10 - -/* For handle_IPXWAN() */ -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - -/****** Data Structures *****************************************************/ - -/* This is an extention of the 'struct device' we create for each network - * interface to keep the rest of channel-specific data. - */ -typedef struct fr_channel -{ - wanpipe_common_t common; - char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ - unsigned dlci_configured ; /* check whether configured or not */ - unsigned cir_status; /* check whether CIR enabled or not */ - unsigned dlci; /* logical channel number */ - unsigned cir; /* committed information rate */ - unsigned bc; /* committed burst size */ - unsigned be; /* excess burst size */ - unsigned mc; /* multicast support on or off */ - unsigned tx_int_status; /* Transmit Interrupt Status */ - unsigned short pkt_length; /* Packet Length */ - unsigned long router_start_time;/* Router start time in seconds */ - unsigned long tick_counter; /* counter for transmit time out */ - char dev_pending_devtint; /* interface pending dev_tint() */ - void *dlci_int_interface; /* pointer to the DLCI Interface */ - unsigned long IB_addr; /* physical address of Interface Byte */ - unsigned long state_tick; /* time of the last state change */ - unsigned char enable_IPX; /* Enable/Disable the use of IPX */ - unsigned long network_number; /* Internal Network Number for IPX*/ - sdla_t *card; /* -> owner */ - unsigned route_flag; /* Add/Rem dest addr in route tables */ - unsigned inarp; /* Inverse Arp Request status */ - long inarp_ready; /* Ready to send requests */ - int inarp_interval; /* Time between InArp Requests */ - unsigned long inarp_tick; /* InArp jiffies tick counter */ - long interface_down; /* Bring interface down on disconnect */ - struct net_device_stats ifstats; /* interface statistics */ - if_send_stat_t drvstats_if_send; - rx_intr_stat_t drvstats_rx_intr; - pipe_mgmt_stat_t drvstats_gen; - unsigned long router_up_time; - - unsigned short transmit_length; - struct sk_buff *delay_skb; - - bh_data_t *bh_head; /* Circular buffer for chdlc_bh */ - unsigned long tq_working; - volatile int bh_write; - volatile int bh_read; - atomic_t bh_buff_used; - - /* Polling task queue. Each interface - * has its own task queue, which is used - * to defer events from the interrupt */ - struct work_struct fr_poll_work; - struct timer_list fr_arp_timer; - - u32 ip_local; - u32 ip_remote; - long config_dlci; - long unconfig_dlci; - - /* Whether this interface should be setup as a gateway. - * Used by dynamic route setup code */ - u8 gateway; - - /* True interface type */ - u8 true_if_encoding; - u8 fr_header[FR_HEADER_LEN]; - char fr_header_len; - -} fr_channel_t; - -/* Route Flag options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 -#define ARP_REQ 0x04 - -/* inarp options */ -#define INARP_NONE 0x00 -#define INARP_REQUEST 0x01 -#define INARP_CONFIGURED 0x02 - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x01 -#define TMR_INT_ENABLED_UPDATE 0x02 -#define TMR_INT_ENABLED_ARP 0x04 -#define TMR_INT_ENABLED_UPDATE_STATE 0x08 -#define TMR_INT_ENABLED_CONFIG 0x10 -#define TMR_INT_ENABLED_UNCONFIG 0x20 - - -typedef struct dlci_status -{ - unsigned short dlci PACKED; - unsigned char state PACKED; -} dlci_status_t; - -typedef struct dlci_IB_mapping -{ - unsigned short dlci PACKED; - unsigned long addr_value PACKED; -} dlci_IB_mapping_t; - -/* This structure is used for DLCI list Tx interrupt mode. It is used to - enable interrupt bit and set the packet length for transmission - */ -typedef struct fr_dlci_interface -{ - unsigned char gen_interrupt PACKED; - unsigned short packet_length PACKED; - unsigned char reserved PACKED; -} fr_dlci_interface_t; - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/* variable for keeping track of number of interrupts generated during - * interrupt test routine - */ -static int Intr_test_counter; - -/****** Function Prototypes *************************************************/ - -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device *wandev); -static int new_if(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf); -static int del_if(struct wan_device *wandev, struct net_device *dev); -static void disable_comm (sdla_t *card); - -/* WANPIPE-specific entry points */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); - -/* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); - -static void if_tx_timeout(struct net_device *dev); - -static int if_rebuild_hdr (struct sk_buff *skb); - -static int if_send(struct sk_buff *skb, struct net_device *dev); -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); - -/* Interrupt handlers */ -static void fr_isr(sdla_t *card); -static void rx_intr(sdla_t *card); -static void tx_intr(sdla_t *card); -static void timer_intr(sdla_t *card); -static void spur_intr(sdla_t *card); - -/* Frame relay firmware interface functions */ -static int fr_read_version(sdla_t *card, char *str); -static int fr_configure(sdla_t *card, fr_conf_t *conf); -static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); -static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); -static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); -static int fr_comm_enable(sdla_t *card); -static void fr_comm_disable(sdla_t *card); -static int fr_get_err_stats(sdla_t *card); -static int fr_get_stats(sdla_t *card); -static int fr_add_dlci(sdla_t *card, int dlci); -static int fr_activate_dlci(sdla_t *card, int dlci); -static int fr_delete_dlci (sdla_t* card, int dlci); -static int fr_issue_isf(sdla_t *card, int isf); -static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, - void *buf); -static int fr_send_data_header(sdla_t *card, int dlci, unsigned char attr, int len, - void *buf,unsigned char hdr_len); -static unsigned int fr_send_hdr(sdla_t *card, int dlci, unsigned int offset); - -static int check_dlci_config (sdla_t *card, fr_channel_t *chan); -static void initialize_rx_tx_buffers (sdla_t *card); - - -/* Firmware asynchronous event handlers */ -static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); -static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox); -static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); - -/* Miscellaneous functions */ -static int update_chan_state(struct net_device *dev); -static void set_chan_state(struct net_device *dev, int state); -static struct net_device *find_channel(sdla_t *card, unsigned dlci); -static int is_tx_ready(sdla_t *card, fr_channel_t *chan); -static unsigned int dec_to_uint(unsigned char *str, int len); -static int reply_udp( unsigned char *data, unsigned int mbox_len ); - -static int intr_test( sdla_t* card ); -static void init_chan_statistics( fr_channel_t* chan ); -static void init_global_statistics( sdla_t* card ); -static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); -static int setup_for_delayed_transmit(struct net_device* dev, - struct sk_buff *skb); - -struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev); -static int check_tx_status(sdla_t *card, struct net_device *dev); - -/* Frame Relay Socket API */ -static void trigger_fr_bh (fr_channel_t *); -static void fr_bh(struct net_device *dev); -static int fr_bh_cleanup(struct net_device *dev); -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); - -static void trigger_fr_poll(struct net_device *dev); -static void fr_poll(struct net_device *dev); -//static void add_gateway(struct net_device *dev); - -static void trigger_unconfig_fr(struct net_device *dev); -static void unconfig_fr (sdla_t *); - -static void trigger_config_fr (sdla_t *); -static void config_fr (sdla_t *); - - -/* Inverse ARP and Dynamic routing functions */ -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev); -int is_arp(void *buf); -int send_inarp_request(sdla_t *card, struct net_device *dev); - -static void trigger_fr_arp(struct net_device *dev); -static void fr_arp (unsigned long data); - - -/* Udp management functions */ -static int process_udp_mgmt_pkt(sdla_t *card); -static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ); -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, int dlci); - -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, - unsigned long network_number, unsigned char incoming); - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, - unsigned char enable_IPX, unsigned long network_number); - -/* Lock Functions: SMP supported */ -void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags); -void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); - -unsigned short calc_checksum (char *, int); -static int setup_fr_header(struct sk_buff *skb, - struct net_device* dev, char op_mode); - - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Frame relay protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpf_init(sdla_t *card, wandev_conf_t *conf) -{ - - int err; - fr508_flags_t* flags; - - union - { - char str[80]; - fr_conf_t cfg; - } u; - - fr_buf_info_t* buf_info; - int i; - - - printk(KERN_INFO "\n"); - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_FR) { - - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - - } - - /* Initialize protocol-specific fields of adapter data space */ - switch (card->hw.fwid) { - - case SFID_FR508: - card->mbox = (void*)(card->hw.dpmbase + - FR508_MBOX_OFFS); - card->flags = (void*)(card->hw.dpmbase + - FR508_FLAG_OFFS); - if(card->hw.type == SDLA_S514) { - card->mbox += FR_MB_VECTOR; - card->flags += FR_MB_VECTOR; - } - card->isr = &fr_isr; - break; - - default: - return -EINVAL; - } - - flags = card->flags; - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: running frame relay firmware v%s\n", - card->devname, u.str); - - /* Adjust configuration */ - conf->mtu += FR_HEADER_LEN; - conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ? - min_t(unsigned int, conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) : - FR_CHANNEL_MTU + FR_HEADER_LEN; - - conf->bps = min_t(unsigned int, conf->bps, 2048000); - - /* Initialze the configuration structure sent to the board to zero */ - memset(&u.cfg, 0, sizeof(u.cfg)); - - memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); - - /* Configure adapter firmware */ - - u.cfg.mtu = conf->mtu; - u.cfg.kbps = conf->bps / 1000; - - u.cfg.cir_fwd = u.cfg.cir_bwd = 16; - u.cfg.bc_fwd = u.cfg.bc_bwd = 16; - - u.cfg.options = 0x0000; - printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); - - switch (conf->u.fr.signalling) { - - case WANOPT_FR_ANSI: - u.cfg.options = 0x0000; - break; - - case WANOPT_FR_Q933: - u.cfg.options |= 0x0200; - break; - - case WANOPT_FR_LMI: - u.cfg.options |= 0x0400; - break; - - case WANOPT_NO: - u.cfg.options |= 0x0800; - break; - default: - printk(KERN_INFO "%s: Illegal Signalling option\n", - card->wandev.name); - return -EINVAL; - } - - - card->wandev.signalling = conf->u.fr.signalling; - - if (conf->station == WANOPT_CPE) { - - - if (conf->u.fr.signalling == WANOPT_NO){ - printk(KERN_INFO - "%s: ERROR - For NO signalling, station must be set to Node!", - card->devname); - return -EINVAL; - } - - u.cfg.station = 0; - u.cfg.options |= 0x8000; /* auto config DLCI */ - card->u.f.dlci_num = 0; - - } else { - - u.cfg.station = 1; /* switch emulation mode */ - - /* For switch emulation we have to create a list of dlci(s) - * that will be sent to be global SET_DLCI_CONFIGURATION - * command in fr_configure() routine. - */ - - card->u.f.dlci_num = min_t(unsigned int, max_t(unsigned int, conf->u.fr.dlci_num, 1), 100); - - for ( i = 0; i < card->u.f.dlci_num; i++) { - - card->u.f.node_dlci[i] = (unsigned short) - conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; - - } - } - - if (conf->clocking == WANOPT_INTERNAL) - u.cfg.port |= 0x0001; - - if (conf->interface == WANOPT_RS232) - u.cfg.port |= 0x0002; - - if (conf->u.fr.t391) - u.cfg.t391 = min_t(unsigned int, conf->u.fr.t391, 30); - else - u.cfg.t391 = 5; - - if (conf->u.fr.t392) - u.cfg.t392 = min_t(unsigned int, conf->u.fr.t392, 30); - else - u.cfg.t392 = 15; - - if (conf->u.fr.n391) - u.cfg.n391 = min_t(unsigned int, conf->u.fr.n391, 255); - else - u.cfg.n391 = 2; - - if (conf->u.fr.n392) - u.cfg.n392 = min_t(unsigned int, conf->u.fr.n392, 10); - else - u.cfg.n392 = 3; - - if (conf->u.fr.n393) - u.cfg.n393 = min_t(unsigned int, conf->u.fr.n393, 10); - else - u.cfg.n393 = 4; - - if (fr_configure(card, &u.cfg)) - return -EIO; - - if (card->hw.type == SDLA_S514) { - - buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + - FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + - card->hw.dpmbase); - }else{ - buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - - FR_MB_VECTOR + card->hw.dpmbase); - } - - card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; - - card->u.f.tx_interrupts_pending = 0; - - card->wandev.mtu = conf->mtu; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->poll = NULL; - card->exec = &wpf_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.ttl = conf->ttl; - card->wandev.udp_port = conf->udp_port; - card->disable_comm = &disable_comm; - card->u.f.arp_dev = NULL; - - /* Intialize global statistics for a card */ - init_global_statistics( card ); - - card->TracingEnabled = 0; - - /* Interrupt Test */ - Intr_test_counter = 0; - card->intr_mode = INTR_TEST_MODE; - err = intr_test( card ); - - printk(KERN_INFO "%s: End of Interrupt Test rc=0x%x count=%i\n", - card->devname,err,Intr_test_counter); - - if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_ERR "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - printk(KERN_ERR "Please choose another interrupt\n"); - err = -EIO; - return err; - } - - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); - - - /* Apr 28 2000. Nenad Corbic - * Enable commnunications here, not in if_open or new_if, since - * interfaces come down when the link is disconnected. - */ - - /* If you enable comms and then set ints, you get a Tx int as you - * perform the SET_INT_TRIGGERS command. So, we only set int - * triggers and then adjust the interrupt mask (to disable Tx ints) - * before enabling comms. - */ - if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | - FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , - card->wandev.mtu, 0)) { - return -EIO; - } - - flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); - - if (fr_comm_enable(card)) { - return -EIO; - } - wanpipe_set_state(card, WAN_CONNECTED); - spin_lock_init(&card->u.f.if_send_lock); - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics. - */ -static int update(struct wan_device* wandev) -{ - volatile sdla_t* card; - unsigned long timeout; - fr508_flags_t* flags; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - card = wandev->private; - flags = card->flags; - - - card->u.f.update_comms_stats = 1; - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; - flags->imask |= FR_INTR_TIMER; - timeout = jiffies; - for(;;) { - if(card->u.f.update_comms_stats == 0) - break; - if (time_after(jiffies, timeout + 1 * HZ)){ - card->u.f.update_comms_stats = 0; - return -EAGAIN; - } - } - - return 0; -} - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - fr_channel_t* chan; - int dlci = 0; - int err = 0; - - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - - printk(KERN_INFO "%s: Invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); - - if (chan == NULL) - return -ENOMEM; - - memset(chan, 0, sizeof(fr_channel_t)); - strcpy(chan->name, conf->name); - chan->card = card; - - /* verify media address */ - if (isdigit(conf->addr[0])) { - - dlci = dec_to_uint(conf->addr, 0); - - if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { - - chan->dlci = dlci; - - } else { - - printk(KERN_ERR - "%s: Invalid DLCI %u on interface %s!\n", - wandev->name, dlci, chan->name); - err = -EINVAL; - } - - } else { - printk(KERN_ERR - "%s: Invalid media address on interface %s!\n", - wandev->name, chan->name); - err = -EINVAL; - } - - if ((chan->true_if_encoding = conf->true_if_encoding) == WANOPT_YES){ - printk(KERN_INFO - "%s: Enabling, true interface type encoding.\n", - card->devname); - } - - - - /* Setup wanpipe as a router (WANPIPE) even if it is - * a bridged DLCI, or as an API - */ - if (strcmp(conf->usedby, "WANPIPE") == 0 || - strcmp(conf->usedby, "BRIDGE") == 0 || - strcmp(conf->usedby, "BRIDGE_N") == 0){ - - if(strcmp(conf->usedby, "WANPIPE") == 0){ - chan->common.usedby = WANPIPE; - - printk(KERN_INFO "%s: Running in WANPIPE mode.\n", - card->devname); - - }else if(strcmp(conf->usedby, "BRIDGE") == 0){ - - chan->common.usedby = BRIDGE; - - printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE) mode.\n", - card->devname); - }else if( strcmp(conf->usedby, "BRIDGE_N") == 0 ){ - - chan->common.usedby = BRIDGE_NODE; - - printk(KERN_INFO "%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", - card->devname); - } - - if (!err){ - /* Dynamic interface configuration option. - * On disconnect, if the options is selected, - * the interface will be brought down */ - if (conf->if_down == WANOPT_YES){ - set_bit(DYN_OPT_ON,&chan->interface_down); - printk(KERN_INFO - "%s: Dynamic interface configuration enabled.\n", - card->devname); - } - } - - } else if(strcmp(conf->usedby, "API") == 0){ - - chan->common.usedby = API; - printk(KERN_INFO "%s: Running in API mode.\n", - wandev->name); - } - - if (err) { - - kfree(chan); - return err; - } - - /* place cir,be,bc and other channel specific information into the - * chan structure - */ - if (conf->cir) { - - chan->cir = max_t(unsigned int, 1, - min_t(unsigned int, conf->cir, 512)); - chan->cir_status = CIR_ENABLED; - - - /* If CIR is enabled, force BC to equal CIR - * this solves number of potential problems if CIR is - * set and BC is not - */ - chan->bc = chan->cir; - - if (conf->be){ - chan->be = max_t(unsigned int, - 0, min_t(unsigned int, conf->be, 511)); - }else{ - conf->be = 0; - } - - printk (KERN_INFO "%s: CIR enabled for DLCI %i \n", - wandev->name,chan->dlci); - printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %i\n", - wandev->name,chan->cir,chan->bc,chan->be); - - - }else{ - chan->cir_status = CIR_DISABLED; - printk (KERN_INFO "%s: CIR disabled for DLCI %i\n", - wandev->name,chan->dlci); - } - - chan->mc = conf->mc; - - if (conf->inarp == WANOPT_YES){ - printk(KERN_INFO "%s: Inverse ARP Support Enabled\n",card->devname); - chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; - chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; - }else{ - printk(KERN_INFO "%s: Inverse ARP Support Disabled\n",card->devname); - chan->inarp = INARP_NONE; - chan->inarp_interval = 10; - } - - - chan->dlci_configured = DLCI_NOT_CONFIGURED; - - - /*FIXME: IPX disabled in this WANPIPE version */ - if (conf->enable_IPX == WANOPT_YES){ - printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPX\n", - card->devname); - kfree(chan); - return -EINVAL; - }else{ - chan->enable_IPX = WANOPT_NO; - } - - if (conf->network_number){ - chan->network_number = conf->network_number; - }else{ - chan->network_number = 0xDEADBEEF; - } - - chan->route_flag = NO_ROUTE; - - init_chan_statistics(chan); - - chan->transmit_length = 0; - - /* prepare network device data space for registration */ - strcpy(dev->name,chan->name); - - dev->init = &if_init; - dev->priv = chan; - - /* Initialize FR Polling Task Queue - * We need a poll routine for each network - * interface. - */ - INIT_WORK(&chan->fr_poll_work, (void *)fr_poll, dev); - - init_timer(&chan->fr_arp_timer); - chan->fr_arp_timer.data=(unsigned long)dev; - chan->fr_arp_timer.function = fr_arp; - - wandev->new_if_cnt++; - - /* Tells us that if this interface is a - * gateway or not */ - if ((chan->gateway = conf->gateway) == WANOPT_YES){ - printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", - card->devname,dev->name); - } - - /* M. Grant Patch Apr 28 2000 - * Disallow duplicate dlci configurations. */ - if (card->u.f.dlci_to_dev_map[chan->dlci] != NULL) { - kfree(chan); - return -EBUSY; - } - - /* Configure this dlci at a later date, when - * the interface comes up. i.e. when if_open() - * executes */ - set_bit(0,&chan->config_dlci); - - printk(KERN_INFO "\n"); - - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - unsigned long smp_flags=0; - - /* This interface is dead, make sure the - * ARP timer is stopped */ - del_timer(&chan->fr_arp_timer); - - /* If we are a NODE, we must unconfigure this DLCI - * Trigger an unconfigure command that will - * be executed in timer interrupt. We must wait - * for the command to complete. */ - trigger_unconfig_fr(dev); - - lock_adapter_irq(&wandev->lock, &smp_flags); - wandev->new_if_cnt--; - unlock_adapter_irq(&wandev->lock, &smp_flags); - - return 0; -} - - -/*===================================================================== - * disable_comm - * - * Description: - * Disable communications. - * This code runs in shutdown (sdlamain.c) - * under critical flag. Therefore it is not - * necessary to set a critical flag here - * - * Usage: - * Commnunications are disabled only on a card - * shutdown. - */ - -static void disable_comm (sdla_t *card) -{ - printk(KERN_INFO "%s: Disabling Communications!\n", - card->devname); - fr_comm_disable(card); -} - -/****** WANPIPE-specific entry points ***************************************/ - -/*============================================================================ - * Execute adapter interface command. - */ -static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err, len; - fr_cmd_t cmd; - - if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) - return -EFAULT; - - /* execute command */ - do - { - memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - - if (cmd.length){ - if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) - return -EFAULT; - } - - if (sdla_exec(mbox)) - err = mbox->cmd.result; - - else return -EIO; - - } while (err && retry-- && fr_event(card, err, mbox)); - - /* return result */ - if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) - return -EFAULT; - - len = mbox->cmd.length; - - if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) - return -EFAULT; - return 0; -} - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct wan_device* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = NULL; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - if (chan->common.usedby == WANPIPE || chan->common.usedby == API){ - - /* Initialize media-specific parameters */ - if (chan->true_if_encoding){ - dev->type = ARPHRD_DLCI; /* This breaks tcpdump */ - }else{ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - } - - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - /* Enable Multicast addressing */ - if (chan->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } - - dev->mtu = wandev->mtu - FR_HEADER_LEN; - /* For an API, the maximum number of bytes that the stack will pass - to the driver is (dev->mtu + dev->hard_header_len). So, adjust the - mtu so that a frame of maximum size can be transmitted by the API. - */ - if(chan->common.usedby == API) { - dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); - } - - dev->hard_header_len = FR_HEADER_LEN;/* media header length */ - dev->addr_len = 2; /* hardware address length */ - *(unsigned short*)dev->dev_addr = htons(chan->dlci); - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - - }else{ - - /* Setup the interface for Bridging */ - int hw_addr=0; - ether_setup(dev); - - /* Use a random number to generate the MAC address */ - memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); - get_random_bytes(&hw_addr, sizeof(hw_addr)); - *(int *)(dev->dev_addr + 2) += hw_addr; - } - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - SET_MODULE_OWNER(dev); - - return 0; -} - -/*============================================================================ - * Open network interface. - * o if this is the first open, then enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - int err = 0; - struct timeval tv; - - if (netif_running(dev)) - return -EBUSY; - - /* Initialize the task queue */ - chan->tq_working=0; - - INIT_WORK(&chan->common.wanpipe_work, (void *)fr_bh, dev); - - /* Allocate and initialize BH circular buffer */ - chan->bh_head = kmalloc((sizeof(bh_data_t)*MAX_BH_BUFF),GFP_ATOMIC); - memset(chan->bh_head,0,(sizeof(bh_data_t)*MAX_BH_BUFF)); - atomic_set(&chan->bh_buff_used, 0); - - netif_start_queue(dev); - - wanpipe_open(card); - do_gettimeofday( &tv ); - chan->router_start_time = tv.tv_sec; - - if (test_bit(0,&chan->config_dlci)){ - trigger_config_fr (card); - }else if (chan->inarp == INARP_REQUEST){ - trigger_fr_arp(dev); - } - - return err; -} - -/*============================================================================ - * Close network interface. - * o if this is the last open, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->inarp == INARP_CONFIGURED) { - chan->inarp = INARP_REQUEST; - } - - netif_stop_queue(dev); - wanpipe_close(card); - - return 0; -} - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ -static int if_rebuild_hdr (struct sk_buff* skb) -{ - struct net_device *dev = skb->dev; - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - chan->drvstats_if_send.if_send_tbusy++; - ++chan->ifstats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", - card->devname, dev->name); - chan->drvstats_if_send.if_send_tbusy_timeout++; - netif_wake_queue (dev); - -} - - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o set critical flag when accessing board. - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * - * 2. Using netif_start_queue() and netif_stop_queue() - * will inhibit further transmit requests from the protocol stack - * and can be used for flow control with protocol layer. - */ -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - int err; - unsigned char *sendpacket; - fr508_flags_t* adptr_flags = card->flags; - int udp_type; - long delay_tx_queued = 0; - unsigned long smp_flags=0; - unsigned char attr = 0; - - chan->drvstats_if_send.if_send_entry++; - - netif_stop_queue(dev); - - if (skb == NULL) { - /* if we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - chan->drvstats_if_send.if_send_skb_null ++; - - netif_wake_queue(dev); - return 0; - } - - /* If a peripheral task is running just drop packets */ - if (test_bit(PERI_CRIT, &card->wandev.critical)){ - - printk(KERN_INFO "%s: Critical in if_send(): Peripheral running!\n", - card->devname); - - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - - /* We must set the 'tbusy' flag if we already have a packet queued for - transmission in the transmit interrupt handler. However, we must - ensure that the transmit interrupt does not reset the 'tbusy' flag - just before we set it, as this will result in a "transmit timeout". - */ - set_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); - if(chan->transmit_length) { - netif_stop_queue(dev); - chan->tick_counter = jiffies; - clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); - return 1; - } - clear_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical); - - /* Move the if_header() code to here. By inserting frame - * relay header in if_header() we would break the - * tcpdump and other packet sniffers */ - chan->fr_header_len = setup_fr_header(skb,dev,chan->common.usedby); - if (chan->fr_header_len < 0 ){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - - sendpacket = skb->data; - - udp_type = udp_pkt_type(skb, card); - - if(udp_type != UDP_INVALID_TYPE) { - if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, - chan->dlci)) { - adptr_flags->imask |= FR_INTR_TIMER; - if (udp_type == UDP_FPIPE_TYPE){ - chan->drvstats_if_send. - if_send_PIPE_request ++; - } - } - netif_start_queue(dev); - return 0; - } - - //FIXME: can we do better than sendpacket[2]? - if ((chan->common.usedby == WANPIPE) && (sendpacket[2] == 0x45)) { - - /* check to see if the source IP address is a broadcast or */ - /* multicast IP address */ - if(chk_bcast_mcast_addr(card, dev, skb)){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - } - - - /* Lock the S514/S508 card: SMP Supported */ - s508_s514_lock(card,&smp_flags); - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - - chan->drvstats_if_send.if_send_critical_non_ISR ++; - chan->ifstats.tx_dropped ++; - printk(KERN_INFO "%s Critical in IF_SEND: if_send() already running!\n", - card->devname); - goto if_send_start_and_exit; - } - - /* API packet check: minimum packet size must be greater than - * 16 byte API header */ - if((chan->common.usedby == API) && (skb->len <= sizeof(api_tx_hdr_t))) { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - - goto if_send_start_and_exit; - - }else{ - /* During API transmission, get rid of the API header */ - if (chan->common.usedby == API) { - api_tx_hdr_t* api_tx_hdr; - api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; - attr = api_tx_hdr->attr; - skb_pull(skb,sizeof(api_tx_hdr_t)); - } - } - - if (card->wandev.state != WAN_CONNECTED) { - chan->drvstats_if_send.if_send_wan_disconnected ++; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - } else if (chan->common.state != WAN_CONNECTED) { - chan->drvstats_if_send.if_send_dlci_disconnected ++; - - /* Update the DLCI state in timer interrupt */ - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE_STATE; - adptr_flags->imask |= FR_INTR_TIMER; - - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - } else if (!is_tx_ready(card, chan)) { - /* No tx buffers available, store for delayed transmit */ - if (!setup_for_delayed_transmit(dev, skb)){ - set_bit(1,&delay_tx_queued); - } - chan->drvstats_if_send.if_send_no_bfrs++; - - } else if (!skb->protocol) { - /* No protocols drop packet */ - chan->drvstats_if_send.if_send_protocol_error ++; - ++card->wandev.stats.tx_errors; - - } else if (test_bit(ARP_CRIT,&card->wandev.critical)){ - /* We are trying to send an ARP Packet, block IP data until - * ARP is sent */ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - - } else { - //FIXME: IPX is not implemented in this version of Frame Relay ? - if((chan->common.usedby == WANPIPE) && - sendpacket[1] == 0x00 && - sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) { - - if( chan->enable_IPX ) { - switch_net_numbers(sendpacket, - chan->network_number, 0); - } else { - //FIXME: Take this out when IPX is fixed - printk(KERN_INFO - "%s: WARNING: Unsupported IPX data in send, packet dropped\n", - card->devname); - } - - }else{ - err = fr_send_data_header(card, chan->dlci, attr, skb->len, skb->data, chan->fr_header_len); - if (err) { - switch(err) { - case FRRES_CIR_OVERFLOW: - case FRRES_BUFFER_OVERFLOW: - if (!setup_for_delayed_transmit(dev, skb)){ - set_bit(1,&delay_tx_queued); - } - chan->drvstats_if_send. - if_send_adptr_bfrs_full ++; - break; - - case FRRES_TOO_LONG: - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Error: Frame too long, transmission failed %i\n", - card->devname, (unsigned int)skb->len); - } - /* Drop down to default */ - default: - chan->drvstats_if_send. - if_send_dlci_disconnected ++; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - } else { - chan->drvstats_if_send. - if_send_bfr_passed_to_adptr++; - ++chan->ifstats.tx_packets; - ++card->wandev.stats.tx_packets; - - chan->ifstats.tx_bytes += skb->len; - card->wandev.stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - } - } - } - -if_send_start_and_exit: - - netif_start_queue(dev); - - /* If we queued the packet for transmission, we must not - * deallocate it. The packet is unlinked from the IP stack - * not copied. Therefore, we must keep the original packet */ - if (!test_bit(1,&delay_tx_queued)) { - dev_kfree_skb_any(skb); - }else{ - adptr_flags->imask |= FR_INTR_TXRDY; - card->u.f.tx_interrupts_pending ++; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - - s508_s514_unlock(card,&smp_flags); - - return 0; -} - - - -/*============================================================================ - * Setup so that a frame can be transmitted on the occurrence of a transmit - * interrupt. - */ -static int setup_for_delayed_transmit(struct net_device* dev, - struct sk_buff *skb) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - fr_dlci_interface_t* dlci_interface; - int len = skb->len; - - /* Check that the dlci is properly configured, - * before using tx interrupt */ - if (!chan->dlci_int_interface){ - if (net_ratelimit()){ - printk(KERN_INFO - "%s: ERROR on DLCI %i: Not configured properly !\n", - card->devname, chan->dlci); - printk(KERN_INFO "%s: Please contact Sangoma Technologies\n", - card->devname); - } - return 1; - } - - dlci_interface = chan->dlci_int_interface; - - if(chan->transmit_length) { - printk(KERN_INFO "%s: Big mess in setup_for_del...\n", - card->devname); - return 1; - } - - if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { - //FIXME: increment some statistic */ - return 1; - } - - chan->transmit_length = len; - chan->delay_skb = skb; - - dlci_interface->gen_interrupt |= FR_INTR_TXRDY; - dlci_interface->packet_length = len; - - /* Turn on TX interrupt at the end of if_send */ - return 0; -} - - -/*============================================================================ - * Check to see if the packet to be transmitted contains a broadcast or - * multicast source IP address. - * Return 0 if not broadcast/multicast address, otherwise return 1. - */ - -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb) -{ - u32 src_ip_addr; - u32 broadcast_ip_addr = 0; - struct in_device *in_dev; - fr_channel_t* chan = dev->priv; - - /* read the IP source address from the outgoing packet */ - src_ip_addr = *(u32 *)(skb->data + 14); - - /* read the IP broadcast address for the device */ - in_dev = dev->ip_ptr; - if(in_dev != NULL) { - struct in_ifaddr *ifa= in_dev->ifa_list; - if(ifa != NULL) - broadcast_ip_addr = ifa->ifa_broadcast; - else - return 0; - } - - /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { - printk(KERN_INFO - "%s: Broadcast Source Address silently discarded\n", - card->devname); - return 1; - } - - /* check if the IP Source Address is a Multicast address */ - if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) && - (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { - printk(KERN_INFO - "%s: Multicast Source Address silently discarded\n", - card->devname); - return 1; - } - - return 0; -} - -/*============================================================================ - * Reply to UDP Management system. - * Return nothing. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - - - fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; - - /* Set length of packet */ - len = //sizeof(fr_encap_hdr_t)+ - sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* fill in UDP reply */ - fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - fr_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = fr_udp_pkt->udp_pkt.udp_src_port; - fr_udp_pkt->udp_pkt.udp_src_port = - fr_udp_pkt->udp_pkt.udp_dst_port; - fr_udp_pkt->udp_pkt.udp_dst_port = temp; - - - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *) - (fr_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *) - (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - /* calculate UDP checksum */ - fr_udp_pkt->udp_pkt.udp_checksum = 0; - - fr_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET/*+sizeof(fr_encap_hdr_t)*/], - udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = udp_length + sizeof(ip_pkt_t); - temp = (ip_length<<8)|(ip_length>>8); - fr_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = fr_udp_pkt->ip_pkt.ip_src_address; - fr_udp_pkt->ip_pkt.ip_src_address = - fr_udp_pkt->ip_pkt.ip_dst_address; - fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - - /* fill in IP checksum */ - fr_udp_pkt->ip_pkt.hdr_checksum = 0; - fr_udp_pkt->ip_pkt.hdr_checksum = - calc_checksum(&data[/*sizeof(fr_encap_hdr_t)*/0], - sizeof(ip_pkt_t)); - - return len; -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - -/* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[14] << 24) + - (sendpacket[15] << 16) + (sendpacket[16] << 8) + - sendpacket[17]); - - if (!incoming) { - /* If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[14] = sendpacket[15] = sendpacket[16] = - sendpacket[17] = 0x00; - } - } else { - /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) { - sendpacket[14] = (unsigned char)(network_number >> 24); - sendpacket[15] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[16] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[17] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[26] << 24) + - (sendpacket[27] << 16) + (sendpacket[28] << 8) + - sendpacket[29]); - - if( !incoming ) { - /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[26] = sendpacket[27] = sendpacket[28] = - sendpacket[29] = 0x00; - } - } else { - /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) { - sendpacket[26] = (unsigned char)(network_number >> 24); - sendpacket[27] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[28] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[29] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats *if_stats(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - - if(chan == NULL) - return NULL; - - return &chan->ifstats; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * fr_isr: S508 frame relay interrupt service routine. - * - * Description: - * Frame relay main interrupt service route. This - * function check the interrupt type and takes - * the appropriate action. - */ -static void fr_isr (sdla_t* card) -{ - fr508_flags_t* flags = card->flags; - char *ptr = &flags->iflag; - int i,err; - fr_mbox_t* mbox = card->mbox; - - /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. */ - card->in_isr = 1; - - ++card->statistics.isr_entry; - - - /* All peripheral (configuraiton, re-configuration) events - * take presidence over the ISR. Thus, retrigger */ - if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - ++card->statistics.isr_already_critical; - goto fr_isr_exit; - } - - if(card->hw.type != SDLA_S514) { - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: If Send Running!\n", - card->devname); - ++card->statistics.isr_already_critical; - goto fr_isr_exit; - } - } - - switch (flags->iflag) { - - case FR_INTR_RXRDY: /* receive interrupt */ - ++card->statistics.isr_rx; - rx_intr(card); - break; - - - case FR_INTR_TXRDY: /* transmit interrupt */ - ++ card->statistics.isr_tx; - tx_intr(card); - break; - - case FR_INTR_READY: - Intr_test_counter++; - ++card->statistics.isr_intr_test; - break; - - case FR_INTR_DLC: /* Event interrupt occurred */ - mbox->cmd.command = FR_READ_STATUS; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - fr_event(card, err, mbox); - break; - - case FR_INTR_TIMER: /* Timer interrupt */ - timer_intr(card); - break; - - default: - ++card->statistics.isr_spurious; - spur_intr(card); - printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", - card->devname, flags->iflag); - - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - - break; - } - -fr_isr_exit: - - card->in_isr = 0; - flags->iflag = 0; - return; -} - - - -/*=========================================================== - * rx_intr Receive interrupt handler. - * - * Description - * Upon receiveing an interrupt: - * 1. Check that the firmware is in sync with - * the driver. - * 2. Find an appropriate network interface - * based on the received dlci number. - * 3. Check that the netowrk interface exists - * and that it's setup properly. - * 4. Copy the data into an skb buffer. - * 5. Check the packet type and take - * appropriate acton: UPD, API, ARP or Data. - */ - -static void rx_intr (sdla_t* card) -{ - fr_rx_buf_ctl_t* frbuf = card->rxmb; - fr508_flags_t* flags = card->flags; - fr_channel_t* chan; - char *ptr = &flags->iflag; - struct sk_buff* skb; - struct net_device* dev; - void* buf; - unsigned dlci, len, offs, len_incl_hdr; - int i, udp_type; - - - /* Check that firmware buffers are in sync */ - if (frbuf->flag != 0x01) { - - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)frbuf, frbuf->flag); - - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - - ++card->statistics.rx_intr_corrupt_rx_bfr; - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it means that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - fr_set_intr_mode(card, 0, 0, 0); - return; - } - - len = frbuf->length; - dlci = frbuf->dlci; - offs = frbuf->offset; - - /* Find the network interface for this packet */ - dev = find_channel(card, dlci); - - - /* Check that the network interface is active and - * properly setup */ - if (dev == NULL) { - if( net_ratelimit()) { - printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", - card->devname, dlci); - } - ++card->statistics.rx_intr_on_orphaned_DLCI; - ++card->wandev.stats.rx_dropped; - goto rx_done; - } - - if ((chan = dev->priv) == NULL){ - if( net_ratelimit()) { - printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", - card->devname, dlci); - } - ++card->statistics.rx_intr_on_orphaned_DLCI; - ++card->wandev.stats.rx_dropped; - goto rx_done; - } - - skb = dev_alloc_skb(len); - - if (!netif_running(dev) || (skb == NULL)){ - - ++chan->ifstats.rx_dropped; - - if(skb == NULL) { - if (net_ratelimit()) { - printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - } - chan->drvstats_rx_intr.rx_intr_no_socket ++; - } - - if (!netif_running(dev)){ - chan->drvstats_rx_intr. - rx_intr_dev_not_started ++; - if (skb){ - dev_kfree_skb_any(skb); - } - } - goto rx_done; - } - - /* Copy data from the board into the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) { - unsigned tmp = card->u.f.rx_top - offs + 1; - - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - - - /* We got the packet from the bard. - * Check the packet type and take appropriate action */ - - udp_type = udp_pkt_type( skb, card ); - - if(udp_type != UDP_INVALID_TYPE) { - - /* UDP Debug packet received, store the - * packet and handle it in timer interrupt */ - - skb_pull(skb, 1); - if (wanrouter_type_trans(skb, dev)){ - if(store_udp_mgmt_pkt(udp_type,UDP_PKT_FRM_NETWORK,card,skb,dlci)){ - - flags->imask |= FR_INTR_TIMER; - - if (udp_type == UDP_FPIPE_TYPE){ - ++chan->drvstats_rx_intr.rx_intr_PIPE_request; - } - } - } - - }else if (chan->common.usedby == API) { - - /* We are in API mode. - * Add an API header to the RAW packet - * and queue it into a circular buffer. - * Then kick the fr_bh() bottom half handler */ - - api_rx_hdr_t* api_rx_hdr; - chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack ++; - chan->ifstats.rx_packets ++; - card->wandev.stats.rx_packets ++; - - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - - skb_push(skb, sizeof(api_rx_hdr_t)); - api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; - api_rx_hdr->attr = frbuf->attr; - api_rx_hdr->time_stamp = frbuf->tmstamp; - - skb->protocol = htons(ETH_P_IP); - skb->mac.raw = skb->data; - skb->dev = dev; - skb->pkt_type = WAN_PACKET_DATA; - - bh_enqueue(dev, skb); - - trigger_fr_bh(chan); - - }else if (handle_IPXWAN(skb->data,chan->name,chan->enable_IPX, chan->network_number)){ - - //FIXME: Frame Relay IPX is not supported, Yet ! - //if (chan->enable_IPX) { - // fr_send(card, dlci, 0, skb->len,skb->data); - //} - dev_kfree_skb_any(skb); - - } else if (is_arp(skb->data)) { - - /* ARP support enabled Mar 16 2000 - * Process incoming ARP reply/request, setup - * dynamic routes. */ - - if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { - if (net_ratelimit()){ - printk (KERN_INFO - "%s: Error processing ARP Packet.\n", - card->devname); - } - } - dev_kfree_skb_any(skb); - - } else if (skb->data[0] != 0x03) { - - if (net_ratelimit()) { - printk(KERN_INFO "%s: Non IETF packet discarded.\n", - card->devname); - } - dev_kfree_skb_any(skb); - - } else { - - len_incl_hdr = skb->len; - /* Decapsulate packet and pass it up the - protocol stack */ - skb->dev = dev; - - if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ - - /* Make sure it's an Ethernet frame, otherwise drop it */ - if (!memcmp(skb->data, "\x03\x00\x80\x00\x80\xC2\x00\x07", 8)) { - skb_pull(skb, 8); - skb->protocol=eth_type_trans(skb,dev); - }else{ - ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - goto rx_done; - } - }else{ - - /* remove hardware header */ - buf = skb_pull(skb, 1); - - if (!wanrouter_type_trans(skb, dev)) { - - /* can't decapsulate packet */ - dev_kfree_skb_any(skb); - - ++chan->drvstats_rx_intr.rx_intr_bfr_not_passed_to_stack; - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - goto rx_done; - } - skb->mac.raw = skb->data; - } - - - /* Send a packet up the IP stack */ - skb->dev->last_rx = jiffies; - netif_rx(skb); - ++chan->drvstats_rx_intr.rx_intr_bfr_passed_to_stack; - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - - chan->ifstats.rx_bytes += len_incl_hdr; - card->wandev.stats.rx_bytes += len_incl_hdr; - } - -rx_done: - - /* Release buffer element and calculate a pointer to the next one */ - frbuf->flag = 0; - card->rxmb = ++frbuf; - if ((void*)frbuf > card->u.f.rxmb_last) - card->rxmb = card->u.f.rxmb_base; - -} - -/*================================================================== - * tx_intr: Transmit interrupt handler. - * - * Rationale: - * If the board is busy transmitting, if_send() will - * buffers a single packet and turn on - * the tx interrupt. Tx interrupt will be called - * by the board, once the firmware can send more - * data. Thus, no polling is required. - * - * Description: - * Tx interrupt is called for each - * configured dlci channel. Thus: - * 1. Obtain the netowrk interface based on the - * dlci number. - * 2. Check that network interface is up and - * properly setup. - * 3. Check for a buffered packet. - * 4. Transmit the packet. - * 5. If we are in WANPIPE mode, mark the - * NET_BH handler. - * 6. If we are in API mode, kick - * the AF_WANPIPE socket for more data. - * - */ -static void tx_intr(sdla_t *card) -{ - fr508_flags_t* flags = card->flags; - fr_tx_buf_ctl_t* bctl; - struct net_device* dev; - fr_channel_t* chan; - - if(card->hw.type == SDLA_S514){ - bctl = (void*)(flags->tse_offs + card->hw.dpmbase); - }else{ - bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase); - } - - /* Find the structure and make it unbusy */ - dev = find_channel(card, flags->dlci); - if (dev == NULL){ - printk(KERN_INFO "NO DEV IN TX Interrupt\n"); - goto end_of_tx_intr; - } - - if ((chan = dev->priv) == NULL){ - printk(KERN_INFO "NO CHAN IN TX Interrupt\n"); - goto end_of_tx_intr; - } - - if(!chan->transmit_length || !chan->delay_skb) { - printk(KERN_INFO "%s: tx int error - transmit length zero\n", - card->wandev.name); - goto end_of_tx_intr; - } - - /* If the 'if_send()' procedure is currently checking the 'tbusy' - status, then we cannot transmit. Instead, we configure the microcode - so as to re-issue this transmit interrupt at a later stage. - */ - if (test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { - - fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; - bctl->flag = 0xA0; - dlci_interface->gen_interrupt |= FR_INTR_TXRDY; - return; - - }else{ - bctl->dlci = flags->dlci; - bctl->length = chan->transmit_length+chan->fr_header_len; - sdla_poke(&card->hw, - fr_send_hdr(card,bctl->dlci,bctl->offset), - chan->delay_skb->data, - chan->delay_skb->len); - bctl->flag = 0xC0; - - ++chan->ifstats.tx_packets; - ++card->wandev.stats.tx_packets; - chan->ifstats.tx_bytes += chan->transmit_length; - card->wandev.stats.tx_bytes += chan->transmit_length; - - /* We must free an sk buffer, which we used - * for delayed transmission; Otherwise, the sock - * will run out of memory */ - dev_kfree_skb_any(chan->delay_skb); - - chan->delay_skb = NULL; - chan->transmit_length = 0; - - dev->trans_start = jiffies; - - if (netif_queue_stopped(dev)){ - /* If using API, than wakeup socket BH handler */ - if (chan->common.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - } - -end_of_tx_intr: - - /* if any other interfaces have transmit interrupts pending, - * do not disable the global transmit interrupt */ - if(!(-- card->u.f.tx_interrupts_pending)) - flags->imask &= ~FR_INTR_TXRDY; - - -} - - -/*============================================================================ - * timer_intr: Timer interrupt handler. - * - * Rationale: - * All commans must be executed within the timer - * interrupt since no two commands should execute - * at the same time. - * - * Description: - * The timer interrupt is used to: - * 1. Processing udp calls from 'fpipemon'. - * 2. Processing update calls from /proc file system - * 3. Reading board-level statistics for - * updating the proc file system. - * 4. Sending inverse ARP request packets. - * 5. Configure a dlci/channel. - * 6. Unconfigure a dlci/channel. (Node only) - */ - -static void timer_intr(sdla_t *card) -{ - fr508_flags_t* flags = card->flags; - - /* UDP Debuging: fpipemon call */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { - if(card->u.f.udp_type == UDP_FPIPE_TYPE) { - if(process_udp_mgmt_pkt(card)) { - card->u.f.timer_int_enabled &= - ~TMR_INT_ENABLED_UDP; - } - } - } - - /* /proc update call : triggered from update() */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { - fr_get_err_stats(card); - fr_get_stats(card); - card->u.f.update_comms_stats = 0; - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; - } - - /* Update the channel state call. This is call is - * triggered by if_send() function */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){ - struct net_device *dev; - if (card->wandev.state == WAN_CONNECTED){ - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)){ - fr_channel_t *chan = dev->priv; - if (chan->common.state != WAN_CONNECTED){ - update_chan_state(dev); - } - } - } - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE_STATE; - } - - /* configure a dlci/channel */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_CONFIG){ - config_fr(card); - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; - } - - /* unconfigure a dlci/channel */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG){ - unconfig_fr(card); - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; - } - - - /* Transmit ARP packets */ - if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){ - int i=0; - struct net_device *dev; - - if (card->u.f.arp_dev == NULL) - card->u.f.arp_dev = card->wandev.dev; - - dev = card->u.f.arp_dev; - - for (;;){ - - fr_channel_t *chan = dev->priv; - - /* If the interface is brought down cancel sending In-ARPs */ - if (!(dev->flags&IFF_UP)){ - clear_bit(0,&chan->inarp_ready); - } - - if (test_bit(0,&chan->inarp_ready)){ - - if (check_tx_status(card,dev)){ - set_bit(ARP_CRIT,&card->wandev.critical); - break; - } - - if (!send_inarp_request(card,dev)){ - trigger_fr_arp(dev); - chan->inarp_tick = jiffies; - } - - clear_bit(0,&chan->inarp_ready); - dev = move_dev_to_next(card,dev); - break; - } - dev = move_dev_to_next(card,dev); - - if (++i == card->wandev.new_if_cnt){ - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_ARP; - break; - } - } - card->u.f.arp_dev = dev; - } - - if(!card->u.f.timer_int_enabled) - flags->imask &= ~FR_INTR_TIMER; -} - - -/*============================================================================ - * spur_intr: Spurious interrupt handler. - * - * Description: - * We don't know this interrupt. - * Print a warning. - */ - -static void spur_intr (sdla_t* card) -{ - if (net_ratelimit()){ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); - } -} - - -//FIXME: Fix the IPX in next version -/*=========================================================================== - * Return 0 for non-IPXWAN packet - * 1 for IPXWAN packet or IPX is not enabled! - * FIXME: Use a IPX structure here not offsets - */ -static int handle_IPXWAN(unsigned char *sendpacket, - char *devname, unsigned char enable_IPX, - unsigned long network_number) -{ - int i; - - if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && sendpacket[7] == 0x37) { - - /* It's an IPX packet */ - if (!enable_IPX){ - /* Return 1 so we don't pass it up the stack. */ - //FIXME: Take this out when IPX is fixed - if (net_ratelimit()){ - printk (KERN_INFO - "%s: WARNING: Unsupported IPX packet received and dropped\n", - devname); - } - return 1; - } - } else { - /* It's not IPX so return and pass it up the stack. */ - return 0; - } - - if( sendpacket[24] == 0x90 && sendpacket[25] == 0x04){ - /* It's IPXWAN */ - - if( sendpacket[10] == 0x02 && sendpacket[42] == 0x00){ - - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", - devname); - - /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP - */ - for(i = 49; sendpacket[i] == 0x00; i += 5){ - /* 0x02 is the option for Unnumbered RIP/SAP */ - if( sendpacket[i + 4] != 0x02){ - sendpacket[i + 1] = 0; - } - } - - /* Skip over the extended Node ID option */ - if( sendpacket[i] == 0x04 ){ - i += 8; - } - - /* We also want to turn off all header compression opt. - */ - for(; sendpacket[i] == 0x80 ;){ - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - /* Set the packet type to timer response */ - sendpacket[42] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", - devname); - - } else if( sendpacket[42] == 0x02 ){ - - /* This is an information request packet */ - printk(KERN_INFO - "%s: Received IPXWAN Information Request packet\n", - devname); - - /* Set the packet type to information response */ - sendpacket[42] = 0x03; - - /* Set the router name */ - sendpacket[59] = 'F'; - sendpacket[60] = 'P'; - sendpacket[61] = 'I'; - sendpacket[62] = 'P'; - sendpacket[63] = 'E'; - sendpacket[64] = '-'; - sendpacket[65] = CVHexToAscii(network_number >> 28); - sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); - for(i = 73; i < 107; i+= 1) - { - sendpacket[i] = 0; - } - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", - devname); - } else { - - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - /* Set the WNodeID to our network address */ - sendpacket[43] = (unsigned char)(network_number >> 24); - sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[46] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } - - /* If we get here, it's an IPX-data packet so it'll get passed up the - * stack. - * switch the network numbers - */ - switch_net_numbers(sendpacket, network_number ,1); - return 0; -} -/*============================================================================ - * process_route - * - * Rationale: - * If the interface goes down, or we receive an ARP request, - * we have to change the network interface ip addresses. - * This cannot be done within the interrupt. - * - * Description: - * - * This routine is called as a polling routine to dynamically - * add/delete routes negotiated by inverse ARP. It is in this - * "task" because we don't want routes to be added while in - * interrupt context. - * - * Usage: - * This function is called by fr_poll() polling funtion. - */ - -static void process_route(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - - struct ifreq if_info; - struct sockaddr_in *if_data; - mm_segment_t fs = get_fs(); - u32 ip_tmp; - int err; - - - switch(chan->route_flag){ - - case ADD_ROUTE: - - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = chan->ip_remote; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); - - set_fs(fs); /* restore old block */ - - if (err) { - printk(KERN_INFO - "%s: Route Add failed. Error: %d\n", - card->devname,err); - printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", - chan->name, NIPQUAD(chan->ip_remote)); - - }else { - printk(KERN_INFO "%s: Route Added Successfully: %u.%u.%u.%u\n", - card->devname,NIPQUAD(chan->ip_remote)); - chan->route_flag = ROUTE_ADDED; - } - break; - - case REMOVE_ROUTE: - - /* Set remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - ip_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); - - set_fs(get_ds()); /* get user space block */ - - if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data->sin_addr.s_addr = 0; - if_data->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); - - set_fs(fs); - - if (err) { - printk(KERN_INFO - "%s: Deleting of route failed. Error: %d\n", - card->devname,err); - printk(KERN_INFO "%s: Address: %u.%u.%u.%u\n", - dev->name,NIPQUAD(chan->ip_remote) ); - - } else { - printk(KERN_INFO "%s: Route Removed Sucessfuly: %u.%u.%u.%u\n", - card->devname,NIPQUAD(ip_tmp)); - chan->route_flag = NO_ROUTE; - } - break; - - } /* Case Statement */ - -} - - - -/****** Frame Relay Firmware-Specific Functions *****************************/ - -/*============================================================================ - * Read firmware code version. - * o fill string str with firmware version info. - */ -static int fr_read_version (sdla_t* card, char* str) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.command = FR_READ_CODE_VERSION; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err && str) { - int len = mbox->cmd.length; - memcpy(str, mbox->data, len); - str[len] = '\0'; - } - return err; -} - -/*============================================================================ - * Set global configuration. - */ -static int fr_configure (sdla_t* card, fr_conf_t *conf) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int dlci_num = card->u.f.dlci_num; - int err, i; - - do - { - memcpy(mbox->data, conf, sizeof(fr_conf_t)); - - if (dlci_num) for (i = 0; i < dlci_num; ++i) - ((fr_conf_t*)mbox->data)->dlci[i] = - card->u.f.node_dlci[i]; - - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.length = - sizeof(fr_conf_t) + dlci_num * sizeof(short); - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - /*NC Oct 12 2000 */ - if (err != CMD_OK){ - printk(KERN_ERR "%s: Frame Relay Configuration Failed: rc=0x%x\n", - card->devname,err); - } - - return err; -} - -/*============================================================================ - * Set DLCI configuration. - */ -static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); - mbox->cmd.dlci = (unsigned short) dlci; - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.length = sizeof(fr_dlc_conf_t); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry--); - - return err; -} -/*============================================================================ - * Set interrupt mode. - */ -static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, - unsigned short timeout) -{ - fr_mbox_t* mbox = card->mbox; - fr508_intr_ctl_t* ictl = (void*)mbox->data; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(ictl, 0, sizeof(fr508_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - ictl->irq = card->hw.irq; - - /* indicate timeout on timer */ - if (mode & 0x20) ictl->timeout = timeout; - - mbox->cmd.length = sizeof(fr508_intr_ctl_t); - mbox->cmd.command = FR_SET_INTR_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * Enable communications. - */ -static int fr_comm_enable (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.command = FR_COMM_ENABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * fr_comm_disable - * - * Warning: This functin is called by the shutdown() procedure. It is void - * since dev->priv are has already been deallocated and no - * error checking is possible using fr_event() function. - */ -static void fr_comm_disable (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do { - mbox->cmd.command = FR_SET_MODEM_STATUS; - mbox->cmd.length = 1; - mbox->data[0] = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry--); - - retry = MAX_CMD_RETRY; - - do - { - mbox->cmd.command = FR_COMM_DISABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry--); - - return; -} - - - -/*============================================================================ - * Get communications error statistics. - */ -static int fr_get_err_stats (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - - do - { - mbox->cmd.command = FR_READ_ERROR_STATS; - mbox->cmd.length = 0; - mbox->cmd.dlci = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_comm_stat_t* stats = (void*)mbox->data; - card->wandev.stats.rx_over_errors = stats->rx_overruns; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_aborts; - card->wandev.stats.rx_length_errors = stats->rx_too_long; - card->wandev.stats.tx_aborted_errors = stats->tx_aborts; - - } - - return err; -} - -/*============================================================================ - * Get statistics. - */ -static int fr_get_stats (sdla_t* card) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - - do - { - mbox->cmd.command = FR_READ_STATISTICS; - mbox->cmd.length = 0; - mbox->cmd.dlci = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_link_stat_t* stats = (void*)mbox->data; - card->wandev.stats.rx_frame_errors = stats->rx_bad_format; - card->wandev.stats.rx_dropped = - stats->rx_dropped + stats->rx_dropped2; - } - - return err; -} - -/*============================================================================ - * Add DLCI(s) (Access Node only!). - * This routine will perform the ADD_DLCIs command for the specified DLCI. - */ -static int fr_add_dlci (sdla_t* card, int dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - unsigned short* dlci_list = (void*)mbox->data; - - mbox->cmd.length = sizeof(short); - dlci_list[0] = dlci; - mbox->cmd.command = FR_ADD_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * Activate DLCI(s) (Access Node only!). - * This routine will perform the ACTIVATE_DLCIs command with a DLCI number. - */ -static int fr_activate_dlci (sdla_t* card, int dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - unsigned short* dlci_list = (void*)mbox->data; - - mbox->cmd.length = sizeof(short); - dlci_list[0] = dlci; - mbox->cmd.command = FR_ACTIVATE_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - -/*============================================================================ - * Delete DLCI(s) (Access Node only!). - * This routine will perform the DELETE_DLCIs command with a DLCI number. - */ -static int fr_delete_dlci (sdla_t* card, int dlci) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - unsigned short* dlci_list = (void*)mbox->data; - - mbox->cmd.length = sizeof(short); - dlci_list[0] = dlci; - mbox->cmd.command = FR_DELETE_DLCI; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - - - -/*============================================================================ - * Issue in-channel signalling frame. - */ -static int fr_issue_isf (sdla_t* card, int isf) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->data[0] = isf; - mbox->cmd.length = 1; - mbox->cmd.command = FR_ISSUE_IS_FRAME; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - return err; -} - - -static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset) -{ - struct net_device *dev = find_channel(card,dlci); - fr_channel_t *chan; - - if (!dev || !(chan=dev->priv)) - return offset; - - if (chan->fr_header_len){ - sdla_poke(&card->hw, offset, chan->fr_header, chan->fr_header_len); - } - - return offset+chan->fr_header_len; -} - -/*============================================================================ - * Send a frame on a selected DLCI. - */ -static int fr_send_data_header (sdla_t* card, int dlci, unsigned char attr, int len, - void *buf, unsigned char hdr_len) -{ - fr_mbox_t* mbox = card->mbox + 0x800; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len+hdr_len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_tx_buf_ctl_t* frbuf; - - if(card->hw.type == SDLA_S514) - frbuf = (void*)(*(unsigned long*)mbox->data + - card->hw.dpmbase); - else - frbuf = (void*)(*(unsigned long*)mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); - - sdla_poke(&card->hw, fr_send_hdr(card,dlci,frbuf->offset), buf, len); - frbuf->flag = 0x01; - } - - return err; -} - -static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, - void *buf) -{ - fr_mbox_t* mbox = card->mbox + 0x800; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; - mbox->cmd.command = FR_WRITE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - fr_tx_buf_ctl_t* frbuf; - - if(card->hw.type == SDLA_S514) - frbuf = (void*)(*(unsigned long*)mbox->data + - card->hw.dpmbase); - else - frbuf = (void*)(*(unsigned long*)mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); - - sdla_poke(&card->hw, frbuf->offset, buf, len); - frbuf->flag = 0x01; - } - - return err; -} - - -/****** Firmware Asynchronous Event Handlers ********************************/ - -/*============================================================================ - * Main asyncronous event/error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) -{ - fr508_flags_t* flags = card->flags; - char *ptr = &flags->iflag; - int i; - - switch (event) { - - case FRRES_MODEM_FAILURE: - return fr_modem_failure(card, mbox); - - case FRRES_CHANNEL_DOWN: { - struct net_device *dev; - - /* Remove all routes from associated DLCI's */ - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - fr_channel_t *chan = dev->priv; - if (chan->route_flag == ROUTE_ADDED) { - chan->route_flag = REMOVE_ROUTE; - } - - if (chan->inarp == INARP_CONFIGURED) { - chan->inarp = INARP_REQUEST; - } - - /* If the link becomes disconnected then, - * all channels will be disconnected - * as well. - */ - set_chan_state(dev,WAN_DISCONNECTED); - } - - wanpipe_set_state(card, WAN_DISCONNECTED); - return 1; - } - - case FRRES_CHANNEL_UP: { - struct net_device *dev; - - /* FIXME: Only startup devices that are on the list */ - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - - set_chan_state(dev,WAN_CONNECTED); - } - - wanpipe_set_state(card, WAN_CONNECTED); - return 1; - } - - case FRRES_DLCI_CHANGE: - return fr_dlci_change(card, mbox); - - case FRRES_DLCI_MISMATCH: - printk(KERN_INFO "%s: DLCI list mismatch!\n", - card->devname); - return 1; - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command); - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i)); - printk(KERN_INFO "\n"); - - break; - - case FRRES_DLCI_INACTIVE: - break; - - case FRRES_CIR_OVERFLOW: - break; - - case FRRES_BUFFER_OVERFLOW: - break; - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - , card->devname, mbox->cmd.command, event); - } - - return 0; -} - -/*============================================================================ - * Handle modem error. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) -{ - printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", - card->devname, mbox->data[0]); - - switch (mbox->cmd.command){ - case FR_WRITE: - - case FR_READ: - return 0; - } - - return 1; -} - -/*============================================================================ - * Handle DLCI status change. - * - * Return zero if previous command has to be cancelled. - */ -static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) -{ - dlci_status_t* status = (void*)mbox->data; - int cnt = mbox->cmd.length / sizeof(dlci_status_t); - fr_channel_t *chan; - struct net_device* dev2; - - - for (; cnt; --cnt, ++status) { - - unsigned short dlci= status->dlci; - struct net_device* dev = find_channel(card, dlci); - - if (dev == NULL){ - printk(KERN_INFO - "%s: CPE contains unconfigured DLCI= %d\n", - card->devname, dlci); - - printk(KERN_INFO - "%s: unconfigured DLCI %d reported by network\n" - , card->devname, dlci); - - }else{ - if (status->state == FR_LINK_INOPER) { - printk(KERN_INFO - "%s: DLCI %u is inactive!\n", - card->devname, dlci); - - if (dev && netif_running(dev)) - set_chan_state(dev, WAN_DISCONNECTED); - } - - if (status->state & FR_DLCI_DELETED) { - - printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); - - if (dev && netif_running(dev)){ - - fr_channel_t *chan = dev->priv; - - if (chan->route_flag == ROUTE_ADDED) { - chan->route_flag = REMOVE_ROUTE; - /* The state change will trigger - * the fr polling routine */ - } - - if (chan->inarp == INARP_CONFIGURED) { - chan->inarp = INARP_REQUEST; - } - - set_chan_state(dev, WAN_DISCONNECTED); - } - - } else if (status->state & FR_DLCI_ACTIVE) { - - chan = dev->priv; - - /* This flag is used for configuring specific - DLCI(s) when they become active. - */ - chan->dlci_configured = DLCI_CONFIG_PENDING; - - set_chan_state(dev, WAN_CONNECTED); - - } - } - } - - for (dev2 = card->wandev.dev; dev2; - dev2 = *((struct net_device **)dev2->priv)){ - - chan = dev2->priv; - - if (chan->dlci_configured == DLCI_CONFIG_PENDING) { - if (fr_init_dlci(card, chan)){ - return 1; - } - } - - } - return 1; -} - - -static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) -{ - fr_dlc_conf_t cfg; - - memset(&cfg, 0, sizeof(cfg)); - - if ( chan->cir_status == CIR_DISABLED) { - - cfg.cir_fwd = cfg.cir_bwd = 16; - cfg.bc_fwd = cfg.bc_bwd = 16; - cfg.conf_flags = 0x0001; - - }else if (chan->cir_status == CIR_ENABLED) { - - cfg.cir_fwd = cfg.cir_bwd = chan->cir; - cfg.bc_fwd = cfg.bc_bwd = chan->bc; - cfg.be_fwd = cfg.be_bwd = chan->be; - cfg.conf_flags = 0x0000; - } - - if (fr_dlci_configure( card, &cfg , chan->dlci)){ - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); - return 1; - } - - chan->dlci_configured = DLCI_CONFIGURED; - - /* Read the interface byte mapping into the channel - * structure. - */ - read_DLCI_IB_mapping( card, chan ); - - return 0; -} -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * Update channel state. - */ -static int update_chan_state(struct net_device* dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - mbox->cmd.command = FR_LIST_ACTIVE_DLCI; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) { - - unsigned short* list = (void*)mbox->data; - int cnt = mbox->cmd.length / sizeof(short); - - err=1; - - for (; cnt; --cnt, ++list) { - - if (*list == chan->dlci) { - set_chan_state(dev, WAN_CONNECTED); - - - /* May 23 2000. NC - * When a dlci is added or restarted, - * the dlci_int_interface pointer must - * be reinitialized. */ - if (!chan->dlci_int_interface){ - err=fr_init_dlci (card,chan); - } - break; - } - } - } - - return err; -} - -/*============================================================================ - * Set channel state. - */ -static void set_chan_state(struct net_device* dev, int state) -{ - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->common.state != state) { - - switch (state) { - - case WAN_CONNECTED: - printk(KERN_INFO - "%s: Interface %s: DLCI %d connected\n", - card->devname, dev->name, chan->dlci); - - /* If the interface was previoulsy down, - * bring it up, since the channel is active */ - - trigger_fr_poll (dev); - trigger_fr_arp (dev); - break; - - case WAN_CONNECTING: - printk(KERN_INFO - "%s: Interface %s: DLCI %d connecting\n", - card->devname, dev->name, chan->dlci); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO - "%s: Interface %s: DLCI %d disconnected!\n", - card->devname, dev->name, chan->dlci); - - /* If the interface is up, bring it down, - * since the channel is now disconnected */ - trigger_fr_poll (dev); - break; - } - - chan->common.state = state; - } - - chan->state_tick = jiffies; -} - -/*============================================================================ - * Find network device by its channel number. - * - * We need this critical flag because we change - * the dlci_to_dev_map outside the interrupt. - * - * NOTE: del_if() functions updates this array, it uses - * the spin locks to avoid corruption. - */ -static struct net_device* find_channel(sdla_t* card, unsigned dlci) -{ - if(dlci > HIGHEST_VALID_DLCI) - return NULL; - - return(card->u.f.dlci_to_dev_map[dlci]); -} - -/*============================================================================ - * Check to see if a frame can be sent. If no transmit buffers available, - * enable transmit interrupts. - * - * Return: 1 - Tx buffer(s) available - * 0 - no buffers available - */ -static int is_tx_ready (sdla_t* card, fr_channel_t* chan) -{ - unsigned char sb; - - if(card->hw.type == SDLA_S514) - return 1; - - sb = inb(card->hw.port); - if (sb & 0x02) - return 1; - - return 0; -} - -/*============================================================================ - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. - */ -static unsigned int dec_to_uint (unsigned char* str, int len) -{ - unsigned val; - - if (!len) - len = strlen(str); - - for (val = 0; len && isdigit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned)'0'); - - return val; -} - - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, int dlci) -{ - int udp_pkt_stored = 0; - - struct net_device *dev = find_channel(card, dlci); - fr_channel_t *chan; - - if (!dev || !(chan=dev->priv)) - return 1; - - if(!card->u.f.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ - card->u.f.udp_pkt_lgth = skb->len + chan->fr_header_len; - card->u.f.udp_type = udp_type; - card->u.f.udp_pkt_src = udp_pkt_src; - card->u.f.udp_dlci = dlci; - memcpy(card->u.f.udp_pkt_data, skb->data, skb->len); - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP; - udp_pkt_stored = 1; - - }else{ - printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n", - dlci); - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - -/*============================================================================== - * Process UDP call of type FPIPE8ND - */ -static int process_udp_mgmt_pkt(sdla_t* card) -{ - - int c_retry = MAX_CMD_RETRY; - unsigned char *buf; - unsigned char frames; - unsigned int len; - unsigned short buffer_length; - struct sk_buff *new_skb; - fr_mbox_t* mbox = card->mbox; - int err; - struct timeval tv; - int udp_mgmt_req_valid = 1; - struct net_device* dev; - fr_channel_t* chan; - fr_udp_pkt_t *fr_udp_pkt; - unsigned short num_trc_els; - fr_trc_el_t* ptr_trc_el; - fr_trc_el_t trc_el; - fpipemon_trc_t* fpipemon_trc; - - char udp_pkt_src = card->u.f.udp_pkt_src; - int dlci = card->u.f.udp_dlci; - - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - if (!dev){ - card->u.f.udp_pkt_lgth = 0; - return 1; - } - if ((chan = dev->priv) == NULL){ - card->u.f.udp_pkt_lgth = 0; - return 1; - } - - /* If the UDP packet is from the network, we are going to have to - transmit a response. Before doing so, we must check to see that - we are not currently transmitting a frame (in 'if_send()') and - that we are not already in a 'delayed transmit' state. - */ - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if (check_tx_status(card,dev)){ - card->u.f.udp_pkt_lgth = 0; - return 1; - } - } - - fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data; - - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - switch(fr_udp_pkt->cblock.command) { - - case FR_READ_MODEM_STATUS: - case FR_READ_STATUS: - case FPIPE_ROUTER_UP_TIME: - case FR_READ_ERROR_STATS: - case FPIPE_DRIVER_STAT_GEN: - case FR_READ_STATISTICS: - case FR_READ_ADD_DLC_STATS: - case FR_READ_CONFIG: - case FR_READ_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - /* set length to 0 */ - fr_udp_pkt->cblock.length = 0; - /* set return code */ - fr_udp_pkt->cblock.result = 0xCD; - - chan->drvstats_gen.UDP_PIPE_mgmt_direction_err ++; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,fr_udp_pkt->cblock.command); - } - - } else { - - switch(fr_udp_pkt->cblock.command) { - - case FPIPE_ENABLE_TRACING: - if(!card->TracingEnabled) { - do { - mbox->cmd.command = FR_SET_TRACE_CONFIG; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = fr_udp_pkt->data[0] | - RESET_TRC; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } while (err && c_retry-- && fr_event(card, err, - mbox)); - - if(err) { - card->TracingEnabled = 0; - /* set the return code */ - fr_udp_pkt->cblock.result = - mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - - sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF, - &num_trc_els, 2); - sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF, - &card->u.f.trc_el_base, 4); - card->u.f.curr_trc_el = card->u.f.trc_el_base; - card->u.f.trc_el_last = card->u.f.curr_trc_el + - ((num_trc_els - 1) * - sizeof(fr_trc_el_t)); - - /* Calculate the maximum trace data area in */ - /* the UDP packet */ - card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT - - //sizeof(fr_encap_hdr_t) - - sizeof(ip_pkt_t) - - sizeof(udp_pkt_t) - - sizeof(wp_mgmt_t) - - sizeof(cblock_t)); - - /* set return code */ - fr_udp_pkt->cblock.result = 0; - - } else { - /* set return code to line trace already - enabled */ - fr_udp_pkt->cblock.result = 1; - } - - mbox->cmd.length = 0; - card->TracingEnabled = 1; - break; - - - case FPIPE_DISABLE_TRACING: - if(card->TracingEnabled) { - - do { - mbox->cmd.command = FR_SET_TRACE_CONFIG; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = ~ACTIVATE_TRC; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } while (err && c_retry-- && fr_event(card, err, mbox)); - } - - /* set return code */ - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 0; - card->TracingEnabled = 0; - break; - - case FPIPE_GET_TRACE_INFO: - - /* Line trace cannot be performed on the 502 */ - if(!card->TracingEnabled) { - /* set return code */ - fr_udp_pkt->cblock.result = 1; - mbox->cmd.length = 0; - break; - } - - ptr_trc_el = (void *)card->u.f.curr_trc_el; - - buffer_length = 0; - fr_udp_pkt->data[0x00] = 0x00; - - for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) { - - sdla_peek(&card->hw, (unsigned long)ptr_trc_el, - (void *)&trc_el.flag, - sizeof(fr_trc_el_t)); - if(trc_el.flag == 0x00) { - break; - } - if((card->u.f.trc_bfr_space - buffer_length) - < sizeof(fpipemon_trc_hdr_t)) { - fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; - break; - } - - fpipemon_trc = - (fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length]; - fpipemon_trc->fpipemon_trc_hdr.status = - trc_el.attr; - fpipemon_trc->fpipemon_trc_hdr.tmstamp = - trc_el.tmstamp; - fpipemon_trc->fpipemon_trc_hdr.length = - trc_el.length; - - if(!trc_el.offset || !trc_el.length) { - - fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; - - }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) > - (card->u.f.trc_bfr_space - buffer_length)){ - - fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; - fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; - - }else { - fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; - sdla_peek(&card->hw, trc_el.offset, - fpipemon_trc->data, - trc_el.length); - } - - trc_el.flag = 0x00; - sdla_poke(&card->hw, (unsigned long)ptr_trc_el, - &trc_el.flag, 1); - - ptr_trc_el ++; - if((void *)ptr_trc_el > card->u.f.trc_el_last) - ptr_trc_el = (void*)card->u.f.trc_el_base; - - buffer_length += sizeof(fpipemon_trc_hdr_t); - if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { - buffer_length += trc_el.length; - } - - if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) { - break; - } - } - - if(frames == MAX_FRMS_TRACED) { - fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; - } - - card->u.f.curr_trc_el = (void *)ptr_trc_el; - - /* set the total number of frames passed */ - fr_udp_pkt->data[0x00] |= - ((frames << 1) & (MAX_FRMS_TRACED << 1)); - - /* set the data length and return code */ - fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length; - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_FT1_READ_STATUS: - sdla_peek(&card->hw, 0xF020, - &fr_udp_pkt->data[0x00] , 2); - fr_udp_pkt->cblock.length = mbox->cmd.length = 2; - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_FLUSH_DRIVER_STATS: - init_chan_statistics(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - - case FPIPE_ROUTER_UP_TIME: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - - chan->router_start_time; - *(unsigned long *)&fr_udp_pkt->data = - chan->router_up_time; - mbox->cmd.length = fr_udp_pkt->cblock.length = 4; - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_DRIVER_STAT_IFSEND: - memcpy(fr_udp_pkt->data, - &chan->drvstats_if_send.if_send_entry, - sizeof(if_send_stat_t)); - mbox->cmd.length = fr_udp_pkt->cblock.length =sizeof(if_send_stat_t); - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_DRIVER_STAT_INTR: - - memcpy(fr_udp_pkt->data, - &card->statistics.isr_entry, - sizeof(global_stats_t)); - - memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)], - &chan->drvstats_rx_intr.rx_intr_no_socket, - sizeof(rx_intr_stat_t)); - - mbox->cmd.length = fr_udp_pkt->cblock.length = - sizeof(global_stats_t) + - sizeof(rx_intr_stat_t); - fr_udp_pkt->cblock.result = 0; - break; - - case FPIPE_DRIVER_STAT_GEN: - memcpy(fr_udp_pkt->data, - &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, - sizeof(pipe_mgmt_stat_t)); - - memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], - &card->statistics, sizeof(global_stats_t)); - - mbox->cmd.length = fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - fr_udp_pkt->cblock.result = 0; - break; - - - case FR_FT1_STATUS_CTRL: - if(fr_udp_pkt->data[0] == 1) { - if(rCount++ != 0 ){ - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if(fr_udp_pkt->data[0] == 0) { - if( --rCount != 0) { - fr_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - goto udp_mgmt_dflt; - - - default: -udp_mgmt_dflt: - do { - memcpy(&mbox->cmd, - &fr_udp_pkt->cblock.command, - sizeof(fr_cmd_t)); - if(mbox->cmd.length) { - memcpy(&mbox->data, - (char *)fr_udp_pkt->data, - mbox->cmd.length); - } - - err = sdla_exec(mbox) ? mbox->cmd.result : - CMD_TIMEOUT; - } while (err && c_retry-- && fr_event(card, err, mbox)); - - if(!err) - chan->drvstats_gen. - UDP_PIPE_mgmt_adptr_cmnd_OK ++; - else - chan->drvstats_gen. - UDP_PIPE_mgmt_adptr_cmnd_timeout ++; - - /* copy the result back to our buffer */ - memcpy(&fr_udp_pkt->cblock.command, - &mbox->cmd, sizeof(fr_cmd_t)); - - if(mbox->cmd.length) { - memcpy(&fr_udp_pkt->data, - &mbox->data, mbox->cmd.length); - } - } - } - - /* Fill UDP TTL */ - fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length); - - if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - chan->fr_header_len=2; - chan->fr_header[0]=Q922_UI; - chan->fr_header[1]=NLPID_IP; - - err = fr_send_data_header(card, dlci, 0, len, - card->u.f.udp_pkt_data,chan->fr_header_len); - if (err){ - chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; - }else{ - chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; - } - - } else { - /* Allocate socket buffer */ - if((new_skb = dev_alloc_skb(len)) != NULL) { - - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, card->u.f.udp_pkt_data, len); - - chan->drvstats_gen. - UDP_PIPE_mgmt_passed_to_stack ++; - new_skb->dev = dev; - new_skb->protocol = htons(ETH_P_IP); - new_skb->mac.raw = new_skb->data; - netif_rx(new_skb); - - } else { - chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } - - card->u.f.udp_pkt_lgth = 0; - - return 1; -} - -/*============================================================================== - * Send Inverse ARP Request - */ - -int send_inarp_request(sdla_t *card, struct net_device *dev) -{ - int err=0; - - arphdr_1490_t *ArpPacket; - arphdr_fr_t *arphdr; - fr_channel_t *chan = dev->priv; - struct in_device *in_dev; - - in_dev = dev->ip_ptr; - - if(in_dev != NULL ) { - - ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); - /* SNAP Header indicating ARP */ - ArpPacket->control = 0x03; - ArpPacket->pad = 0x00; - ArpPacket->NLPID = 0x80; - ArpPacket->OUI[0] = 0; - ArpPacket->OUI[1] = 0; - ArpPacket->OUI[2] = 0; - ArpPacket->PID = 0x0608; - - arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet - - /* InARP request */ - arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ - arphdr->ar_pro = 0x0008; /* IP Protocol */ - arphdr->ar_hln = 2; /* HW addr length */ - arphdr->ar_pln = 4; /* IP addr length */ - arphdr->ar_op = htons(0x08); /* InARP Request */ - arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ - if(in_dev->ifa_list != NULL) - arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else - arphdr->ar_sip = 0; - arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ - arphdr->ar_tip = 0; /* Remote Address -- what we want */ - - err = fr_send(card, chan->dlci, 0, sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), - (void *)ArpPacket); - - if (!err){ - printk(KERN_INFO "\n%s: Sending InARP request on DLCI %d.\n", - card->devname, chan->dlci); - clear_bit(ARP_CRIT,&card->wandev.critical); - } - - kfree(ArpPacket); - }else{ - printk(KERN_INFO "%s: INARP ERROR: %s doesn't have a local IP address!\n", - card->devname,dev->name); - return 1; - } - - return 0; -} - - -/*============================================================================== - * Check packet for ARP Type - */ - -int is_arp(void *buf) -{ - arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; - - if (arphdr->pad == 0x00 && - arphdr->NLPID == 0x80 && - arphdr->PID == 0x0608) - return 1; - else return 0; -} - -/*============================================================================== - * Process ARP Packet Type - */ - -int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev) -{ - - - arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ - fr_rx_buf_ctl_t* frbuf = card->rxmb; - struct in_device *in_dev; - fr_channel_t *chan = dev->priv; - - /* Before we transmit ARP packet, we must check - * to see that we are not currently transmitting a - * frame (in 'if_send()') and that we are not - * already in a 'delayed transmit' state. */ - if (check_tx_status(card,dev)){ - if (net_ratelimit()){ - printk(KERN_INFO "%s: Disabling comminication to process ARP\n", - card->devname); - } - set_bit(ARP_CRIT,&card->wandev.critical); - return 0; - } - - in_dev = dev->ip_ptr; - - /* Check that IP addresses exist for our network address */ - if (in_dev == NULL || in_dev->ifa_list == NULL) - return -1; - - switch (ntohs(arphdr->ar_op)) { - - case 0x08: // Inverse ARP request -- Send Reply, add route. - - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr -InArp Req: %u.%u.%u.%u\n", - card->devname, NIPQUAD(arphdr->ar_sip)); - - - /* Check that the network address is the same as ours, only - * if the netowrk mask is not 255.255.255.255. Otherwise - * this check would not make sense */ - - if (in_dev->ifa_list->ifa_mask != 0xFFFFFFFF && - (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != - (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)){ - printk(KERN_INFO - "%s: Invalid PtP address. %u.%u.%u.%u InARP ignored.\n", - card->devname,NIPQUAD(arphdr->ar_sip)); - - printk(KERN_INFO "%s: mask %u.%u.%u.%u\n", - card->devname, NIPQUAD(in_dev->ifa_list->ifa_mask)); - printk(KERN_INFO "%s: local %u.%u.%u.%u\n", - card->devname,NIPQUAD(in_dev->ifa_list->ifa_local)); - return -1; - } - - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip){ - printk(KERN_INFO - "%s: Local addr = PtP addr. InARP ignored.\n", - card->devname); - return -1; - } - - arphdr->ar_op = htons(0x09); /* InARP Reply */ - - /* Set addresses */ - arphdr->ar_tip = arphdr->ar_sip; - arphdr->ar_sip = in_dev->ifa_list->ifa_local; - - chan->ip_local = in_dev->ifa_list->ifa_local; - chan->ip_remote = arphdr->ar_sip; - - fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); - - if (test_bit(ARP_CRIT,&card->wandev.critical)){ - if (net_ratelimit()){ - printk(KERN_INFO "%s: ARP Processed Enabling Communication!\n", - card->devname); - } - } - clear_bit(ARP_CRIT,&card->wandev.critical); - - chan->ip_local = in_dev->ifa_list->ifa_local; - chan->ip_remote = arphdr->ar_sip; - - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ - - chan->route_flag = ADD_ROUTE; - trigger_fr_poll (dev); - - break; - - case 0x09: // Inverse ARP reply - - /* Check for valid Address */ - printk(KERN_INFO "%s: Recvd PtP addr %u.%u.%u.%u -InArp Reply\n", - card->devname, NIPQUAD(arphdr->ar_sip)); - - - /* Compare network addresses, only if network mask - * is not 255.255.255.255 It would not make sense - * to perform this test if the mask was all 1's */ - - if (in_dev->ifa_list->ifa_mask != 0xffffffff && - (in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != - (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { - - printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", - card->devname); - return -1; - } - - /* Make sure that the received IP address is not - * the same as our own local address */ - if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { - printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", - card->devname); - return -1; - } - - chan->ip_local = in_dev->ifa_list->ifa_local; - chan->ip_remote = arphdr->ar_sip; - - /* Add Route Flag */ - /* The route will be added in the polling routine so - that it is not interrupt context. */ - - chan->route_flag = ADD_ROUTE; - chan->inarp = INARP_CONFIGURED; - trigger_fr_poll(dev); - - break; - default: - break; // ARP's and RARP's -- Shouldn't happen. - } - - return 0; -} - - -/*============================================================ - * trigger_fr_arp - * - * Description: - * Add an fr_arp() task into a arp - * timer handler for a specific dlci/interface. - * This will kick the fr_arp() routine - * within the specified time interval. - * - * Usage: - * This timer is used to send ARP requests at - * certain time intervals. - * Called by an interrupt to request an action - * at a later date. - */ - -static void trigger_fr_arp(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - - mod_timer(&chan->fr_arp_timer, jiffies + chan->inarp_interval * HZ); - return; -} - - - -/*============================================================================== - * ARP Request Action - * - * This funciton is called by timer interrupt to send an arp request - * to the remote end. - */ - -static void fr_arp (unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - fr_channel_t *chan = dev->priv; - volatile sdla_t *card = chan->card; - fr508_flags_t* flags = card->flags; - - /* Send ARP packets for all devs' until - * ARP state changes to CONFIGURED */ - - if (chan->inarp == INARP_REQUEST && - chan->common.state == WAN_CONNECTED && - card->wandev.state == WAN_CONNECTED){ - set_bit(0,&chan->inarp_ready); - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_ARP; - flags->imask |= FR_INTR_TIMER; - } - - return; -} - - -/*============================================================================== - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ - * TEST_COUNTER times. - */ -static int intr_test( sdla_t* card ) -{ - fr_mbox_t* mb = card->mbox; - int err,i; - - err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); - - if (err == CMD_OK) { - - for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { - /* Run command READ_CODE_VERSION */ - mb->cmd.length = 0; - mb->cmd.command = FR_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - fr_event(card, err, mb); - } - - } else { - return err; - } - - err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); - - if( err != CMD_OK ) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. FPIPE8ND ? - */ -static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) -{ - fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data; - - /* Quick HACK */ - - - if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && - (fr_udp_pkt->udp_pkt.udp_dst_port == - ntohs(card->wandev.udp_port)) && - (fr_udp_pkt->wp_mgmt.request_reply == - UDPMGMT_REQUEST)) { - if(!strncmp(fr_udp_pkt->wp_mgmt.signature, - UDPMGMT_FPIPE_SIGNATURE, 8)){ - return UDP_FPIPE_TYPE; - } - } - return UDP_INVALID_TYPE; -} - - -/*============================================================================== - * Initializes the Statistics values in the fr_channel structure. - */ -void init_chan_statistics( fr_channel_t* chan) -{ - memset(&chan->drvstats_if_send.if_send_entry, 0, - sizeof(if_send_stat_t)); - memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, - sizeof(rx_intr_stat_t)); - memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, - sizeof(pipe_mgmt_stat_t)); -} - -/*============================================================================== - * Initializes the Statistics values in the Sdla_t structure. - */ -void init_global_statistics( sdla_t* card ) -{ - /* Intialize global statistics for a card */ - memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); -} - -static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) -{ - fr_mbox_t* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - dlci_IB_mapping_t* result; - int err, counter, found; - - do { - mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && fr_event(card, err, mbox)); - - if( mbox->cmd.result != 0){ - printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", - chan->name); - } - - counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); - result = (void *)mbox->data; - - found = 0; - for (; counter; --counter, ++result) { - if ( result->dlci == chan->dlci ) { - chan->IB_addr = result->addr_value; - if(card->hw.type == SDLA_S514){ - chan->dlci_int_interface = - (void*)(card->hw.dpmbase + - chan->IB_addr); - }else{ - chan->dlci_int_interface = - (void*)(card->hw.dpmbase + - (chan->IB_addr & 0x00001FFF)); - - } - found = 1; - break; - } - } - if (!found) - printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", - card->devname, chan->dlci); -} - - - -void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) -{ - if (card->hw.type != SDLA_S514){ - - spin_lock_irqsave(&card->wandev.lock, *smp_flags); - }else{ - spin_lock(&card->u.f.if_send_lock); - } - return; -} - - -void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) -{ - if (card->hw.type != SDLA_S514){ - - spin_unlock_irqrestore (&card->wandev.lock, *smp_flags); - }else{ - spin_unlock(&card->u.f.if_send_lock); - } - return; -} - - - -/*---------------------------------------------------------------------- - RECEIVE INTERRUPT: BOTTOM HALF HANDLERS - ----------------------------------------------------------------------*/ - - -/*======================================================== - * bh_enqueue - * - * Description: - * Insert a received packet into a circular - * rx queue. This packet will be picked up - * by fr_bh() and sent up the stack to the - * user. - * - * Usage: - * This function is called by rx interrupt, - * in API mode. - * - */ - -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) -{ - /* Check for full */ - fr_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - - - if (atomic_read(&chan->bh_buff_used) == MAX_BH_BUFF){ - ++card->wandev.stats.rx_dropped; - dev_kfree_skb_any(skb); - return 1; - } - - ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; - - if (chan->bh_write == (MAX_BH_BUFF-1)){ - chan->bh_write=0; - }else{ - ++chan->bh_write; - } - - atomic_inc(&chan->bh_buff_used); - - return 0; -} - - -/*======================================================== - * trigger_fr_bh - * - * Description: - * Kick the fr_bh() handler - * - * Usage: - * rx interrupt calls this function during - * the API mode. - */ - -static void trigger_fr_bh (fr_channel_t *chan) -{ - if (!test_and_set_bit(0,&chan->tq_working)){ - wanpipe_queue_work(&chan->common.wanpipe_work); - } -} - - -/*======================================================== - * fr_bh - * - * Description: - * Frame relay receive BH handler. - * Dequeue data from the BH circular - * buffer and pass it up the API sock. - * - * Rationale: - * This fuction is used to offload the - * rx_interrupt during API operation mode. - * The fr_bh() function executes for each - * dlci/interface. - * - * Once receive interrupt copies data from the - * card into an skb buffer, the skb buffer - * is appended to a circular BH buffer. - * Then the interrupt kicks fr_bh() to finish the - * job at a later time (not within the interrupt). - * - * Usage: - * Interrupts use this to defer a task to - * a polling routine. - * - */ - -static void fr_bh(struct net_device * dev) -{ - fr_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - struct sk_buff *skb; - - if (atomic_read(&chan->bh_buff_used) == 0){ - clear_bit(0, &chan->tq_working); - return; - } - - while (atomic_read(&chan->bh_buff_used)){ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - clear_bit(0, &chan->tq_working); - return; - } - - skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; - - if (skb != NULL){ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - ++card->wandev.stats.rx_dropped; - ++chan->ifstats.rx_dropped; - dev_kfree_skb_any(skb); - fr_bh_cleanup(dev); - continue; - } - - if (chan->common.func(skb,dev,chan->common.sk) != 0){ - /* Sock full cannot send, queue us for - * another try */ - atomic_set(&chan->common.receive_block,1); - return; - }else{ - fr_bh_cleanup(dev); - } - }else{ - fr_bh_cleanup(dev); - } - } - clear_bit(0, &chan->tq_working); - - return; -} - -static int fr_bh_cleanup(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - - ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; - - if (chan->bh_read == (MAX_BH_BUFF-1)){ - chan->bh_read=0; - }else{ - ++chan->bh_read; - } - - atomic_dec(&chan->bh_buff_used); - return 0; -} - - -/*---------------------------------------------------------------------- - POLL BH HANDLERS AND KICK ROUTINES - ----------------------------------------------------------------------*/ - -/*============================================================ - * trigger_fr_poll - * - * Description: - * Add a fr_poll() task into a tq_scheduler bh handler - * for a specific dlci/interface. This will kick - * the fr_poll() routine at a later time. - * - * Usage: - * Interrupts use this to defer a taks to - * a polling routine. - * - */ -static void trigger_fr_poll(struct net_device *dev) -{ - fr_channel_t* chan = dev->priv; - schedule_work(&chan->fr_poll_work); - return; -} - - -/*============================================================ - * fr_poll - * - * Rationale: - * We cannot manipulate the routing tables, or - * ip addresses withing the interrupt. Therefore - * we must perform such actons outside an interrupt - * at a later time. - * - * Description: - * Frame relay polling routine, responsible for - * shutting down interfaces upon disconnect - * and adding/removing routes. - * - * Usage: - * This function is executed for each frame relay - * dlci/interface through a tq_schedule bottom half. - * - * trigger_fr_poll() function is used to kick - * the fr_poll routine. - */ - -static void fr_poll(struct net_device *dev) -{ - - fr_channel_t* chan; - sdla_t *card; - u8 check_gateway=0; - - if (!dev || (chan = dev->priv) == NULL) - return; - - card = chan->card; - - /* (Re)Configuraiton is in progress, stop what you are - * doing and get out */ - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - return; - } - - switch (chan->common.state){ - - case WAN_DISCONNECTED: - - if (test_bit(DYN_OPT_ON,&chan->interface_down) && - !test_bit(DEV_DOWN, &chan->interface_down) && - dev->flags&IFF_UP){ - - printk(KERN_INFO "%s: Interface %s is Down.\n", - card->devname,dev->name); - change_dev_flags(dev,dev->flags&~IFF_UP); - set_bit(DEV_DOWN, &chan->interface_down); - chan->route_flag = NO_ROUTE; - - }else{ - if (chan->inarp != INARP_NONE) - process_route(dev); - } - break; - - case WAN_CONNECTED: - - if (test_bit(DYN_OPT_ON,&chan->interface_down) && - test_bit(DEV_DOWN, &chan->interface_down) && - !(dev->flags&IFF_UP)){ - - printk(KERN_INFO "%s: Interface %s is Up.\n", - card->devname,dev->name); - - change_dev_flags(dev,dev->flags|IFF_UP); - clear_bit(DEV_DOWN, &chan->interface_down); - check_gateway=1; - } - - if (chan->inarp != INARP_NONE){ - process_route(dev); - check_gateway=1; - } - - if (chan->gateway && check_gateway) - add_gateway(card,dev); - - break; - - } - - return; -} - -/*============================================================== - * check_tx_status - * - * Rationale: - * We cannot transmit from an interrupt while - * the if_send is transmitting data. Therefore, - * we must check whether the tx buffers are - * begin used, before we transmit from an - * interrupt. - * - * Description: - * Checks whether it's safe to use the transmit - * buffers. - * - * Usage: - * ARP and UDP handling routines use this function - * because, they need to transmit data during - * an interrupt. - */ - -static int check_tx_status(sdla_t *card, struct net_device *dev) -{ - - if (card->hw.type == SDLA_S514){ - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical) || - test_bit(SEND_TXIRQ_CRIT, (void*)&card->wandev.critical)) { - return 1; - } - } - - if (netif_queue_stopped(dev) || (card->u.f.tx_interrupts_pending)) - return 1; - - return 0; -} - -/*=============================================================== - * move_dev_to_next - * - * Description: - * Move the dev pointer to the next location in the - * link list. Check if we are at the end of the - * list, if so start from the begining. - * - * Usage: - * Timer interrupt uses this function to efficiently - * step through the devices that need to send ARP data. - * - */ - -struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) -{ - if (card->wandev.new_if_cnt != 1){ - if (!*((struct net_device **)dev->priv)) - return card->wandev.dev; - else - return *((struct net_device **)dev->priv); - } - return dev; -} - -/*============================================================== - * trigger_config_fr - * - * Rationale: - * All commands must be performed inside of a - * interrupt. - * - * Description: - * Kick the config_fr() routine throught the - * timer interrupt. - */ - - -static void trigger_config_fr (sdla_t *card) -{ - fr508_flags_t* flags = card->flags; - - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->imask |= FR_INTR_TIMER; -} - - -/*============================================================== - * config_fr - * - * Rationale: - * All commands must be performed inside of a - * interrupt. - & - * Description: - * Configure a DLCI. This function is executed - * by a timer_interrupt. The if_open() function - * triggers it. - * - * Usage: - * new_if() collects all data necessary to - * configure the DLCI. It sets the chan->dlci_ready - * bit. When the if_open() function is executed - * it checks this bit, and if its set it triggers - * the timer interrupt to execute the config_fr() - * function. - */ - -static void config_fr (sdla_t *card) -{ - struct net_device *dev; - fr_channel_t *chan; - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - - if ((chan=dev->priv) == NULL) - continue; - - if (!test_bit(0,&chan->config_dlci)) - continue; - - clear_bit(0,&chan->config_dlci); - - /* If signalling is set to NO, then setup - * DLCI addresses right away. Don't have to wait for - * link to connect. - */ - if (card->wandev.signalling == WANOPT_NO){ - printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", - card->wandev.name); - if (fr_init_dlci(card,chan)){ - printk(KERN_INFO "%s: ERROR: Failed to configure DLCI %i !\n", - card->devname, chan->dlci); - return; - } - } - - if (card->wandev.station == WANOPT_CPE) { - - update_chan_state(dev); - - /* CPE: issue full status enquiry */ - fr_issue_isf(card, FR_ISF_FSE); - - } else { - /* FR switch: activate DLCI(s) */ - - /* For Switch emulation we have to ADD and ACTIVATE - * the DLCI(s) that were configured with the SET_DLCI_ - * CONFIGURATION command. Add and Activate will fail if - * DLCI specified is not included in the list. - * - * Also If_open is called once for each interface. But - * it does not get in here for all the interface. So - * we have to pass the entire list of DLCI(s) to add - * activate routines. - */ - - if (!check_dlci_config (card, chan)){ - fr_add_dlci(card, chan->dlci); - fr_activate_dlci(card, chan->dlci); - } - } - - card->u.f.dlci_to_dev_map[chan->dlci] = dev; - } - return; -} - - -/*============================================================== - * config_fr - * - * Rationale: - * All commands must be executed during an interrupt. - * - * Description: - * Trigger uncofig_fr() function through - * the timer interrupt. - * - */ - -static void trigger_unconfig_fr(struct net_device *dev) -{ - fr_channel_t *chan = dev->priv; - volatile sdla_t *card = chan->card; - unsigned long timeout; - fr508_flags_t* flags = card->flags; - int reset_critical=0; - - if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ - clear_bit(PERI_CRIT,(void*)&card->wandev.critical); - reset_critical=1; - } - - /* run unconfig_dlci() function - * throught the timer interrupt */ - set_bit(0,(void*)&chan->unconfig_dlci); - card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UNCONFIG; - flags->imask |= FR_INTR_TIMER; - - /* Wait for the command to complete */ - timeout = jiffies; - for(;;) { - - if(!(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UNCONFIG)) - break; - - if (time_after(jiffies, timeout + 1 * HZ)){ - card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UNCONFIG; - printk(KERN_INFO "%s: Failed to delete DLCI %i\n", - card->devname,chan->dlci); - break; - } - } - - if (reset_critical){ - set_bit(PERI_CRIT,(void*)&card->wandev.critical); - } -} - -/*============================================================== - * unconfig_fr - * - * Rationale: - * All commands must be executed during an interrupt. - * - * Description: - * Remove the dlci from firmware. - * This funciton is used in NODE shutdown. - */ - -static void unconfig_fr (sdla_t *card) -{ - struct net_device *dev; - fr_channel_t *chan; - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)){ - - if ((chan=dev->priv) == NULL) - continue; - - if (!test_bit(0,&chan->unconfig_dlci)) - continue; - - clear_bit(0,&chan->unconfig_dlci); - - if (card->wandev.station == WANOPT_NODE){ - printk(KERN_INFO "%s: Unconfiguring DLCI %i\n", - card->devname,chan->dlci); - fr_delete_dlci(card,chan->dlci); - } - card->u.f.dlci_to_dev_map[chan->dlci] = NULL; - } -} - -static int setup_fr_header(struct sk_buff *skb, struct net_device* dev, - char op_mode) -{ - fr_channel_t *chan=dev->priv; - - if (op_mode == WANPIPE) { - chan->fr_header[0]=Q922_UI; - - switch (htons(skb->protocol)){ - case ETH_P_IP: - chan->fr_header[1]=NLPID_IP; - break; - default: - return -EINVAL; - } - - return 2; - } - - /* If we are in bridging mode, we must apply - * an Ethernet header - */ - if (op_mode == BRIDGE || op_mode == BRIDGE_NODE) { - /* Encapsulate the packet as a bridged Ethernet frame. */ -#ifdef DEBUG - printk(KERN_INFO "%s: encapsulating skb for frame relay\n", - dev->name); -#endif - chan->fr_header[0] = 0x03; - chan->fr_header[1] = 0x00; - chan->fr_header[2] = 0x80; - chan->fr_header[3] = 0x00; - chan->fr_header[4] = 0x80; - chan->fr_header[5] = 0xC2; - chan->fr_header[6] = 0x00; - chan->fr_header[7] = 0x07; - - /* Yuck. */ - skb->protocol = ETH_P_802_3; - return 8; - } - - return 0; -} - - -static int check_dlci_config (sdla_t *card, fr_channel_t *chan) -{ - fr_mbox_t* mbox = card->mbox; - int err=0; - fr_conf_t *conf=NULL; - unsigned short dlci_num = chan->dlci; - int dlci_offset=0; - struct net_device *dev = NULL; - - mbox->cmd.command = FR_READ_CONFIG; - mbox->cmd.length = 0; - mbox->cmd.dlci = dlci_num; - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err == CMD_OK){ - return 0; - } - - for (dev = card->wandev.dev; dev; - dev=*((struct net_device **)dev->priv)) - set_chan_state(dev,WAN_DISCONNECTED); - - printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num); - - mbox->cmd.command = FR_COMM_DISABLE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK){ - fr_event(card, err, mbox); - return 2; - } - - printk(KERN_INFO "Disabled Communications \n"); - - mbox->cmd.command = FR_READ_CONFIG; - mbox->cmd.length = 0; - mbox->cmd.dlci = 0; - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK){ - fr_event(card, err, mbox); - return 2; - } - - conf = (fr_conf_t *)mbox->data; - - dlci_offset=0; - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - fr_channel_t *chan_tmp = dev->priv; - conf->dlci[dlci_offset] = chan_tmp->dlci; - dlci_offset++; - } - - printk(KERN_INFO "Got Fr configuration Buffer Length is %x Dlci %i Dlci Off %i\n", - mbox->cmd.length, - mbox->cmd.length > 0x20 ? conf->dlci[0] : -1, - dlci_offset ); - - mbox->cmd.length = 0x20 + dlci_offset*2; - - mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.dlci = 0; - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK){ - fr_event(card, err, mbox); - return 2; - } - - initialize_rx_tx_buffers (card); - - - printk(KERN_INFO "Configuraiton Succeded for new DLCI %i\n",dlci_num); - - if (fr_comm_enable (card)){ - return 2; - } - - printk(KERN_INFO "Enabling Communications \n"); - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)) { - fr_channel_t *chan_tmp = dev->priv; - fr_init_dlci(card,chan_tmp); - fr_add_dlci(card, chan_tmp->dlci); - fr_activate_dlci(card, chan_tmp->dlci); - } - - printk(KERN_INFO "END OF CONFIGURAITON %i\n",dlci_num); - - return 1; -} - -static void initialize_rx_tx_buffers (sdla_t *card) -{ - fr_buf_info_t* buf_info; - - if (card->hw.type == SDLA_S514) { - - buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + - FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + - card->hw.dpmbase); - }else{ - buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); - - card->rxmb = (void*)(buf_info->rse_next - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_base = - (void*)(buf_info->rse_base - - FR_MB_VECTOR + card->hw.dpmbase); - - card->u.f.rxmb_last = - (void*)(buf_info->rse_base + - (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - - FR_MB_VECTOR + card->hw.dpmbase); - } - - card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; - - card->u.f.tx_interrupts_pending = 0; - - return; -} - - - -MODULE_LICENSE("GPL"); - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdla_ft1.c b/drivers/net/wan/sdla_ft1.c deleted file mode 100644 index 9d6528a50f7b..000000000000 --- a/drivers/net/wan/sdla_ft1.c +++ /dev/null @@ -1,345 +0,0 @@ -/***************************************************************************** -* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. -* -* Authors: Nenad Corbic -* Gideon Hack -* -* Copyright: (c) 1995-1999 Sangoma Technologies Inc. -* -* 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. -* ============================================================================ -* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. -* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing -* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). -* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. -* Aug 07, 1998 David Fong Initial version. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ -#include /* time_after() macro */ - -#include -#include - -#include /* sockaddr_in */ -#include -#include -#include /* htons(), etc. */ -#include -#include - -#include /* CHDLC firmware API definitions */ - -/****** Defines & Macros ****************************************************/ - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x0001 -#define TMR_INT_ENABLED_UPDATE 0x0002 - -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define IFF_POINTTOPOINT 0x10 - -#define WANPIPE 0x00 -#define API 0x01 -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) - - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - struct net_device *slave; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int wpft1_exec (struct sdla *card, void *u_cmd, void *u_data); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpft1_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_CHDLC) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Use primary port */ - card->u.c.comm_port = 0; - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if (time_after(jiffies, timeout + 1*HZ)) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running FT1 Configuration firmware v%s\n", - card->devname, u.str); - - card->isr = NULL; - card->poll = NULL; - card->exec = &wpft1_exec; - card->wandev.update = NULL; - card->wandev.new_if = NULL; - card->wandev.del_if = NULL; - card->wandev.state = WAN_DUALPORT; - card->wandev.udp_port = conf->udp_port; - - card->wandev.new_if_cnt = 0; - - /* This is for the ports link state */ - card->u.c.state = WAN_DISCONNECTED; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = 0x7F; - card->wandev.interface = 0; - - card->wandev.clocking = 0; - - port_num = card->u.c.comm_port; - - /* Setup Port Bps */ - - card->wandev.bps = 0; - - card->wandev.mtu = MIN_LGTH_CHDLC_DATA_CFG; - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - card->wandev.state = WAN_FT1_READY; - printk(KERN_INFO "%s: FT1 Config Ready !\n",card->devname); - - return 0; -} - -static int wpft1_exec(sdla_t *card, void *u_cmd, void *u_data) -{ - CHDLC_MAILBOX_STRUCT* mbox = card->mbox; - int len; - - if (copy_from_user((void*)&mbox->command, u_cmd, sizeof(ft1_exec_cmd_t))){ - return -EFAULT; - } - - len = mbox->buffer_length; - - if (len) { - if( copy_from_user((void*)&mbox->data, u_data, len)){ - return -EFAULT; - } - } - - /* execute command */ - if (!sdla_exec(mbox)){ - return -EIO; - } - - /* return result */ - if( copy_to_user(u_cmd, (void*)&mbox->command, sizeof(ft1_exec_cmd_t))){ - return -EFAULT; - } - - len = mbox->buffer_length; - - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)){ - return -EFAULT; - } - - return 0; - -} - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) -{ - unsigned cmd = mb->command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - case S514_BOTH_PORTS_SAME_CLK_MODE: - if(cmd == SET_CHDLC_CONFIGURATION) { - printk(KERN_INFO - "%s: Configure both ports for the same clock source\n", - card->devname); - break; - } - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - } - - return 0; -} - -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c deleted file mode 100644 index a4b489cccbbf..000000000000 --- a/drivers/net/wan/sdla_ppp.c +++ /dev/null @@ -1,3430 +0,0 @@ -/***************************************************************************** -* sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. -* -* Author: Nenad Corbic -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* 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. -* ============================================================================ -* Feb 28, 2001 Nenad Corbic o Updated if_tx_timeout() routine for -* 2.4.X kernels. -* Nov 29, 2000 Nenad Corbic o Added the 2.4.x kernel support: -* get_ip_address() function has moved -* into the ppp_poll() routine. It cannot -* be called from an interrupt. -* Nov 07, 2000 Nenad Corbic o Added security features for UDP debugging: -* Deny all and specify allowed requests. -* May 02, 2000 Nenad Corbic o Added the dynamic interface shutdown -* option. When the link goes down, the -* network interface IFF_UP flag is reset. -* Mar 06, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. -* Feb 25, 2000 Nenad Corbic o Fixed the FT1 UDP debugger problem. -* Feb 09, 2000 Nenad Coribc o Shutdown bug fix. update() was called -* with NULL dev pointer: no check. -* Jan 24, 2000 Nenad Corbic o Disabled use of CMD complete inter. -* Dev 15, 1999 Nenad Corbic o Fixed up header files for 2.0.X kernels -* Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels -* Moved dynamic route processing into -* a polling routine. -* Oct 07, 1999 Nenad Corbic o Support for S514 PCI card. -* Gideon Hack o UPD and Updates executed using timer interrupt -* Sep 10, 1999 Nenad Corbic o Fixed up the /proc statistics -* Jul 20, 1999 Nenad Corbic o Remove the polling routines and use -* interrupts instead. -* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. -* Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. -* Jun 22, 1998 David Fong o Added remote IP address assignment -* Mar 15, 1998 Alan Cox o 2.1.8x basic port. -* Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. -* Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. -* o Implemented new routines like -* ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), -* tokenize() and strstrip(). -* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs -* while they have been disabled. -* Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by -* disabling and enabling of irqs. -* o Added new counters for stats on disable/enable -* IRQs. -* Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data' -* before every netif_rx(). -* o Free up the device structure in del_if(). -* Nov 07, 1997 Jaspreet Singh o Changed the delay to zero for Line tracing -* command. -* Oct 20, 1997 Jaspreet Singh o Added hooks in for Router UP time. -* Oct 16, 1997 Jaspreet Singh o The critical flag is used to maintain flow -* control by avoiding RACE conditions. The -* cli() and restore_flags() are taken out. -* A new structure, "ppp_private_area", is added -* to provide Driver Statistics. -* Jul 21, 1997 Jaspreet Singh o Protected calls to sdla_peek() by adding -* save_flags(), cli() and restore_flags(). -* Jul 07, 1997 Jaspreet Singh o Added configurable TTL for UDP packets -* o Added ability to discard mulitcast and -* broacast source addressed packets. -* Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities -* New case (0x25) statement in if_send routine. -* Added a global variable rCount to keep track -* of FT1 status enabled on the board. -* May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for -* 508 card to reflect changes in the new -* ppp508.sfm for supporting:continous transmission -* of Configure-Request packets without receiving a -* reply -* OR-ed 0x300 to conf_flags -* o Changed connect_tmout from 900 to 0 -* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple boards -* Apr 25, 1997 Farhan Thawar o added UDP Management stuff -* Mar 11, 1997 Farhan Thawar Version 3.1.1 -* o fixed (+1) bug in rx_intr() -* o changed if_send() to return 0 if -* wandev.critical() is true -* o free socket buffer in if_send() if -* returning 0 -* Jan 15, 1997 Gene Kozin Version 3.1.0 -* o implemented exec() entry point -* Jan 06, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ -#include /* htons(), etc. */ -#include /* sockaddr_in */ -#include /* time_after() macro */ - - -#include -#include -#include - -#include -#include /* PPP firmware API definitions */ -#include /* S514 Type Definition */ -/****** Defines & Macros ****************************************************/ - -#define PPP_DFLT_MTU 1500 /* default MTU */ -#define PPP_MAX_MTU 4000 /* maximum MTU */ -#define PPP_HDR_LEN 1 - -#define MAX_IP_ERRORS 100 - -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */ - -/* For handle_IPXWAN() */ -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - -/* Macro for enabling/disabling debugging comments */ -//#define NEX_DEBUG -#ifdef NEX_DEBUG -#define NEX_PRINTK(format, a...) printk(format, ## a) -#else -#define NEX_PRINTK(format, a...) -#endif /* NEX_DEBUG */ - -#define DCD(a) ( a & 0x08 ? "HIGH" : "LOW" ) -#define CTS(a) ( a & 0x20 ? "HIGH" : "LOW" ) -#define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" ) -#define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" ) - -#define TMR_INT_ENABLED_UPDATE 0x01 -#define TMR_INT_ENABLED_PPP_EVENT 0x02 -#define TMR_INT_ENABLED_UDP 0x04 -#define TMR_INT_ENABLED_CONFIG 0x20 - -/* Set Configuraton Command Definitions */ -#define PERCENT_TX_BUFF 60 -#define TIME_BETWEEN_CONF_REQ 30 -#define TIME_BETWEEN_PAP_CHAP_REQ 30 -#define WAIT_PAP_CHAP_WITHOUT_REPLY 300 -#define WAIT_AFTER_DCD_CTS_LOW 5 -#define TIME_DCD_CTS_LOW_AFTER_LNK_DOWN 10 -#define WAIT_DCD_HIGH_AFTER_ENABLE_COMM 900 -#define MAX_CONF_REQ_WITHOUT_REPLY 10 -#define MAX_TERM_REQ_WITHOUT_REPLY 2 -#define NUM_CONF_NAK_WITHOUT_REPLY 5 -#define NUM_AUTH_REQ_WITHOUT_REPLY 10 - -#define END_OFFSET 0x1F0 - - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with PPP specific data - */ - -typedef struct ppp_private_area -{ - struct net_device *slave; - sdla_t* card; - unsigned long router_start_time; /*router start time in sec */ - unsigned long tick_counter; /*used for 5 second counter*/ - unsigned mc; /*multicast support on or off*/ - unsigned char enable_IPX; - unsigned long network_number; - unsigned char pap; - unsigned char chap; - unsigned char sysname[31]; /* system name for in-bnd auth*/ - unsigned char userid[511]; /* list of user ids */ - unsigned char passwd[511]; /* list of passwords */ - unsigned protocol; /* SKB Protocol */ - u32 ip_local; /* Local IP Address */ - u32 ip_remote; /* remote IP Address */ - - u32 ip_local_tmp; - u32 ip_remote_tmp; - - unsigned char timer_int_enabled; /* Who enabled the timer inter*/ - unsigned char update_comms_stats; /* Used by update function */ - unsigned long curr_trace_addr; /* Trace information */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - - unsigned char interface_down; /* Brind down interface when channel - goes down */ - unsigned long config_wait_timeout; /* After if_open() if in dynamic if mode, - wait a few seconds before configuring */ - - unsigned short udp_pkt_lgth; - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - - /* PPP specific statistics */ - - if_send_stat_t if_send_stat; - rx_intr_stat_t rx_intr_stat; - pipe_mgmt_stat_t pipe_mgmt_stat; - - unsigned long router_up_time; - - /* Polling work queue entry. Each interface - * has its own work queue entry, which is used - * to defer events from the interrupt */ - struct work_struct poll_work; - struct timer_list poll_delay_timer; - - u8 gateway; - u8 config_ppp; - u8 ip_error; - -}ppp_private_area_t; - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ - -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device *wandev); -static int new_if(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf); -static int del_if(struct wan_device *wandev, struct net_device *dev); - -/* WANPIPE-specific entry points */ -static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); - -/* Network device interface */ -static int if_init(struct net_device *dev); -static int if_open(struct net_device *dev); -static int if_close(struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - void *daddr, void *saddr, unsigned len); - -static void if_tx_timeout(struct net_device *dev); - -static int if_rebuild_hdr(struct sk_buff *skb); -static struct net_device_stats *if_stats(struct net_device *dev); -static int if_send(struct sk_buff *skb, struct net_device *dev); - - -/* PPP firmware interface functions */ -static int ppp_read_version(sdla_t *card, char *str); -static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); -static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); -static int ppp_configure(sdla_t *card, void *data); -static int ppp_set_intr_mode(sdla_t *card, unsigned char mode); -static int ppp_comm_enable(sdla_t *card); -static int ppp_comm_disable(sdla_t *card); -static int ppp_comm_disable_shutdown(sdla_t *card); -static int ppp_get_err_stats(sdla_t *card); -static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); -static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); - -static void wpp_isr(sdla_t *card); -static void rx_intr(sdla_t *card); -static void event_intr(sdla_t *card); -static void timer_intr(sdla_t *card); - -/* Background polling routines */ -static void process_route(sdla_t *card); -static void retrigger_comm(sdla_t *card); - -/* Miscellaneous functions */ -static int read_info( sdla_t *card ); -static int read_connection_info (sdla_t *card); -static void remove_route( sdla_t *card ); -static int config508(struct net_device *dev, sdla_t *card); -static void show_disc_cause(sdla_t * card, unsigned cause); -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, - ppp_private_area_t *ppp_priv_area); -static void init_ppp_tx_rx_buff( sdla_t *card ); -static int intr_test( sdla_t *card ); -static int udp_pkt_type( struct sk_buff *skb , sdla_t *card); -static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area); -static void init_global_statistics( sdla_t *card ); -static int tokenize(char *str, char **tokens); -static char* strstrip(char *str, char *s); -static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, - struct sk_buff *skb); - -static int config_ppp (sdla_t *); -static void ppp_poll(struct net_device *dev); -static void trigger_ppp_poll(struct net_device *dev); -static void ppp_poll_delay (unsigned long dev_ptr); - - -static int Read_connection_info; -static int Intr_test_counter; -static unsigned short available_buffer_space; - - -/* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, - unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, - unsigned long network_number, unsigned short proto); - -/* Lock Functions */ -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - ppp_private_area_t* ppp_priv_area ); -static unsigned short calc_checksum (char *data, int len); -static void disable_comm (sdla_t *card); -static int detect_and_fix_tx_bug (sdla_t *card); - -/****** Public Functions ****************************************************/ - -/*============================================================================ - * PPP protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wpp_init(sdla_t *card, wandev_conf_t *conf) -{ - ppp_flags_t *flags; - union - { - char str[80]; - } u; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_PPP) { - - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - - } - - /* Initialize miscellaneous pointers to structures on the adapter */ - switch (card->hw.type) { - - case SDLA_S508: - card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS); - card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS); - break; - - case SDLA_S514: - card->mbox =(void*)(card->hw.dpmbase + PPP514_MB_OFFS); - card->flags=(void*)(card->hw.dpmbase + PPP514_FLG_OFFS); - break; - - default: - return -EINVAL; - - } - flags = card->flags; - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); - /* Adjust configuration and set defaults */ - card->wandev.mtu = (conf->mtu) ? - min_t(unsigned int, conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; - - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpp_isr; - card->poll = NULL; - card->exec = &wpp_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.udp_port = conf->udp_port; - card->wandev.ttl = conf->ttl; - card->wandev.state = WAN_DISCONNECTED; - card->disable_comm = &disable_comm; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->u.p.authenticator = conf->u.ppp.authenticator; - card->u.p.ip_mode = conf->u.ppp.ip_mode ? - conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; - card->TracingEnabled = 0; - Read_connection_info = 1; - - /* initialize global statistics */ - init_global_statistics( card ); - - - - if (!card->configured){ - int err; - - Intr_test_counter = 0; - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk("%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - printk( "%s: Please choose another interrupt\n",card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); - card->configured = 1; - } - - ppp_set_intr_mode(card, PPP_INTR_TIMER); - - /* Turn off the transmit and timer interrupt */ - flags->imask &= ~PPP_INTR_TIMER; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics. - */ -static int update(struct wan_device *wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile ppp_private_area_t *ppp_priv_area; - ppp_flags_t *flags = card->flags; - unsigned long timeout; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* Shutdown bug fix. This function can be - * called with NULL dev pointer during - * shutdown - */ - if ((dev=card->wandev.dev) == NULL){ - return -ENODEV; - } - - if ((ppp_priv_area=dev->priv) == NULL){ - return -ENODEV; - } - - ppp_priv_area->update_comms_stats = 2; - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; - flags->imask |= PPP_INTR_TIMER; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies; - for(;;) { - if(ppp_priv_area->update_comms_stats == 0){ - break; - } - if (time_after(jiffies, timeout + 1 * HZ)){ - ppp_priv_area->update_comms_stats = 0; - ppp_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - - return 0; -} - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device *wandev, struct net_device *dev, - wanif_conf_t *conf) -{ - sdla_t *card = wandev->private; - ppp_private_area_t *ppp_priv_area; - - if (wandev->ndev) - return -EEXIST; - - - printk(KERN_INFO "%s: Configuring Interface: %s\n", - card->devname, conf->name); - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - - printk(KERN_INFO "%s: Invalid interface name!\n", - card->devname); - return -EINVAL; - - } - - /* allocate and initialize private data */ - ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); - - if( ppp_priv_area == NULL ) - return -ENOMEM; - - memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); - - ppp_priv_area->card = card; - - /* initialize data */ - strcpy(card->u.p.if_name, conf->name); - - /* initialize data in ppp_private_area structure */ - - init_ppp_priv_struct( ppp_priv_area ); - - ppp_priv_area->mc = conf->mc; - ppp_priv_area->pap = conf->pap; - ppp_priv_area->chap = conf->chap; - - /* Option to bring down the interface when - * the link goes down */ - if (conf->if_down){ - set_bit(DYN_OPT_ON,&ppp_priv_area->interface_down); - printk("%s: Dynamic interface configuration enabled\n", - card->devname); - } - - /* If no user ids are specified */ - if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){ - kfree(ppp_priv_area); - return -EINVAL; - } - - /* If no passwords are specified */ - if(!strlen(conf->passwd) && (ppp_priv_area->pap||ppp_priv_area->chap)){ - kfree(ppp_priv_area); - return -EINVAL; - } - - if(strlen(conf->sysname) > 31){ - kfree(ppp_priv_area); - return -EINVAL; - } - - /* If no system name is specified */ - if(!strlen(conf->sysname) && (card->u.p.authenticator)){ - kfree(ppp_priv_area); - return -EINVAL; - } - - /* copy the data into the ppp private structure */ - memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); - memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); - memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); - - - ppp_priv_area->enable_IPX = conf->enable_IPX; - if (conf->network_number){ - ppp_priv_area->network_number = conf->network_number; - }else{ - ppp_priv_area->network_number = 0xDEADBEEF; - } - - /* Tells us that if this interface is a - * gateway or not */ - if ((ppp_priv_area->gateway = conf->gateway) == WANOPT_YES){ - printk(KERN_INFO "%s: Interface %s is set as a gateway.\n", - card->devname,card->u.p.if_name); - } - - /* prepare network device data space for registration */ - strcpy(dev->name,card->u.p.if_name); - - dev->init = &if_init; - dev->priv = ppp_priv_area; - dev->mtu = min_t(unsigned int, dev->mtu, card->wandev.mtu); - - /* Initialize the polling work routine */ - INIT_WORK(&ppp_priv_area->poll_work, (void*)(void*)ppp_poll, dev); - - /* Initialize the polling delay timer */ - init_timer(&ppp_priv_area->poll_delay_timer); - ppp_priv_area->poll_delay_timer.data = (unsigned long)dev; - ppp_priv_area->poll_delay_timer.function = ppp_poll_delay; - - - /* Since we start with dummy IP addresses we can say - * that route exists */ - printk(KERN_INFO "\n"); - - return 0; -} - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device *wandev, struct net_device *dev) -{ - return 0; -} - -static void disable_comm (sdla_t *card) -{ - ppp_comm_disable_shutdown(card); - return; -} - -/****** WANPIPE-specific entry points ***************************************/ - -/*============================================================================ - * Execute adapter interface command. - */ - -//FIXME: Why do we need this ???? -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) -{ - ppp_mbox_t *mbox = card->mbox; - int len; - - if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) - return -EFAULT; - - len = mbox->cmd.length; - - if (len) { - - if( copy_from_user((void*)&mbox->data, u_data, len)) - return -EFAULT; - - } - - /* execute command */ - if (!sdla_exec(mbox)) - return -EIO; - - /* return result */ - if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t))) - return -EFAULT; - len = mbox->cmd.length; - - if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) - return -EFAULT; - - return 0; -} - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - struct wan_device *wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - /* Enable Mulitcasting if specified by user*/ - if (ppp_priv_area->mc == WANOPT_YES){ - dev->flags |= IFF_MULTICAST; - } - - dev->mtu = wandev->mtu; - dev->hard_header_len = PPP_HDR_LEN; /* media header length */ - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - SET_MODULE_OWNER(dev); - - return 0; -} - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - struct timeval tv; - //unsigned long smp_flags; - - if (netif_running(dev)) - return -EBUSY; - - wanpipe_open(card); - - netif_start_queue(dev); - - do_gettimeofday( &tv ); - ppp_priv_area->router_start_time = tv.tv_sec; - - /* We cannot configure the card here because we don't - * have access to the interface IP addresses. - * Once the interface initilization is complete, we will be - * able to access the IP addresses. Therefore, - * configure the ppp link in the poll routine */ - set_bit(0,&ppp_priv_area->config_ppp); - ppp_priv_area->config_wait_timeout=jiffies; - - /* Start the PPP configuration after 1sec delay. - * This will give the interface initilization time - * to finish its configuration */ - mod_timer(&ppp_priv_area->poll_delay_timer, jiffies + HZ); - return 0; -} - -/*============================================================================ - * Close network interface. - * o if this is the last open, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - - netif_stop_queue(dev); - wanpipe_close(card); - - del_timer (&ppp_priv_area->poll_delay_timer); - return 0; -} - -/*============================================================================ - * Build media header. - * - * The trick here is to put packet type (Ethertype) into 'protocol' field of - * the socket buffer, so that we don't forget it. If packet type is not - * supported, set skb->protocol to 0 and discard packet later. - * - * Return: media header length. - */ -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - switch (type) - { - case ETH_P_IP: - case ETH_P_IPX: - skb->protocol = htons(type); - break; - - default: - skb->protocol = 0; - } - - return PPP_HDR_LEN; -} - -/*============================================================================ - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - */ -static int if_rebuild_hdr (struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - ppp_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++ chan->if_send_stat.if_send_tbusy; - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - ++chan->if_send_stat.if_send_tbusy_timeout; - netif_wake_queue (dev); -} - - - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ -static int if_send (struct sk_buff *skb, struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card = ppp_priv_area->card; - unsigned char *sendpacket; - unsigned long smp_flags; - ppp_flags_t *flags = card->flags; - int udp_type; - int err=0; - - ++ppp_priv_area->if_send_stat.if_send_entry; - - netif_stop_queue(dev); - - if (skb == NULL) { - - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - - ++ppp_priv_area->if_send_stat.if_send_skb_null; - - netif_wake_queue(dev); - return 0; - } - - sendpacket = skb->data; - - udp_type = udp_pkt_type( skb, card ); - - - if (udp_type == UDP_PTPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - ppp_priv_area)){ - flags->imask |= PPP_INTR_TIMER; - } - ++ppp_priv_area->if_send_stat.if_send_PIPE_request; - netif_start_queue(dev); - return 0; - } - - /* Check for broadcast and multicast addresses - * If found, drop (deallocate) a packet and return. - */ - if(chk_bcast_mcast_addr(card, dev, skb)){ - ++card->wandev.stats.tx_dropped; - dev_kfree_skb_any(skb); - netif_start_queue(dev); - return 0; - } - - - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - - ++card->wandev.stats.tx_dropped; - ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; - netif_start_queue(dev); - goto if_send_exit_crit; - } - - if (card->wandev.state != WAN_CONNECTED) { - - ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - - } else if (!skb->protocol) { - ++ppp_priv_area->if_send_stat.if_send_protocol_error; - ++card->wandev.stats.tx_errors; - netif_start_queue(dev); - - } else { - - /*If it's IPX change the network numbers to 0 if they're ours.*/ - if( skb->protocol == htons(ETH_P_IPX) ) { - if(ppp_priv_area->enable_IPX) { - switch_net_numbers( skb->data, - ppp_priv_area->network_number, 0); - } else { - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_exit_crit; - } - } - - if (ppp_send(card, skb->data, skb->len, skb->protocol)) { - netif_stop_queue(dev); - ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; - ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; - } else { - ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; - netif_start_queue(dev); - dev->trans_start = jiffies; - } - } - -if_send_exit_crit: - - if (!(err=netif_queue_stopped(dev))){ - dev_kfree_skb_any(skb); - }else{ - ppp_priv_area->tick_counter = jiffies; - flags->imask |= PPP_INTR_TXRDY; /* unmask Tx interrupts */ - } - - clear_bit(SEND_CRIT,&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - ppp_private_area_t* ppp_priv_area ) -{ - int udp_pkt_stored = 0; - - if(!ppp_priv_area->udp_pkt_lgth && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){ - ppp_priv_area->udp_pkt_lgth = skb->len; - ppp_priv_area->udp_pkt_src = udp_pkt_src; - memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len); - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP; - ppp_priv_area->protocol = skb->protocol; - udp_pkt_stored = 1; - }else{ - if (skb->len > MAX_LGTH_UDP_MGNT_PKT){ - printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n", - card->devname, skb->len); - }else{ - printk(KERN_INFO "%s: PIPEMON UPD request already pending\n", - card->devname); - } - ppp_priv_area->udp_pkt_lgth = 0; - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - ppp_udp_pkt_t *p_udp_pkt = (ppp_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - /* fill in UDP reply */ - p_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound=1; - } - - temp = (udp_length<<8)|(udp_length>>8); - p_udp_pkt->udp_pkt.udp_length = temp; - - - /* swap UDP ports */ - temp = p_udp_pkt->udp_pkt.udp_src_port; - p_udp_pkt->udp_pkt.udp_src_port = - p_udp_pkt->udp_pkt.udp_dst_port; - p_udp_pkt->udp_pkt.udp_dst_port = temp; - - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - /* calculate UDP checksum */ - p_udp_pkt->udp_pkt.udp_checksum = 0; - p_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = udp_length + sizeof(ip_pkt_t); - temp = (ip_length<<8)|(ip_length>>8); - p_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = p_udp_pkt->ip_pkt.ip_src_address; - p_udp_pkt->ip_pkt.ip_src_address = p_udp_pkt->ip_pkt.ip_dst_address; - p_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - p_udp_pkt->ip_pkt.hdr_checksum = 0; - p_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); - - return len; - -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - -/* - If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - if incoming is 1 - if the net number is 0 make it ours - -*/ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); - - if (!incoming) { - //If the destination network number is ours, make it 0 - if( pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; - } - } else { - //If the incoming network is 0, make it ours - if( pnetwork_number == 0) { - sendpacket[6] = (unsigned char)(network_number >> 24); - sendpacket[7] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - - if( !incoming ) { - //If the source network is ours, make it 0 - if( pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; - } - } else { - //If the source network is 0, make it ours - if( pnetwork_number == 0 ) { - sendpacket[18] = (unsigned char)(network_number >> 24); - sendpacket[19] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. - */ -static struct net_device_stats *if_stats(struct net_device *dev) -{ - - ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t* card; - - if( ppp_priv_area == NULL ) - return NULL; - - card = ppp_priv_area->card; - return &card->wandev.stats; -} - -/****** PPP Firmware Interface Functions ************************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int ppp_read_version(sdla_t *card, char *str) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - - ppp_error(card, err, mb); - - else if (str) { - - int len = mb->cmd.length; - - memcpy(str, mb->data, len); - str[len] = '\0'; - - } - - return err; -} -/*=========================================================================== - * Set Out-Bound Authentication. -*/ -static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + - strlen(ppp_priv_area->passwd) + 2 ) ); - memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid)); - memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), - ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); - - mb->cmd.length = strlen(ppp_priv_area->userid) + - strlen(ppp_priv_area->passwd) + 2 ; - - mb->cmd.command = PPP_SET_OUTBOUND_AUTH; - - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - return err; -} - -/*=========================================================================== - * Set In-Bound Authentication. -*/ -static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) -{ - ppp_mbox_t *mb = card->mbox; - int err, i; - char* user_tokens[32]; - char* pass_tokens[32]; - int userids, passwds; - int add_ptr; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memset(&mb->data, 0, 1008); - memcpy(mb->data, ppp_priv_area->sysname, - strlen(ppp_priv_area->sysname)); - - /* Parse the userid string and the password string and build a string - to copy it to the data area of the command structure. The string - will look like "SYS_NAMEUSER1PASS1USER2PASS2 - .... " - */ - userids = tokenize( ppp_priv_area->userid, user_tokens); - passwds = tokenize( ppp_priv_area->passwd, pass_tokens); - - if (userids != passwds){ - printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname); - return 1; - } - - add_ptr = strlen(ppp_priv_area->sysname) + 1; - for (i=0; idata + add_ptr), user_tokens[i], - strlen(user_tokens[i])); - memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), - pass_tokens[i], strlen(pass_tokens[i])); - add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + - strlen(pass_tokens[i]) + 1; - } - - mb->cmd.length = add_ptr + 1; - mb->cmd.command = PPP_SET_INBOUND_AUTH; - - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - return err; -} - - -/*============================================================================ - * Tokenize string. - * Parse a string of the following syntax: - * ,,... - * and fill array of tokens with pointers to string elements. - * - */ -static int tokenize (char *str, char **tokens) -{ - int cnt = 0; - - tokens[0] = strsep(&str, "/"); - while (tokens[cnt] && (cnt < 32 - 1)) - { - tokens[cnt] = strstrip(tokens[cnt], " \t"); - tokens[++cnt] = strsep(&str, "/"); - } - return cnt; -} - -/*============================================================================ - * Strip leading and trailing spaces off the string str. - */ -static char* strstrip (char *str, char* s) -{ - char *eos = str + strlen(str); /* -> end of string */ - - while (*str && strchr(s, *str)) - ++str /* strip leading spaces */ - ; - while ((eos > str) && strchr(s, *(eos - 1))) - --eos /* strip trailing spaces */ - ; - *eos = '\0'; - return str; -} -/*============================================================================ - * Configure PPP firmware. - */ -static int ppp_configure(sdla_t *card, void *data) -{ - ppp_mbox_t *mb = card->mbox; - int data_len = sizeof(ppp508_conf_t); - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - memcpy(mb->data, data, data_len); - mb->cmd.length = data_len; - mb->cmd.command = PPP_SET_CONFIG; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - return err; -} - -/*============================================================================ - * Set interrupt mode. - */ -static int ppp_set_intr_mode(sdla_t *card, unsigned char mode) -{ - ppp_mbox_t *mb = card->mbox; - ppp_intr_info_t *ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - ppp_intr_data->i_enable = mode; - - ppp_intr_data->irq = card->hw.irq; - mb->cmd.length = 2; - - /* If timer has been enabled, set the timer delay to 1sec */ - if (mode & 0x80){ - ppp_intr_data->timer_len = 250; //5;//100; //250; - mb->cmd.length = 4; - } - - mb->cmd.command = PPP_SET_INTR_FLAGS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - - - return err; -} - -/*============================================================================ - * Enable communications. - */ -static int ppp_comm_enable(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_ENABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) - ppp_error(card, err, mb); - else - card->u.p.comm_enabled = 1; - - return err; -} - -/*============================================================================ - * Disable communications. - */ -static int ppp_comm_disable(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_DISABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - else - card->u.p.comm_enabled = 0; - - return err; -} - -static int ppp_comm_disable_shutdown(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - ppp_intr_info_t *ppp_intr_data; - int err; - - if (!mb){ - return 1; - } - - ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; - - /* Disable all interrupts */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - ppp_intr_data->i_enable = 0; - - ppp_intr_data->irq = card->hw.irq; - mb->cmd.length = 2; - - mb->cmd.command = PPP_SET_INTR_FLAGS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - /* Disable communicatinons */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_COMM_DISABLE; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - card->u.p.comm_enabled = 0; - - return 0; -} - - - -/*============================================================================ - * Get communications error statistics. - */ -static int ppp_get_err_stats(sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.command = PPP_READ_ERROR_STATS; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err == CMD_OK) { - - ppp_err_stats_t* stats = (void*)mb->data; - card->wandev.stats.rx_over_errors = stats->rx_overrun; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_abort; - card->wandev.stats.rx_length_errors = stats->rx_lost; - card->wandev.stats.tx_aborted_errors = stats->tx_abort; - - } else - ppp_error(card, err, mb); - - return err; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ -static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto) -{ - ppp_buf_ctl_t *txbuf = card->u.p.txbuf; - - if (txbuf->flag) - return 1; - - sdla_poke(&card->hw, txbuf->buf.ptr, data, len); - - txbuf->length = len; /* frame length */ - - if (proto == htons(ETH_P_IPX)) - txbuf->proto = 0x01; /* protocol ID */ - else - txbuf->proto = 0x00; /* protocol ID */ - - txbuf->flag = 1; /* start transmission */ - - /* Update transmit buffer control fields */ - card->u.p.txbuf = ++txbuf; - - if ((void*)txbuf > card->u.p.txbuf_last) - card->u.p.txbuf = card->u.p.txbuf_base; - - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb) -{ - unsigned cmd = mb->cmd.command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - , card->devname, cmd, err); - } - - return 0; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * PPP interrupt service routine. - */ -static void wpp_isr (sdla_t *card) -{ - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - struct net_device *dev = card->wandev.dev; - int i; - - card->in_isr = 1; - ++card->statistics.isr_entry; - - if (!dev && flags->iflag != PPP_INTR_CMD){ - card->in_isr = 0; - flags->iflag = 0; - return; - } - - if (test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - card->in_isr = 0; - flags->iflag = 0; - return; - } - - - if(card->hw.type != SDLA_S514){ - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { - ++card->statistics.isr_already_critical; - printk (KERN_INFO "%s: Critical while in ISR!\n", - card->devname); - card->in_isr = 0; - flags->iflag = 0; - return; - } - } - - switch (flags->iflag) { - - case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/ - ++card->statistics.isr_rx; - rx_intr(card); - break; - - case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/ - ++card->statistics.isr_tx; - flags->imask &= ~PPP_INTR_TXRDY; - netif_wake_queue(dev); - break; - - case PPP_INTR_CMD: /* interface command completed */ - ++Intr_test_counter; - ++card->statistics.isr_intr_test; - break; - - case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ - case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ - case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ - case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ - event_intr(card); - break; - - case PPP_INTR_TIMER: - timer_intr(card); - break; - - default: /* unexpected interrupt */ - ++card->statistics.isr_spurious; - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - } - - card->in_isr = 0; - flags->iflag = 0; - return; -} - -/*============================================================================ - * Receive interrupt handler. - */ -static void rx_intr(sdla_t *card) -{ - ppp_buf_ctl_t *rxbuf = card->rxmb; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area; - struct sk_buff *skb; - unsigned len; - void *buf; - int i; - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; - int udp_type; - - - if (rxbuf->flag != 0x01) { - - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)rxbuf, rxbuf->flag); - - printk(KERN_INFO "%s: ID Bytes = ",card->devname); - - for(i = 0; i < 8; i ++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - - ++card->statistics.rx_intr_corrupt_rx_bfr; - - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it means that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - ppp_set_intr_mode(card,0); - return; - } - - if (dev && netif_running(dev) && dev->priv){ - - len = rxbuf->length; - ppp_priv_area = dev->priv; - - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - - if (skb != NULL) { - - /* Copy data to the socket buffer */ - unsigned addr = rxbuf->buf.ptr; - - if ((addr + len) > card->u.p.rx_top + 1) { - - unsigned tmp = card->u.p.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.p.rx_base; - len -= tmp; - } - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - - /* Decapsulate packet */ - switch (rxbuf->proto) { - - case 0x00: - skb->protocol = htons(ETH_P_IP); - break; - - case 0x01: - skb->protocol = htons(ETH_P_IPX); - break; - } - - udp_type = udp_pkt_type( skb, card ); - - if (udp_type == UDP_PTPIPE_TYPE){ - - /* Handle a UDP Request in Timer Interrupt */ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, - ppp_priv_area)){ - flags->imask |= PPP_INTR_TIMER; - } - ++ppp_priv_area->rx_intr_stat.rx_intr_PIPE_request; - - - } else if (handle_IPXWAN(skb->data,card->devname, - ppp_priv_area->enable_IPX, - ppp_priv_area->network_number, - skb->protocol)) { - - /* Handle an IPXWAN packet */ - if( ppp_priv_area->enable_IPX) { - - /* Make sure we are not already sending */ - if (!test_bit(SEND_CRIT, &card->wandev.critical)){ - ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); - } - dev_kfree_skb_any(skb); - - } else { - ++card->wandev.stats.rx_dropped; - } - } else { - /* Pass data up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - - ++card->wandev.stats.rx_packets; - card->wandev.stats.rx_bytes += skb->len; - ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; - netif_rx(skb); - dev->last_rx = jiffies; - } - - } else { - - if (net_ratelimit()){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - ++card->wandev.stats.rx_dropped; - ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; - } - - } else { - ++card->statistics.rx_intr_dev_not_started; - } - - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->flag = 0x00; - card->rxmb = ++rxbuf; - if ((void*)rxbuf > card->u.p.rxbuf_last) - card->rxmb = card->u.p.rxbuf_base; -} - - -void event_intr (sdla_t *card) -{ - - struct net_device* dev = card->wandev.dev; - ppp_private_area_t* ppp_priv_area = dev->priv; - volatile ppp_flags_t *flags = card->flags; - - switch (flags->iflag){ - - case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ - - if (net_ratelimit()){ - printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", - card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); - } - break; - - case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ - - NEX_PRINTK (KERN_INFO "Data link disconnected intr Cause %X\n", - flags->disc_cause); - - if (flags->disc_cause & - (PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP | - PPP_REMOTE_TERMINATION)) { - - if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - set_bit(0,&Read_connection_info); - } - wanpipe_set_state(card, WAN_DISCONNECTED); - - show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - trigger_ppp_poll(dev); - } - break; - - case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ - - NEX_PRINTK (KERN_INFO "%s: PPP Link Open, LCP=%s IP=%s\n", - card->devname,LCP(flags->lcp_state), - IP(flags->ip_state)); - - if (flags->lcp_state == 0x09 && - (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){ - - /* Initialize the polling timer and set the state - * to WAN_CONNNECTED */ - - - /* BUG FIX: When the protocol restarts, during heavy - * traffic, board tx buffers and driver tx buffers - * can go out of sync. This checks the condition - * and if the tx buffers are out of sync, the - * protocols are restarted. - * I don't know why the board tx buffer is out - * of sync. It could be that a packets is tx - * while the link is down, but that is not - * possible. The other possiblility is that the - * firmware doesn't reinitialize properly. - * FIXME: A better fix should be found. - */ - if (detect_and_fix_tx_bug(card)){ - - ppp_comm_disable(card); - - wanpipe_set_state(card, WAN_DISCONNECTED); - - ppp_priv_area->timer_int_enabled |= - TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - break; - } - - card->state_tick = jiffies; - wanpipe_set_state(card, WAN_CONNECTED); - - NEX_PRINTK(KERN_INFO "CON: L Tx: %lx B Tx: %lx || L Rx %lx B Rx %lx\n", - (unsigned long)card->u.p.txbuf, *card->u.p.txbuf_next, - (unsigned long)card->rxmb, *card->u.p.rxbuf_next); - - /* Tell timer interrupt that PPP event occurred */ - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - - /* If we are in PEER mode, we must first obtain the - * IP information and then go into the poll routine */ - if (card->u.p.ip_mode != WANOPT_PPP_PEER){ - trigger_ppp_poll(dev); - } - } - break; - - case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ - - NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); - - if (card->u.p.ip_mode == WANOPT_PPP_PEER) { - set_bit(0,&Read_connection_info); - } - - wanpipe_set_state(card, WAN_DISCONNECTED); - - show_disc_cause(card, flags->disc_cause); - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_PPP_EVENT; - flags->imask |= PPP_INTR_TIMER; - trigger_ppp_poll(dev); - break; - - default: - printk(KERN_INFO "%s: Error, Invalid PPP Event\n",card->devname); - } -} - - - -/* TIMER INTERRUPT */ - -void timer_intr (sdla_t *card) -{ - - struct net_device* dev = card->wandev.dev; - ppp_private_area_t* ppp_priv_area = dev->priv; - ppp_flags_t *flags = card->flags; - - - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG){ - if (!config_ppp(card)){ - ppp_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_CONFIG; - } - } - - /* Update statistics */ - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ - ppp_get_err_stats(card); - if(!(--ppp_priv_area->update_comms_stats)){ - ppp_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - } - } - - /* PPIPEMON UDP request */ - - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP){ - process_udp_mgmt_pkt(card,dev, ppp_priv_area); - ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; - } - - /* PPP Event */ - if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){ - - if (card->wandev.state == WAN_DISCONNECTED){ - retrigger_comm(card); - } - - /* If the state is CONNECTING, it means that communicatins were - * enabled. When the remote side enables its comminication we - * should get an interrupt PPP_INTR_OPEN, thus turn off polling - */ - - else if (card->wandev.state == WAN_CONNECTING){ - /* Turn off the timer interrupt */ - ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; - } - - /* If state is connected and we are in PEER mode - * poll for an IP address which will be provided by remote end. - */ - else if ((card->wandev.state == WAN_CONNECTED && - card->u.p.ip_mode == WANOPT_PPP_PEER) && - test_bit(0,&Read_connection_info)){ - - card->state_tick = jiffies; - if (read_connection_info (card)){ - printk(KERN_INFO "%s: Failed to read PEER IP Addresses\n", - card->devname); - }else{ - clear_bit(0,&Read_connection_info); - set_bit(1,&Read_connection_info); - trigger_ppp_poll(dev); - } - }else{ - //FIXME Put the comment back int - ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; - } - - }/* End of PPP_EVENT */ - - - /* Only disable the timer interrupt if there are no udp, statistic */ - /* updates or events pending */ - if(!ppp_priv_area->timer_int_enabled) { - flags->imask &= ~PPP_INTR_TIMER; - } -} - - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) -{ - int i; - - if( proto == htons(ETH_P_IPX) ) { - //It's an IPX packet - if(!enable_IPX) { - //Return 1 so we don't pass it up the stack. - return 1; - } - } else { - //It's not IPX so pass it up the stack. - return 0; - } - - if( sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) - { - //It's IPXWAN - - if( sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) - { - //It's a timer request packet - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); - - //Go through the routing options and answer no to every - //option except Unnumbered RIP/SAP - for(i = 41; sendpacket[i] == 0x00; i += 5) - { - //0x02 is the option for Unnumbered RIP/SAP - if( sendpacket[i + 4] != 0x02) - { - sendpacket[i + 1] = 0; - } - } - - //Skip over the extended Node ID option - if( sendpacket[i] == 0x04 ) - { - i += 8; - } - - //We also want to turn off all header compression opt. - for(; sendpacket[i] == 0x80 ;) - { - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - //Set the packet type to timer response - sendpacket[34] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); - } - else if( sendpacket[34] == 0x02 ) - { - //This is an information request packet - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); - - //Set the packet type to information response - sendpacket[34] = 0x03; - - //Set the router name - sendpacket[51] = 'P'; - sendpacket[52] = 'T'; - sendpacket[53] = 'P'; - sendpacket[54] = 'I'; - sendpacket[55] = 'P'; - sendpacket[56] = 'E'; - sendpacket[57] = '-'; - sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for(i = 66; i < 99; i+= 1) - { - sendpacket[i] = 0; - } - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); - } - else - { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - //Set the WNodeID to our network address - sendpacket[35] = (unsigned char)(network_number >> 24); - sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } else { - //If we get here it's an IPX-data packet, so it'll get passed up the stack. - - //switch the network numbers - switch_net_numbers(sendpacket, network_number, 1); - return 0; - } -} - -/****** Background Polling Routines ****************************************/ - -/* All polling functions are invoked by the TIMER interrupt in the wpp_isr - * routine. - */ - -/*============================================================================ - * Monitor active link phase. - */ -static void process_route (sdla_t *card) -{ - ppp_flags_t *flags = card->flags; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - - if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && - (flags->ip_state == 0x09)){ - - /* We get ip_local from the firmware in PEER mode. - * Therefore, if ip_local is 0, we failed to obtain - * the remote IP address. */ - if (ppp_priv_area->ip_local == 0) - return; - - printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); - if (read_info( card )) { - printk(KERN_INFO - "%s: An error occurred in IP assignment.\n", - card->devname); - } else { - struct in_device *in_dev = dev->ip_ptr; - if (in_dev != NULL ) { - struct in_ifaddr *ifa = in_dev->ifa_list; - - printk(KERN_INFO "%s: Assigned Lcl. Addr: %u.%u.%u.%u\n", - card->devname, NIPQUAD(ifa->ifa_local)); - printk(KERN_INFO "%s: Assigned Rmt. Addr: %u.%u.%u.%u\n", - card->devname, NIPQUAD(ifa->ifa_address)); - }else{ - printk(KERN_INFO - "%s: Error: Failed to add a route for PPP interface %s\n", - card->devname,dev->name); - } - } - } -} - -/*============================================================================ - * Monitor physical link disconnected phase. - * o if interface is up and the hold-down timeout has expired, then retry - * connection. - */ -static void retrigger_comm(sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - - if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { - - wanpipe_set_state(card, WAN_CONNECTING); - - if(ppp_comm_enable(card) == CMD_OK){ - init_ppp_tx_rx_buff( card ); - } - } -} - -/****** Miscellaneous Functions *********************************************/ - -/*============================================================================ - * Configure S508 adapter. - */ -static int config508(struct net_device *dev, sdla_t *card) -{ - ppp508_conf_t cfg; - struct in_device *in_dev = dev->ip_ptr; - ppp_private_area_t *ppp_priv_area = dev->priv; - - /* Prepare PPP configuration structure */ - memset(&cfg, 0, sizeof(ppp508_conf_t)); - - if (card->wandev.clocking) - cfg.line_speed = card->wandev.bps; - - if (card->wandev.interface == WANOPT_RS232) - cfg.conf_flags |= INTERFACE_LEVEL_RS232; - - - cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/ - cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */ - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; /* Default */ - cfg.restart_tmr = TIME_BETWEEN_CONF_REQ; /* 30 = 3sec */ - cfg.auth_rsrt_tmr = TIME_BETWEEN_PAP_CHAP_REQ; /* 30 = 3sec */ - cfg.auth_wait_tmr = WAIT_PAP_CHAP_WITHOUT_REPLY; /* 300 = 30s */ - cfg.mdm_fail_tmr = WAIT_AFTER_DCD_CTS_LOW; /* 5 = 0.5s */ - cfg.dtr_drop_tmr = TIME_DCD_CTS_LOW_AFTER_LNK_DOWN; /* 10 = 1s */ - cfg.connect_tmout = WAIT_DCD_HIGH_AFTER_ENABLE_COMM; /* 900 = 90s */ - cfg.conf_retry = MAX_CONF_REQ_WITHOUT_REPLY; /* 10 = 1s */ - cfg.term_retry = MAX_TERM_REQ_WITHOUT_REPLY; /* 2 times */ - cfg.fail_retry = NUM_CONF_NAK_WITHOUT_REPLY; /* 5 times */ - cfg.auth_retry = NUM_AUTH_REQ_WITHOUT_REPLY; /* 10 times */ - - - if( !card->u.p.authenticator ) { - printk(KERN_INFO "%s: Device is not configured as an authenticator\n", - card->devname); - cfg.auth_options = NO_AUTHENTICATION; - }else{ - printk(KERN_INFO "%s: Device is configured as an authenticator\n", - card->devname); - cfg.auth_options = INBOUND_AUTH; - } - - if( ppp_priv_area->pap == WANOPT_YES){ - cfg.auth_options |=PAP_AUTH; - printk(KERN_INFO "%s: Pap enabled\n", card->devname); - } - if( ppp_priv_area->chap == WANOPT_YES){ - cfg.auth_options |= CHAP_AUTH; - printk(KERN_INFO "%s: Chap enabled\n", card->devname); - } - - - if (ppp_priv_area->enable_IPX == WANOPT_YES){ - printk(KERN_INFO "%s: Enabling IPX Protocol\n",card->devname); - cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT; - }else{ - cfg.ipx_options = DISABLE_IPX; - } - - switch (card->u.p.ip_mode) { - - case WANOPT_PPP_STATIC: - - printk(KERN_INFO "%s: PPP IP Mode: STATIC\n",card->devname); - cfg.ip_options = L_AND_R_IP_NO_ASSIG | - ENABLE_IP; - cfg.ip_local = in_dev->ifa_list->ifa_local; - cfg.ip_remote = in_dev->ifa_list->ifa_address; - /* Debugging code used to check that IP addresses - * obtained from the kernel are correct */ - - NEX_PRINTK(KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", - NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); - break; - - case WANOPT_PPP_HOST: - - printk(KERN_INFO "%s: PPP IP Mode: HOST\n",card->devname); - cfg.ip_options = L_IP_LOCAL_ASSIG | - R_IP_LOCAL_ASSIG | - ENABLE_IP; - cfg.ip_local = in_dev->ifa_list->ifa_local; - cfg.ip_remote = in_dev->ifa_list->ifa_address; - /* Debugging code used to check that IP addresses - * obtained from the kernel are correct */ - NEX_PRINTK (KERN_INFO "Local %u.%u.%u.%u Remote %u.%u.%u.%u Name %s\n", - NIPQUAD(ip_local),NIPQUAD(ip_remote), dev->name); - - break; - - case WANOPT_PPP_PEER: - - printk(KERN_INFO "%s: PPP IP Mode: PEER\n",card->devname); - cfg.ip_options = L_IP_REMOTE_ASSIG | - R_IP_REMOTE_ASSIG | - ENABLE_IP; - cfg.ip_local = 0x00; - cfg.ip_remote = 0x00; - break; - - default: - printk(KERN_INFO "%s: ERROR: Unsupported PPP Mode Selected\n", - card->devname); - printk(KERN_INFO "%s: PPP IP Modes: STATIC, PEER or HOST\n", - card->devname); - return 1; - } - - return ppp_configure(card, &cfg); -} - -/*============================================================================ - * Show disconnection cause. - */ -static void show_disc_cause(sdla_t *card, unsigned cause) -{ - if (cause & 0x0802) - - printk(KERN_INFO "%s: link terminated by peer\n", - card->devname); - - else if (cause & 0x0004) - - printk(KERN_INFO "%s: link terminated by user\n", - card->devname); - - else if (cause & 0x0008) - - printk(KERN_INFO "%s: authentication failed\n", card->devname); - - else if (cause & 0x0010) - - printk(KERN_INFO - "%s: authentication protocol negotiation failed\n", - card->devname); - - else if (cause & 0x0020) - - printk(KERN_INFO - "%s: peer's request for authentication rejected\n", - card->devname); - - else if (cause & 0x0040) - - printk(KERN_INFO "%s: MRU option rejected by peer\n", - card->devname); - - else if (cause & 0x0080) - - printk(KERN_INFO "%s: peer's MRU was too small\n", - card->devname); - - else if (cause & 0x0100) - - printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", - card->devname); - - else if (cause & 0x0200) - - printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" - , card->devname); - - else if (cause & 0x0400) - - printk(KERN_INFO - "%s: failed to negotiate peer's IPXCP options\n", - card->devname); -} - -/*============================================================================= - * Process UDP call of type PTPIPEAB. - */ -static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, - ppp_private_area_t *ppp_priv_area ) -{ - unsigned char buf2[5]; - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short data_length, buffer_length, real_len; - unsigned long data_ptr; - int udp_mgmt_req_valid = 1; - ppp_mbox_t *mbox = card->mbox; - struct timeval tv; - int err; - ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t*)&ppp_priv_area->udp_pkt_data; - - memcpy(&buf2, &card->wandev.udp_port, 2 ); - - - if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - switch(ppp_udp_pkt->cblock.command) { - - case PPIPE_GET_IBA_DATA: - case PPP_READ_CONFIG: - case PPP_GET_CONNECTION_INFO: - case PPIPE_ROUTER_UP_TIME: - case PPP_READ_STATISTICS: - case PPP_READ_ERROR_STATS: - case PPP_READ_PACKET_STATS: - case PPP_READ_LCP_STATS: - case PPP_READ_IPCP_STATS: - case PPP_READ_IPXCP_STATS: - case PPP_READ_PAP_STATS: - case PPP_READ_CHAP_STATS: - case PPP_READ_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - - /* set length to 0 */ - ppp_udp_pkt->cblock.length = 0x00; - - /* set return code */ - ppp_udp_pkt->cblock.result = 0xCD; - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,ppp_udp_pkt->cblock.command); - } - } else { - /* Initialize the trace element */ - trace_element_t trace_element; - - switch (ppp_udp_pkt->cblock.command){ - - /* PPIPE_ENABLE_TRACING */ - case PPIPE_ENABLE_TRACING: - if (!card->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = PPP_DATALINE_MONITOR; - mbox->cmd.length = 0x01; - mbox->data[0] = ppp_udp_pkt->data[0]; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) { - - ppp_error(card, err, mbox); - card->TracingEnabled = 0; - - /* set the return code */ - - ppp_udp_pkt->cblock.result = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - - sdla_peek(&card->hw, 0xC000, &buf2, 2); - - ppp_priv_area->curr_trace_addr = 0; - memcpy(&ppp_priv_area->curr_trace_addr, &buf2, 2); - ppp_priv_area->start_trace_addr = - ppp_priv_area->curr_trace_addr; - ppp_priv_area->end_trace_addr = - ppp_priv_area->start_trace_addr + END_OFFSET; - - /* MAX_SEND_BUFFER_SIZE - 28 (IP header) - - 32 (ppipemon CBLOCK) */ - available_buffer_space = MAX_LGTH_UDP_MGNT_PKT - - sizeof(ip_pkt_t)- - sizeof(udp_pkt_t)- - sizeof(wp_mgmt_t)- - sizeof(cblock_t); - } - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 0; - card->TracingEnabled = 1; - break; - - /* PPIPE_DISABLE_TRACING */ - case PPIPE_DISABLE_TRACING: - - if(card->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x33; - mbox->cmd.length = 1; - mbox->data[0] = 0x00; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - - } - - /*set return code*/ - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 0; - card->TracingEnabled = 0; - break; - - /* PPIPE_GET_TRACE_INFO */ - case PPIPE_GET_TRACE_INFO: - - if(!card->TracingEnabled) { - /* set return code */ - ppp_udp_pkt->cblock.result = 1; - mbox->cmd.length = 0; - } - - buffer_length = 0; - - /* frames < 62, where 62 is the number of trace - information elements. There is in total 496 - bytes of space and each trace information - element is 8 bytes. - */ - for ( frames=0; frames<62; frames++) { - - trace_pkt_t *trace_pkt = (trace_pkt_t *) - &ppp_udp_pkt->data[buffer_length]; - - /* Read the whole trace packet */ - sdla_peek(&card->hw, ppp_priv_area->curr_trace_addr, - &trace_element, sizeof(trace_element_t)); - - /* no data on board so exit */ - if( trace_element.opp_flag == 0x00 ) - break; - - data_ptr = trace_element.trace_data_ptr; - - /* See if there is actual data on the trace buffer */ - if (data_ptr){ - data_length = trace_element.trace_length; - }else{ - data_length = 0; - ppp_udp_pkt->data[0] |= 0x02; - } - - //FIXME: Do we need this check - if ((available_buffer_space - buffer_length) - < (sizeof(trace_element_t)+1)){ - - /*indicate we have more frames - * on board and exit - */ - ppp_udp_pkt->data[0] |= 0x02; - break; - } - - trace_pkt->status = trace_element.trace_type; - trace_pkt->time_stamp = trace_element.trace_time_stamp; - trace_pkt->real_length = trace_element.trace_length; - - real_len = trace_element.trace_length; - - if(data_ptr == 0){ - trace_pkt->data_avail = 0x00; - }else{ - /* we can take it next time */ - if ((available_buffer_space - buffer_length)< - (real_len + sizeof(trace_pkt_t))){ - - ppp_udp_pkt->data[0] |= 0x02; - break; - } - trace_pkt->data_avail = 0x01; - - /* get the data */ - sdla_peek(&card->hw, data_ptr, - &trace_pkt->data, - real_len); - } - /* zero the opp flag to - show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, ppp_priv_area->curr_trace_addr, - &buf2, 1); - - /* now move onto the next - frame */ - ppp_priv_area->curr_trace_addr += 8; - - /* check if we passed the last address */ - if ( ppp_priv_area->curr_trace_addr >= - ppp_priv_area->end_trace_addr){ - - ppp_priv_area->curr_trace_addr = - ppp_priv_area->start_trace_addr; - } - - /* update buffer length and make sure its even */ - - if ( trace_pkt->data_avail == 0x01 ) { - buffer_length += real_len - 1; - } - - /* for the header */ - buffer_length += 8; - - if( buffer_length & 0x0001 ) - buffer_length += 1; - } - - /* ok now set the total number of frames passed - in the high 5 bits */ - ppp_udp_pkt->data[0] |= (frames << 2); - - /* set the data length */ - mbox->cmd.length = buffer_length; - ppp_udp_pkt->cblock.length = buffer_length; - - /* set return code */ - ppp_udp_pkt->cblock.result = 0; - break; - - /* PPIPE_GET_IBA_DATA */ - case PPIPE_GET_IBA_DATA: - - mbox->cmd.length = 0x09; - - sdla_peek(&card->hw, 0xF003, &ppp_udp_pkt->data, - mbox->cmd.length); - - /* set the length of the data */ - ppp_udp_pkt->cblock.length = 0x09; - - /* set return code */ - ppp_udp_pkt->cblock.result = 0x00; - ppp_udp_pkt->cblock.result = 0; - break; - - /* PPIPE_FT1_READ_STATUS */ - case PPIPE_FT1_READ_STATUS: - sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data[0], 2); - ppp_udp_pkt->cblock.length = mbox->cmd.length = 2; - ppp_udp_pkt->cblock.result = 0; - break; - - case PPIPE_FLUSH_DRIVER_STATS: - init_ppp_priv_struct( ppp_priv_area ); - init_global_statistics( card ); - mbox->cmd.length = 0; - ppp_udp_pkt->cblock.result = 0; - break; - - - case PPIPE_ROUTER_UP_TIME: - - do_gettimeofday( &tv ); - ppp_priv_area->router_up_time = tv.tv_sec - - ppp_priv_area->router_start_time; - *(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time; - mbox->cmd.length = 4; - ppp_udp_pkt->cblock.result = 0; - break; - - /* PPIPE_DRIVER_STATISTICS */ - case PPIPE_DRIVER_STAT_IFSEND: - memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, - sizeof(if_send_stat_t)); - - - ppp_udp_pkt->cblock.result = 0; - ppp_udp_pkt->cblock.length = sizeof(if_send_stat_t); - mbox->cmd.length = sizeof(if_send_stat_t); - break; - - case PPIPE_DRIVER_STAT_INTR: - memcpy(&ppp_udp_pkt->data, &card->statistics, - sizeof(global_stats_t)); - - memcpy(&ppp_udp_pkt->data+sizeof(global_stats_t), - &ppp_priv_area->rx_intr_stat, - sizeof(rx_intr_stat_t)); - - ppp_udp_pkt->cblock.result = 0; - ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - mbox->cmd.length = ppp_udp_pkt->cblock.length; - break; - - case PPIPE_DRIVER_STAT_GEN: - memcpy( &ppp_udp_pkt->data, - &ppp_priv_area->pipe_mgmt_stat, - sizeof(pipe_mgmt_stat_t)); - - memcpy(&ppp_udp_pkt->data+sizeof(pipe_mgmt_stat_t), - &card->statistics, sizeof(global_stats_t)); - - ppp_udp_pkt->cblock.result = 0; - ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - mbox->cmd.length = ppp_udp_pkt->cblock.length; - break; - - - /* FT1 MONITOR STATUS */ - case FT1_MONITOR_STATUS_CTRL: - - /* Enable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 1) { - - if( rCount++ != 0 ) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( ppp_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - ppp_udp_pkt->cblock.result = 0; - mbox->cmd.length = 1; - break; - } - } - goto udp_dflt_cmd; - - /* WARNING: FIXME: This should be fixed. - * The FT1 Status Ctrl doesn't have a break - * statment. Thus, no code must be inserted - * HERE: between default and above case statement */ - - default: -udp_dflt_cmd: - - /* it's a board command */ - mbox->cmd.command = ppp_udp_pkt->cblock.command; - mbox->cmd.length = ppp_udp_pkt->cblock.length; - - if(mbox->cmd.length) { - memcpy(&mbox->data,(unsigned char *)ppp_udp_pkt->data, - mbox->cmd.length); - } - - /* run the command on the board */ - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) { - - ppp_error(card, err, mbox); - ++ppp_priv_area->pipe_mgmt_stat. - UDP_PIPE_mgmt_adptr_cmnd_timeout; - break; - } - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; - - /* copy the result back to our buffer */ - memcpy(&ppp_udp_pkt->cblock,mbox, sizeof(cblock_t)); - - if(mbox->cmd.length) { - memcpy(&ppp_udp_pkt->data,&mbox->data,mbox->cmd.length); - } - - } /* end of switch */ - } /* end of else */ - - /* Fill UDP TTL */ - ppp_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length); - - if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - /* Make sure we are not already sending */ - if (!test_bit(SEND_CRIT,&card->wandev.critical)){ - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; - ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); - } - - } else { - - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - - /* copy data into new_skb */ - - buf = skb_put(new_skb, len); - memcpy(buf,ppp_priv_area->udp_pkt_data, len); - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; - - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - netif_rx(new_skb); - dev->last_rx = jiffies; - - } else { - - ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; - printk(KERN_INFO "no socket buffers available!\n"); - } - } - - ppp_priv_area->udp_pkt_lgth = 0; - - return; -} - -/*============================================================================= - * Initial the ppp_private_area structure. - */ -static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area ) -{ - - memset(&ppp_priv_area->if_send_stat, 0, sizeof(if_send_stat_t)); - memset(&ppp_priv_area->rx_intr_stat, 0, sizeof(rx_intr_stat_t)); - memset(&ppp_priv_area->pipe_mgmt_stat, 0, sizeof(pipe_mgmt_stat_t)); -} - -/*============================================================================ - * Initialize Global Statistics - */ -static void init_global_statistics( sdla_t *card ) -{ - memset(&card->statistics, 0, sizeof(global_stats_t)); -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ -static void init_ppp_tx_rx_buff( sdla_t *card ) -{ - ppp508_buf_info_t* info; - - if (card->hw.type == SDLA_S514) { - - info = (void*)(card->hw.dpmbase + PPP514_BUF_OFFS); - - card->u.p.txbuf_base = (void*)(card->hw.dpmbase + - info->txb_ptr); - - card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + - (info->txb_num - 1); - - card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + - info->rxb_ptr); - - card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + - (info->rxb_num - 1); - - } else { - - info = (void*)(card->hw.dpmbase + PPP508_BUF_OFFS); - - card->u.p.txbuf_base = (void*)(card->hw.dpmbase + - (info->txb_ptr - PPP508_MB_VECT)); - - card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + - (info->txb_num - 1); - - card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + - (info->rxb_ptr - PPP508_MB_VECT)); - - card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + - (info->rxb_num - 1); - } - - card->u.p.txbuf_next = (unsigned long*)&info->txb_nxt; - card->u.p.rxbuf_next = (unsigned long*)&info->rxb1_ptr; - - card->u.p.rx_base = info->rxb_base; - card->u.p.rx_top = info->rxb_end; - - card->u.p.txbuf = card->u.p.txbuf_base; - card->rxmb = card->u.p.rxbuf_base; - -} - -/*============================================================================= - * Read Connection Information (ie for Remote IP address assginment). - * Called when ppp interface connected. - */ -static int read_info( sdla_t *card ) -{ - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - int err; - - struct ifreq if_info; - struct sockaddr_in *if_data1, *if_data2; - mm_segment_t fs; - - /* Set Local and remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - - fs = get_fs(); - set_fs(get_ds()); /* get user space block */ - - /* Change the local and remote ip address of the interface. - * This will also add in the destination route. - */ - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = ppp_priv_area->ip_local; - if_data1->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFADDR, &if_info ); - if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; - if_data2->sin_addr.s_addr = ppp_priv_area->ip_remote; - if_data2->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); - - set_fs(fs); /* restore old block */ - - if (err) { - printk (KERN_INFO "%s: Adding of route failed: %i\n", - card->devname,err); - printk (KERN_INFO "%s: Local : %u.%u.%u.%u\n", - card->devname,NIPQUAD(ppp_priv_area->ip_local)); - printk (KERN_INFO "%s: Remote: %u.%u.%u.%u\n", - card->devname,NIPQUAD(ppp_priv_area->ip_remote)); - } - return err; -} - -/*============================================================================= - * Remove Dynamic Route. - * Called when ppp interface disconnected. - */ - -static void remove_route( sdla_t *card ) -{ - - struct net_device *dev = card->wandev.dev; - long ip_addr; - int err; - - mm_segment_t fs; - struct ifreq if_info; - struct sockaddr_in *if_data1; - struct in_device *in_dev = dev->ip_ptr; - struct in_ifaddr *ifa = in_dev->ifa_list; - - ip_addr = ifa->ifa_local; - - /* Set Local and remote addresses */ - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - - fs = get_fs(); - set_fs(get_ds()); /* get user space block */ - - /* Change the local ip address of the interface to 0. - * This will also delete the destination route. - */ - if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; - if_data1->sin_addr.s_addr = 0; - if_data1->sin_family = AF_INET; - err = devinet_ioctl( SIOCSIFADDR, &if_info ); - - set_fs(fs); /* restore old block */ - - - if (err) { - printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", - card->devname, err); - return; - }else{ - printk (KERN_INFO "%s: PPP Deleting dynamic route %u.%u.%u.%u successfuly\n", - card->devname, NIPQUAD(ip_addr)); - } - return; -} - -/*============================================================================= - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ -static int intr_test( sdla_t *card ) -{ - ppp_mbox_t *mb = card->mbox; - int err,i; - - err = ppp_set_intr_mode( card, 0x08 ); - - if (err == CMD_OK) { - - for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { - /* Run command READ_CODE_VERSION */ - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = PPP_READ_CODE_VERSION; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - ppp_error(card, err, mb); - } - } - else return err; - - err = ppp_set_intr_mode( card, 0 ); - if (err != CMD_OK) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? - */ -static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ) -{ - unsigned char *sendpacket; - unsigned char buf2[5]; - ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; - - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - - if( ppp_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45 && /* IP packet */ - sendpacket[9] == 0x11 && /* UDP packet */ - sendpacket[22] == buf2[1] && /* UDP Port */ - sendpacket[23] == buf2[0] && - sendpacket[36] == 0x01 ) { - - if ( sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ - sendpacket[29] == 0x54 && - sendpacket[30] == 0x50 && - sendpacket[31] == 0x49 && - sendpacket[32] == 0x50 && - sendpacket[33] == 0x45 && - sendpacket[34] == 0x41 && - sendpacket[35] == 0x42 ){ - - return UDP_PTPIPE_TYPE; - - } else if(sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[29] == 0x52 && - sendpacket[30] == 0x56 && - sendpacket[31] == 0x53 && - sendpacket[32] == 0x54 && - sendpacket[33] == 0x41 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x53 ){ - - return UDP_DRVSTATS_TYPE; - - } else - return UDP_INVALID_TYPE; - - } else - return UDP_INVALID_TYPE; - -} - -/*============================================================================ - * Check to see if the packet to be transmitted contains a broadcast or - * multicast source IP address. - */ - -static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, - struct sk_buff *skb) -{ - u32 src_ip_addr; - u32 broadcast_ip_addr = 0; - struct in_device *in_dev; - - /* read the IP source address from the outgoing packet */ - src_ip_addr = *(u32 *)(skb->data + 12); - - /* read the IP broadcast address for the device */ - in_dev = dev->ip_ptr; - if(in_dev != NULL) { - struct in_ifaddr *ifa= in_dev->ifa_list; - if(ifa != NULL) - broadcast_ip_addr = ifa->ifa_broadcast; - else - return 0; - } - - /* check if the IP Source Address is a Broadcast address */ - if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { - printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", - card->devname); - return 1; - } - - /* check if the IP Source Address is a Multicast address */ - if((ntohl(src_ip_addr) >= 0xE0000001) && - (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", - card->devname); - return 1; - } - - return 0; -} - -void s508_lock (sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); -} - -void s508_unlock (sdla_t *card, unsigned long *smp_flags) -{ - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - -static int read_connection_info (sdla_t *card) -{ - ppp_mbox_t *mb = card->mbox; - struct net_device *dev = card->wandev.dev; - ppp_private_area_t *ppp_priv_area = dev->priv; - ppp508_connect_info_t *ppp508_connect_info; - int err; - - memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = PPP_GET_CONNECTION_INFO; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK) { - ppp_error(card, err, mb); - ppp_priv_area->ip_remote = 0; - ppp_priv_area->ip_local = 0; - } - else { - ppp508_connect_info = (ppp508_connect_info_t *)mb->data; - ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote; - ppp_priv_area->ip_local = ppp508_connect_info->ip_local; - - NEX_PRINTK(KERN_INFO "READ CONNECTION GOT IP ADDRESS %x, %x\n", - ppp_priv_area->ip_remote, - ppp_priv_area->ip_local); - } - - return err; -} - -/*=============================================================================== - * config_ppp - * - * Configure the ppp protocol and enable communications. - * - * The if_open function binds this function to the poll routine. - * Therefore, this function will run every time the ppp interface - * is brought up. - * - * If the communications are not enabled, proceed to configure - * the card and enable communications. - * - * If the communications are enabled, it means that the interface - * was shutdown by ether the user or driver. In this case, we - * have to check that the IP addresses have not changed. If - * the IP addresses changed, we have to reconfigure the firmware - * and update the changed IP addresses. Otherwise, just exit. - */ -static int config_ppp (sdla_t *card) -{ - - struct net_device *dev = card->wandev.dev; - ppp_flags_t *flags = card->flags; - ppp_private_area_t *ppp_priv_area = dev->priv; - - if (card->u.p.comm_enabled){ - - if (ppp_priv_area->ip_local_tmp != ppp_priv_area->ip_local || - ppp_priv_area->ip_remote_tmp != ppp_priv_area->ip_remote){ - - /* The IP addersses have changed, we must - * stop the communications and reconfigure - * the card. Reason: the firmware must know - * the local and remote IP addresses. */ - disable_comm(card); - wanpipe_set_state(card, WAN_DISCONNECTED); - printk(KERN_INFO - "%s: IP addresses changed!\n", - card->devname); - printk(KERN_INFO "%s: Restarting communications ...\n", - card->devname); - }else{ - /* IP addresses are the same and the link is up, - * we don't have to do anything here. Therefore, exit */ - return 0; - } - } - - /* Record the new IP addreses */ - ppp_priv_area->ip_local = ppp_priv_area->ip_local_tmp; - ppp_priv_area->ip_remote = ppp_priv_area->ip_remote_tmp; - - if (config508(dev, card)){ - printk(KERN_INFO "%s: Failed to configure PPP device\n", - card->devname); - return 0; - } - - if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| - PPP_INTR_TXRDY| - PPP_INTR_MODEM| - PPP_INTR_DISC | - PPP_INTR_OPEN | - PPP_INTR_DROP_DTR | - PPP_INTR_TIMER)) { - - printk(KERN_INFO "%s: Failed to configure board interrupts !\n", - card->devname); - return 0; - } - - /* Turn off the transmit and timer interrupt */ - flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; - - - /* If you are not the authenticator and any one of the protocol is - * enabled then we call the set_out_bound_authentication. - */ - if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { - if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ - printk(KERN_INFO "%s: Outbound authentication failed !\n", - card->devname); - return 0; - } - } - - /* If you are the authenticator and any one of the protocol is enabled - * then we call the set_in_bound_authentication. - */ - if (card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)){ - if (ppp_set_inbnd_auth(card, ppp_priv_area)){ - printk(KERN_INFO "%s: Inbound authentication failed !\n", - card->devname); - return 0; - } - } - - /* If we fail to enable communications here it's OK, - * since the DTR timer will cause a disconnected, which - * will retrigger communication in timer_intr() */ - if (ppp_comm_enable(card) == CMD_OK) { - wanpipe_set_state(card, WAN_CONNECTING); - init_ppp_tx_rx_buff(card); - } - - return 0; -} - -/*============================================================ - * ppp_poll - * - * Rationale: - * We cannot manipulate the routing tables, or - * ip addresses withing the interrupt. Therefore - * we must perform such actons outside an interrupt - * at a later time. - * - * Description: - * PPP polling routine, responsible for - * shutting down interfaces upon disconnect - * and adding/removing routes. - * - * Usage: - * This function is executed for each ppp - * interface through a tq_schedule bottom half. - * - * trigger_ppp_poll() function is used to kick - * the ppp_poll routine. - */ -static void ppp_poll(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area; - sdla_t *card; - u8 check_gateway=0; - ppp_flags_t *flags; - - if (!dev || (ppp_priv_area = dev->priv) == NULL) - return; - - card = ppp_priv_area->card; - flags = card->flags; - - /* Shutdown is in progress, stop what you are - * doing and get out */ - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - clear_bit(POLL_CRIT,&card->wandev.critical); - return; - } - - /* if_open() function has triggered the polling routine - * to determine the configured IP addresses. Once the - * addresses are found, trigger the chdlc configuration */ - if (test_bit(0,&ppp_priv_area->config_ppp)){ - - ppp_priv_area->ip_local_tmp = get_ip_address(dev,WAN_LOCAL_IP); - ppp_priv_area->ip_remote_tmp = get_ip_address(dev,WAN_POINTOPOINT_IP); - - if (ppp_priv_area->ip_local_tmp == ppp_priv_area->ip_remote_tmp && - card->u.p.ip_mode == WANOPT_PPP_HOST){ - - if (++ppp_priv_area->ip_error > MAX_IP_ERRORS){ - printk(KERN_INFO "\n%s: --- WARNING ---\n", - card->devname); - printk(KERN_INFO "%s: The local IP address is the same as the\n", - card->devname); - printk(KERN_INFO "%s: Point-to-Point IP address.\n", - card->devname); - printk(KERN_INFO "%s: --- WARNING ---\n\n", - card->devname); - }else{ - clear_bit(POLL_CRIT,&card->wandev.critical); - ppp_priv_area->poll_delay_timer.expires = jiffies+HZ; - add_timer(&ppp_priv_area->poll_delay_timer); - return; - } - } - - ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->imask |= PPP_INTR_TIMER; - ppp_priv_area->ip_error=0; - - clear_bit(0,&ppp_priv_area->config_ppp); - clear_bit(POLL_CRIT,&card->wandev.critical); - return; - } - - /* Dynamic interface implementation, as well as dynamic - * routing. */ - - switch (card->wandev.state) { - - case WAN_DISCONNECTED: - - /* If the dynamic interface configuration is on, and interface - * is up, then bring down the netowrk interface */ - - if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && - !test_bit(DEV_DOWN,&ppp_priv_area->interface_down) && - card->wandev.dev->flags & IFF_UP){ - - printk(KERN_INFO "%s: Interface %s down.\n", - card->devname,card->wandev.dev->name); - change_dev_flags(card->wandev.dev, - (card->wandev.dev->flags&~IFF_UP)); - set_bit(DEV_DOWN,&ppp_priv_area->interface_down); - }else{ - /* We need to check if the local IP address is - * zero. If it is, we shouldn't try to remove it. - * For some reason the kernel crashes badly if - * we try to remove the route twice */ - - if (card->wandev.dev->flags & IFF_UP && - get_ip_address(card->wandev.dev,WAN_LOCAL_IP) && - card->u.p.ip_mode == WANOPT_PPP_PEER){ - - remove_route(card); - } - } - break; - - case WAN_CONNECTED: - - /* In SMP machine this code can execute before the interface - * comes up. In this case, we must make sure that we do not - * try to bring up the interface before dev_open() is finished */ - - - /* DEV_DOWN will be set only when we bring down the interface - * for the very first time. This way we know that it was us - * that brought the interface down */ - - if (test_bit(DYN_OPT_ON,&ppp_priv_area->interface_down) && - test_bit(DEV_DOWN, &ppp_priv_area->interface_down) && - !(card->wandev.dev->flags & IFF_UP)){ - - printk(KERN_INFO "%s: Interface %s up.\n", - card->devname,card->wandev.dev->name); - - change_dev_flags(card->wandev.dev,(card->wandev.dev->flags|IFF_UP)); - clear_bit(DEV_DOWN,&ppp_priv_area->interface_down); - check_gateway=1; - } - - if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && - test_bit(1,&Read_connection_info)) { - - process_route(card); - clear_bit(1,&Read_connection_info); - check_gateway=1; - } - - if (ppp_priv_area->gateway && check_gateway) - add_gateway(card,dev); - - break; - } - clear_bit(POLL_CRIT,&card->wandev.critical); - return; -} - -/*============================================================ - * trigger_ppp_poll - * - * Description: - * Add a ppp_poll() task into a tq_scheduler bh handler - * for a specific interface. This will kick - * the ppp_poll() routine at a later time. - * - * Usage: - * Interrupts use this to defer a taks to - * a polling routine. - * - */ - -static void trigger_ppp_poll(struct net_device *dev) -{ - ppp_private_area_t *ppp_priv_area; - if ((ppp_priv_area=dev->priv) != NULL){ - - sdla_t *card = ppp_priv_area->card; - - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - return; - } - - if (test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ - return; - } - - schedule_work(&ppp_priv_area->poll_work); - } - return; -} - -static void ppp_poll_delay (unsigned long dev_ptr) -{ - struct net_device *dev = (struct net_device *)dev_ptr; - trigger_ppp_poll(dev); -} - -/*============================================================ - * detect_and_fix_tx_bug - * - * Description: - * On connect, if the board tx buffer ptr is not the same - * as the driver tx buffer ptr, we found a firmware bug. - * Report the bug to the above layer. To fix the - * error restart communications again. - * - * Usage: - * - */ - -static int detect_and_fix_tx_bug (sdla_t *card) -{ - if (((unsigned long)card->u.p.txbuf_base&0xFFF) != ((*card->u.p.txbuf_next)&0xFFF)){ - NEX_PRINTK(KERN_INFO "Major Error, Fix the bug\n"); - return 1; - } - return 0; -} - -MODULE_LICENSE("GPL"); - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c deleted file mode 100644 index 63f846d6f3a6..000000000000 --- a/drivers/net/wan/sdla_x25.c +++ /dev/null @@ -1,5497 +0,0 @@ -/***************************************************************************** -* sdla_x25.c WANPIPE(tm) Multiprotocol WAN Link Driver. X.25 module. -* -* Author: Nenad Corbic -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* 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. -* ============================================================================ -* Apr 03, 2001 Nenad Corbic o Fixed the rx_skb=NULL bug in x25 in rx_intr(). -* Dec 26, 2000 Nenad Corbic o Added a new polling routine, that uses -* a kernel timer (more efficient). -* Dec 25, 2000 Nenad Corbic o Updated for 2.4.X kernel -* Jul 26, 2000 Nenad Corbic o Increased the local packet buffering -* for API to 4096+header_size. -* Jul 17, 2000 Nenad Corbic o Fixed the x25 startup bug. Enable -* communications only after all interfaces -* come up. HIGH SVC/PVC is used to calculate -* the number of channels. -* Enable protocol only after all interfaces -* are enabled. -* Jul 10, 2000 Nenad Corbic o Fixed the M_BIT bug. -* Apr 25, 2000 Nenad Corbic o Pass Modem messages to the API. -* Disable idle timeout in X25 API. -* Apr 14, 2000 Nenad Corbic o Fixed: Large LCN number support. -* Maximum LCN number is 4095. -* Maximum number of X25 channels is 255. -* Apr 06, 2000 Nenad Corbic o Added SMP Support. -* Mar 29, 2000 Nenad Corbic o Added support for S514 PCI Card -* Mar 23, 2000 Nenad Corbic o Improved task queue, BH handling. -* Mar 14, 2000 Nenad Corbic o Updated Protocol Violation handling -* routines. Bug Fix. -* Mar 10, 2000 Nenad Corbic o Bug Fix: corrupted mbox recovery. -* Mar 09, 2000 Nenad Corbic o Fixed the auto HDLC bug. -* Mar 08, 2000 Nenad Corbic o Fixed LAPB HDLC startup problems. -* Application must bring the link up -* before tx/rx, and bring the -* link down on close(). -* Mar 06, 2000 Nenad Corbic o Added an option for logging call setup -* information. -* Feb 29, 2000 Nenad Corbic o Added support for LAPB HDLC API -* Feb 25, 2000 Nenad Corbic o Fixed the modem failure handling. -* No Modem OOB message will be passed -* to the user. -* Feb 21, 2000 Nenad Corbic o Added Xpipemon Debug Support -* Dec 30, 1999 Nenad Corbic o Socket based X25API -* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X kernel -* Mar 15, 1998 Alan Cox o 2.1.x porting -* Dec 19, 1997 Jaspreet Singh o Added multi-channel IPX support -* Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs -* when they are disabled. -* Nov 17, 1997 Farhan Thawar o Added IPX support -* o Changed if_send() to now buffer packets when -* the board is busy -* o Removed queueing of packets via the polling -* routing -* o Changed if_send() critical flags to properly -* handle race conditions -* Nov 06, 1997 Farhan Thawar o Added support for SVC timeouts -* o Changed PVC encapsulation to ETH_P_IP -* Jul 21, 1997 Jaspreet Singh o Fixed freeing up of buffers using kfree() -* when packets are received. -* Mar 11, 1997 Farhan Thawar Version 3.1.1 -* o added support for V35 -* o changed if_send() to return 0 if -* wandev.critical() is true -* o free socket buffer in if_send() if -* returning 0 -* o added support for single '@' address to -* accept all incoming calls -* o fixed bug in set_chan_state() to disconnect -* Jan 15, 1997 Gene Kozin Version 3.1.0 -* o implemented exec() entry point -* Jan 07, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -/*====================================================== - * Includes - *=====================================================*/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include -#include /* time_after() macro */ -#include /* htons(), etc. */ -#include -#include /* Experimental delay */ - -#include - -#include -#include -#include /* X.25 firmware API definitions */ -#include -#include - - -/*====================================================== - * Defines & Macros - *=====================================================*/ - - -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ - -#define X25_CHAN_MTU 4096 /* unfragmented logical channel MTU */ -#define X25_HRDHDR_SZ 7 /* max encapsulation header size */ -#define X25_CONCT_TMOUT (90*HZ) /* link connection timeout */ -#define X25_RECON_TMOUT (10*HZ) /* link connection timeout */ -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ -#define MAX_BH_BUFF 10 -#define M_BIT 0x01 - -//#define PRINT_DEBUG 1 -#ifdef PRINT_DEBUG -#define DBG_PRINTK(format, a...) printk(format, ## a) -#else -#define DBG_PRINTK(format, a...) -#endif - -#define TMR_INT_ENABLED_POLL_ACTIVE 0x01 -#define TMR_INT_ENABLED_POLL_CONNECT_ON 0x02 -#define TMR_INT_ENABLED_POLL_CONNECT_OFF 0x04 -#define TMR_INT_ENABLED_POLL_DISCONNECT 0x08 -#define TMR_INT_ENABLED_CMD_EXEC 0x10 -#define TMR_INT_ENABLED_UPDATE 0x20 -#define TMR_INT_ENABLED_UDP_PKT 0x40 - -#define MAX_X25_ADDR_SIZE 16 -#define MAX_X25_DATA_SIZE 129 -#define MAX_X25_FACL_SIZE 110 - -#define TRY_CMD_AGAIN 2 -#define DELAY_RESULT 1 -#define RETURN_RESULT 0 - -#define DCD(x) (x & 0x03 ? "HIGH" : "LOW") -#define CTS(x) (x & 0x05 ? "HIGH" : "LOW") - - -/* Driver will not write log messages about - * modem status if defined.*/ -#define MODEM_NOT_LOG 1 - -/*==================================================== - * For IPXWAN - *===================================================*/ - -#define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - - -/*==================================================== - * MEMORY DEBUGGING FUNCTION - *==================================================== - -#define KMEM_SAFETYZONE 8 - -static void * dbg_kmalloc(unsigned int size, int prio, int line) { - int i = 0; - void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); - char * c1 = v; - c1 += sizeof(unsigned int); - *((unsigned int *)v) = size; - - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; - c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; - c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; - c1 += 8; - } - v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; - printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); - return v; -} -static void dbg_kfree(void * v, int line) { - unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); - unsigned int size = *sp; - char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; - int i = 0; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' - || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { - printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' - || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' - ) { - printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - printk(KERN_INFO "line %d kfree(%p)\n",line,v); - v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); - kfree(v); -} - -#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) -#define kfree(x) dbg_kfree(x,__LINE__) - -==============================================================*/ - - - -/*=============================================== - * Data Structures - *===============================================*/ - - -/*======================================================== - * Name: x25_channel - * - * Purpose: To hold private informaton for each - * logical channel. - * - * Rationale: Per-channel debugging is possible if each - * channel has its own private area. - * - * Assumptions: - * - * Description: This is an extention of the struct net_device - * we create for each network interface to keep - * the rest of X.25 channel-specific data. - * - * Construct: Typedef - */ -typedef struct x25_channel -{ - wanpipe_common_t common; /* common area for x25api and socket */ - char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ - char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */ - unsigned tx_pkt_size; - unsigned short protocol; /* ethertype, 0 - multiplexed */ - char drop_sequence; /* mark sequence for dropping */ - unsigned long state_tick; /* time of the last state change */ - unsigned idle_timeout; /* sec, before disconnecting */ - unsigned long i_timeout_sofar; /* # of sec's we've been idle */ - unsigned hold_timeout; /* sec, before re-connecting */ - unsigned long tick_counter; /* counter for transmit time out */ - char devtint; /* Weather we should dev_tint() */ - struct sk_buff* rx_skb; /* receive socket buffer */ - struct sk_buff* tx_skb; /* transmit socket buffer */ - - bh_data_t *bh_head; /* Circular buffer for x25api_bh */ - unsigned long tq_working; - volatile int bh_write; - volatile int bh_read; - atomic_t bh_buff_used; - - sdla_t* card; /* -> owner */ - struct net_device *dev; /* -> bound devce */ - - int ch_idx; - unsigned char enable_IPX; - unsigned long network_number; - struct net_device_stats ifstats; /* interface statistics */ - unsigned short transmit_length; - unsigned short tx_offset; - char transmit_buffer[X25_CHAN_MTU+sizeof(x25api_hdr_t)]; - - if_send_stat_t if_send_stat; - rx_intr_stat_t rx_intr_stat; - pipe_mgmt_stat_t pipe_mgmt_stat; - - unsigned long router_start_time; /* Router start time in seconds */ - unsigned long router_up_time; - -} x25_channel_t; - -/* FIXME Take this out */ - -#ifdef NEX_OLD_CALL_INFO -typedef struct x25_call_info -{ - char dest[17]; PACKED;/* ASCIIZ destination address */ - char src[17]; PACKED;/* ASCIIZ source address */ - char nuser; PACKED;/* number of user data bytes */ - unsigned char user[127]; PACKED;/* user data */ - char nfacil; PACKED;/* number of facilities */ - struct - { - unsigned char code; PACKED; - unsigned char parm; PACKED; - } facil[64]; /* facilities */ -} x25_call_info_t; -#else -typedef struct x25_call_info -{ - char dest[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ destination address */ - char src[MAX_X25_ADDR_SIZE] PACKED;/* ASCIIZ source address */ - unsigned char nuser PACKED; - unsigned char user[MAX_X25_DATA_SIZE] PACKED;/* user data */ - unsigned char nfacil PACKED; - unsigned char facil[MAX_X25_FACL_SIZE] PACKED; - unsigned short lcn PACKED; -} x25_call_info_t; -#endif - - - -/*=============================================== - * Private Function Prototypes - *==============================================*/ - - -/*================================================= - * WAN link driver entry points. These are - * called by the WAN router module. - */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); -static int del_if(struct wan_device* wandev, struct net_device* dev); -static void disable_comm (sdla_t* card); -static void disable_comm_shutdown(sdla_t *card); - - - -/*================================================= - * WANPIPE-specific entry points - */ -static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); -static void x25api_bh(struct net_device *dev); -static int x25api_bh_cleanup(struct net_device *dev); -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb); - - -/*================================================= - * Network device interface - */ -static int if_init(struct net_device* dev); -static int if_open(struct net_device* dev); -static int if_close(struct net_device* dev); -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, unsigned len); -static int if_rebuild_hdr (struct sk_buff* skb); -static int if_send(struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats *if_stats(struct net_device* dev); - -static void if_tx_timeout(struct net_device *dev); - -/*================================================= - * Interrupt handlers - */ -static void wpx_isr (sdla_t *); -static void rx_intr (sdla_t *); -static void tx_intr (sdla_t *); -static void status_intr (sdla_t *); -static void event_intr (sdla_t *); -static void spur_intr (sdla_t *); -static void timer_intr (sdla_t *); - -static int tx_intr_send(sdla_t *card, struct net_device *dev); -static struct net_device *move_dev_to_next(sdla_t *card, - struct net_device *dev); - -/*================================================= - * Background polling routines - */ -static void wpx_poll (sdla_t* card); -static void poll_disconnected (sdla_t* card); -static void poll_connecting (sdla_t* card); -static void poll_active (sdla_t* card); -static void trigger_x25_poll(sdla_t *card); -static void x25_timer_routine(unsigned long data); - - - -/*================================================= - * X.25 firmware interface functions - */ -static int x25_get_version (sdla_t* card, char* str); -static int x25_configure (sdla_t* card, TX25Config* conf); -static int hdlc_configure (sdla_t* card, TX25Config* conf); -static int set_hdlc_level (sdla_t* card); -static int x25_get_err_stats (sdla_t* card); -static int x25_get_stats (sdla_t* card); -static int x25_set_intr_mode (sdla_t* card, int mode); -static int x25_close_hdlc (sdla_t* card); -static int x25_open_hdlc (sdla_t* card); -static int x25_setup_hdlc (sdla_t* card); -static int x25_set_dtr (sdla_t* card, int dtr); -static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan); -static int x25_place_call (sdla_t* card, x25_channel_t* chan); -static int x25_accept_call (sdla_t* card, int lcn, int qdm); -static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn); -static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf); -static int x25_fetch_events (sdla_t* card); -static int x25_error (sdla_t* card, int err, int cmd, int lcn); - -/*================================================= - * X.25 asynchronous event handlers - */ -static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); -static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb); - - -/*================================================= - * Miscellaneous functions - */ -static int connect (sdla_t* card); -static int disconnect (sdla_t* card); -static struct net_device* get_dev_by_lcn(struct wan_device* wandev, - unsigned lcn); -static int chan_connect(struct net_device* dev); -static int chan_disc(struct net_device* dev); -static void set_chan_state(struct net_device* dev, int state); -static int chan_send(struct net_device *dev, void* buff, unsigned data_len, - unsigned char tx_intr); -static unsigned char bps_to_speed_code (unsigned long bps); -static unsigned int dec_to_uint (unsigned char* str, int len); -static unsigned int hex_to_uint (unsigned char*, int); -static void parse_call_info (unsigned char*, x25_call_info_t*); -static struct net_device *find_channel(sdla_t *card, unsigned lcn); -static void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn); -static void setup_for_delayed_transmit(struct net_device *dev, - void *buf, unsigned len); - - -/*================================================= - * X25 API Functions - */ -static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, - struct sk_buff **); -static void timer_intr_exec(sdla_t *, unsigned char); -static int execute_delayed_cmd(sdla_t *card, struct net_device *dev, - mbox_cmd_t *usr_cmd, char bad_cmd); -static int api_incoming_call (sdla_t*, TX25Mbox *, int); -static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int); -static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, - TX25Mbox* mbox); -static int clear_confirm_event (sdla_t *, TX25Mbox*); -static void send_oob_msg (sdla_t *card, struct net_device *dev, TX25Mbox *mbox); -static int timer_intr_cmd_exec(sdla_t *card); -static void api_oob_event (sdla_t *card,TX25Mbox *mbox); -static int check_bad_command(sdla_t *card, struct net_device *dev); -static int channel_disconnect(sdla_t* card, struct net_device *dev); -static void hdlc_link_down (sdla_t*); - -/*================================================= - * XPIPEMON Functions - */ -static int process_udp_mgmt_pkt(sdla_t *); -static int udp_pkt_type( struct sk_buff *, sdla_t*); -static int reply_udp( unsigned char *, unsigned int); -static void init_x25_channel_struct( x25_channel_t *); -static void init_global_statistics( sdla_t *); -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t *card, - struct net_device *dev, - struct sk_buff *skb, int lcn); -static unsigned short calc_checksum (char *, int); - - - -/*================================================= - * IPX functions - */ -static void switch_net_numbers(unsigned char *, unsigned long, unsigned char); -static int handle_IPXWAN(unsigned char *, char *, unsigned char , - unsigned long , unsigned short ); - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -static void S508_S514_lock(sdla_t *, unsigned long *); -static void S508_S514_unlock(sdla_t *, unsigned long *); - - -/*================================================= - * Global Variables - *=================================================*/ - - - -/*================================================= - * Public Functions - *=================================================*/ - - - - -/*=================================================================== - * wpx_init: X.25 Protocol Initialization routine. - * - * Purpose: To initialize the protocol/firmware. - * - * Rationale: This function is called by setup() function, in - * sdlamain.c, to dynamically setup the x25 protocol. - * This is the first protocol specific function, which - * executes once on startup. - * - * Description: This procedure initializes the x25 firmware and - * sets up the mailbox, transmit and receive buffer - * pointers. It also initializes all debugging structures - * and sets up the X25 environment. - * - * Sets up hardware options defined by user in [wanpipe#] - * section of wanpipe#.conf configuration file. - * - * At this point adapter is completely initialized - * and X.25 firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the - * adapter data space. - * - * Called by: setup() function in sdlamain.c - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 o.k. - * < 0 failure. - */ - -int wpx_init (sdla_t* card, wandev_conf_t* conf) -{ - union{ - char str[80]; - TX25Config cfg; - } u; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_X25){ - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id) - ; - return -EINVAL; - } - - /* Initialize protocol-specific fields */ - card->mbox = (void*)(card->hw.dpmbase + X25_MBOX_OFFS); - card->rxmb = (void*)(card->hw.dpmbase + X25_RXMBOX_OFFS); - card->flags = (void*)(card->hw.dpmbase + X25_STATUS_OFFS); - - /* Initialize for S514 Card */ - if(card->hw.type == SDLA_S514) { - card->mbox += X25_MB_VECTOR; - card->flags += X25_MB_VECTOR; - card->rxmb += X25_MB_VECTOR; - } - - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - if (x25_get_version(card, NULL) || x25_get_version(card, u.str)) - return -EIO; - - - /* X25 firmware can run ether in X25 or LAPB HDLC mode. - * Check the user defined option and configure accordingly */ - if (conf->u.x25.LAPB_hdlc_only == WANOPT_YES){ - if (set_hdlc_level(card) != CMD_OK){ - return -EIO; - }else{ - printk(KERN_INFO "%s: running LAP_B HDLC firmware v%s\n", - card->devname, u.str); - } - card->u.x.LAPB_hdlc = 1; - }else{ - printk(KERN_INFO "%s: running X.25 firmware v%s\n", - card->devname, u.str); - card->u.x.LAPB_hdlc = 0; - } - - /* Configure adapter. Here we set resonable defaults, then parse - * device configuration structure and set configuration options. - * Most configuration options are verified and corrected (if - * necessary) since we can't rely on the adapter to do so. - */ - memset(&u.cfg, 0, sizeof(u.cfg)); - u.cfg.t1 = 3; - u.cfg.n2 = 10; - u.cfg.autoHdlc = 1; /* automatic HDLC connection */ - u.cfg.hdlcWindow = 7; - u.cfg.pktWindow = 2; - u.cfg.station = 1; /* DTE */ - u.cfg.options = 0x0090; /* disable D-bit pragmatics */ - u.cfg.ccittCompat = 1988; - u.cfg.t10t20 = 30; - u.cfg.t11t21 = 30; - u.cfg.t12t22 = 30; - u.cfg.t13t23 = 30; - u.cfg.t16t26 = 30; - u.cfg.t28 = 30; - u.cfg.r10r20 = 5; - u.cfg.r12r22 = 5; - u.cfg.r13r23 = 5; - u.cfg.responseOpt = 1; /* RR's after every packet */ - - if (card->u.x.LAPB_hdlc){ - u.cfg.hdlcMTU = 1027; - } - - if (conf->u.x25.x25_conf_opt){ - u.cfg.options = conf->u.x25.x25_conf_opt; - } - - if (conf->clocking != WANOPT_EXTERNAL) - u.cfg.baudRate = bps_to_speed_code(conf->bps); - - if (conf->station != WANOPT_DTE){ - u.cfg.station = 0; /* DCE mode */ - } - - if (conf->interface != WANOPT_RS232 ){ - u.cfg.hdlcOptions |= 0x80; /* V35 mode */ - } - - /* adjust MTU */ - if (!conf->mtu || (conf->mtu >= 1024)) - card->wandev.mtu = 1024; - else if (conf->mtu >= 512) - card->wandev.mtu = 512; - else if (conf->mtu >= 256) - card->wandev.mtu = 256; - else if (conf->mtu >= 128) - card->wandev.mtu = 128; - else - card->wandev.mtu = 64; - - u.cfg.defPktSize = u.cfg.pktMTU = card->wandev.mtu; - - if (conf->u.x25.hi_pvc){ - card->u.x.hi_pvc = min_t(unsigned int, conf->u.x25.hi_pvc, MAX_LCN_NUM); - card->u.x.lo_pvc = min_t(unsigned int, conf->u.x25.lo_pvc, card->u.x.hi_pvc); - } - - if (conf->u.x25.hi_svc){ - card->u.x.hi_svc = min_t(unsigned int, conf->u.x25.hi_svc, MAX_LCN_NUM); - card->u.x.lo_svc = min_t(unsigned int, conf->u.x25.lo_svc, card->u.x.hi_svc); - } - - /* Figure out the total number of channels to configure */ - card->u.x.num_of_ch = 0; - if (card->u.x.hi_svc != 0){ - card->u.x.num_of_ch = (card->u.x.hi_svc - card->u.x.lo_svc) + 1; - } - if (card->u.x.hi_pvc != 0){ - card->u.x.num_of_ch += (card->u.x.hi_pvc - card->u.x.lo_pvc) + 1; - } - - if (card->u.x.num_of_ch == 0){ - printk(KERN_INFO "%s: ERROR, Minimum number of PVC/SVC channels is 1 !\n" - "%s: Please set the Lowest/Highest PVC/SVC values !\n", - card->devname,card->devname); - return -ECHRNG; - } - - u.cfg.loPVC = card->u.x.lo_pvc; - u.cfg.hiPVC = card->u.x.hi_pvc; - u.cfg.loTwoWaySVC = card->u.x.lo_svc; - u.cfg.hiTwoWaySVC = card->u.x.hi_svc; - - if (conf->u.x25.hdlc_window) - u.cfg.hdlcWindow = min_t(unsigned int, conf->u.x25.hdlc_window, 7); - if (conf->u.x25.pkt_window) - u.cfg.pktWindow = min_t(unsigned int, conf->u.x25.pkt_window, 7); - - if (conf->u.x25.t1) - u.cfg.t1 = min_t(unsigned int, conf->u.x25.t1, 30); - if (conf->u.x25.t2) - u.cfg.t2 = min_t(unsigned int, conf->u.x25.t2, 29); - if (conf->u.x25.t4) - u.cfg.t4 = min_t(unsigned int, conf->u.x25.t4, 240); - if (conf->u.x25.n2) - u.cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30); - - if (conf->u.x25.t10_t20) - u.cfg.t10t20 = min_t(unsigned int, conf->u.x25.t10_t20,255); - if (conf->u.x25.t11_t21) - u.cfg.t11t21 = min_t(unsigned int, conf->u.x25.t11_t21,255); - if (conf->u.x25.t12_t22) - u.cfg.t12t22 = min_t(unsigned int, conf->u.x25.t12_t22,255); - if (conf->u.x25.t13_t23) - u.cfg.t13t23 = min_t(unsigned int, conf->u.x25.t13_t23,255); - if (conf->u.x25.t16_t26) - u.cfg.t16t26 = min_t(unsigned int, conf->u.x25.t16_t26, 255); - if (conf->u.x25.t28) - u.cfg.t28 = min_t(unsigned int, conf->u.x25.t28, 255); - - if (conf->u.x25.r10_r20) - u.cfg.r10r20 = min_t(unsigned int, conf->u.x25.r10_r20,250); - if (conf->u.x25.r12_r22) - u.cfg.r12r22 = min_t(unsigned int, conf->u.x25.r12_r22,250); - if (conf->u.x25.r13_r23) - u.cfg.r13r23 = min_t(unsigned int, conf->u.x25.r13_r23,250); - - - if (conf->u.x25.ccitt_compat) - u.cfg.ccittCompat = conf->u.x25.ccitt_compat; - - /* initialize adapter */ - if (card->u.x.LAPB_hdlc){ - if (hdlc_configure(card, &u.cfg) != CMD_OK) - return -EIO; - }else{ - if (x25_configure(card, &u.cfg) != CMD_OK) - return -EIO; - } - - if ((x25_close_hdlc(card) != CMD_OK) || /* close HDLC link */ - (x25_set_dtr(card, 0) != CMD_OK)) /* drop DTR */ - return -EIO; - - /* Initialize protocol-specific fields of adapter data space */ - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpx_isr; - card->poll = NULL; //&wpx_poll; - card->disable_comm = &disable_comm; - card->exec = &wpx_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - - /* WARNING: This function cannot exit with an error - * after the change of state */ - card->wandev.state = WAN_DISCONNECTED; - - card->wandev.enable_tx_int = 0; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->u.x.tx_dev = NULL; - card->u.x.no_dev = 0; - - - /* Configure for S514 PCI Card */ - if (card->hw.type == SDLA_S514) { - card->u.x.hdlc_buf_status = - (volatile unsigned char *) - (card->hw.dpmbase + X25_MB_VECTOR+ X25_MISC_HDLC_BITS); - }else{ - card->u.x.hdlc_buf_status = - (volatile unsigned char *)(card->hw.dpmbase + X25_MISC_HDLC_BITS); - } - - card->u.x.poll_device=NULL; - card->wandev.udp_port = conf->udp_port; - - /* Enable or disable call setup logging */ - if (conf->u.x25.logging == WANOPT_YES){ - printk(KERN_INFO "%s: Enabling Call Logging.\n", - card->devname); - card->u.x.logging = 1; - }else{ - card->u.x.logging = 0; - } - - /* Enable or disable modem status reporting */ - if (conf->u.x25.oob_on_modem == WANOPT_YES){ - printk(KERN_INFO "%s: Enabling OOB on Modem change.\n", - card->devname); - card->u.x.oob_on_modem = 1; - }else{ - card->u.x.oob_on_modem = 0; - } - - init_global_statistics(card); - - INIT_WORK(&card->u.x.x25_poll_work, (void *)wpx_poll, card); - - init_timer(&card->u.x.x25_timer); - card->u.x.x25_timer.data = (unsigned long)card; - card->u.x.x25_timer.function = x25_timer_routine; - - return 0; -} - -/*========================================================= - * WAN Device Driver Entry Points - *========================================================*/ - -/*============================================================ - * Name: update(), Update device status & statistics. - * - * Purpose: To provide debugging and statitical - * information to the /proc file system. - * /proc/net/wanrouter/wanpipe# - * - * Rationale: The /proc file system is used to collect - * information about the kernel and drivers. - * Using the /proc file system the user - * can see exactly what the sangoma drivers are - * doing. And in what state they are in. - * - * Description: Collect all driver statistical information - * and pass it to the top laywer. - * - * Since we have to execute a debugging command, - * to obtain firmware statitics, we trigger a - * UPDATE function within the timer interrtup. - * We wait until the timer update is complete. - * Once complete return the appropriate return - * code to indicate that the update was successful. - * - * Called by: device_stat() in wanmain.c - * - * Assumptions: - * - * Warnings: This function will degrade the performance - * of the router, since it uses the mailbox. - * - * Return: 0 OK - * <0 Failed (or busy). - */ - -static int update(struct wan_device* wandev) -{ - volatile sdla_t* card; - TX25Status* status; - unsigned long timeout; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - if (test_bit(SEND_CRIT, (void*)&wandev->critical)) - return -EAGAIN; - - if (!wandev->dev) - return -ENODEV; - - card = wandev->private; - status = card->flags; - - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; - status->imask |= INTR_ON_TIMER; - timeout = jiffies; - - for (;;){ - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE)){ - break; - } - if (time_after(jiffies, timeout + 1*HZ)){ - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - return 0; -} - - -/*=================================================================== - * Name: new_if - * - * Purpose: To allocate and initialize resources for a - * new logical channel. - * - * Rationale: A new channel can be added dynamically via - * ioctl call. - * - * Description: Allocate a private channel structure, x25_channel_t. - * Parse the user interface options from wanpipe#.conf - * configuration file. - * Bind the private are into the network device private - * area pointer (dev->priv). - * Prepare the network device structure for registration. - * - * Called by: ROUTER_IFNEW Ioctl call, from wanrouter_ioctl() - * (wanmain.c) - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok - * <0 Failed (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf) -{ - sdla_t* card = wandev->private; - x25_channel_t* chan; - int err = 0; - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); - return -EINVAL; - } - - if(card->wandev.new_if_cnt++ > 0 && card->u.x.LAPB_hdlc) { - printk(KERN_INFO "%s: Error: Running LAPB HDLC Mode !\n", - card->devname); - printk(KERN_INFO - "%s: Maximum number of network interfaces must be one !\n", - card->devname); - return -EEXIST; - } - - /* allocate and initialize private data */ - chan = kmalloc(sizeof(x25_channel_t), GFP_ATOMIC); - if (chan == NULL){ - return -ENOMEM; - } - - memset(chan, 0, sizeof(x25_channel_t)); - - /* Bug Fix: Seg Err on PVC startup - * It must be here since bind_lcn_to_dev expects - * it bellow */ - dev->priv = chan; - - strcpy(chan->name, conf->name); - chan->card = card; - chan->dev = dev; - chan->common.sk = NULL; - chan->common.func = NULL; - chan->common.rw_bind = 0; - chan->tx_skb = chan->rx_skb = NULL; - - /* verify media address */ - if (conf->addr[0] == '@'){ /* SVC */ - chan->common.svc = 1; - strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ); - - /* Set channel timeouts (default if not specified) */ - chan->idle_timeout = (conf->idle_timeout) ? - conf->idle_timeout : 90; - chan->hold_timeout = (conf->hold_timeout) ? - conf->hold_timeout : 10; - - }else if (isdigit(conf->addr[0])){ /* PVC */ - int lcn = dec_to_uint(conf->addr, 0); - - if ((lcn >= card->u.x.lo_pvc) && (lcn <= card->u.x.hi_pvc)){ - bind_lcn_to_dev (card, dev, lcn); - }else{ - printk(KERN_ERR - "%s: PVC %u is out of range on interface %s!\n", - wandev->name, lcn, chan->name); - err = -EINVAL; - } - }else{ - printk(KERN_ERR - "%s: invalid media address on interface %s!\n", - wandev->name, chan->name); - err = -EINVAL; - } - - if(strcmp(conf->usedby, "WANPIPE") == 0){ - printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", - wandev->name, chan->name); - chan->common.usedby = WANPIPE; - chan->protocol = htons(ETH_P_IP); - - }else if(strcmp(conf->usedby, "API") == 0){ - chan->common.usedby = API; - printk(KERN_INFO "%s: Running in API mode %s\n", - wandev->name, chan->name); - chan->protocol = htons(X25_PROT); - } - - - if (err){ - kfree(chan); - dev->priv = NULL; - return err; - } - - chan->enable_IPX = conf->enable_IPX; - - if (chan->enable_IPX) - chan->protocol = htons(ETH_P_IPX); - - if (conf->network_number) - chan->network_number = conf->network_number; - else - chan->network_number = 0xDEADBEEF; - - /* prepare network device data space for registration */ - strcpy(dev->name,chan->name); - - dev->init = &if_init; - - init_x25_channel_struct(chan); - - return 0; -} - -/*=================================================================== - * Name: del_if(), Remove a logical channel. - * - * Purpose: To dynamically remove a logical channel. - * - * Rationale: Each logical channel should be dynamically - * removable. This functin is called by an - * IOCTL_IFDEL ioctl call or shutdown(). - * - * Description: Do nothing. - * - * Called by: IOCTL_IFDEL : wanrouter_ioctl() from wanmain.c - * shutdown() from sdlamain.c - * - * Assumptions: - * - * Warnings: - * - * Return: 0 Ok. Void function. - */ - -//FIXME Del IF Should be taken out now. - -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - return 0; -} - - -/*============================================================ - * Name: wpx_exec - * - * Description: Execute adapter interface command. - * This option is currently dissabled. - *===========================================================*/ - -static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) -{ - return 0; -} - -/*============================================================ - * Name: disable_comm - * - * Description: Disable communications during shutdown. - * Dont check return code because there is - * nothing we can do about it. - * - * Warning: Dev and private areas are gone at this point. - *===========================================================*/ - -static void disable_comm(sdla_t* card) -{ - disable_comm_shutdown(card); - del_timer(&card->u.x.x25_timer); - return; -} - - -/*============================================================ - * Network Device Interface - *===========================================================*/ - -/*=================================================================== - * Name: if_init(), Netowrk Interface Initialization - * - * Purpose: To initialize a network interface device structure. - * - * Rationale: During network interface startup, the if_init - * is called by the kernel to initialize the - * netowrk device structure. Thus a driver - * can customze a network device. - * - * Description: Initialize the netowrk device call back - * routines. This is where we tell the kernel - * which function to use when it wants to send - * via our interface. - * Furthermore, we initialize the device flags, - * MTU and physical address of the board. - * - * Called by: Kernel (/usr/src/linux/net/core/dev.c) - * (dev->init()) - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok : Void function. - */ -static int if_init(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct wan_device* wandev = &card->wandev; - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->flags |= IFF_POINTOPOINT; - dev->flags |= IFF_NOARP; - - if (chan->common.usedby == API){ - dev->mtu = X25_CHAN_MTU+sizeof(x25api_hdr_t); - }else{ - dev->mtu = card->wandev.mtu; - } - - dev->hard_header_len = X25_HRDHDR_SZ; /* media header length */ - dev->addr_len = 2; /* hardware address length */ - - if (!chan->common.svc){ - *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); - } - - /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; - SET_MODULE_OWNER(dev); - - /* FIXME Why are we doing this */ - set_chan_state(dev, WAN_DISCONNECTED); - return 0; -} - - -/*=================================================================== - * Name: if_open(), Open/Bring up the Netowrk Interface - * - * Purpose: To bring up a network interface. - * - * Rationale: - * - * Description: Open network interface. - * o prevent module from unloading by incrementing use count - * o if link is disconnected then initiate connection - * - * Called by: Kernel (/usr/src/linux/net/core/dev.c) - * (dev->open()) - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok - * <0 Failure: Interface will not come up. - */ - -static int if_open(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct timeval tv; - unsigned long smp_flags; - - if (netif_running(dev)) - return -EBUSY; - - chan->tq_working = 0; - - /* Initialize the workqueue */ - INIT_WORK(&chan->common.wanpipe_work, (void *)x25api_bh, dev); - - /* Allocate and initialize BH circular buffer */ - /* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */ - chan->bh_head = kmalloc((sizeof(bh_data_t)*(MAX_BH_BUFF+1)),GFP_ATOMIC); - - if (chan->bh_head == NULL){ - printk(KERN_INFO "%s: ERROR, failed to allocate memory ! BH_BUFFERS !\n", - card->devname); - - return -ENOBUFS; - } - memset(chan->bh_head,0,(sizeof(bh_data_t)*(MAX_BH_BUFF+1))); - atomic_set(&chan->bh_buff_used, 0); - - /* Increment the number of interfaces */ - ++card->u.x.no_dev; - - wanpipe_open(card); - - /* LAPB protocol only uses one interface, thus - * start the protocol after it comes up. */ - if (card->u.x.LAPB_hdlc){ - if (card->open_cnt == 1){ - TX25Status* status = card->flags; - S508_S514_lock(card, &smp_flags); - x25_set_intr_mode(card, INTR_ON_TIMER); - status->imask &= ~INTR_ON_TIMER; - S508_S514_unlock(card, &smp_flags); - } - }else{ - /* X25 can have multiple interfaces thus, start the - * protocol once all interfaces are up */ - - //FIXME: There is a bug here. If interface is - //brought down and up, it will try to enable comm. - if (card->open_cnt == card->u.x.num_of_ch){ - - S508_S514_lock(card, &smp_flags); - connect(card); - S508_S514_unlock(card, &smp_flags); - - mod_timer(&card->u.x.x25_timer, jiffies + HZ); - } - } - /* Device is not up until the we are in connected state */ - do_gettimeofday( &tv ); - chan->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - return 0; -} - -/*=================================================================== - * Name: if_close(), Close/Bring down the Netowrk Interface - * - * Purpose: To bring down a network interface. - * - * Rationale: - * - * Description: Close network interface. - * o decrement use module use count - * - * Called by: Kernel (/usr/src/linux/net/core/dev.c) - * (dev->close()) - * ifconfig down: will trigger the kernel - * which will call this function. - * - * Assumptions: None - * - * Warnings: None - * - * Return: 0 Ok - * <0 Failure: Interface will not exit properly. - */ -static int if_close(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - unsigned long smp_flags; - - netif_stop_queue(dev); - - if ((chan->common.state == WAN_CONNECTED) || - (chan->common.state == WAN_CONNECTING)){ - S508_S514_lock(card, &smp_flags); - chan_disc(dev); - S508_S514_unlock(card, &smp_flags); - } - - wanpipe_close(card); - - S508_S514_lock(card, &smp_flags); - if (chan->bh_head){ - int i; - struct sk_buff *skb; - - for (i=0; i<(MAX_BH_BUFF+1); i++){ - skb = ((bh_data_t *)&chan->bh_head[i])->skb; - if (skb != NULL){ - dev_kfree_skb_any(skb); - } - } - kfree(chan->bh_head); - chan->bh_head=NULL; - } - S508_S514_unlock(card, &smp_flags); - - /* If this is the last close, disconnect physical link */ - if (!card->open_cnt){ - S508_S514_lock(card, &smp_flags); - disconnect(card); - x25_set_intr_mode(card, 0); - S508_S514_unlock(card, &smp_flags); - } - - /* Decrement the number of interfaces */ - --card->u.x.no_dev; - return 0; -} - -/*====================================================================== - * Build media header. - * o encapsulate packet according to encapsulation type. - * - * The trick here is to put packet type (Ethertype) into 'protocol' - * field of the socket buffer, so that we don't forget it. - * If encapsulation fails, set skb->protocol to 0 and discard - * packet later. - * - * Return: media header length. - *======================================================================*/ - -static int if_header(struct sk_buff* skb, struct net_device* dev, - unsigned short type, void* daddr, void* saddr, - unsigned len) -{ - x25_channel_t* chan = dev->priv; - int hdr_len = dev->hard_header_len; - - skb->protocol = htons(type); - if (!chan->protocol){ - hdr_len = wanrouter_encapsulate(skb, dev, type); - if (hdr_len < 0){ - hdr_len = 0; - skb->protocol = htons(0); - } - } - return hdr_len; -} - -/*=============================================================== - * Re-build media header. - * - * Return: 1 physical address resolved. - * 0 physical address not resolved - *==============================================================*/ - -static int if_rebuild_hdr (struct sk_buff* skb) -{ - struct net_device *dev = skb->dev; - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); - return 1; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++chan->if_send_stat.if_send_tbusy_timeout; - printk (KERN_INFO "%s: Transmit timed out on %s\n", - card->devname, dev->name); - netif_wake_queue (dev); -} - - -/*========================================================================= - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission). - * o check link state. If link is not up, then drop the packet. - * o check channel status. If it's down then initiate a call. - * o pass a packet to corresponding WAN device. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - * - *========================================================================*/ - -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - int udp_type; - unsigned long smp_flags=0; - - ++chan->if_send_stat.if_send_entry; - - netif_stop_queue(dev); - - /* No need to check frame length, since socket code - * will perform the check for us */ - - chan->tick_counter = jiffies; - - /* Critical region starts here */ - S508_S514_lock(card, &smp_flags); - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - printk(KERN_INFO "Hit critical in if_send()! %lx\n",card->wandev.critical); - goto if_send_crit_exit; - } - - udp_type = udp_pkt_type(skb, card); - - if(udp_type != UDP_INVALID_TYPE) { - - if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, dev, skb, - chan->common.lcn)) { - - status->imask |= INTR_ON_TIMER; - if (udp_type == UDP_XPIPE_TYPE){ - chan->if_send_stat.if_send_PIPE_request++; - } - } - netif_start_queue(dev); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - S508_S514_unlock(card, &smp_flags); - return 0; - } - - if (chan->transmit_length){ - //FIXME: This check doesn't make sense any more - if (chan->common.state != WAN_CONNECTED){ - chan->transmit_length=0; - atomic_set(&chan->common.driver_busy,0); - }else{ - netif_stop_queue(dev); - ++card->u.x.tx_interrupts_pending; - status->imask |= INTR_ON_TX_FRAME; - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - S508_S514_unlock(card, &smp_flags); - return 1; - } - } - - if (card->wandev.state != WAN_CONNECTED){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_wan_disconnected; - - }else if ( chan->protocol && (chan->protocol != skb->protocol)){ - printk(KERN_INFO - "%s: unsupported Ethertype 0x%04X on interface %s!\n", - chan->name, htons(skb->protocol), dev->name); - - printk(KERN_INFO "PROTO %Xn", htons(chan->protocol)); - ++chan->ifstats.tx_errors; - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_protocol_error; - - }else switch (chan->common.state){ - - case WAN_DISCONNECTED: - /* Try to establish connection. If succeded, then start - * transmission, else drop a packet. - */ - if (chan->common.usedby == API){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - }else{ - if (chan_connect(dev) != 0){ - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - } - /* fall through */ - - case WAN_CONNECTED: - if( skb->protocol == htons(ETH_P_IPX)) { - if(chan->enable_IPX) { - switch_net_numbers( skb->data, - chan->network_number, 0); - } else { - ++card->wandev.stats.tx_dropped; - ++chan->ifstats.tx_dropped; - ++chan->if_send_stat.if_send_protocol_error; - goto if_send_crit_exit; - } - } - /* We never drop here, if cannot send than, copy - * a packet into a transmit buffer - */ - chan_send(dev, skb->data, skb->len, 0); - break; - - default: - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - break; - } - - -if_send_crit_exit: - - dev_kfree_skb_any(skb); - - netif_start_queue(dev); - clear_bit(SEND_CRIT,(void*)&card->wandev.critical); - S508_S514_unlock(card, &smp_flags); - return 0; -} - -/*============================================================================ - * Setup so that a frame can be transmitted on the occurrence of a transmit - * interrupt. - *===========================================================================*/ - -static void setup_for_delayed_transmit(struct net_device* dev, void* buf, - unsigned len) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - - ++chan->if_send_stat.if_send_adptr_bfrs_full; - - if(chan->transmit_length) { - printk(KERN_INFO "%s: Error, transmit length set in delayed transmit!\n", - card->devname); - return; - } - - if (chan->common.usedby == API){ - if (len > X25_CHAN_MTU+sizeof(x25api_hdr_t)) { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - printk(KERN_INFO "%s: Length is too big for delayed transmit\n", - card->devname); - return; - } - }else{ - if (len > X25_MAX_DATA) { - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - printk(KERN_INFO "%s: Length is too big for delayed transmit\n", - card->devname); - return; - } - } - - chan->transmit_length = len; - atomic_set(&chan->common.driver_busy,1); - memcpy(chan->transmit_buffer, buf, len); - - ++chan->if_send_stat.if_send_tx_int_enabled; - - /* Enable Transmit Interrupt */ - ++card->u.x.tx_interrupts_pending; - status->imask |= INTR_ON_TX_FRAME; -} - - -/*=============================================================== - * net_device_stats - * - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - * - *==============================================================*/ -static struct net_device_stats *if_stats(struct net_device* dev) -{ - x25_channel_t *chan = dev->priv; - - if(chan == NULL) - return NULL; - - return &chan->ifstats; -} - - -/* - * Interrupt Handlers - */ - -/* - * X.25 Interrupt Service Routine. - */ - -static void wpx_isr (sdla_t* card) -{ - TX25Status* status = card->flags; - - card->in_isr = 1; - ++card->statistics.isr_entry; - - if (test_bit(PERI_CRIT,(void*)&card->wandev.critical)){ - card->in_isr=0; - status->iflags = 0; - return; - } - - if (test_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - - printk(KERN_INFO "%s: wpx_isr: wandev.critical set to 0x%02lx, int type = 0x%02x\n", - card->devname, card->wandev.critical, status->iflags); - card->in_isr = 0; - status->iflags = 0; - return; - } - - /* For all interrupts set the critical flag to CRITICAL_RX_INTR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ - switch (status->iflags){ - - case RX_INTR_PENDING: /* receive interrupt */ - rx_intr(card); - break; - - case TX_INTR_PENDING: /* transmit interrupt */ - tx_intr(card); - break; - - case MODEM_INTR_PENDING: /* modem status interrupt */ - status_intr(card); - break; - - case X25_ASY_TRANS_INTR_PENDING: /* network event interrupt */ - event_intr(card); - break; - - case TIMER_INTR_PENDING: - timer_intr(card); - break; - - default: /* unwanted interrupt */ - spur_intr(card); - } - - card->in_isr = 0; - status->iflags = 0; /* clear interrupt condition */ -} - -/* - * Receive interrupt handler. - * This routine handles fragmented IP packets using M-bit according to the - * RFC1356. - * o map ligical channel number to network interface. - * o allocate socket buffer or append received packet to the existing one. - * o if M-bit is reset (i.e. it's the last packet in a sequence) then - * decapsulate packet and pass socket buffer to the protocol stack. - * - * Notes: - * 1. When allocating a socket buffer, if M-bit is set then more data is - * coming and we have to allocate buffer for the maximum IP packet size - * expected on this channel. - * 2. If something goes wrong and X.25 packet has to be dropped (e.g. no - * socket buffers available) the whole packet sequence must be discarded. - */ - -static void rx_intr (sdla_t* card) -{ - TX25Mbox* rxmb = card->rxmb; - unsigned lcn = rxmb->cmd.lcn; - struct net_device* dev = find_channel(card,lcn); - x25_channel_t* chan; - struct sk_buff* skb=NULL; - - if (dev == NULL){ - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n", - card->devname, lcn); - return; - } - - chan = dev->priv; - chan->i_timeout_sofar = jiffies; - - - /* Copy the data from the board, into an - * skb buffer - */ - if (wanpipe_pull_data_in_skb(card,dev,&skb)){ - ++chan->ifstats.rx_dropped; - ++card->wandev.stats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_no_socket; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - return; - } - - dev->last_rx = jiffies; /* timestamp */ - - - /* ------------ API ----------------*/ - - if (chan->common.usedby == API){ - - if (bh_enqueue(dev, skb)){ - ++chan->ifstats.rx_dropped; - ++card->wandev.stats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - dev_kfree_skb_any(skb); - return; - } - - ++chan->ifstats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - - - chan->rx_skb = NULL; - if (!test_and_set_bit(0, &chan->tq_working)){ - wanpipe_queue_work(&chan->common.wanpipe_work); - } - return; - } - - - /* ------------- WANPIPE -------------------*/ - - /* set rx_skb to NULL so we won't access it later when kernel already owns it */ - chan->rx_skb=NULL; - - /* Decapsulate packet, if necessary */ - if (!skb->protocol && !wanrouter_type_trans(skb, dev)){ - /* can't decapsulate packet */ - dev_kfree_skb_any(skb); - ++chan->ifstats.rx_errors; - ++chan->ifstats.rx_dropped; - ++card->wandev.stats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - - }else{ - if( handle_IPXWAN(skb->data, chan->name, - chan->enable_IPX, chan->network_number, - skb->protocol)){ - - if( chan->enable_IPX ){ - if(chan_send(dev, skb->data, skb->len,0)){ - chan->tx_skb = skb; - }else{ - dev_kfree_skb_any(skb); - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - } - }else{ - /* increment IPX packet dropped statistic */ - ++chan->ifstats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - } - }else{ - skb->mac.raw = skb->data; - chan->ifstats.rx_bytes += skb->len; - ++chan->ifstats.rx_packets; - ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; - netif_rx(skb); - } - } - - return; -} - - -static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev, - struct sk_buff **skb) -{ - void *bufptr; - TX25Mbox* rxmb = card->rxmb; - unsigned len = rxmb->cmd.length; /* packet length */ - unsigned qdm = rxmb->cmd.qdm; /* Q,D and M bits */ - x25_channel_t *chan = dev->priv; - struct sk_buff *new_skb = *skb; - - if (chan->common.usedby == WANPIPE){ - if (chan->drop_sequence){ - if (!(qdm & 0x01)){ - chan->drop_sequence = 0; - } - return 1; - } - new_skb = chan->rx_skb; - }else{ - /* Add on the API header to the received - * data - */ - len += sizeof(x25api_hdr_t); - } - - if (new_skb == NULL){ - int bufsize; - - if (chan->common.usedby == WANPIPE){ - bufsize = (qdm & 0x01) ? dev->mtu : len; - }else{ - bufsize = len; - } - - /* Allocate new socket buffer */ - new_skb = dev_alloc_skb(bufsize + dev->hard_header_len); - if (new_skb == NULL){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - chan->drop_sequence = 1; /* set flag */ - ++chan->ifstats.rx_dropped; - return 1; - } - } - - if (skb_tailroom(new_skb) < len){ - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb_any(new_skb); - if (chan->common.usedby == WANPIPE){ - chan->rx_skb = NULL; - if (qdm & 0x01){ - chan->drop_sequence = 1; - } - } - - printk(KERN_INFO "%s: unexpectedly long packet sequence " - "on interface %s!\n", card->devname, dev->name); - ++chan->ifstats.rx_length_errors; - return 1; - } - - bufptr = skb_put(new_skb,len); - - - if (chan->common.usedby == API){ - /* Fill in the x25api header - */ - x25api_t * api_data = (x25api_t*)bufptr; - api_data->hdr.qdm = rxmb->cmd.qdm; - api_data->hdr.cause = rxmb->cmd.cause; - api_data->hdr.diagn = rxmb->cmd.diagn; - api_data->hdr.length = rxmb->cmd.length; - memcpy(api_data->data, rxmb->data, rxmb->cmd.length); - }else{ - memcpy(bufptr, rxmb->data, len); - } - - new_skb->dev = dev; - - if (chan->common.usedby == API){ - new_skb->mac.raw = new_skb->data; - new_skb->protocol = htons(X25_PROT); - new_skb->pkt_type = WAN_PACKET_DATA; - }else{ - new_skb->protocol = chan->protocol; - chan->rx_skb = new_skb; - } - - /* If qdm bit is set, more data is coming - * thus, exit and wait for more data before - * sending the packet up. (Used by router only) - */ - if ((qdm & 0x01) && (chan->common.usedby == WANPIPE)) - return 1; - - *skb = new_skb; - - return 0; -} - -/*=============================================================== - * tx_intr - * - * Transmit interrupt handler. - * For each dev, check that there is something to send. - * If data available, transmit. - * - *===============================================================*/ - -static void tx_intr (sdla_t* card) -{ - struct net_device *dev; - TX25Status* status = card->flags; - unsigned char more_to_tx=0; - x25_channel_t *chan=NULL; - int i=0; - - if (card->u.x.tx_dev == NULL){ - card->u.x.tx_dev = card->wandev.dev; - } - - dev = card->u.x.tx_dev; - - for (;;){ - - chan = dev->priv; - if (chan->transmit_length){ - /* Device was set to transmit, check if the TX - * buffers are available - */ - if (chan->common.state != WAN_CONNECTED){ - chan->transmit_length = 0; - atomic_set(&chan->common.driver_busy,0); - chan->tx_offset=0; - if (netif_queue_stopped(dev)){ - if (chan->common.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - dev = move_dev_to_next(card,dev); - break; - } - - if ((status->cflags[chan->ch_idx] & 0x40 || card->u.x.LAPB_hdlc) && - (*card->u.x.hdlc_buf_status & 0x40) ){ - /* Tx buffer available, we can send */ - - if (tx_intr_send(card, dev)){ - more_to_tx=1; - } - - /* If more than one interface present, move the - * device pointer to the next interface, so on the - * next TX interrupt we will try sending from it. - */ - dev = move_dev_to_next(card,dev); - break; - }else{ - /* Tx buffers not available, but device set - * the TX interrupt. Set more_to_tx and try - * to transmit for other devices. - */ - more_to_tx=1; - dev = move_dev_to_next(card,dev); - } - - }else{ - /* This device was not set to transmit, - * go to next - */ - dev = move_dev_to_next(card,dev); - } - - if (++i == card->u.x.no_dev){ - if (!more_to_tx){ - DBG_PRINTK(KERN_INFO "%s: Nothing to Send in TX INTR\n", - card->devname); - } - break; - } - - } //End of FOR - - card->u.x.tx_dev = dev; - - if (!more_to_tx){ - /* if any other interfaces have transmit interrupts pending, */ - /* do not disable the global transmit interrupt */ - if (!(--card->u.x.tx_interrupts_pending)){ - status->imask &= ~INTR_ON_TX_FRAME; - } - } - return; -} - -/*=============================================================== - * move_dev_to_next - * - * - *===============================================================*/ - - -struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev) -{ - if (card->u.x.no_dev != 1){ - if (!*((struct net_device **)dev->priv)) - return card->wandev.dev; - else - return *((struct net_device **)dev->priv); - } - return dev; -} - -/*=============================================================== - * tx_intr_send - * - * - *===============================================================*/ - -static int tx_intr_send(sdla_t *card, struct net_device *dev) -{ - x25_channel_t* chan = dev->priv; - - if (chan_send (dev,chan->transmit_buffer,chan->transmit_length,1)){ - - /* Packet was split up due to its size, do not disable - * tx_intr - */ - return 1; - } - - chan->transmit_length=0; - atomic_set(&chan->common.driver_busy,0); - chan->tx_offset=0; - - /* If we are in API mode, wakeup the - * sock BH handler, not the NET_BH */ - if (netif_queue_stopped(dev)){ - if (chan->common.usedby == API){ - netif_start_queue(dev); - wakeup_sk_bh(dev); - }else{ - netif_wake_queue(dev); - } - } - return 0; -} - - -/*=============================================================== - * timer_intr - * - * Timer interrupt handler. - * Check who called the timer interrupt and perform - * action accordingly. - * - *===============================================================*/ - -static void timer_intr (sdla_t *card) -{ - TX25Status* status = card->flags; - - if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC){ - - if (timer_intr_cmd_exec(card) == 0){ - card->u.x.timer_int_enabled &= - ~TMR_INT_ENABLED_CMD_EXEC; - } - - }else if(card->u.x.timer_int_enabled & TMR_INT_ENABLED_UDP_PKT) { - - if ((*card->u.x.hdlc_buf_status & 0x40) && - card->u.x.udp_type == UDP_XPIPE_TYPE){ - - if(process_udp_mgmt_pkt(card)) { - card->u.x.timer_int_enabled &= - ~TMR_INT_ENABLED_UDP_PKT; - } - } - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) { - - struct net_device *dev = card->u.x.poll_device; - x25_channel_t *chan = NULL; - - if (!dev){ - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; - return; - } - chan = dev->priv; - - printk(KERN_INFO - "%s: Closing down Idle link %s on LCN %d\n", - card->devname,chan->name,chan->common.lcn); - chan->i_timeout_sofar = jiffies; - chan_disc(dev); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_ACTIVE; - card->u.x.poll_device=NULL; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_ON) { - - wanpipe_set_state(card, WAN_CONNECTED); - if (card->u.x.LAPB_hdlc){ - struct net_device *dev = card->wandev.dev; - set_chan_state(dev,WAN_CONNECTED); - send_delayed_cmd_result(card,dev,card->mbox); - } - - /* 0x8F enable all interrupts */ - x25_set_intr_mode(card, INTR_ON_RX_FRAME| - INTR_ON_TX_FRAME| - INTR_ON_MODEM_STATUS_CHANGE| - //INTR_ON_COMMAND_COMPLETE| - X25_ASY_TRANS_INTR_PENDING | - INTR_ON_TIMER | - DIRECT_RX_INTR_USAGE - ); - - status->imask &= ~INTR_ON_TX_FRAME; /* mask Tx interrupts */ - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_ON; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_CONNECT_OFF) { - - //printk(KERN_INFO "Poll connect, Turning OFF\n"); - disconnect(card); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_CONNECT_OFF; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_DISCONNECT) { - - //printk(KERN_INFO "POll disconnect, trying to connect\n"); - connect(card); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_POLL_DISCONNECT; - - }else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_UPDATE){ - - if (*card->u.x.hdlc_buf_status & 0x40){ - x25_get_err_stats(card); - x25_get_stats(card); - card->u.x.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; - } - } - - if(!card->u.x.timer_int_enabled){ - //printk(KERN_INFO "Turning Timer Off \n"); - status->imask &= ~INTR_ON_TIMER; - } -} - -/*==================================================================== - * Modem status interrupt handler. - *===================================================================*/ -static void status_intr (sdla_t* card) -{ - - /* Added to avoid Modem status message flooding */ - static TX25ModemStatus last_stat; - - TX25Mbox* mbox = card->mbox; - TX25ModemStatus *modem_status; - struct net_device *dev; - x25_channel_t *chan; - int err; - - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_MODEM_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err){ - x25_error(card, err, X25_READ_MODEM_STATUS, 0); - }else{ - - modem_status = (TX25ModemStatus*)mbox->data; - - /* Check if the last status was the same - * if it was, do NOT print message again */ - - if (last_stat.status != modem_status->status){ - - printk(KERN_INFO "%s: Modem Status Change: DCD=%s, CTS=%s\n", - card->devname,DCD(modem_status->status),CTS(modem_status->status)); - - last_stat.status = modem_status->status; - - if (card->u.x.oob_on_modem){ - - mbox->cmd.pktType = mbox->cmd.command; - mbox->cmd.result = 0x08; - - /* Send a OOB to all connected sockets */ - for (dev = card->wandev.dev; dev; - dev = *((struct net_device**)dev->priv)) { - chan=dev->priv; - if (chan->common.usedby == API){ - send_oob_msg(card,dev,mbox); - } - } - - /* The modem OOB message will probably kill the - * the link. If we don't clear the flag here, - * a deadlock could occur */ - if (atomic_read(&card->u.x.command_busy)){ - atomic_set(&card->u.x.command_busy,0); - } - } - } - } - - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err){ - x25_error(card, err, X25_HDLC_LINK_STATUS, 0); - } - -} - -/*==================================================================== - * Network event interrupt handler. - *===================================================================*/ -static void event_intr (sdla_t* card) -{ - x25_fetch_events(card); -} - -/*==================================================================== - * Spurious interrupt handler. - * o print a warning - * o - *====================================================================*/ - -static void spur_intr (sdla_t* card) -{ - printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); -} - - -/* - * Background Polling Routines - */ - -/*==================================================================== - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - *====================================================================*/ - -static void wpx_poll (sdla_t *card) -{ - if (!card->wandev.dev){ - goto wpx_poll_exit; - } - - if (card->open_cnt != card->u.x.num_of_ch){ - goto wpx_poll_exit; - } - - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - goto wpx_poll_exit; - } - - if (test_bit(SEND_CRIT,&card->wandev.critical)){ - goto wpx_poll_exit; - } - - switch(card->wandev.state){ - case WAN_CONNECTED: - poll_active(card); - break; - - case WAN_CONNECTING: - poll_connecting(card); - break; - - case WAN_DISCONNECTED: - poll_disconnected(card); - break; - } - -wpx_poll_exit: - clear_bit(POLL_CRIT,&card->wandev.critical); - return; -} - -static void trigger_x25_poll(sdla_t *card) -{ - schedule_work(&card->u.x.x25_poll_work); -} - -/*==================================================================== - * Handle physical link establishment phase. - * o if connection timed out, disconnect the link. - *===================================================================*/ - -static void poll_connecting (sdla_t* card) -{ - volatile TX25Status* status = card->flags; - - if (status->gflags & X25_HDLC_ABM){ - - timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_ON); - - }else if ((jiffies - card->state_tick) > CONNECT_TIMEOUT){ - - timer_intr_exec (card, TMR_INT_ENABLED_POLL_CONNECT_OFF); - - } -} - -/*==================================================================== - * Handle physical link disconnected phase. - * o if hold-down timeout has expired and there are open interfaces, - * connect link. - *===================================================================*/ - -static void poll_disconnected (sdla_t* card) -{ - struct net_device *dev; - x25_channel_t *chan; - TX25Status* status = card->flags; - - if (!card->u.x.LAPB_hdlc && card->open_cnt && - ((jiffies - card->state_tick) > HOLD_DOWN_TIME)){ - timer_intr_exec(card, TMR_INT_ENABLED_POLL_DISCONNECT); - } - - - if ((dev=card->wandev.dev) == NULL) - return; - - if ((chan=dev->priv) == NULL) - return; - - if (chan->common.usedby == API && - atomic_read(&chan->common.command) && - card->u.x.LAPB_hdlc){ - - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; - - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; - } - -} - -/*==================================================================== - * Handle active link phase. - * o fetch X.25 asynchronous events. - * o kick off transmission on all interfaces. - *===================================================================*/ - -static void poll_active (sdla_t* card) -{ - struct net_device* dev; - TX25Status* status = card->flags; - - for (dev = card->wandev.dev; dev; - dev = *((struct net_device **)dev->priv)){ - x25_channel_t* chan = dev->priv; - - /* If SVC has been idle long enough, close virtual circuit */ - if ( chan->common.svc && - chan->common.state == WAN_CONNECTED && - chan->common.usedby == WANPIPE ){ - - if( (jiffies - chan->i_timeout_sofar) / HZ > chan->idle_timeout ){ - /* Close svc */ - card->u.x.poll_device=dev; - timer_intr_exec (card, TMR_INT_ENABLED_POLL_ACTIVE); - } - } - -#ifdef PRINT_DEBUG - chan->ifstats.tx_compressed = atomic_read(&chan->common.command); - chan->ifstats.tx_errors = chan->common.state; - chan->ifstats.rx_fifo_errors = atomic_read(&card->u.x.command_busy); - ++chan->ifstats.tx_bytes; - - chan->ifstats.rx_fifo_errors=atomic_read(&chan->common.disconnect); - chan->ifstats.multicast=atomic_read(&chan->bh_buff_used); - chan->ifstats.rx_length_errors=*card->u.x.hdlc_buf_status; -#endif - - if (chan->common.usedby == API && - atomic_read(&chan->common.command) && - !card->u.x.LAPB_hdlc){ - - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; - - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; - } - - if ((chan->common.usedby == API) && - atomic_read(&chan->common.disconnect)){ - - if (chan->common.state == WAN_DISCONNECTED){ - atomic_set(&chan->common.disconnect,0); - return; - } - - atomic_set(&chan->common.command,X25_CLEAR_CALL); - if (!(card->u.x.timer_int_enabled & TMR_INT_ENABLED_CMD_EXEC)) - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_CMD_EXEC; - - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; - } - } -} - -static void timer_intr_exec(sdla_t *card, unsigned char TYPE) -{ - TX25Status* status = card->flags; - card->u.x.timer_int_enabled |= TYPE; - if (!(status->imask & INTR_ON_TIMER)) - status->imask |= INTR_ON_TIMER; -} - - -/*==================================================================== - * SDLA Firmware-Specific Functions - * - * Almost all X.25 commands can unexpetedly fail due to so called 'X.25 - * asynchronous events' such as restart, interrupt, incoming call request, - * call clear request, etc. They can't be ignored and have to be delt with - * immediately. To tackle with this problem we execute each interface - * command in a loop until good return code is received or maximum number - * of retries is reached. Each interface command returns non-zero return - * code, an asynchronous event/error handler x25_error() is called. - *====================================================================*/ - -/*==================================================================== - * Read X.25 firmware version. - * Put code version as ASCII string in str. - *===================================================================*/ - -static int x25_get_version (sdla_t* card, char* str) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_CODE_VERSION; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && - x25_error(card, err, X25_READ_CODE_VERSION, 0)); - - if (!err && str) - { - int len = mbox->cmd.length; - - memcpy(str, mbox->data, len); - str[len] = '\0'; - } - return err; -} - -/*==================================================================== - * Configure adapter. - *===================================================================*/ - -static int x25_configure (sdla_t* card, TX25Config* conf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); - mbox->cmd.length = sizeof(TX25Config); - mbox->cmd.command = X25_SET_CONFIGURATION; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); - return err; -} - -/*==================================================================== - * Configure adapter for HDLC only. - *===================================================================*/ - -static int hdlc_configure (sdla_t* card, TX25Config* conf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, (void*)conf, sizeof(TX25Config)); - mbox->cmd.length = sizeof(TX25Config); - mbox->cmd.command = X25_HDLC_SET_CONFIG; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_CONFIGURATION, 0)); - - return err; -} - -static int set_hdlc_level (sdla_t* card) -{ - - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = SET_PROTOCOL_LEVEL; - mbox->cmd.length = 1; - mbox->data[0] = HDLC_LEVEL; //| DO_HDLC_LEVEL_ERROR_CHECKING; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, SET_PROTOCOL_LEVEL, 0)); - - return err; -} - - - -/*==================================================================== - * Get communications error statistics. - *====================================================================*/ - -static int x25_get_err_stats (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_READ_COMM_ERR; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)); - - if (!err) - { - THdlcCommErr* stats = (void*)mbox->data; - - card->wandev.stats.rx_over_errors = stats->rxOverrun; - card->wandev.stats.rx_crc_errors = stats->rxBadCrc; - card->wandev.stats.rx_missed_errors = stats->rxAborted; - card->wandev.stats.tx_aborted_errors = stats->txAborted; - } - return err; -} - -/*==================================================================== - * Get protocol statistics. - *===================================================================*/ - -static int x25_get_stats (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_READ_STATISTICS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_STATISTICS, 0)) ; - - if (!err) - { - TX25Stats* stats = (void*)mbox->data; - - card->wandev.stats.rx_packets = stats->rxData; - card->wandev.stats.tx_packets = stats->txData; - } - return err; -} - -/*==================================================================== - * Close HDLC link. - *===================================================================*/ - -static int x25_close_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_CLOSE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_CLOSE, 0)); - - return err; -} - - -/*==================================================================== - * Open HDLC link. - *===================================================================*/ - -static int x25_open_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_OPEN; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_OPEN, 0)); - - return err; -} - -/*===================================================================== - * Setup HDLC link. - *====================================================================*/ -static int x25_setup_hdlc (sdla_t* card) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_HDLC_LINK_SETUP; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_SETUP, 0)); - - return err; -} - -/*==================================================================== - * Set (raise/drop) DTR. - *===================================================================*/ - -static int x25_set_dtr (sdla_t* card, int dtr) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->data[0] = 0; - mbox->data[2] = 0; - mbox->data[1] = dtr ? 0x02 : 0x01; - mbox->cmd.length = 3; - mbox->cmd.command = X25_SET_GLOBAL_VARS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_GLOBAL_VARS, 0)); - - return err; -} - -/*==================================================================== - * Set interrupt mode. - *===================================================================*/ - -static int x25_set_intr_mode (sdla_t* card, int mode) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->data[0] = mode; - if (card->hw.fwid == SFID_X25_508){ - mbox->data[1] = card->hw.irq; - mbox->data[2] = 2; - mbox->cmd.length = 3; - }else { - mbox->cmd.length = 1; - } - mbox->cmd.command = X25_SET_INTERRUPT_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_SET_INTERRUPT_MODE, 0)); - - return err; -} - -/*==================================================================== - * Read X.25 channel configuration. - *===================================================================*/ - -static int x25_get_chan_conf (sdla_t* card, x25_channel_t* chan) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int lcn = chan->common.lcn; - int err; - - do{ - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.command = X25_READ_CHANNEL_CONFIG; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_READ_CHANNEL_CONFIG, lcn)); - - if (!err) - { - TX25Status* status = card->flags; - - /* calculate an offset into the array of status bytes */ - if (card->u.x.hi_svc <= X25_MAX_CHAN){ - - chan->ch_idx = lcn - 1; - - }else{ - int offset; - - /* FIX: Apr 14 2000 : Nenad Corbic - * The data field was being compared to 0x1F using - * '&&' instead of '&'. - * This caused X25API to fail for LCNs greater than 255. - */ - switch (mbox->data[0] & 0x1F) - { - case 0x01: - offset = status->pvc_map; break; - case 0x03: - offset = status->icc_map; break; - case 0x07: - offset = status->twc_map; break; - case 0x0B: - offset = status->ogc_map; break; - default: - offset = 0; - } - chan->ch_idx = lcn - 1 - offset; - } - - /* get actual transmit packet size on this channel */ - switch(mbox->data[1] & 0x38) - { - case 0x00: - chan->tx_pkt_size = 16; - break; - case 0x08: - chan->tx_pkt_size = 32; - break; - case 0x10: - chan->tx_pkt_size = 64; - break; - case 0x18: - chan->tx_pkt_size = 128; - break; - case 0x20: - chan->tx_pkt_size = 256; - break; - case 0x28: - chan->tx_pkt_size = 512; - break; - case 0x30: - chan->tx_pkt_size = 1024; - break; - } - if (card->u.x.logging) - printk(KERN_INFO "%s: X.25 packet size on LCN %d is %d.\n", - card->devname, lcn, chan->tx_pkt_size); - } - return err; -} - -/*==================================================================== - * Place X.25 call. - *====================================================================*/ - -static int x25_place_call (sdla_t* card, x25_channel_t* chan) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - char str[64]; - - - if (chan->protocol == htons(ETH_P_IP)){ - sprintf(str, "-d%s -uCC", chan->addr); - - }else if (chan->protocol == htons(ETH_P_IPX)){ - sprintf(str, "-d%s -u800000008137", chan->addr); - - } - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - strcpy(mbox->data, str); - mbox->cmd.length = strlen(str); - mbox->cmd.command = X25_PLACE_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_PLACE_CALL, 0)); - - if (!err){ - bind_lcn_to_dev (card, chan->dev, mbox->cmd.lcn); - } - return err; -} - -/*==================================================================== - * Accept X.25 call. - *====================================================================*/ - -static int x25_accept_call (sdla_t* card, int lcn, int qdm) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.qdm = qdm; - mbox->cmd.command = X25_ACCEPT_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_ACCEPT_CALL, lcn)); - - return err; -} - -/*==================================================================== - * Clear X.25 call. - *====================================================================*/ - -static int x25_clear_call (sdla_t* card, int lcn, int cause, int diagn) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.lcn = lcn; - mbox->cmd.cause = cause; - mbox->cmd.diagn = diagn; - mbox->cmd.command = X25_CLEAR_CALL; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, X25_CLEAR_CALL, lcn)); - - return err; -} - -/*==================================================================== - * Send X.25 data packet. - *====================================================================*/ - -static int x25_send (sdla_t* card, int lcn, int qdm, int len, void* buf) -{ - TX25Mbox* mbox = card->mbox; - int retry = MAX_CMD_RETRY; - int err; - unsigned char cmd; - - if (card->u.x.LAPB_hdlc) - cmd = X25_HDLC_WRITE; - else - cmd = X25_WRITE; - - do - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - memcpy(mbox->data, buf, len); - mbox->cmd.length = len; - mbox->cmd.lcn = lcn; - - if (card->u.x.LAPB_hdlc){ - mbox->cmd.pf = qdm; - }else{ - mbox->cmd.qdm = qdm; - } - - mbox->cmd.command = cmd; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && retry-- && x25_error(card, err, cmd , lcn)); - - - /* If buffers are busy the return code for LAPB HDLC is - * 1. The above functions are looking for return code - * of X25RES_NOT_READY if busy. */ - - if (card->u.x.LAPB_hdlc && err == 1){ - err = X25RES_NOT_READY; - } - - return err; -} - -/*==================================================================== - * Fetch X.25 asynchronous events. - *===================================================================*/ - -static int x25_fetch_events (sdla_t* card) -{ - TX25Status* status = card->flags; - TX25Mbox* mbox = card->mbox; - int err = 0; - - if (status->gflags & 0x20) - { - memset(&mbox->cmd, 0, sizeof(TX25Cmd)); - mbox->cmd.command = X25_IS_DATA_AVAILABLE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) x25_error(card, err, X25_IS_DATA_AVAILABLE, 0); - } - return err; -} - -/*==================================================================== - * X.25 asynchronous event/error handler. - * This routine is called each time interface command returns - * non-zero return code to handle X.25 asynchronous events and - * common errors. Return non-zero to repeat command or zero to - * cancel it. - * - * Notes: - * 1. This function may be called recursively, as handling some of the - * asynchronous events (e.g. call request) requires execution of the - * interface command(s) that, in turn, may also return asynchronous - * events. To avoid re-entrancy problems we copy mailbox to dynamically - * allocated memory before processing events. - *====================================================================*/ - -static int x25_error (sdla_t* card, int err, int cmd, int lcn) -{ - int retry = 1; - unsigned dlen = ((TX25Mbox*)card->mbox)->cmd.length; - TX25Mbox* mb; - - mb = kmalloc(sizeof(TX25Mbox) + dlen, GFP_ATOMIC); - if (mb == NULL) - { - printk(KERN_ERR "%s: x25_error() out of memory!\n", - card->devname); - return 0; - } - memcpy(mb, card->mbox, sizeof(TX25Mbox) + dlen); - switch (err){ - - case X25RES_ASYNC_PACKET: /* X.25 asynchronous packet was received */ - - mb->data[dlen] = '\0'; - - switch (mb->cmd.pktType & 0x7F){ - - case ASE_CALL_RQST: /* incoming call */ - retry = incoming_call(card, cmd, lcn, mb); - break; - - case ASE_CALL_ACCEPTED: /* connected */ - retry = call_accepted(card, cmd, lcn, mb); - break; - - case ASE_CLEAR_RQST: /* call clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; - - case ASE_RESET_RQST: /* reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - api_oob_event (card,mb); - break; - - case ASE_RESTART_RQST: /* restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; - - case ASE_CLEAR_CONFRM: - if (clear_confirm_event (card,mb)) - break; - - /* I use the goto statement here so if - * somebody inserts code between the - * case and default, we will not have - * ghost problems */ - - goto dflt_1; - - default: -dflt_1: - printk(KERN_INFO "%s: X.25 event 0x%02X on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.pktType, - mb->cmd.lcn, mb->cmd.cause, mb->cmd.diagn); - } - break; - - case X25RES_PROTO_VIOLATION: /* X.25 protocol violation indication */ - - /* Bug Fix: Mar 14 2000 - * The Protocol violation error conditions were - * not handled previously */ - - switch (mb->cmd.pktType & 0x7F){ - - case PVE_CLEAR_RQST: /* Clear request */ - retry = call_cleared(card, cmd, lcn, mb); - break; - - case PVE_RESET_RQST: /* Reset request */ - printk(KERN_INFO "%s: X.25 reset request on LCN %d! " - "Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, mb->cmd.cause, - mb->cmd.diagn); - api_oob_event (card,mb); - break; - - case PVE_RESTART_RQST: /* Restart request */ - retry = restart_event(card, cmd, lcn, mb); - break; - - default : - printk(KERN_INFO - "%s: X.25 protocol violation on LCN %d! " - "Packet:0x%02X Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.lcn, - mb->cmd.pktType & 0x7F, mb->cmd.cause, mb->cmd.diagn); - api_oob_event(card,mb); - } - break; - - case 0x42: /* X.25 timeout */ - retry = timeout_event(card, cmd, lcn, mb); - break; - - case 0x43: /* X.25 retry limit exceeded */ - printk(KERN_INFO - "%s: exceeded X.25 retry limit on LCN %d! " - "Packet:0x%02X Diagn:0x%02X\n", card->devname, - mb->cmd.lcn, mb->cmd.pktType, mb->cmd.diagn) - ; - break; - - case 0x08: /* modem failure */ -#ifndef MODEM_NOT_LOG - printk(KERN_INFO "%s: modem failure!\n", card->devname); -#endif /* MODEM_NOT_LOG */ - api_oob_event(card,mb); - break; - - case 0x09: /* N2 retry limit */ - printk(KERN_INFO "%s: exceeded HDLC retry limit!\n", - card->devname); - api_oob_event(card,mb); - break; - - case 0x06: /* unnumbered frame was received while in ABM */ - printk(KERN_INFO "%s: received Unnumbered frame 0x%02X!\n", - card->devname, mb->data[0]); - api_oob_event(card,mb); - break; - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd) - ; - retry = 0; /* abort command */ - break; - - case X25RES_NOT_READY: - retry = 1; - break; - - case 0x01: - if (card->u.x.LAPB_hdlc) - break; - - if (mb->cmd.command == 0x16) - break; - /* I use the goto statement here so if - * somebody inserts code between the - * case and default, we will not have - * ghost problems */ - goto dflt_2; - - default: -dflt_2: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X! Lcn %i\n", - card->devname, cmd, err, mb->cmd.lcn) - ; - retry = 0; /* abort command */ - } - kfree(mb); - return retry; -} - -/*==================================================================== - * X.25 Asynchronous Event Handlers - * These functions are called by the x25_error() and should return 0, if - * the command resulting in the asynchronous event must be aborted. - *====================================================================*/ - - - -/*==================================================================== - *Handle X.25 incoming call request. - * RFC 1356 establishes the following rules: - * 1. The first octet in the Call User Data (CUD) field of the call - * request packet contains NLPID identifying protocol encapsulation - * 2. Calls MUST NOT be accepted unless router supports requested - * protocol encapsulation. - * 3. A diagnostic code 249 defined by ISO/IEC 8208 may be used - * when clearing a call because protocol encapsulation is not - * supported. - * 4. If an incoming call is received while a call request is - * pending (i.e. call collision has occurred), the incoming call - * shall be rejected and call request shall be retried. - *====================================================================*/ - -static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - struct wan_device* wandev = &card->wandev; - int new_lcn = mb->cmd.lcn; - struct net_device* dev = get_dev_by_lcn(wandev, new_lcn); - x25_channel_t* chan = NULL; - int accept = 0; /* set to '1' if o.k. to accept call */ - unsigned int user_data; - x25_call_info_t* info; - - /* Make sure there is no call collision */ - if (dev != NULL) - { - printk(KERN_INFO - "%s: X.25 incoming call collision on LCN %d!\n", - card->devname, new_lcn); - - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - /* Make sure D bit is not set in call request */ -//FIXME: THIS IS NOT TURE !!!! TAKE IT OUT -// if (mb->cmd.qdm & 0x02) -// { -// printk(KERN_INFO -// "%s: X.25 incoming call on LCN %d with D-bit set!\n", -// card->devname, new_lcn); -// -// x25_clear_call(card, new_lcn, 0, 0); -// return 1; -// } - - /* Parse call request data */ - info = kmalloc(sizeof(x25_call_info_t), GFP_ATOMIC); - if (info == NULL) - { - printk(KERN_ERR - "%s: not enough memory to parse X.25 incoming call " - "on LCN %d!\n", card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - parse_call_info(mb->data, info); - - if (card->u.x.logging) - printk(KERN_INFO "\n%s: X.25 incoming call on LCN %d!\n", - card->devname, new_lcn); - - /* Conver the first two ASCII characters into an - * interger. Used to check the incoming protocol - */ - user_data = hex_to_uint(info->user,2); - - /* Find available channel */ - for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { - chan = dev->priv; - - if (chan->common.usedby == API) - continue; - - if (!chan->common.svc || (chan->common.state != WAN_DISCONNECTED)) - continue; - - if (user_data == NLPID_IP && chan->protocol != htons(ETH_P_IP)){ - printk(KERN_INFO "IP packet but configured for IPX : %x, %x\n", - htons(chan->protocol), info->user[0]); - continue; - } - - if (user_data == NLPID_SNAP && chan->protocol != htons(ETH_P_IPX)){ - printk(KERN_INFO "IPX packet but configured for IP: %x\n", - htons(chan->protocol)); - continue; - } - if (strcmp(info->src, chan->addr) == 0) - break; - - /* If just an '@' is specified, accept all incoming calls */ - if (strcmp(chan->addr, "") == 0) - break; - } - - if (dev == NULL){ - - /* If the call is not for any WANPIPE interfaces - * check to see if there is an API listening queue - * waiting for data. If there is send the packet - * up the stack. - */ - if (card->sk != NULL && card->func != NULL){ - if (api_incoming_call(card,mb,new_lcn)){ - x25_clear_call(card, new_lcn, 0, 0); - } - accept = 0; - }else{ - printk(KERN_INFO "%s: no channels available!\n", - card->devname); - - x25_clear_call(card, new_lcn, 0, 0); - } - - }else if (info->nuser == 0){ - - printk(KERN_INFO - "%s: no user data in incoming call on LCN %d!\n", - card->devname, new_lcn) - ; - x25_clear_call(card, new_lcn, 0, 0); - - }else switch (info->user[0]){ - - case 0: /* multiplexed */ - chan->protocol = htons(0); - accept = 1; - break; - - case NLPID_IP: /* IP datagrams */ - accept = 1; - break; - - case NLPID_SNAP: /* IPX datagrams */ - accept = 1; - break; - - default: - printk(KERN_INFO - "%s: unsupported NLPID 0x%02X in incoming call " - "on LCN %d!\n", card->devname, info->user[0], new_lcn); - x25_clear_call(card, new_lcn, 0, 249); - } - - if (accept && (x25_accept_call(card, new_lcn, 0) == CMD_OK)){ - - bind_lcn_to_dev (card, chan->dev, new_lcn); - - if (x25_get_chan_conf(card, chan) == CMD_OK) - set_chan_state(dev, WAN_CONNECTED); - else - x25_clear_call(card, new_lcn, 0, 0); - } - kfree(info); - return 1; -} - -/*==================================================================== - * Handle accepted call. - *====================================================================*/ - -static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = find_channel(card, new_lcn); - x25_channel_t* chan; - - if (dev == NULL){ - printk(KERN_INFO - "%s: clearing orphaned connection on LCN %d!\n", - card->devname, new_lcn); - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - if (card->u.x.logging) - printk(KERN_INFO "%s: X.25 call accepted on Dev %s and LCN %d!\n", - card->devname, dev->name, new_lcn); - - /* Get channel configuration and notify router */ - chan = dev->priv; - if (x25_get_chan_conf(card, chan) != CMD_OK) - { - x25_clear_call(card, new_lcn, 0, 0); - return 1; - } - - set_chan_state(dev, WAN_CONNECTED); - - if (chan->common.usedby == API){ - send_delayed_cmd_result(card,dev,mb); - bind_lcn_to_dev (card, dev, new_lcn); - } - - return 1; -} - -/*==================================================================== - * Handle cleared call. - *====================================================================*/ - -static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - struct net_device* dev = find_channel(card, new_lcn); - x25_channel_t *chan; - unsigned char old_state; - - if (card->u.x.logging){ - printk(KERN_INFO "%s: X.25 clear request on LCN %d! Cause:0x%02X " - "Diagn:0x%02X\n", - card->devname, new_lcn, mb->cmd.cause, mb->cmd.diagn); - } - - if (dev == NULL){ - printk(KERN_INFO "%s: X.25 clear request : No device for clear\n", - card->devname); - return 1; - } - - chan=dev->priv; - - old_state = chan->common.state; - - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - - switch (old_state){ - - case WAN_CONNECTING: - send_delayed_cmd_result(card,dev,mb); - break; - case WAN_CONNECTED: - send_oob_msg(card,dev,mb); - break; - } - } - - return ((cmd == X25_WRITE) && (lcn == new_lcn)) ? 0 : 1; -} - -/*==================================================================== - * Handle X.25 restart event. - *====================================================================*/ - -static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - struct wan_device* wandev = &card->wandev; - struct net_device* dev; - x25_channel_t *chan; - unsigned char old_state; - - printk(KERN_INFO - "%s: X.25 restart request! Cause:0x%02X Diagn:0x%02X\n", - card->devname, mb->cmd.cause, mb->cmd.diagn); - - /* down all logical channels */ - for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) { - chan=dev->priv; - old_state = chan->common.state; - - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - switch (old_state){ - - case WAN_CONNECTING: - send_delayed_cmd_result(card,dev,mb); - break; - case WAN_CONNECTED: - send_oob_msg(card,dev,mb); - break; - } - } - } - return (cmd == X25_WRITE) ? 0 : 1; -} - -/*==================================================================== - * Handle timeout event. - *====================================================================*/ - -static int timeout_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb) -{ - unsigned new_lcn = mb->cmd.lcn; - - if (mb->cmd.pktType == 0x05) /* call request time out */ - { - struct net_device* dev = find_channel(card,new_lcn); - - printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n", - card->devname, new_lcn); - - if (dev){ - x25_channel_t *chan = dev->priv; - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - send_delayed_cmd_result(card,dev,card->mbox); - } - } - }else{ - printk(KERN_INFO "%s: X.25 packet 0x%02X timeout on LCN %d!\n", - card->devname, mb->cmd.pktType, new_lcn); - } - return 1; -} - -/* - * Miscellaneous - */ - -/*==================================================================== - * Establish physical connection. - * o open HDLC and raise DTR - * - * Return: 0 connection established - * 1 connection is in progress - * <0 error - *===================================================================*/ - -static int connect (sdla_t* card) -{ - TX25Status* status = card->flags; - - if (x25_open_hdlc(card) || x25_setup_hdlc(card)) - return -EIO; - - wanpipe_set_state(card, WAN_CONNECTING); - - x25_set_intr_mode(card, INTR_ON_TIMER); - status->imask &= ~INTR_ON_TIMER; - - return 1; -} - -/* - * Tear down physical connection. - * o close HDLC link - * o drop DTR - * - * Return: 0 - * <0 error - */ - -static int disconnect (sdla_t* card) -{ - wanpipe_set_state(card, WAN_DISCONNECTED); - x25_set_intr_mode(card, INTR_ON_TIMER); /* disable all interrupt except timer */ - x25_close_hdlc(card); /* close HDLC link */ - x25_set_dtr(card, 0); /* drop DTR */ - return 0; -} - -/* - * Find network device by its channel number. - */ - -static struct net_device* get_dev_by_lcn(struct wan_device* wandev, - unsigned lcn) -{ - struct net_device* dev; - - for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) - if (((x25_channel_t*)dev->priv)->common.lcn == lcn) - break; - return dev; -} - -/* - * Initiate connection on the logical channel. - * o for PVC we just get channel configuration - * o for SVCs place an X.25 call - * - * Return: 0 connected - * >0 connection in progress - * <0 failure - */ - -static int chan_connect(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - - if (chan->common.svc && chan->common.usedby == WANPIPE){ - if (!chan->addr[0]){ - printk(KERN_INFO "%s: No Destination Address\n", - card->devname); - return -EINVAL; /* no destination address */ - } - printk(KERN_INFO "%s: placing X.25 call to %s ...\n", - card->devname, chan->addr); - - if (x25_place_call(card, chan) != CMD_OK) - return -EIO; - - set_chan_state(dev, WAN_CONNECTING); - return 1; - }else{ - if (x25_get_chan_conf(card, chan) != CMD_OK) - return -EIO; - - set_chan_state(dev, WAN_CONNECTED); - } - return 0; -} - -/* - * Disconnect logical channel. - * o if SVC then clear X.25 call - */ - -static int chan_disc(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - - if (chan->common.svc){ - x25_clear_call(chan->card, chan->common.lcn, 0, 0); - - /* For API we disconnect on clear - * confirmation. - */ - if (chan->common.usedby == API) - return 0; - } - - set_chan_state(dev, WAN_DISCONNECTED); - - return 0; -} - -/* - * Set logical channel state. - */ - -static void set_chan_state(struct net_device* dev, int state) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - unsigned long flags; - - save_flags(flags); - cli(); - if (chan->common.state != state) - { - switch (state) - { - case WAN_CONNECTED: - if (card->u.x.logging){ - printk (KERN_INFO - "%s: interface %s connected, lcn %i !\n", - card->devname, dev->name,chan->common.lcn); - } - *(unsigned short*)dev->dev_addr = htons(chan->common.lcn); - chan->i_timeout_sofar = jiffies; - - /* LAPB is PVC Based */ - if (card->u.x.LAPB_hdlc) - chan->common.svc=0; - break; - - case WAN_CONNECTING: - if (card->u.x.logging){ - printk (KERN_INFO - "%s: interface %s connecting, lcn %i ...\n", - card->devname, dev->name, chan->common.lcn); - } - break; - - case WAN_DISCONNECTED: - if (card->u.x.logging){ - printk (KERN_INFO - "%s: interface %s disconnected, lcn %i !\n", - card->devname, dev->name,chan->common.lcn); - } - atomic_set(&chan->common.disconnect,0); - - if (chan->common.svc) { - *(unsigned short*)dev->dev_addr = 0; - card->u.x.svc_to_dev_map[(chan->common.lcn%X25_MAX_CHAN)]=NULL; - chan->common.lcn = 0; - } - - if (chan->transmit_length){ - chan->transmit_length=0; - atomic_set(&chan->common.driver_busy,0); - chan->tx_offset=0; - if (netif_queue_stopped(dev)){ - netif_wake_queue(dev); - } - } - atomic_set(&chan->common.command,0); - break; - - case WAN_DISCONNECTING: - if (card->u.x.logging){ - printk (KERN_INFO - "\n%s: interface %s disconnecting, lcn %i ...\n", - card->devname, dev->name,chan->common.lcn); - } - atomic_set(&chan->common.disconnect,0); - break; - } - chan->common.state = state; - } - chan->state_tick = jiffies; - restore_flags(flags); -} - -/* - * Send packet on a logical channel. - * When this function is called, tx_skb field of the channel data - * space points to the transmit socket buffer. When transmission - * is complete, release socket buffer and reset 'tbusy' flag. - * - * Return: 0 - transmission complete - * 1 - busy - * - * Notes: - * 1. If packet length is greater than MTU for this channel, we'll fragment - * the packet into 'complete sequence' using M-bit. - * 2. When transmission is complete, an event notification should be issued - * to the router. - */ - -static int chan_send(struct net_device* dev, void* buff, unsigned data_len, - unsigned char tx_intr) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - TX25Status* status = card->flags; - unsigned len=0, qdm=0, res=0, orig_len = 0; - void *data; - - /* Check to see if channel is ready */ - if ((!(status->cflags[chan->ch_idx] & 0x40) && !card->u.x.LAPB_hdlc) || - !(*card->u.x.hdlc_buf_status & 0x40)){ - - if (!tx_intr){ - setup_for_delayed_transmit (dev, buff, data_len); - return 0; - }else{ - /* By returning 0 to tx_intr the packet will be dropped */ - ++card->wandev.stats.tx_dropped; - ++chan->ifstats.tx_dropped; - printk(KERN_INFO "%s: ERROR, Tx intr could not send, dropping %s:\n", - card->devname,dev->name); - ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; - return 0; - } - } - - if (chan->common.usedby == API){ - /* Remove the API Header */ - x25api_hdr_t *api_data = (x25api_hdr_t *)buff; - - /* Set the qdm bits from the packet header - * User has the option to set the qdm bits - */ - qdm = api_data->qdm; - - orig_len = len = data_len - sizeof(x25api_hdr_t); - data = (unsigned char*)buff + sizeof(x25api_hdr_t); - }else{ - data = buff; - orig_len = len = data_len; - } - - if (tx_intr){ - /* We are in tx_intr, minus the tx_offset from - * the total length. The tx_offset part of the - * data has already been sent. Also, move the - * data pointer to proper offset location. - */ - len -= chan->tx_offset; - data = (unsigned char*)data + chan->tx_offset; - } - - /* Check if the packet length is greater than MTU - * If YES: Cut the len to MTU and set the M bit - */ - if (len > chan->tx_pkt_size && !card->u.x.LAPB_hdlc){ - len = chan->tx_pkt_size; - qdm |= M_BIT; - } - - - /* Pass only first three bits of the qdm byte to the send - * routine. In case user sets any other bit which might - * cause errors. - */ - - switch(x25_send(card, chan->common.lcn, (qdm&0x07), len, data)){ - case 0x00: /* success */ - chan->i_timeout_sofar = jiffies; - - dev->trans_start=jiffies; - - if ((qdm & M_BIT) && !card->u.x.LAPB_hdlc){ - if (!tx_intr){ - /* The M bit was set, which means that part of the - * packet has been sent. Copy the packet into a buffer - * and set the offset to len, so on next tx_inter - * the packet will be sent using the below offset. - */ - chan->tx_offset += len; - - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - - if (chan->tx_offset < orig_len){ - setup_for_delayed_transmit (dev, buff, data_len); - } - res=0; - }else{ - /* We are already in tx_inter, thus data is already - * in the buffer. Update the offset and wait for - * next tx_intr. We add on to the offset, since data can - * be X number of times larger than max data size. - */ - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - - ++chan->if_send_stat.if_send_bfr_passed_to_adptr; - chan->tx_offset += len; - - /* The user can set the qdm bit as well. - * If the entire packet was sent and qdm is still - * set, than it's the user who has set the M bit. In that, - * case indicate that the packet was send by returning - * 0 and wait for a new packet. Otherwise, wait for next - * tx interrupt to send the rest of the packet */ - - if (chan->tx_offset < orig_len){ - res=1; - }else{ - res=0; - } - } - }else{ - ++chan->ifstats.tx_packets; - chan->ifstats.tx_bytes += len; - ++chan->if_send_stat.if_send_bfr_passed_to_adptr; - res=0; - } - break; - - case 0x33: /* Tx busy */ - if (tx_intr){ - printk(KERN_INFO "%s: Tx_intr: Big Error dropping packet %s\n", - card->devname,dev->name); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; - res=0; - }else{ - DBG_PRINTK(KERN_INFO - "%s: Send: Big Error should have tx: storring %s\n", - card->devname,dev->name); - setup_for_delayed_transmit (dev, buff, data_len); - res=1; - } - break; - - default: /* failure */ - ++chan->ifstats.tx_errors; - if (tx_intr){ - printk(KERN_INFO "%s: Tx_intr: Failure to send, dropping %s\n", - card->devname,dev->name); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - ++chan->if_send_stat.if_send_bfr_not_passed_to_adptr; - res=0; - }else{ - DBG_PRINTK(KERN_INFO "%s: Send: Failure to send !!!, storing %s\n", - card->devname,dev->name); - setup_for_delayed_transmit (dev, buff, data_len); - res=1; - } - break; - } - return res; -} - - -/* - * Parse X.25 call request data and fill x25_call_info_t structure. - */ - -static void parse_call_info (unsigned char* str, x25_call_info_t* info) -{ - memset(info, 0, sizeof(x25_call_info_t)); - for (; *str; ++str) - { - int i; - unsigned char ch; - - if (*str == '-') switch (str[1]) { - - /* Take minus 2 off the maximum size so that - * last byte is 0. This way we can use string - * manipulaton functions on call information. - */ - - case 'd': /* destination address */ - for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->dest[i] = ch; - } - break; - - case 's': /* source address */ - for (i = 0; i < (MAX_X25_ADDR_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->src[i] = ch; - } - break; - - case 'u': /* user data */ - for (i = 0; i < (MAX_X25_DATA_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->user[i] = ch; - } - info->nuser = i; - break; - - case 'f': /* facilities */ - for (i = 0; i < (MAX_X25_FACL_SIZE-2); ++i){ - ch = str[2+i]; - if (isspace(ch)) break; - info->facil[i] = ch; - } - info->nfacil = i; - break; - } - } -} - -/* - * Convert line speed in bps to a number used by S502 code. - */ - -static unsigned char bps_to_speed_code (unsigned long bps) -{ - unsigned char number; - - if (bps <= 1200) number = 0x01; - else if (bps <= 2400) number = 0x02; - else if (bps <= 4800) number = 0x03; - else if (bps <= 9600) number = 0x04; - else if (bps <= 19200) number = 0x05; - else if (bps <= 38400) number = 0x06; - else if (bps <= 45000) number = 0x07; - else if (bps <= 56000) number = 0x08; - else if (bps <= 64000) number = 0x09; - else if (bps <= 74000) number = 0x0A; - else if (bps <= 112000) number = 0x0B; - else if (bps <= 128000) number = 0x0C; - else number = 0x0D; - - return number; -} - -/* - * Convert decimal string to unsigned integer. - * If len != 0 then only 'len' characters of the string are converted. - */ - -static unsigned int dec_to_uint (unsigned char* str, int len) -{ - unsigned val; - - if (!len) - len = strlen(str); - - for (val = 0; len && isdigit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned)'0'); - - return val; -} - -/* - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. - */ - -static unsigned int hex_to_uint (unsigned char* str, int len) -{ - unsigned val, ch; - - if (!len) - len = strlen(str); - - for (val = 0; len; ++str, --len) - { - ch = *str; - if (isdigit(ch)) - val = (val << 4) + (ch - (unsigned)'0'); - else if (isxdigit(ch)) - val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10); - else break; - } - return val; -} - - -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) -{ - int i; - - if( proto == ETH_P_IPX) { - /* It's an IPX packet */ - if(!enable_IPX) { - /* Return 1 so we don't pass it up the stack. */ - return 1; - } - } else { - /* It's not IPX so pass it up the stack.*/ - return 0; - } - - if( sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) - { - /* It's IPXWAN */ - - if( sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) - { - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); - - /* Go through the routing options and answer no to every - * option except Unnumbered RIP/SAP - */ - for(i = 41; sendpacket[i] == 0x00; i += 5) - { - /* 0x02 is the option for Unnumbered RIP/SAP */ - if( sendpacket[i + 4] != 0x02) - { - sendpacket[i + 1] = 0; - } - } - - /* Skip over the extended Node ID option */ - if( sendpacket[i] == 0x04 ) - { - i += 8; - } - - /* We also want to turn off all header compression opt. */ - for(; sendpacket[i] == 0x80 ;) - { - sendpacket[i + 1] = 0; - i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; - } - - /* Set the packet type to timer response */ - sendpacket[34] = 0x01; - - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); - } - else if( sendpacket[34] == 0x02 ) - { - /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); - - /* Set the packet type to information response */ - sendpacket[34] = 0x03; - - /* Set the router name */ - sendpacket[51] = 'X'; - sendpacket[52] = 'T'; - sendpacket[53] = 'P'; - sendpacket[54] = 'I'; - sendpacket[55] = 'P'; - sendpacket[56] = 'E'; - sendpacket[57] = '-'; - sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); - sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for(i = 66; i < 99; i+= 1) - { - sendpacket[i] = 0; - } - - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); - } - else - { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); - return 0; - } - - /* Set the WNodeID to our network address */ - sendpacket[35] = (unsigned char)(network_number >> 24); - sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char)(network_number & 0x000000FF); - - return 1; - } else { - /*If we get here it's an IPX-data packet, so it'll get passed up the stack. - */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); - return 0; - } -} - -/* - * If incoming is 0 (outgoing)- if the net numbers is ours make it 0 - * if incoming is 1 - if the net number is 0 make it ours - */ - -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) -{ - unsigned long pnetwork_number; - - pnetwork_number = (unsigned long)((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); - - - if (!incoming) { - /*If the destination network number is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; - } - } else { - /* If the incoming network is 0, make it ours */ - if( pnetwork_number == 0) { - sendpacket[6] = (unsigned char)(network_number >> 24); - sendpacket[7] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char)(network_number & - 0x000000FF); - } - } - - - pnetwork_number = (unsigned long)((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - - - if( !incoming ) { - /* If the source network is ours, make it 0 */ - if( pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; - } - } else { - /* If the source network is 0, make it ours */ - if( pnetwork_number == 0 ) { - sendpacket[18] = (unsigned char)(network_number >> 24); - sendpacket[19] = (unsigned char)((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char)((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char)(network_number & - 0x000000FF); - } - } -} /* switch_net_numbers */ - - - - -/********************* X25API SPECIFIC FUNCTIONS ****************/ - - -/*=============================================================== - * find_channel - * - * Manages the lcn to device map. It increases performance - * because it eliminates the need to search through the link - * list for a device which is bounded to a specific lcn. - * - *===============================================================*/ - - -struct net_device *find_channel(sdla_t *card, unsigned lcn) -{ - if (card->u.x.LAPB_hdlc){ - - return card->wandev.dev; - - }else{ - /* We don't know whether the incoming lcn - * is a PVC or an SVC channel. But we do know that - * the lcn cannot be for both the PVC and the SVC - * channel. - - * If the lcn number is greater or equal to 255, - * take the modulo 255 of that number. We only have - * 255 locations, thus higher numbers must be mapped - * to a number between 0 and 245. - - * We must separate pvc's and svc's since two don't - * have to be contiguous. Meaning pvc's can start - * from 1 to 10 and svc's can start from 256 to 266. - * But 256%255 is 1, i.e. CONFLICT. - */ - - - /* Highest LCN number must be less or equal to 4096 */ - if ((lcn <= MAX_LCN_NUM) && (lcn > 0)){ - - if (lcn < X25_MAX_CHAN){ - if (card->u.x.svc_to_dev_map[lcn]) - return card->u.x.svc_to_dev_map[lcn]; - - if (card->u.x.pvc_to_dev_map[lcn]) - return card->u.x.pvc_to_dev_map[lcn]; - - }else{ - int new_lcn = lcn%X25_MAX_CHAN; - if (card->u.x.svc_to_dev_map[new_lcn]) - return card->u.x.svc_to_dev_map[new_lcn]; - - if (card->u.x.pvc_to_dev_map[new_lcn]) - return card->u.x.pvc_to_dev_map[new_lcn]; - } - } - return NULL; - } -} - -void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn) -{ - x25_channel_t *chan = dev->priv; - - /* Modulo the lcn number by X25_MAX_CHAN (255) - * because the lcn number can be greater than 255 - * - * We need to split svc and pvc since they don't have - * to be contigous. - */ - - if (chan->common.svc){ - card->u.x.svc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; - }else{ - card->u.x.pvc_to_dev_map[(lcn % X25_MAX_CHAN)] = dev; - } - chan->common.lcn = lcn; -} - - - -/*=============================================================== - * x25api_bh - * - * - *==============================================================*/ - -static void x25api_bh(struct net_device* dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - struct sk_buff *skb; - - if (atomic_read(&chan->bh_buff_used) == 0){ - printk(KERN_INFO "%s: BH Buffer Empty in BH\n", - card->devname); - clear_bit(0, &chan->tq_working); - return; - } - - while (atomic_read(&chan->bh_buff_used)){ - - /* If the sock is in the process of unlinking the - * driver from the socket, we must get out. - * This never happends but is a sanity check. */ - if (test_bit(0,&chan->common.common_critical)){ - clear_bit(0, &chan->tq_working); - return; - } - - /* If LAPB HDLC, do not drop packets if socket is - * not connected. Let the buffer fill up and - * turn off rx interrupt */ - if (card->u.x.LAPB_hdlc){ - if (chan->common.sk == NULL || chan->common.func == NULL){ - clear_bit(0, &chan->tq_working); - return; - } - } - - skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; - - if (skb == NULL){ - printk(KERN_INFO "%s: BH Skb empty for read %i\n", - card->devname,chan->bh_read); - }else{ - - if (chan->common.sk == NULL || chan->common.func == NULL){ - printk(KERN_INFO "%s: BH: Socket disconnected, dropping\n", - card->devname); - dev_kfree_skb_any(skb); - x25api_bh_cleanup(dev); - ++chan->ifstats.rx_dropped; - ++chan->rx_intr_stat.rx_intr_bfr_not_passed_to_stack; - continue; - } - - - if (chan->common.func(skb,dev,chan->common.sk) != 0){ - /* Sock full cannot send, queue us for another - * try - */ - printk(KERN_INFO "%s: BH: !!! Packet failed to send !!!!! \n", - card->devname); - atomic_set(&chan->common.receive_block,1); - return; - }else{ - x25api_bh_cleanup(dev); - ++chan->rx_intr_stat.rx_intr_bfr_passed_to_stack; - } - } - } - clear_bit(0, &chan->tq_working); - - return; -} - -/*=============================================================== - * x25api_bh_cleanup - * - * - *==============================================================*/ - -static int x25api_bh_cleanup(struct net_device *dev) -{ - x25_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - TX25Status* status = card->flags; - - - ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; - - if (chan->bh_read == MAX_BH_BUFF){ - chan->bh_read=0; - }else{ - ++chan->bh_read; - } - - /* If the Receive interrupt was off, it means - * that we filled up our circular buffer. Check - * that we have space in the buffer. If so - * turn the RX interrupt back on. - */ - if (!(status->imask & INTR_ON_RX_FRAME)){ - if (atomic_read(&chan->bh_buff_used) < (MAX_BH_BUFF+1)){ - printk(KERN_INFO "%s: BH: Turning on the interrupt\n", - card->devname); - status->imask |= INTR_ON_RX_FRAME; - } - } - - atomic_dec(&chan->bh_buff_used); - return 0; -} - - -/*=============================================================== - * bh_enqueue - * - * - *==============================================================*/ - -static int bh_enqueue(struct net_device *dev, struct sk_buff *skb) -{ - x25_channel_t* chan = dev->priv; - sdla_t *card = chan->card; - TX25Status* status = card->flags; - - if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ - printk(KERN_INFO "%s: Bottom half buffer FULL\n", - card->devname); - return 1; - } - - ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; - - if (chan->bh_write == MAX_BH_BUFF){ - chan->bh_write=0; - }else{ - ++chan->bh_write; - } - - atomic_inc(&chan->bh_buff_used); - - if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ - printk(KERN_INFO "%s: Buffer is now full, Turning off RX Intr\n", - card->devname); - status->imask &= ~INTR_ON_RX_FRAME; - } - - return 0; -} - - -/*=============================================================== - * timer_intr_cmd_exec - * - * Called by timer interrupt to execute a command - *===============================================================*/ - -static int timer_intr_cmd_exec (sdla_t* card) -{ - struct net_device *dev; - unsigned char more_to_exec=0; - volatile x25_channel_t *chan=NULL; - int i=0,bad_cmd=0,err=0; - - if (card->u.x.cmd_dev == NULL){ - card->u.x.cmd_dev = card->wandev.dev; - } - - dev = card->u.x.cmd_dev; - - for (;;){ - - chan = dev->priv; - - if (atomic_read(&chan->common.command)){ - - bad_cmd = check_bad_command(card,dev); - - if ((!chan->common.mbox || atomic_read(&chan->common.disconnect)) && - !bad_cmd){ - - /* Socket has died or exited, We must bring the - * channel down before anybody else tries to - * use it */ - err = channel_disconnect(card,dev); - }else{ - err = execute_delayed_cmd(card, dev, - (mbox_cmd_t*)chan->common.mbox, - bad_cmd); - } - - switch (err){ - - case RETURN_RESULT: - - /* Return the result to the socket without - * delay. NO_WAIT Command */ - atomic_set(&chan->common.command,0); - if (atomic_read(&card->u.x.command_busy)) - atomic_set(&card->u.x.command_busy,0); - - send_delayed_cmd_result(card,dev,card->mbox); - - more_to_exec=0; - break; - case DELAY_RESULT: - - /* Wait for the remote to respond, before - * sending the result up to the socket. - * WAIT command */ - if (atomic_read(&card->u.x.command_busy)) - atomic_set(&card->u.x.command_busy,0); - - atomic_set(&chan->common.command,0); - more_to_exec=0; - break; - default: - - /* If command could not be executed for - * some reason (i.e return code 0x33 busy) - * set the more_to_exec bit which will - * indicate that this command must be exectued - * again during next timer interrupt - */ - more_to_exec=1; - if (atomic_read(&card->u.x.command_busy) == 0) - atomic_set(&card->u.x.command_busy,1); - break; - } - - bad_cmd=0; - - /* If flags is set, there are no hdlc buffers, - * thus, wait for the next pass and try the - * same command again. Otherwise, start searching - * from next device on the next pass. - */ - if (!more_to_exec){ - dev = move_dev_to_next(card,dev); - } - break; - }else{ - /* This device has nothing to execute, - * go to next. - */ - if (atomic_read(&card->u.x.command_busy)) - atomic_set(&card->u.x.command_busy,0); - dev = move_dev_to_next(card,dev); - } - - if (++i == card->u.x.no_dev){ - if (!more_to_exec){ - DBG_PRINTK(KERN_INFO "%s: Nothing to execute in Timer\n", - card->devname); - if (atomic_read(&card->u.x.command_busy)){ - atomic_set(&card->u.x.command_busy,0); - } - } - break; - } - - } //End of FOR - - card->u.x.cmd_dev = dev; - - if (more_to_exec){ - /* If more commands are pending, do not turn off timer - * interrupt */ - return 1; - }else{ - /* No more commands, turn off timer interrupt */ - return 0; - } -} - -/*=============================================================== - * execute_delayed_cmd - * - * Execute an API command which was passed down from the - * sock. Sock is very limited in which commands it can - * execute. Wait and No Wait commands are supported. - * Place Call, Clear Call and Reset wait commands, where - * Accept Call is a no_wait command. - * - *===============================================================*/ - -static int execute_delayed_cmd(sdla_t* card, struct net_device *dev, - mbox_cmd_t *usr_cmd, char bad_cmd) -{ - TX25Mbox* mbox = card->mbox; - int err; - x25_channel_t *chan = dev->priv; - int delay=RETURN_RESULT; - - if (!(*card->u.x.hdlc_buf_status & 0x40) && !bad_cmd){ - return TRY_CMD_AGAIN; - } - - /* This way a command is guaranteed to be executed for - * a specific lcn, the network interface is bound to. */ - usr_cmd->cmd.lcn = chan->common.lcn; - - - /* If channel is pvc, instead of place call - * run x25_channel configuration. If running LAPB HDLC - * enable communications. - */ - if ((!chan->common.svc) && (usr_cmd->cmd.command == X25_PLACE_CALL)){ - - if (card->u.x.LAPB_hdlc){ - DBG_PRINTK(KERN_INFO "LAPB: Connecting\n"); - connect(card); - set_chan_state(dev,WAN_CONNECTING); - return DELAY_RESULT; - }else{ - DBG_PRINTK(KERN_INFO "%s: PVC is CONNECTING\n",card->devname); - if (x25_get_chan_conf(card, chan) == CMD_OK){ - set_chan_state(dev, WAN_CONNECTED); - }else{ - set_chan_state(dev, WAN_DISCONNECTED); - } - return RETURN_RESULT; - } - } - - /* Copy the socket mbox command onto the board */ - - memcpy(&mbox->cmd, &usr_cmd->cmd, sizeof(TX25Cmd)); - if (usr_cmd->cmd.length){ - memcpy(mbox->data, usr_cmd->data, usr_cmd->cmd.length); - } - - /* Check if command is bad. We need to copy the cmd into - * the buffer regardless since we return the, mbox to - * the user */ - if (bad_cmd){ - mbox->cmd.result=0x01; - return RETURN_RESULT; - } - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - if (err != CMD_OK && err != X25RES_NOT_READY) - x25_error(card, err, usr_cmd->cmd.command, usr_cmd->cmd.lcn); - - if (mbox->cmd.result == X25RES_NOT_READY){ - return TRY_CMD_AGAIN; - } - - switch (mbox->cmd.command){ - - case X25_PLACE_CALL: - - switch (mbox->cmd.result){ - - case CMD_OK: - - /* Check if Place call is a wait command or a - * no wait command */ - if (atomic_read(&chan->common.command) & 0x80) - delay=RETURN_RESULT; - else - delay=DELAY_RESULT; - - - DBG_PRINTK(KERN_INFO "\n%s: PLACE CALL Binding dev %s to lcn %i\n", - card->devname,dev->name, mbox->cmd.lcn); - - bind_lcn_to_dev (card, dev, mbox->cmd.lcn); - set_chan_state(dev, WAN_CONNECTING); - break; - - - default: - delay=RETURN_RESULT; - set_chan_state(dev, WAN_DISCONNECTED); - break; - } - break; - - case X25_ACCEPT_CALL: - - switch (mbox->cmd.result){ - - case CMD_OK: - - DBG_PRINTK(KERN_INFO "\n%s: ACCEPT Binding dev %s to lcn %i\n", - card->devname,dev->name,mbox->cmd.lcn); - - bind_lcn_to_dev (card, dev, mbox->cmd.lcn); - - if (x25_get_chan_conf(card, chan) == CMD_OK){ - - set_chan_state(dev, WAN_CONNECTED); - delay=RETURN_RESULT; - - }else{ - if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ - /* if clear is successful, wait for clear confirm - */ - delay=DELAY_RESULT; - }else{ - /* Do not change the state here. If we fail - * the accept the return code is send up - *the stack, which will ether retry - * or clear the call - */ - DBG_PRINTK(KERN_INFO - "%s: ACCEPT: STATE MAY BE CURRUPTED 2 !!!!!\n", - card->devname); - delay=RETURN_RESULT; - } - } - break; - - - case X25RES_ASYNC_PACKET: - delay=TRY_CMD_AGAIN; - break; - - default: - DBG_PRINTK(KERN_INFO "%s: ACCEPT FAILED\n",card->devname); - if (x25_clear_call(card, usr_cmd->cmd.lcn, 0, 0) == CMD_OK){ - delay=DELAY_RESULT; - }else{ - /* Do not change the state here. If we fail the accept. The - * return code is send up the stack, which will ether retry - * or clear the call */ - DBG_PRINTK(KERN_INFO - "%s: ACCEPT: STATE MAY BE CORRUPTED 1 !!!!!\n", - card->devname); - delay=RETURN_RESULT; - } - } - break; - - case X25_CLEAR_CALL: - - switch (mbox->cmd.result){ - - case CMD_OK: - DBG_PRINTK(KERN_INFO - "CALL CLEAR OK: Dev %s Mbox Lcn %i Chan Lcn %i\n", - dev->name,mbox->cmd.lcn,chan->common.lcn); - set_chan_state(dev, WAN_DISCONNECTING); - delay = DELAY_RESULT; - break; - - case X25RES_CHANNEL_IN_USE: - case X25RES_ASYNC_PACKET: - delay = TRY_CMD_AGAIN; - break; - - case X25RES_LINK_NOT_IN_ABM: - case X25RES_INVAL_LCN: - case X25RES_INVAL_STATE: - set_chan_state(dev, WAN_DISCONNECTED); - delay = RETURN_RESULT; - break; - - default: - /* If command did not execute because of user - * fault, do not change the state. This will - * signal the socket that clear command failed. - * User can retry or close the socket. - * When socket gets killed, it will set the - * chan->disconnect which will signal - * driver to clear the call */ - printk(KERN_INFO "%s: Clear Command Failed, Rc %x\n", - card->devname,mbox->cmd.command); - delay = RETURN_RESULT; - } - break; - } - - return delay; -} - -/*=============================================================== - * api_incoming_call - * - * Pass an incoming call request up the listening - * sock. If the API sock is not listening reject the - * call. - * - *===============================================================*/ - -static int api_incoming_call (sdla_t* card, TX25Mbox *mbox, int lcn) -{ - struct sk_buff *skb; - int len = sizeof(TX25Cmd)+mbox->cmd.length; - - if (alloc_and_init_skb_buf(card, &skb, len)){ - printk(KERN_INFO "%s: API incoming call, no memory\n",card->devname); - return 1; - } - - memcpy(skb_put(skb,len),&mbox->cmd,len); - - skb->mac.raw = skb->data; - skb->protocol = htons(X25_PROT); - skb->pkt_type = WAN_PACKET_ASYNC; - - if (card->func(skb,card->sk) < 0){ - printk(KERN_INFO "%s: MAJOR ERROR: Failed to send up place call \n",card->devname); - dev_kfree_skb_any(skb); - return 1; - } - - return 0; -} - -/*=============================================================== - * send_delayed_cmd_result - * - * Wait commands like PLEACE CALL or CLEAR CALL must wait - * until the result arrives. This function passes - * the result to a waiting sock. - * - *===============================================================*/ -static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev, - TX25Mbox* mbox) -{ - x25_channel_t *chan = dev->priv; - mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; - struct sk_buff *skb; - int len=sizeof(unsigned char); - - atomic_set(&chan->common.command,0); - - /* If the sock is in the process of unlinking the - * driver from the socket, we must get out. - * This never happends but is a sanity check. */ - if (test_bit(0,&chan->common.common_critical)){ - return; - } - - if (!usr_cmd || !chan->common.sk || !chan->common.func){ - DBG_PRINTK(KERN_INFO "Delay result: Sock not bounded sk: %u, func: %u, mbox: %u\n", - (unsigned int)chan->common.sk, - (unsigned int)chan->common.func, - (unsigned int)usr_cmd); - return; - } - - memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); - if (mbox->cmd.length > 0){ - memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); - } - - if (alloc_and_init_skb_buf(card,&skb,len)){ - printk(KERN_INFO "Delay result: No sock buffers\n"); - return; - } - - memcpy(skb_put(skb,len),&mbox->cmd.command,len); - - skb->mac.raw = skb->data; - skb->pkt_type = WAN_PACKET_CMD; - - chan->common.func(skb,dev,chan->common.sk); -} - -/*=============================================================== - * clear_confirm_event - * - * Pass the clear confirmation event up the sock. The - * API will disconnect only after the clear confirmation - * has been received. - * - * Depending on the state, clear confirmation could - * be an OOB event, or a result of an API command. - *===============================================================*/ - -static int clear_confirm_event (sdla_t *card, TX25Mbox* mb) -{ - struct net_device *dev; - x25_channel_t *chan; - unsigned char old_state; - - dev = find_channel(card,mb->cmd.lcn); - if (!dev){ - DBG_PRINTK(KERN_INFO "%s: *** GOT CLEAR BUT NO DEV %i\n", - card->devname,mb->cmd.lcn); - return 0; - } - - chan=dev->priv; - DBG_PRINTK(KERN_INFO "%s: GOT CLEAR CONFIRM %s: Mbox lcn %i Chan lcn %i\n", - card->devname, dev->name, mb->cmd.lcn, chan->common.lcn); - - /* If not API fall through to default. - * If API, send the result to a waiting - * socket. - */ - - old_state = chan->common.state; - set_chan_state(dev, WAN_DISCONNECTED); - - if (chan->common.usedby == API){ - switch (old_state) { - - case WAN_DISCONNECTING: - case WAN_CONNECTING: - send_delayed_cmd_result(card,dev,mb); - break; - case WAN_CONNECTED: - send_oob_msg(card,dev,mb); - break; - } - return 1; - } - - return 0; -} - -/*=============================================================== - * send_oob_msg - * - * Construct an NEM Message and pass it up the connected - * sock. If the sock is not bounded discard the NEM. - * - *===============================================================*/ - -static void send_oob_msg(sdla_t *card, struct net_device *dev, TX25Mbox *mbox) -{ - x25_channel_t *chan = dev->priv; - mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox; - struct sk_buff *skb; - int len=sizeof(x25api_hdr_t)+mbox->cmd.length; - x25api_t *api_hdr; - - /* If the sock is in the process of unlinking the - * driver from the socket, we must get out. - * This never happends but is a sanity check. */ - if (test_bit(0,&chan->common.common_critical)){ - return; - } - - if (!usr_cmd || !chan->common.sk || !chan->common.func){ - DBG_PRINTK(KERN_INFO "OOB MSG: Sock not bounded\n"); - return; - } - - memcpy(&usr_cmd->cmd, &mbox->cmd, sizeof(TX25Cmd)); - if (mbox->cmd.length > 0){ - memcpy(usr_cmd->data, mbox->data, mbox->cmd.length); - } - - if (alloc_and_init_skb_buf(card,&skb,len)){ - printk(KERN_INFO "%s: OOB MSG: No sock buffers\n",card->devname); - return; - } - - api_hdr = (x25api_t*)skb_put(skb,len); - api_hdr->hdr.pktType = mbox->cmd.pktType & 0x7F; - api_hdr->hdr.qdm = mbox->cmd.qdm; - api_hdr->hdr.cause = mbox->cmd.cause; - api_hdr->hdr.diagn = mbox->cmd.diagn; - api_hdr->hdr.length = mbox->cmd.length; - api_hdr->hdr.result = mbox->cmd.result; - api_hdr->hdr.lcn = mbox->cmd.lcn; - - if (mbox->cmd.length > 0){ - memcpy(api_hdr->data,mbox->data,mbox->cmd.length); - } - - skb->mac.raw = skb->data; - skb->pkt_type = WAN_PACKET_ERR; - - if (chan->common.func(skb,dev,chan->common.sk) < 0){ - if (bh_enqueue(dev,skb)){ - printk(KERN_INFO "%s: Dropping OOB MSG\n",card->devname); - dev_kfree_skb_any(skb); - } - } - - DBG_PRINTK(KERN_INFO "%s: OOB MSG OK, %s, lcn %i\n", - card->devname, dev->name, mbox->cmd.lcn); -} - -/*=============================================================== - * alloc_and_init_skb_buf - * - * Allocate and initialize an skb buffer. - * - *===============================================================*/ - -static int alloc_and_init_skb_buf (sdla_t *card, struct sk_buff **skb, int len) -{ - struct sk_buff *new_skb = *skb; - - new_skb = dev_alloc_skb(len + X25_HRDHDR_SZ); - if (new_skb == NULL){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - return 1; - } - - if (skb_tailroom(new_skb) < len){ - /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb_any(new_skb); - printk(KERN_INFO "%s: Listen: unexpectedly long packet sequence\n" - ,card->devname); - *skb = NULL; - return 1; - } - - *skb = new_skb; - return 0; - -} - -/*=============================================================== - * api_oob_event - * - * Send an OOB event up to the sock - * - *===============================================================*/ - -static void api_oob_event (sdla_t *card,TX25Mbox *mbox) -{ - struct net_device *dev = find_channel(card, mbox->cmd.lcn); - x25_channel_t *chan; - - if (!dev) - return; - - chan=dev->priv; - - if (chan->common.usedby == API) - send_oob_msg(card,dev,mbox); - -} - - - - -static int channel_disconnect(sdla_t* card, struct net_device *dev) -{ - - int err; - x25_channel_t *chan = dev->priv; - - DBG_PRINTK(KERN_INFO "%s: TIMER: %s, Device down disconnecting\n", - card->devname,dev->name); - - if (chan->common.svc){ - err = x25_clear_call(card,chan->common.lcn,0,0); - }else{ - /* If channel is PVC or LAPB HDLC, there is no call - * to be cleared, thus drop down to the default - * area - */ - err = 1; - } - - switch (err){ - - case X25RES_CHANNEL_IN_USE: - case X25RES_NOT_READY: - err = TRY_CMD_AGAIN; - break; - case CMD_OK: - DBG_PRINTK(KERN_INFO "CALL CLEAR OK: Dev %s Chan Lcn %i\n", - dev->name,chan->common.lcn); - - set_chan_state(dev,WAN_DISCONNECTING); - atomic_set(&chan->common.command,0); - err = DELAY_RESULT; - break; - default: - /* If LAPB HDLC protocol, bring the whole link down - * once the application terminates - */ - - set_chan_state(dev,WAN_DISCONNECTED); - - if (card->u.x.LAPB_hdlc){ - DBG_PRINTK(KERN_INFO "LAPB: Disconnecting Link\n"); - hdlc_link_down (card); - } - atomic_set(&chan->common.command,0); - err = RETURN_RESULT; - break; - } - - return err; -} - -static void hdlc_link_down (sdla_t *card) -{ - TX25Mbox* mbox = card->mbox; - int retry = 5; - int err=0; - - do { - memset(mbox,0,sizeof(TX25Mbox)); - mbox->cmd.command = X25_HDLC_LINK_DISC; - mbox->cmd.length = 1; - mbox->data[0]=0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - - } while (err && retry-- && x25_error(card, err, X25_HDLC_LINK_DISC, 0)); - - if (err) - printk(KERN_INFO "%s: Hdlc Link Down Failed %x\n",card->devname,err); - - disconnect (card); - -} - -static int check_bad_command(sdla_t* card, struct net_device *dev) -{ - x25_channel_t *chan = dev->priv; - int bad_cmd = 0; - - switch (atomic_read(&chan->common.command)&0x7F){ - - case X25_PLACE_CALL: - if (chan->common.state != WAN_DISCONNECTED) - bad_cmd=1; - break; - case X25_CLEAR_CALL: - if (chan->common.state == WAN_DISCONNECTED) - bad_cmd=1; - break; - case X25_ACCEPT_CALL: - if (chan->common.state != WAN_CONNECTING) - bad_cmd=1; - break; - case X25_RESET: - if (chan->common.state != WAN_CONNECTED) - bad_cmd=1; - break; - default: - bad_cmd=1; - break; - } - - if (bad_cmd){ - printk(KERN_INFO "%s: Invalid State, BAD Command %x, dev %s, lcn %i, st %i\n", - card->devname,atomic_read(&chan->common.command),dev->name, - chan->common.lcn, chan->common.state); - } - - return bad_cmd; -} - - - -/*************************** XPIPEMON FUNCTIONS **************************/ - -/*============================================================================== - * Process UDP call of type XPIPE - */ - -static int process_udp_mgmt_pkt(sdla_t *card) -{ - int c_retry = MAX_CMD_RETRY; - unsigned int len; - struct sk_buff *new_skb; - TX25Mbox *mbox = card->mbox; - int err; - int udp_mgmt_req_valid = 1; - struct net_device *dev; - x25_channel_t *chan; - unsigned short lcn; - struct timeval tv; - - - x25_udp_pkt_t *x25_udp_pkt; - x25_udp_pkt = (x25_udp_pkt_t *)card->u.x.udp_pkt_data; - - dev = card->u.x.udp_dev; - chan = dev->priv; - lcn = chan->common.lcn; - - switch(x25_udp_pkt->cblock.command) { - - /* XPIPE_ENABLE_TRACE */ - case XPIPE_ENABLE_TRACING: - - /* XPIPE_GET_TRACE_INFO */ - case XPIPE_GET_TRACE_INFO: - - /* SET FT1 MODE */ - case XPIPE_SET_FT1_MODE: - - if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_direction_err; - udp_mgmt_req_valid = 0; - break; - } - - /* XPIPE_FT1_READ_STATUS */ - case XPIPE_FT1_READ_STATUS: - - /* FT1 MONITOR STATUS */ - case XPIPE_FT1_STATUS_CTRL: - if(card->hw.fwid != SFID_X25_508) { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_type_err; - udp_mgmt_req_valid = 0; - break; - } - default: - break; - } - - if(!udp_mgmt_req_valid) { - /* set length to 0 */ - x25_udp_pkt->cblock.length = 0; - /* set return code */ - x25_udp_pkt->cblock.result = (card->hw.fwid != SFID_X25_508) ? 0x1F : 0xCD; - - } else { - - switch (x25_udp_pkt->cblock.command) { - - - case XPIPE_FLUSH_DRIVER_STATS: - init_x25_channel_struct(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - - - case XPIPE_DRIVER_STAT_IFSEND: - memcpy(x25_udp_pkt->data, &chan->if_send_stat, sizeof(if_send_stat_t)); - mbox->cmd.length = sizeof(if_send_stat_t); - x25_udp_pkt->cblock.length = mbox->cmd.length; - break; - - case XPIPE_DRIVER_STAT_INTR: - memcpy(&x25_udp_pkt->data[0], &card->statistics, sizeof(global_stats_t)); - memcpy(&x25_udp_pkt->data[sizeof(global_stats_t)], - &chan->rx_intr_stat, sizeof(rx_intr_stat_t)); - - mbox->cmd.length = sizeof(global_stats_t) + - sizeof(rx_intr_stat_t); - x25_udp_pkt->cblock.length = mbox->cmd.length; - break; - - case XPIPE_DRIVER_STAT_GEN: - memcpy(x25_udp_pkt->data, - &chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err, - sizeof(pipe_mgmt_stat_t)); - - memcpy(&x25_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], - &card->statistics, sizeof(global_stats_t)); - - x25_udp_pkt->cblock.result = 0; - x25_udp_pkt->cblock.length = sizeof(global_stats_t)+ - sizeof(rx_intr_stat_t); - mbox->cmd.length = x25_udp_pkt->cblock.length; - break; - - case XPIPE_ROUTER_UP_TIME: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - chan->router_start_time; - *(unsigned long *)&x25_udp_pkt->data = chan->router_up_time; - x25_udp_pkt->cblock.length = mbox->cmd.length = 4; - x25_udp_pkt->cblock.result = 0; - break; - - default : - - do { - memcpy(&mbox->cmd, &x25_udp_pkt->cblock.command, sizeof(TX25Cmd)); - if(mbox->cmd.length){ - memcpy(&mbox->data, - (char *)x25_udp_pkt->data, - mbox->cmd.length); - } - - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } while (err && c_retry-- && x25_error(card, err, mbox->cmd.command, 0)); - - - if ( err == CMD_OK || - (err == 1 && - (mbox->cmd.command == 0x06 || - mbox->cmd.command == 0x16) ) ){ - - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; - } else { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_timeout; - } - - /* copy the result back to our buffer */ - memcpy(&x25_udp_pkt->cblock.command, &mbox->cmd, sizeof(TX25Cmd)); - - if(mbox->cmd.length) { - memcpy(&x25_udp_pkt->data, &mbox->data, mbox->cmd.length); - } - break; - - } //switch - - } - - /* Fill UDP TTL */ - - x25_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - len = reply_udp(card->u.x.udp_pkt_data, mbox->cmd.length); - - - if(card->u.x.udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - err = x25_send(card, lcn, 0, len, card->u.x.udp_pkt_data); - if (!err) - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_passed; - else - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_send_failed; - - } else { - - /* Allocate socket buffer */ - if((new_skb = dev_alloc_skb(len)) != NULL) { - void *buf; - - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, card->u.x.udp_pkt_data, len); - - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->dev = dev; - - if (chan->common.usedby == API) - new_skb->protocol = htons(X25_PROT); - else - new_skb->protocol = htons(ETH_P_IP); - - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; - - } else { - ++chan->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } - - card->u.x.udp_pkt_lgth = 0; - - return 1; -} - - -/*============================================================================== - * Determine what type of UDP call it is. DRVSTATS or XPIPE8ND ? - */ -static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) -{ - x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)skb->data; - - if((x25_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (x25_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && - (x25_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && - (x25_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { - - if(!strncmp(x25_udp_pkt->wp_mgmt.signature, - UDPMGMT_XPIPE_SIGNATURE, 8)){ - return UDP_XPIPE_TYPE; - }else{ - printk(KERN_INFO "%s: UDP Packet, Failed Signature !\n", - card->devname); - } - } - - return UDP_INVALID_TYPE; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return nothing. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - - - x25_udp_pkt_t *x25_udp_pkt = (x25_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* fill in UDP reply */ - x25_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - mbox_len; - - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - x25_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = x25_udp_pkt->udp_pkt.udp_src_port; - x25_udp_pkt->udp_pkt.udp_src_port = - x25_udp_pkt->udp_pkt.udp_dst_port; - x25_udp_pkt->udp_pkt.udp_dst_port = temp; - - - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *) - (x25_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *) - (x25_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - /* calculate UDP checksum */ - x25_udp_pkt->udp_pkt.udp_checksum = 0; - - x25_udp_pkt->udp_pkt.udp_checksum = - calc_checksum(&data[UDP_OFFSET], udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - x25_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = x25_udp_pkt->ip_pkt.ip_src_address; - x25_udp_pkt->ip_pkt.ip_src_address = - x25_udp_pkt->ip_pkt.ip_dst_address; - x25_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - - /* fill in IP checksum */ - x25_udp_pkt->ip_pkt.hdr_checksum = 0; - x25_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data, sizeof(ip_pkt_t)); - - return len; -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, - struct net_device *dev, struct sk_buff *skb, - int lcn) -{ - int udp_pkt_stored = 0; - - if(!card->u.x.udp_pkt_lgth && (skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ - card->u.x.udp_pkt_lgth = skb->len; - card->u.x.udp_type = udp_type; - card->u.x.udp_pkt_src = udp_pkt_src; - card->u.x.udp_lcn = lcn; - card->u.x.udp_dev = dev; - memcpy(card->u.x.udp_pkt_data, skb->data, skb->len); - card->u.x.timer_int_enabled |= TMR_INT_ENABLED_UDP_PKT; - udp_pkt_stored = 1; - - }else{ - printk(KERN_INFO "%s: ERROR: UDP packet not stored for LCN %d\n", - card->devname,lcn); - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK){ - dev_kfree_skb_any(skb); - }else{ - dev_kfree_skb_any(skb); - } - - return(udp_pkt_stored); -} - - - -/*============================================================================= - * Initial the ppp_private_area structure. - */ -static void init_x25_channel_struct( x25_channel_t *chan ) -{ - memset(&chan->if_send_stat.if_send_entry,0,sizeof(if_send_stat_t)); - memset(&chan->rx_intr_stat.rx_intr_no_socket,0,sizeof(rx_intr_stat_t)); - memset(&chan->pipe_mgmt_stat.UDP_PIPE_mgmt_kmalloc_err,0,sizeof(pipe_mgmt_stat_t)); -} - -/*============================================================================ - * Initialize Global Statistics - */ -static void init_global_statistics( sdla_t *card ) -{ - memset(&card->statistics.isr_entry,0,sizeof(global_stats_t)); -} - - -/*=============================================================== - * SMP Support - * ==============================================================*/ - -static void S508_S514_lock(sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); -} -static void S508_S514_unlock(sdla_t *card, unsigned long *smp_flags) -{ - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - -/*=============================================================== - * x25_timer_routine - * - * A more efficient polling routine. Each half a second - * queue a polling task. We want to do the polling in a - * task not timer, because timer runs in interrupt time. - * - * FIXME Polling should be rethinked. - *==============================================================*/ - -static void x25_timer_routine(unsigned long data) -{ - sdla_t *card = (sdla_t*)data; - - if (!card->wandev.dev){ - printk(KERN_INFO "%s: Stopping the X25 Poll Timer: No Dev.\n", - card->devname); - return; - } - - if (card->open_cnt != card->u.x.num_of_ch){ - printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Interface down.\n", - card->devname); - return; - } - - if (test_bit(PERI_CRIT,&card->wandev.critical)){ - printk(KERN_INFO "%s: Stopping the X25 Poll Timer: Shutting down.\n", - card->devname); - return; - } - - if (!test_and_set_bit(POLL_CRIT,&card->wandev.critical)){ - trigger_x25_poll(card); - } - - card->u.x.x25_timer.expires=jiffies+(HZ>>1); - add_timer(&card->u.x.x25_timer); - return; -} - -void disable_comm_shutdown(sdla_t *card) -{ - TX25Mbox* mbox = card->mbox; - int err; - - /* Turn of interrutps */ - mbox->data[0] = 0; - if (card->hw.fwid == SFID_X25_508){ - mbox->data[1] = card->hw.irq; - mbox->data[2] = 2; - mbox->cmd.length = 3; - }else { - mbox->cmd.length = 1; - } - mbox->cmd.command = X25_SET_INTERRUPT_MODE; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - printk(KERN_INFO "INTERRUPT OFF FAIED %x\n",err); - - /* Bring down HDLC */ - mbox->cmd.command = X25_HDLC_LINK_CLOSE; - mbox->cmd.length = 0; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - printk(KERN_INFO "LINK CLOSED FAILED %x\n",err); - - - /* Brind down DTR */ - mbox->data[0] = 0; - mbox->data[2] = 0; - mbox->data[1] = 0x01; - mbox->cmd.length = 3; - mbox->cmd.command = X25_SET_GLOBAL_VARS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - printk(KERN_INFO "DTR DOWN FAILED %x\n",err); - -} - -MODULE_LICENSE("GPL"); - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c deleted file mode 100644 index 032c0f81928e..000000000000 --- a/drivers/net/wan/sdladrv.c +++ /dev/null @@ -1,2314 +0,0 @@ -/***************************************************************************** -* sdladrv.c SDLA Support Module. Main module. -* -* This module is a library of common hardware-specific functions -* used by all Sangoma drivers. -* -* Author: Gideon Hack -* -* Copyright: (c) 1995-2000 Sangoma Technologies Inc. -* -* 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. -* ============================================================================ -* Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support -* the PCISLOT #0. -* Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code. -* The memory test at address 0xC8000. -* Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci -* interrupt flags on initial load. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Updates for Linux 2.2.X kernels. -* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels -* Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul. -* Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility. -* Jun 12, 1996 Gene Kozin Added support for S503 card. -* Apr 30, 1996 Gene Kozin SDLA hardware interrupt is acknowledged before -* calling protocolspecific ISR. -* Register I/O ports with Linux kernel. -* Miscellaneous bug fixes. -* Dec 20, 1995 Gene Kozin Fixed a bug in interrupt routine. -* Oct 14, 1995 Gene Kozin Initial version. -*****************************************************************************/ - -/***************************************************************************** - * Notes: - * ------ - * 1. This code is ment to be system-independent (as much as possible). To - * achive this, various macros are used to hide system-specific interfaces. - * To compile this code, one of the following constants must be defined: - * - * Platform Define - * -------- ------ - * Linux _LINUX_ - * SCO Unix _SCO_UNIX_ - * - * 2. Supported adapter types: - * - * S502A - * ES502A (S502E) - * S503 - * S507 - * S508 (S509) - * - * 3. S502A Notes: - * - * There is no separate DPM window enable/disable control in S502A. It - * opens immediately after a window number it written to the HMCR - * register. To close the window, HMCR has to be written a value - * ????1111b (e.g. 0x0F or 0xFF). - * - * S502A DPM window cannot be located at offset E000 (e.g. 0xAE000). - * - * There should be a delay of ??? before reading back S502A status - * register. - * - * 4. S502E Notes: - * - * S502E has a h/w bug: although default IRQ line state is HIGH, enabling - * interrupts by setting bit 1 of the control register (BASE) to '1' - * causes it to go LOW! Therefore, disabling interrupts by setting that - * bit to '0' causes low-to-high transition on IRQ line (ghosty - * interrupt). The same occurs when disabling CPU by resetting bit 0 of - * CPU control register (BASE+3) - see the next note. - * - * S502E CPU and DPM control is limited: - * - * o CPU cannot be stopped independently. Resetting bit 0 of the CPUi - * control register (BASE+3) shuts the board down entirely, including - * DPM; - * - * o DPM access cannot be controlled dynamically. Ones CPU is started, - * bit 1 of the control register (BASE) is used to enable/disable IRQ, - * so that access to shared memory cannot be disabled while CPU is - * running. - ****************************************************************************/ - -#define _LINUX_ - -#if defined(_LINUX_) /****** Linux *******************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* support for loadable modules */ -#include /* for jiffies, HZ, etc. */ -#include /* API definitions */ -#include /* SDLA firmware module definitions */ -#include /* SDLA PCI hardware definitions */ -#include /* PCI defines and function prototypes */ -#include /* for inb(), outb(), etc. */ - -#define _INB(port) (inb(port)) -#define _OUTB(port, byte) (outb((byte),(port))) -#define SYSTEM_TICK jiffies - -#include - - -#elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/ - -#if !defined(INKERNEL) -#error This code MUST be compiled in kernel mode! -#endif -#include /* API definitions */ -#include /* SDLA firmware module definitions */ -#include /* for inb(), outb(), etc. */ -#define _INB(port) (inb(port)) -#define _OUTB(port, byte) (outb((port),(byte))) -#define SYSTEM_TICK lbolt - -#else -#error Unknown system type! -#endif - -#define MOD_VERSION 3 -#define MOD_RELEASE 0 - -#define SDLA_IODELAY 100 /* I/O Rd/Wr delay, 10 works for 486DX2-66 */ -#define EXEC_DELAY 20 /* shared memory access delay, mks */ -#define EXEC_TIMEOUT (HZ*2) /* command timeout, in ticks */ - -/* I/O port address range */ -#define S502A_IORANGE 3 -#define S502E_IORANGE 4 -#define S503_IORANGE 3 -#define S507_IORANGE 4 -#define S508_IORANGE 4 - -/* Maximum amount of memory */ -#define S502_MAXMEM 0x10000L -#define S503_MAXMEM 0x10000L -#define S507_MAXMEM 0x40000L -#define S508_MAXMEM 0x40000L - -/* Minimum amount of memory */ -#define S502_MINMEM 0x8000L -#define S503_MINMEM 0x8000L -#define S507_MINMEM 0x20000L -#define S508_MINMEM 0x20000L -#define NO_PORT -1 - - - - - -/****** Function Prototypes *************************************************/ - -/* Hardware-specific functions */ -static int sdla_detect (sdlahw_t* hw); -static int sdla_autodpm (sdlahw_t* hw); -static int sdla_setdpm (sdlahw_t* hw); -static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len); -static int sdla_init (sdlahw_t* hw); -static unsigned long sdla_memtest (sdlahw_t* hw); -static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo); -static unsigned char make_config_byte (sdlahw_t* hw); -static int sdla_start (sdlahw_t* hw, unsigned addr); - -static int init_s502a (sdlahw_t* hw); -static int init_s502e (sdlahw_t* hw); -static int init_s503 (sdlahw_t* hw); -static int init_s507 (sdlahw_t* hw); -static int init_s508 (sdlahw_t* hw); - -static int detect_s502a (int port); -static int detect_s502e (int port); -static int detect_s503 (int port); -static int detect_s507 (int port); -static int detect_s508 (int port); -static int detect_s514 (sdlahw_t* hw); -static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card); - -/* Miscellaneous functions */ -static void peek_by_4 (unsigned long src, void* buf, unsigned len); -static void poke_by_4 (unsigned long dest, void* buf, unsigned len); -static int calibrate_delay (int mks); -static int get_option_index (unsigned* optlist, unsigned optval); -static unsigned check_memregion (void* ptr, unsigned len); -static unsigned test_memregion (void* ptr, unsigned len); -static unsigned short checksum (unsigned char* buf, unsigned len); -static int init_pci_slot(sdlahw_t *); - -static int pci_probe(sdlahw_t *hw); - -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ - -static struct pci_device_id sdladrv_pci_tbl[] = { - { V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl); - -MODULE_LICENSE("GPL"); - -/* private data */ -static char modname[] = "sdladrv"; -static char fullname[] = "SDLA Support Module"; -static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; -static unsigned exec_idle; - -/* Hardware configuration options. - * These are arrays of configuration options used by verification routines. - * The first element of each array is its size (i.e. number of options). - */ -static unsigned s502_port_options[] = - { 4, 0x250, 0x300, 0x350, 0x360 } -; -static unsigned s503_port_options[] = - { 8, 0x250, 0x254, 0x300, 0x304, 0x350, 0x354, 0x360, 0x364 } -; -static unsigned s508_port_options[] = - { 8, 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390 } -; - -static unsigned s502a_irq_options[] = { 0 }; -static unsigned s502e_irq_options[] = { 4, 2, 3, 5, 7 }; -static unsigned s503_irq_options[] = { 5, 2, 3, 4, 5, 7 }; -static unsigned s508_irq_options[] = { 8, 3, 4, 5, 7, 10, 11, 12, 15 }; - -static unsigned s502a_dpmbase_options[] = -{ - 28, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, - 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, -}; -static unsigned s507_dpmbase_options[] = -{ - 32, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, - 0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, -}; -static unsigned s508_dpmbase_options[] = /* incl. S502E and S503 */ -{ - 32, - 0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000, - 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000, - 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000, 0xDE000, - 0xE0000, 0xE2000, 0xE4000, 0xE6000, 0xE8000, 0xEA000, 0xEC000, 0xEE000, -}; - -/* -static unsigned s502_dpmsize_options[] = { 2, 0x2000, 0x10000 }; -static unsigned s507_dpmsize_options[] = { 2, 0x2000, 0x4000 }; -static unsigned s508_dpmsize_options[] = { 1, 0x2000 }; -*/ - -static unsigned s502a_pclk_options[] = { 2, 3600, 7200 }; -static unsigned s502e_pclk_options[] = { 5, 3600, 5000, 7200, 8000, 10000 }; -static unsigned s503_pclk_options[] = { 3, 7200, 8000, 10000 }; -static unsigned s507_pclk_options[] = { 1, 12288 }; -static unsigned s508_pclk_options[] = { 1, 16000 }; - -/* Host memory control register masks */ -static unsigned char s502a_hmcr[] = -{ - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, /* A0000 - AC000 */ - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, /* C0000 - CC000 */ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, /* D0000 - DC000 */ - 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, /* E0000 - EC000 */ -}; -static unsigned char s502e_hmcr[] = -{ - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, /* A0000 - AE000 */ - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, /* C0000 - CE000 */ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* D0000 - DE000 */ - 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, /* E0000 - EE000 */ -}; -static unsigned char s507_hmcr[] = -{ - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, /* A0000 - AE000 */ - 0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, /* B0000 - BE000 */ - 0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, /* C0000 - CE000 */ - 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, /* E0000 - EE000 */ -}; -static unsigned char s508_hmcr[] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A0000 - AE000 */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* C0000 - CE000 */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, /* D0000 - DE000 */ - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, /* E0000 - EE000 */ -}; - -static unsigned char s507_irqmask[] = -{ - 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 -}; - -static int pci_slot_ar[MAX_S514_CARDS]; - -/******* Kernel Loadable Module Entry Points ********************************/ - -/*============================================================================ - * Module 'insert' entry point. - * o print announcement - * o initialize static data - * o calibrate SDLA shared memory access delay. - * - * Return: 0 Ok - * < 0 error. - * Context: process - */ - -static int __init sdladrv_init(void) -{ - int i=0; - - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, MOD_VERSION, MOD_RELEASE, copyright); - exec_idle = calibrate_delay(EXEC_DELAY); -#ifdef WANDEBUG - printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle); -#endif - - /* Initialize the PCI Card array, which - * will store flags, used to mark - * card initialization state */ - for (i=0; itype != SDLA_S514) - printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n", - modname, hw->port); - return -EINVAL; - } - - if(hw->type != SDLA_S514) { - printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", - modname, hw->type, hw->port); - - hw->dpmsize = SDLA_WINDOWSIZE; - switch (hw->type) { - case SDLA_S502A: - hw->io_range = S502A_IORANGE; - irq_opt = s502a_irq_options; - dpmbase_opt = s502a_dpmbase_options; - pclk_opt = s502a_pclk_options; - break; - - case SDLA_S502E: - hw->io_range = S502E_IORANGE; - irq_opt = s502e_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s502e_pclk_options; - break; - - case SDLA_S503: - hw->io_range = S503_IORANGE; - irq_opt = s503_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s503_pclk_options; - break; - - case SDLA_S507: - hw->io_range = S507_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s507_dpmbase_options; - pclk_opt = s507_pclk_options; - break; - - case SDLA_S508: - hw->io_range = S508_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s508_pclk_options; - break; - } - - /* Verify IRQ configuration options */ - if (!get_option_index(irq_opt, hw->irq)) { - printk(KERN_INFO "%s: IRQ %d is invalid!\n", - modname, hw->irq); - return -EINVAL; - } - - /* Verify CPU clock rate configuration options */ - if (hw->pclk == 0) - hw->pclk = pclk_opt[1]; /* use default */ - - else if (!get_option_index(pclk_opt, hw->pclk)) { - printk(KERN_INFO "%s: CPU clock %u is invalid!\n", - modname, hw->pclk); - return -EINVAL; - } - printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", - modname, hw->pclk); - - /* Setup adapter dual-port memory window and test memory */ - if (hw->dpmbase == 0) { - err = sdla_autodpm(hw); - if (err) { - printk(KERN_INFO - "%s: can't find available memory region!\n", - modname); - return err; - } - } - else if (!get_option_index(dpmbase_opt, - virt_to_phys(hw->dpmbase))) { - printk(KERN_INFO - "%s: memory address 0x%lX is invalid!\n", - modname, virt_to_phys(hw->dpmbase)); - return -EINVAL; - } - else if (sdla_setdpm(hw)) { - printk(KERN_INFO - "%s: 8K memory region at 0x%lX is not available!\n", - modname, virt_to_phys(hw->dpmbase)); - return -EINVAL; - } - printk(KERN_INFO - "%s: dual-port memory window is set at 0x%lX.\n", - modname, virt_to_phys(hw->dpmbase)); - - - /* If we find memory in 0xE**** Memory region, - * warn the user to disable the SHADOW RAM. - * Since memory corruption can occur if SHADOW is - * enabled. This can causes random crashes ! */ - if (virt_to_phys(hw->dpmbase) >= 0xE0000){ - printk(KERN_WARNING "\n%s: !!!!!!!! WARNING !!!!!!!!\n",modname); - printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n", - modname, virt_to_phys(hw->dpmbase)); - printk(KERN_WARNING " Please disable the SHADOW RAM, otherwise\n"); - printk(KERN_WARNING " your system might crash randomly from time to time !\n"); - printk(KERN_WARNING "%s: !!!!!!!! WARNING !!!!!!!!\n\n",modname); - } - } - - else { - hw->memory = test_memregion((void*)hw->dpmbase, - MAX_SIZEOF_S514_MEMORY); - if(hw->memory < (256 * 1024)) { - printk(KERN_INFO - "%s: error in testing S514 memory (0x%lX)\n", - modname, hw->memory); - sdla_down(hw); - return -EINVAL; - } - } - - printk(KERN_INFO "%s: found %luK bytes of on-board memory\n", - modname, hw->memory / 1024); - - /* Load firmware. If loader fails then shut down adapter */ - err = sdla_load(hw, sfm, len); - if (err) sdla_down(hw); /* shutdown adapter */ - - return err; -} - -/*============================================================================ - * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc. - */ - -EXPORT_SYMBOL(sdla_down); - -int sdla_down (sdlahw_t* hw) -{ - unsigned port = hw->port; - int i; - unsigned char CPU_no; - u32 int_config, int_status; - - if(!port && (hw->type != SDLA_S514)) - return -EFAULT; - - switch (hw->type) { - case SDLA_S502A: - _OUTB(port, 0x08); /* halt CPU */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - hw->regs[0] = 0x08; - _OUTB(port + 1, 0xFF); /* close memory window */ - hw->regs[1] = 0xFF; - break; - - case SDLA_S502E: - _OUTB(port + 3, 0); /* stop CPU */ - _OUTB(port, 0); /* reset board */ - for (i = 0; i < S502E_IORANGE; ++i) - hw->regs[i] = 0 - ; - break; - - case SDLA_S503: - case SDLA_S507: - case SDLA_S508: - _OUTB(port, 0); /* reset board logic */ - hw->regs[0] = 0; - break; - - case SDLA_S514: - /* halt the adapter */ - *(char *)hw->vector = S514_CPU_HALT; - CPU_no = hw->S514_cpu_no[0]; - - /* disable the PCI IRQ and disable memory access */ - pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config); - int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; - pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config); - read_S514_int_stat(hw, &int_status); - S514_intack(hw, int_status); - if(CPU_no == S514_CPU_A) - pci_write_config_dword(hw->pci_dev, PCI_MAP0_DWORD, - PCI_CPU_A_MEM_DISABLE); - else - pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD, - PCI_CPU_B_MEM_DISABLE); - - /* free up the allocated virtual memory */ - iounmap((void *)hw->dpmbase); - iounmap((void *)hw->vector); - break; - - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Map shared memory window into SDLA address space. - */ - -EXPORT_SYMBOL(sdla_mapmem); - -int sdla_mapmem (sdlahw_t* hw, unsigned long addr) -{ - unsigned port = hw->port; - register int tmp; - - switch (hw->type) { - case SDLA_S502A: - case SDLA_S502E: - if (addr < S502_MAXMEM) { /* verify parameter */ - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S503: - if (addr < S503_MAXMEM) { /* verify parameter */ - tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S507: - if (addr < S507_MAXMEM) { - if (!(_INB(port) & 0x02)) - return -EIO; - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S508: - if (addr < S508_MAXMEM) { - tmp = addr >> 13; /* convert to register mask */ - _OUTB(port + 2, tmp); - hw->regs[2] = tmp; - } - else return -EINVAL; - break; - - case SDLA_S514: - return 0; - - default: - return -EINVAL; - } - hw->vector = addr & 0xFFFFE000L; - return 0; -} - -/*============================================================================ - * Enable interrupt generation. - */ - -static int sdla_inten (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - switch (hw->type) { - case SDLA_S502E: - /* Note thar interrupt control operations on S502E are allowed - * only if CPU is enabled (bit 0 of status register is set). - */ - if (_INB(port) & 0x01) { - _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ - _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ - hw->regs[0] = 0x06; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] | 0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port) & 0x02)) /* verify */ - return -EIO; - break; - - case SDLA_S508: - tmp = hw->regs[0] | 0x10; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port + 1) & 0x10)) /* verify */ - return -EIO; - break; - - case SDLA_S502A: - case SDLA_S507: - break; - - case SDLA_S514: - break; - - default: - return -EINVAL; - - } - return 0; -} - -/*============================================================================ - * Disable interrupt generation. - */ - -#if 0 -int sdla_intde (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - switch (hw->type) { - case SDLA_S502E: - /* Notes: - * 1) interrupt control operations are allowed only if CPU is - * enabled (bit 0 of status register is set). - * 2) disabling interrupts using bit 1 of control register - * causes IRQ line go high, therefore we are going to use - * 0x04 instead: lower it to inhibit interrupts to PC. - */ - if (_INB(port) & 0x01) { - _OUTB(port, hw->regs[0] & ~0x04); - hw->regs[0] &= ~0x04; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] & ~0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) & 0x02) /* verify */ - return -EIO; - break; - - case SDLA_S508: - tmp = hw->regs[0] & ~0x10; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) & 0x10) /* verify */ - return -EIO; - break; - - case SDLA_S502A: - case SDLA_S507: - break; - - default: - return -EINVAL; - } - return 0; -} -#endif /* 0 */ - -/*============================================================================ - * Acknowledge SDLA hardware interrupt. - */ - -static int sdla_intack (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp; - - switch (hw->type) { - case SDLA_S502E: - /* To acknoledge hardware interrupt we have to toggle bit 3 of - * control register: \_/ - * Note that interrupt control operations on S502E are allowed - * only if CPU is enabled (bit 1 of status register is set). - */ - if (_INB(port) & 0x01) { - tmp = hw->regs[0] & ~0x04; - _OUTB(port, tmp); - tmp |= 0x04; - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - else return -EIO; - break; - - case SDLA_S503: - if (_INB(port) & 0x04) { - tmp = hw->regs[0] & ~0x08; - _OUTB(port, tmp); - tmp |= 0x08; - _OUTB(port, tmp); - hw->regs[0] = tmp; - } - break; - - case SDLA_S502A: - case SDLA_S507: - case SDLA_S508: - break; - - default: - return -EINVAL; - } - return 0; -} - - -/*============================================================================ - * Acknowledge S514 hardware interrupt. - */ - -EXPORT_SYMBOL(S514_intack); - -void S514_intack (sdlahw_t* hw, u32 int_status) -{ - pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); -} - - -/*============================================================================ - * Read the S514 hardware interrupt status. - */ - -EXPORT_SYMBOL(read_S514_int_stat); - -void read_S514_int_stat (sdlahw_t* hw, u32* int_status) -{ - pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); -} - - -/*============================================================================ - * Generate an interrupt to adapter's CPU. - */ - -#if 0 -int sdla_intr (sdlahw_t* hw) -{ - unsigned port = hw->port; - - switch (hw->type) { - case SDLA_S502A: - if (!(_INB(port) & 0x40)) { - _OUTB(port, 0x10); /* issue NMI to CPU */ - hw->regs[0] = 0x10; - } - else return -EIO; - break; - - case SDLA_S507: - if ((_INB(port) & 0x06) == 0x06) { - _OUTB(port + 3, 0); - } - else return -EIO; - break; - - case SDLA_S508: - if (_INB(port + 1) & 0x02) { - _OUTB(port, 0x08); - } - else return -EIO; - break; - - case SDLA_S502E: - case SDLA_S503: - default: - return -EINVAL; - } - return 0; -} -#endif /* 0 */ - -/*============================================================================ - * Execute Adapter Command. - * o Set exec flag. - * o Busy-wait until flag is reset. - * o Return number of loops made, or 0 if command timed out. - */ - -EXPORT_SYMBOL(sdla_exec); - -int sdla_exec (void* opflag) -{ - volatile unsigned char* flag = opflag; - unsigned long tstop; - int nloops; - - if(readb(flag) != 0x00) { - printk(KERN_INFO - "WANPIPE: opp flag set on entry to sdla_exec\n"); - return 0; - } - - writeb(0x01, flag); - - tstop = SYSTEM_TICK + EXEC_TIMEOUT; - - for (nloops = 1; (readb(flag) == 0x01); ++ nloops) { - unsigned delay = exec_idle; - while (-- delay); /* delay */ - if (SYSTEM_TICK > tstop) return 0; /* time is up! */ - } - return nloops; -} - -/*============================================================================ - * Read absolute adapter memory. - * Transfer data from adapter's memory to data buffer. - * - * Note: - * Care should be taken when crossing dual-port memory window boundary. - * This function is not atomic, so caller must disable interrupt if - * interrupt routines are accessing adapter shared memory. - */ - -EXPORT_SYMBOL(sdla_peek); - -int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) -{ - - if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL; - - if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ - peek_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); - return 0; - } - - else { /* copy data for the S508 adapter */ - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; - - while (len && !err) { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? - (winsize - curpos) : len; - /* Relocate window and copy block of data */ - err = sdla_mapmem(hw, curvec); - peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf, - curlen); - addr += curlen; - buf = (char*)buf + curlen; - len -= curlen; - } - - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; - } -} - - -/*============================================================================ - * Read data from adapter's memory to a data buffer in 4-byte chunks. - * Note that we ensure that the SDLA memory address is on a 4-byte boundary - * before we begin moving the data in 4-byte chunks. -*/ - -static void peek_by_4 (unsigned long src, void* buf, unsigned len) -{ - - /* byte copy data until we get to a 4-byte boundary */ - while (len && (src & 0x03)) { - *(char *)buf ++ = readb(src ++); - len --; - } - - /* copy data in 4-byte chunks */ - while (len >= 4) { - *(unsigned long *)buf = readl(src); - buf += 4; - src += 4; - len -= 4; - } - - /* byte copy any remaining data */ - while (len) { - *(char *)buf ++ = readb(src ++); - len --; - } -} - - -/*============================================================================ - * Write Absolute Adapter Memory. - * Transfer data from data buffer to adapter's memory. - * - * Note: - * Care should be taken when crossing dual-port memory window boundary. - * This function is not atomic, so caller must disable interrupt if - * interrupt routines are accessing adapter shared memory. - */ - -EXPORT_SYMBOL(sdla_poke); - -int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) -{ - - if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL; - - if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ - poke_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); - return 0; - } - - else { /* copy data for the S508 adapter */ - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; - - while (len && !err) { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? - (winsize - curpos) : len; - /* Relocate window and copy block of data */ - sdla_mapmem(hw, curvec); - poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf, - curlen); - addr += curlen; - buf = (char*)buf + curlen; - len -= curlen; - } - - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; - } -} - - -/*============================================================================ - * Write from a data buffer to adapter's memory in 4-byte chunks. - * Note that we ensure that the SDLA memory address is on a 4-byte boundary - * before we begin moving the data in 4-byte chunks. -*/ - -static void poke_by_4 (unsigned long dest, void* buf, unsigned len) -{ - - /* byte copy data until we get to a 4-byte boundary */ - while (len && (dest & 0x03)) { - writeb (*(char *)buf ++, dest ++); - len --; - } - - /* copy data in 4-byte chunks */ - while (len >= 4) { - writel (*(unsigned long *)buf, dest); - dest += 4; - buf += 4; - len -= 4; - } - - /* byte copy any remaining data */ - while (len) { - writeb (*(char *)buf ++ , dest ++); - len --; - } -} - - -#ifdef DONT_COMPIPLE_THIS -#endif /* DONT_COMPIPLE_THIS */ - -/****** Hardware-Specific Functions *****************************************/ - -/*============================================================================ - * Detect adapter type. - * o if adapter type is specified then call detection routine for that adapter - * type. Otherwise call detection routines for every adapter types until - * adapter is detected. - * - * Notes: - * 1) Detection tests are destructive! Adapter will be left in shutdown state - * after the test. - */ -static int sdla_detect (sdlahw_t* hw) -{ - unsigned port = hw->port; - int err = 0; - - if (!port && (hw->type != SDLA_S514)) - return -EFAULT; - - switch (hw->type) { - case SDLA_S502A: - if (!detect_s502a(port)) err = -ENODEV; - break; - - case SDLA_S502E: - if (!detect_s502e(port)) err = -ENODEV; - break; - - case SDLA_S503: - if (!detect_s503(port)) err = -ENODEV; - break; - - case SDLA_S507: - if (!detect_s507(port)) err = -ENODEV; - break; - - case SDLA_S508: - if (!detect_s508(port)) err = -ENODEV; - break; - - case SDLA_S514: - if (!detect_s514(hw)) err = -ENODEV; - break; - - default: - if (detect_s502a(port)) - hw->type = SDLA_S502A; - else if (detect_s502e(port)) - hw->type = SDLA_S502E; - else if (detect_s503(port)) - hw->type = SDLA_S503; - else if (detect_s507(port)) - hw->type = SDLA_S507; - else if (detect_s508(port)) - hw->type = SDLA_S508; - else err = -ENODEV; - } - return err; -} - -/*============================================================================ - * Autoselect memory region. - * o try all available DMP address options from the top down until success. - */ -static int sdla_autodpm (sdlahw_t* hw) -{ - int i, err = -EINVAL; - unsigned* opt; - - switch (hw->type) { - case SDLA_S502A: - opt = s502a_dpmbase_options; - break; - - case SDLA_S502E: - case SDLA_S503: - case SDLA_S508: - opt = s508_dpmbase_options; - break; - - case SDLA_S507: - opt = s507_dpmbase_options; - break; - - default: - return -EINVAL; - } - - /* Start testing from 8th position, address - * 0xC8000 from the 508 address table. - * We don't want to test A**** addresses, since - * they are usually used for Video */ - for (i = 8; i <= opt[0] && err; i++) { - hw->dpmbase = phys_to_virt(opt[i]); - err = sdla_setdpm(hw); - } - return err; -} - -/*============================================================================ - * Set up adapter dual-port memory window. - * o shut down adapter - * o make sure that no physical memory exists in this region, i.e entire - * region reads 0xFF and is not writable when adapter is shut down. - * o initialize adapter hardware - * o make sure that region is usable with SDLA card, i.e. we can write to it - * when adapter is configured. - */ -static int sdla_setdpm (sdlahw_t* hw) -{ - int err; - - /* Shut down card and verify memory region */ - sdla_down(hw); - if (check_memregion(hw->dpmbase, hw->dpmsize)) - return -EINVAL; - - /* Initialize adapter and test on-board memory segment by segment. - * If memory size appears to be less than shared memory window size, - * assume that memory region is unusable. - */ - err = sdla_init(hw); - if (err) return err; - - if (sdla_memtest(hw) < hw->dpmsize) { /* less than window size */ - sdla_down(hw); - return -EIO; - } - sdla_mapmem(hw, 0L); /* set window vector at bottom */ - return 0; -} - -/*============================================================================ - * Load adapter from the memory image of the SDLA firmware module. - * o verify firmware integrity and compatibility - * o start adapter up - */ -static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) -{ - - int i; - - /* Verify firmware signature */ - if (strcmp(sfm->signature, SFM_SIGNATURE)) { - printk(KERN_INFO "%s: not SDLA firmware!\n", - modname); - return -EINVAL; - } - - /* Verify firmware module format version */ - if (sfm->version != SFM_VERSION) { - printk(KERN_INFO - "%s: firmware format %u rejected! Expecting %u.\n", - modname, sfm->version, SFM_VERSION); - return -EINVAL; - } - - /* Verify firmware module length and checksum */ - if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || - (checksum((void*)&sfm->info, - sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) { - printk(KERN_INFO "%s: firmware corrupted!\n", modname); - return -EINVAL; - } - - /* Announce */ - printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname, - (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", - sfm->info.codeid); - - if(hw->type == SDLA_S514) - printk(KERN_INFO "%s: loading S514 adapter, CPU %c\n", - modname, hw->S514_cpu_no[0]); - - /* Scan through the list of compatible adapters and make sure our - * adapter type is listed. - */ - for (i = 0; - (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); - ++i); - - if (i == SFM_MAX_SDLA) { - printk(KERN_INFO "%s: firmware is not compatible with S%u!\n", - modname, hw->type); - return -EINVAL; - } - - - /* Make sure there is enough on-board memory */ - if (hw->memory < sfm->info.memsize) { - printk(KERN_INFO - "%s: firmware needs %lu bytes of on-board memory!\n", - modname, sfm->info.memsize); - return -EINVAL; - } - - /* Move code onto adapter */ - if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) { - printk(KERN_INFO "%s: failed to load code segment!\n", - modname); - return -EIO; - } - - /* Prepare boot-time configuration data and kick-off CPU */ - sdla_bootcfg(hw, &sfm->info); - if (sdla_start(hw, sfm->info.startoffs)) { - printk(KERN_INFO "%s: Damn... Adapter won't start!\n", - modname); - return -EIO; - } - - /* position DPM window over the mailbox and enable interrupts */ - if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) { - printk(KERN_INFO "%s: adapter hardware failure!\n", - modname); - return -EIO; - } - hw->fwid = sfm->info.codeid; /* set firmware ID */ - return 0; -} - -/*============================================================================ - * Initialize SDLA hardware: setup memory window, IRQ, etc. - */ -static int sdla_init (sdlahw_t* hw) -{ - int i; - - for (i = 0; i < SDLA_MAXIORANGE; ++i) - hw->regs[i] = 0; - - switch (hw->type) { - case SDLA_S502A: return init_s502a(hw); - case SDLA_S502E: return init_s502e(hw); - case SDLA_S503: return init_s503(hw); - case SDLA_S507: return init_s507(hw); - case SDLA_S508: return init_s508(hw); - } - return -EINVAL; -} - -/*============================================================================ - * Test adapter on-board memory. - * o slide DPM window from the bottom up and test adapter memory segment by - * segment. - * Return adapter memory size. - */ -static unsigned long sdla_memtest (sdlahw_t* hw) -{ - unsigned long memsize; - unsigned winsize; - - for (memsize = 0, winsize = hw->dpmsize; - !sdla_mapmem(hw, memsize) && - (test_memregion(hw->dpmbase, winsize) == winsize) - ; - memsize += winsize) - ; - hw->memory = memsize; - return memsize; -} - -/*============================================================================ - * Prepare boot-time firmware configuration data. - * o position DPM window - * o initialize configuration data area - */ -static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) -{ - unsigned char* data; - - if (!sfminfo->datasize) return 0; /* nothing to do */ - - if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) - return -EIO; - - if(hw->type == SDLA_S514) - data = (void*)(hw->dpmbase + sfminfo->dataoffs); - else - data = (void*)((u8 *)hw->dpmbase + - (sfminfo->dataoffs - hw->vector)); - - memset_io (data, 0, sfminfo->datasize); - - writeb (make_config_byte(hw), &data[0x00]); - - switch (sfminfo->codeid) { - case SFID_X25_502: - case SFID_X25_508: - writeb (3, &data[0x01]); /* T1 timer */ - writeb (10, &data[0x03]); /* N2 */ - writeb (7, &data[0x06]); /* HDLC window size */ - writeb (1, &data[0x0B]); /* DTE */ - writeb (2, &data[0x0C]); /* X.25 packet window size */ - writew (128, &data[0x0D]); /* default X.25 data size */ - writew (128, &data[0x0F]); /* maximum X.25 data size */ - break; - } - return 0; -} - -/*============================================================================ - * Prepare configuration byte identifying adapter type and CPU clock rate. - */ -static unsigned char make_config_byte (sdlahw_t* hw) -{ - unsigned char byte = 0; - - switch (hw->pclk) { - case 5000: byte = 0x01; break; - case 7200: byte = 0x02; break; - case 8000: byte = 0x03; break; - case 10000: byte = 0x04; break; - case 16000: byte = 0x05; break; - } - - switch (hw->type) { - case SDLA_S502E: byte |= 0x80; break; - case SDLA_S503: byte |= 0x40; break; - } - return byte; -} - -/*============================================================================ - * Start adapter's CPU. - * o calculate a pointer to adapter's cold boot entry point - * o position DPM window - * o place boot instruction (jp addr) at cold boot entry point - * o start CPU - */ -static int sdla_start (sdlahw_t* hw, unsigned addr) -{ - unsigned port = hw->port; - unsigned char *bootp; - int err, tmp, i; - - if (!port && (hw->type != SDLA_S514)) return -EFAULT; - - switch (hw->type) { - case SDLA_S502A: - bootp = hw->dpmbase; - bootp += 0x66; - break; - - case SDLA_S502E: - case SDLA_S503: - case SDLA_S507: - case SDLA_S508: - case SDLA_S514: - bootp = hw->dpmbase; - break; - - default: - return -EINVAL; - } - - err = sdla_mapmem(hw, 0); - if (err) return err; - - writeb (0xC3, bootp); /* Z80: 'jp' opcode */ - bootp ++; - writew (addr, bootp); - - switch (hw->type) { - case SDLA_S502A: - _OUTB(port, 0x10); /* issue NMI to CPU */ - hw->regs[0] = 0x10; - break; - - case SDLA_S502E: - _OUTB(port + 3, 0x01); /* start CPU */ - hw->regs[3] = 0x01; - for (i = 0; i < SDLA_IODELAY; ++i); - if (_INB(port) & 0x01) { /* verify */ - /* - * Enabling CPU changes functionality of the - * control register, so we have to reset its - * mirror. - */ - _OUTB(port, 0); /* disable interrupts */ - hw->regs[0] = 0; - } - else return -EIO; - break; - - case SDLA_S503: - tmp = hw->regs[0] | 0x09; /* set bits 0 and 3 */ - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port) & 0x01)) /* verify */ - return -EIO; - break; - - case SDLA_S507: - tmp = hw->regs[0] | 0x02; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port) & 0x04)) /* verify */ - return -EIO; - break; - - case SDLA_S508: - tmp = hw->regs[0] | 0x02; - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); - if (!(_INB(port + 1) & 0x02)) /* verify */ - return -EIO; - break; - - case SDLA_S514: - writeb (S514_CPU_START, hw->vector); - break; - - default: - return -EINVAL; - } - return 0; -} - -/*============================================================================ - * Initialize S502A adapter. - */ -static int init_s502a (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s502a(port)) - return -ENODEV; - - hw->regs[0] = 0x08; - hw->regs[1] = 0xFF; - - /* Verify configuration options */ - i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s502a_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window (this also enables memory access) */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - hw->regs[0] = 0x08; - return 0; -} - -/*============================================================================ - * Initialize S502E adapter. - */ -static int init_s502e (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s502e(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x02); - hw->regs[0] = 0x02; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port) & 0x02) ? 0 : -EIO; -} - -/*============================================================================ - * Initialize S503 adapter. - * --------------------------------------------------------------------------- - */ -static int init_s503 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s503(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x02); - hw->regs[0] = 0x02; /* update mirror */ - return 0; -} - -/*============================================================================ - * Initialize S507 adapter. - */ -static int init_s507 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s507(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - tmp = s507_hmcr[i - 1]; - switch (hw->dpmsize) { - case 0x2000: - tmp |= 0x01; - break; - - case 0x10000L: - break; - - default: - return -EINVAL; - } - - /* Enable adapter's logic */ - _OUTB(port, 0x01); - hw->regs[0] = 0x01; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (!(_INB(port) & 0x20)) - return -EIO; - - /* Setup dual-port memory window */ - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - tmp = hw->regs[0] | 0x04; - if (hw->irq) { - i = get_option_index(s508_irq_options, hw->irq); - if (i) tmp |= s507_irqmask[i - 1]; - } - _OUTB(port, tmp); - hw->regs[0] = tmp; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port) & 0x08) ? 0 : -EIO; -} - -/*============================================================================ - * Initialize S508 adapter. - */ -static int init_s508 (sdlahw_t* hw) -{ - unsigned port = hw->port; - int tmp, i; - - if (!detect_s508(port)) - return -ENODEV; - - /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); - if (i == 0) - return -EINVAL; - - /* Setup memory configuration */ - tmp = s508_hmcr[i - 1]; - _OUTB(port + 1, tmp); - hw->regs[1] = tmp; - - /* Enable memory access */ - _OUTB(port, 0x04); - hw->regs[0] = 0x04; /* update mirror */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - return (_INB(port + 1) & 0x04) ? 0 : -EIO; -} - -/*============================================================================ - * Detect S502A adapter. - * Following tests are used to detect S502A adapter: - * 1. All registers other than status (BASE) should read 0xFF - * 2. After writing 00001000b to control register, status register should - * read 01000000b. - * 3. After writing 0 to control register, status register should still - * read 01000000b. - * 4. After writing 00000100b to control register, status register should - * read 01000100b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s502a (int port) -{ - int i, j; - - if (!get_option_index(s502_port_options, port)) - return 0; - - for (j = 1; j < SDLA_MAXIORANGE; ++j) { - if (_INB(port + j) != 0xFF) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0x08); /* halt CPU */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x40) - return 0; - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x40) - return 0; - _OUTB(port, 0x04); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0x44) - return 0; - - /* Reset adapter */ - _OUTB(port, 0x08); - _OUTB(port, 0x08); - _OUTB(port, 0x08); - _OUTB(port + 1, 0xFF); - return 1; -} - -/*============================================================================ - * Detect S502E adapter. - * Following tests are used to verify adapter presence: - * 1. All registers other than status (BASE) should read 0xFF. - * 2. After writing 0 to CPU control register (BASE+3), status register - * (BASE) should read 11111000b. - * 3. After writing 00000100b to port BASE (set bit 2), status register - * (BASE) should read 11111100b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s502e (int port) -{ - int i, j; - - if (!get_option_index(s502_port_options, port)) - return 0; - for (j = 1; j < SDLA_MAXIORANGE; ++j) { - if (_INB(port + j) != 0xFF) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port + 3, 0); /* CPU control reg. */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF8) /* read status */ - return 0; - _OUTB(port, 0x04); /* set bit 2 */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xFC) /* verify */ - return 0; - - /* Reset adapter */ - _OUTB(port, 0); - return 1; -} - -/*============================================================================ - * Detect s503 adapter. - * Following tests are used to verify adapter presence: - * 1. All registers other than status (BASE) should read 0xFF. - * 2. After writing 0 to control register (BASE), status register (BASE) - * should read 11110000b. - * 3. After writing 00000100b (set bit 2) to control register (BASE), - * status register should read 11110010b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s503 (int port) -{ - int i, j; - - if (!get_option_index(s503_port_options, port)) - return 0; - for (j = 1; j < SDLA_MAXIORANGE; ++j) { - if (_INB(port + j) != 0xFF) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0); /* reset control reg.*/ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF0) /* read status */ - return 0; - _OUTB(port, 0x04); /* set bit 2 */ - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if (_INB(port) != 0xF2) /* verify */ - return 0; - - /* Reset adapter */ - _OUTB(port, 0); - return 1; -} - -/*============================================================================ - * Detect s507 adapter. - * Following tests are used to detect s507 adapter: - * 1. All ports should read the same value. - * 2. After writing 0x00 to control register, status register should read - * ?011000?b. - * 3. After writing 0x01 to control register, status register should read - * ?011001?b. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s507 (int port) -{ - int tmp, i, j; - - if (!get_option_index(s508_port_options, port)) - return 0; - tmp = _INB(port); - for (j = 1; j < S507_IORANGE; ++j) { - if (_INB(port + j) != tmp) - return 0; - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - } - - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port) & 0x7E) != 0x30) - return 0; - _OUTB(port, 0x01); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port) & 0x7E) != 0x32) - return 0; - - /* Reset adapter */ - _OUTB(port, 0x00); - return 1; -} - -/*============================================================================ - * Detect s508 adapter. - * Following tests are used to detect s508 adapter: - * 1. After writing 0x00 to control register, status register should read - * ??000000b. - * 2. After writing 0x10 to control register, status register should read - * ??010000b - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s508 (int port) -{ - int i; - - if (!get_option_index(s508_port_options, port)) - return 0; - _OUTB(port, 0x00); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port + 1) & 0x3F) != 0x00) - return 0; - _OUTB(port, 0x10); - for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ - if ((_INB(port + 1) & 0x3F) != 0x10) - return 0; - - /* Reset adapter */ - _OUTB(port, 0x00); - return 1; -} - -/*============================================================================ - * Detect s514 PCI adapter. - * Return 1 if detected o.k. or 0 if failed. - * Note: This test is destructive! Adapter will be left in shutdown - * state after the test. - */ -static int detect_s514 (sdlahw_t* hw) -{ - unsigned char CPU_no, slot_no, auto_slot_cfg; - int number_S514_cards = 0; - u32 S514_mem_base_addr = 0; - u32 ut_u32; - struct pci_dev *pci_dev; - - -#ifndef CONFIG_PCI - printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname); - return 0; -#endif - - /* - The 'setup()' procedure in 'sdlamain.c' passes the CPU number and the - slot number defined in 'router.conf' via the 'port' definition. - */ - CPU_no = hw->S514_cpu_no[0]; - slot_no = hw->S514_slot_no; - auto_slot_cfg = hw->auto_pci_cfg; - - if (auto_slot_cfg){ - printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n", - modname, CPU_no); - - }else{ - printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n", - modname, CPU_no, slot_no); - } - - /* check to see that CPU A or B has been selected in 'router.conf' */ - switch(CPU_no) { - case S514_CPU_A: - case S514_CPU_B: - break; - - default: - printk(KERN_INFO "%s: S514 CPU definition invalid.\n", - modname); - printk(KERN_INFO "Must be 'A' or 'B'\n"); - return 0; - } - - number_S514_cards = find_s514_adapter(hw, 0); - if(!number_S514_cards) - return 0; - - /* we are using a single S514 adapter with a slot of 0 so re-read the */ - /* location of this adapter */ - if((number_S514_cards == 1) && auto_slot_cfg) { - number_S514_cards = find_s514_adapter(hw, 1); - if(!number_S514_cards) { - printk(KERN_INFO "%s: Error finding PCI card\n", - modname); - return 0; - } - } - - pci_dev = hw->pci_dev; - /* read the physical memory base address */ - S514_mem_base_addr = (CPU_no == S514_CPU_A) ? - (pci_dev->resource[1].start) : - (pci_dev->resource[2].start); - - printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n", - modname, S514_mem_base_addr); - if(!S514_mem_base_addr) { - if(CPU_no == S514_CPU_B) - printk(KERN_INFO "%s: CPU #B not present on the card\n", modname); - else - printk(KERN_INFO "%s: No PCI memory allocated to card\n", modname); - return 0; - } - - /* enable the PCI memory */ - pci_read_config_dword(pci_dev, - (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, - &ut_u32); - pci_write_config_dword(pci_dev, - (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, - (ut_u32 | PCI_MEMORY_ENABLE)); - - /* check the IRQ allocated and enable IRQ usage */ - if(!(hw->irq = pci_dev->irq)) { - printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n", - modname); - return 0; - } - - /* BUG FIX : Mar 6 2000 - * On a initial loading of the card, we must check - * and clear PCI interrupt bits, due to a reset - * problem on some other boards. i.e. An interrupt - * might be pending, even after system bootup, - * in which case, when starting wanrouter the machine - * would crash. - */ - if (init_pci_slot(hw)) - return 0; - - pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32); - ut_u32 |= (CPU_no == S514_CPU_A) ? - PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; - pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32); - - printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n", - modname, hw->irq); - - /* map the physical PCI memory to virtual memory */ - hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr, - (unsigned long)MAX_SIZEOF_S514_MEMORY); - /* map the physical control register memory to virtual memory */ - hw->vector = (unsigned long)ioremap( - (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE), - (unsigned long)16); - - if(!hw->dpmbase || !hw->vector) { - printk(KERN_INFO "%s: PCI virtual memory allocation failed\n", - modname); - return 0; - } - - /* halt the adapter */ - writeb (S514_CPU_HALT, hw->vector); - - return 1; -} - -/*============================================================================ - * Find the S514 PCI adapter in the PCI bus. - * Return the number of S514 adapters found (0 if no adapter found). - */ -static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card) -{ - unsigned char slot_no; - int number_S514_cards = 0; - char S514_found_in_slot = 0; - u16 PCI_subsys_vendor; - - struct pci_dev *pci_dev = NULL; - - slot_no = hw->S514_slot_no; - - while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) - != NULL) { - - pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, - &PCI_subsys_vendor); - - if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) - continue; - - hw->pci_dev = pci_dev; - - if(find_first_S514_card) - return(1); - - number_S514_cards ++; - - printk(KERN_INFO - "%s: S514 card found, slot #%d (devfn 0x%X)\n", - modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), - pci_dev->devfn); - - if (hw->auto_pci_cfg){ - hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK); - slot_no = hw->S514_slot_no; - - }else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){ - S514_found_in_slot = 1; - break; - } - } - - /* if no S514 adapter has been found, then exit */ - if (!number_S514_cards) { - printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname); - return 0; - } - /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */ - else if ((number_S514_cards > 1) && hw->auto_pci_cfg) { - printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n" - "%s: More than one S514 adapter found.\n" - "%s: Disable the Autodetect feature and supply\n" - "%s: the PCISLOT numbers for each card.\n", - modname,modname,modname,modname); - return 0; - } - /* if the user has specified a slot number and the S514 adapter has */ - /* not been found in that slot, then exit */ - else if (!hw->auto_pci_cfg && !S514_found_in_slot) { - printk(KERN_INFO - "%s: Error, S514 card not found in specified slot #%d\n", - modname, slot_no); - return 0; - } - - return (number_S514_cards); -} - - - -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * Calibrate SDLA memory access delay. - * Count number of idle loops made within 1 second and then calculate the - * number of loops that should be made to achive desired delay. - */ -static int calibrate_delay (int mks) -{ - unsigned int delay; - unsigned long stop; - - for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay); - return (delay/(1000000L/mks) + 1); -} - -/*============================================================================ - * Get option's index into the options list. - * Return option's index (1 .. N) or zero if option is invalid. - */ -static int get_option_index (unsigned* optlist, unsigned optval) -{ - int i; - - for (i = 1; i <= optlist[0]; ++i) - if ( optlist[i] == optval) - return i; - return 0; -} - -/*============================================================================ - * Check memory region to see if it's available. - * Return: 0 ok. - */ -static unsigned check_memregion (void* ptr, unsigned len) -{ - volatile unsigned char* p = ptr; - - for (; len && (readb (p) == 0xFF); --len, ++p) { - writeb (0, p); /* attempt to write 0 */ - if (readb(p) != 0xFF) { /* still has to read 0xFF */ - writeb (0xFF, p);/* restore original value */ - break; /* not good */ - } - } - - return len; -} - -/*============================================================================ - * Test memory region. - * Return: size of the region that passed the test. - * Note: Region size must be multiple of 2 ! - */ -static unsigned test_memregion (void* ptr, unsigned len) -{ - volatile unsigned short* w_ptr; - unsigned len_w = len >> 1; /* region len in words */ - unsigned i; - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - writew (0xAA55, w_ptr); - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (readw (w_ptr) != 0xAA55) { - len_w = i; - break; - } - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - writew (0x55AA, w_ptr); - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (readw(w_ptr) != 0x55AA) { - len_w = i; - break; - } - - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - writew (0, w_ptr); - - return len_w << 1; -} - -/*============================================================================ - * Calculate 16-bit CRC using CCITT polynomial. - */ -static unsigned short checksum (unsigned char* buf, unsigned len) -{ - unsigned short crc = 0; - unsigned mask, flag; - - for (; len; --len, ++buf) { - for (mask = 0x80; mask; mask >>= 1) { - flag = (crc & 0x8000); - crc <<= 1; - crc |= ((*buf & mask) ? 1 : 0); - if (flag) crc ^= 0x1021; - } - } - return crc; -} - -static int init_pci_slot(sdlahw_t *hw) -{ - - u32 int_status; - int volatile found=0; - int i=0; - - /* Check if this is a very first load for a specific - * pci card. If it is, clear the interrput bits, and - * set the flag indicating that this card was initialized. - */ - - for (i=0; (iS514_slot_no){ - found=1; - break; - } - if (pci_slot_ar[i] == 0xFF){ - break; - } - } - - if (!found){ - read_S514_int_stat(hw,&int_status); - S514_intack(hw,int_status); - if (i == MAX_S514_CARDS){ - printk(KERN_INFO "%s: Critical Error !!!\n",modname); - printk(KERN_INFO - "%s: Number of Sangoma PCI cards exceeded maximum limit.\n", - modname); - printk(KERN_INFO "Please contact Sangoma Technologies\n"); - return 1; - } - pci_slot_ar[i] = hw->S514_slot_no; - } - return 0; -} - -static int pci_probe(sdlahw_t *hw) -{ - - unsigned char slot_no; - int number_S514_cards = 0; - u16 PCI_subsys_vendor; - u16 PCI_card_type; - - struct pci_dev *pci_dev = NULL; - struct pci_bus *bus = NULL; - - slot_no = 0; - - while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) - != NULL) { - - pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, - &PCI_subsys_vendor); - - if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) - continue; - - pci_read_config_word(pci_dev, PCI_CARD_TYPE, - &PCI_card_type); - - bus = pci_dev->bus; - - /* A dual cpu card can support up to 4 physical connections, - * where a single cpu card can support up to 2 physical - * connections. The FT1 card can only support a single - * connection, however we cannot distinguish between a Single - * CPU card and an FT1 card. */ - if (PCI_card_type == S514_DUAL_CPU){ - number_S514_cards += 4; - printk(KERN_INFO - "wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n", - bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), - pci_dev->irq); - }else{ - number_S514_cards += 2; - printk(KERN_INFO - "wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n", - bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), - pci_dev->irq); - } - } - - return number_S514_cards; - -} - - - -EXPORT_SYMBOL(wanpipe_hw_probe); - -unsigned wanpipe_hw_probe(void) -{ - sdlahw_t hw; - unsigned* opt = s508_port_options; - unsigned cardno=0; - int i; - - memset(&hw, 0, sizeof(hw)); - - for (i = 1; i <= opt[0]; i++) { - if (detect_s508(opt[i])){ - /* S508 card can support up to two physical links */ - cardno+=2; - printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]); - } - } - - #ifdef CONFIG_PCI - hw.S514_slot_no = 0; - cardno += pci_probe(&hw); - #else - printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n"); - printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n"); - #endif - - return cardno; -} - -/****** End *****************************************************************/ diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c deleted file mode 100644 index 7a8b22a7ea31..000000000000 --- a/drivers/net/wan/sdlamain.c +++ /dev/null @@ -1,1346 +0,0 @@ -/**************************************************************************** -* sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. -* -* Author: Nenad Corbic -* Gideon Hack -* -* Copyright: (c) 1995-2000 Sangoma Technologies Inc. -* -* 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. -* ============================================================================ -* Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels. -* Removed the polling routine. -* Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic -* device allocation. -* Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels -* 2.2.16 and above. -* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on -* kernels 2.2.16 or greater. The SyncPPP -* has changed. -* Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP. -* Jul 13, 2000 Nenad Corbic Added Multi-PPP support. -* Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection. -* Sep 23, 1999 Nenad Corbic Added support for SMP -* Sep 13, 1999 Nenad Corbic Each port is treated as a separate device. -* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. -* Updates for Linux 2.2.X kernels. -* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel -* Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 -* Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); -* Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 -* Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr -* assignments are taken out and placed in the -* sdla_ppp.c, sdla_fr.c and sdla_x25.c isr -* routines. Took out 'wandev->tx_int_enabled' and -* replaced it with 'wandev->enable_tx_int'. -* May 29, 1997 Jaspreet Singh Flow Control Problem -* added "wandev->tx_int_enabled=1" line in the -* init module. This line initializes the flag for -* preventing Interrupt disabled with device set to -* busy -* Jan 15, 1997 Gene Kozin Version 3.1.0 -* o added UDP management stuff -* Jan 02, 1997 Gene Kozin Initial version. -*****************************************************************************/ - -#include /* OS configuration options */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include -#include /* kmalloc(), kfree() */ -#include /* printk(), and other useful stuff */ -#include /* support for loadable modules */ -#include /* request_region(), release_region() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include - -#include -#include /* phys_to_virt() */ -#include -#include -#include - -#include /* kernel <-> user copy */ -#include - -#include -#include - -#define KMEM_SAFETYZONE 8 - - -#ifndef CONFIG_WANPIPE_FR - #define wpf_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_CHDLC - #define wpc_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_X25 - #define wpx_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_PPP - #define wpp_init(a,b) (-EPROTONOSUPPORT) -#endif - -#ifndef CONFIG_WANPIPE_MULTPPP - #define wsppp_init(a,b) (-EPROTONOSUPPORT) -#endif - - -/***********FOR DEBUGGING PURPOSES********************************************* -static void * dbg_kmalloc(unsigned int size, int prio, int line) { - int i = 0; - void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); - char * c1 = v; - c1 += sizeof(unsigned int); - *((unsigned int *)v) = size; - - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; - c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; - c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; - c1 += 8; - } - v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; - printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); - return v; -} -static void dbg_kfree(void * v, int line) { - unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); - unsigned int size = *sp; - char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; - int i = 0; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' - || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { - printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - c1 += size; - for (i = 0; i < KMEM_SAFETYZONE; i++) { - if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' - || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' - ) { - printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); - printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, - c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); - } - c1 += 8; - } - printk(KERN_INFO "line %d kfree(%p)\n",line,v); - v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); - kfree(v); -} - -#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__) -#define kfree(x) dbg_kfree(x,__LINE__) -******************************************************************************/ - - - -/****** Defines & Macros ****************************************************/ - -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - -#define DRV_VERSION 5 /* version number */ -#define DRV_RELEASE 0 /* release (minor version) number */ -#define MAX_CARDS 16 /* max number of adapters */ - -#ifndef CONFIG_WANPIPE_CARDS /* configurable option */ -#define CONFIG_WANPIPE_CARDS 1 -#endif - -#define CMD_OK 0 /* normal firmware return code */ -#define CMD_TIMEOUT 0xFF /* firmware command timed out */ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -/****** Function Prototypes *************************************************/ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/* WAN link driver entry points */ -static int setup(struct wan_device* wandev, wandev_conf_t* conf); -static int shutdown(struct wan_device* wandev); -static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg); - -/* IOCTL handlers */ -static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int); - -/* Miscellaneous functions */ -STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs); -static void release_hw (sdla_t *card); - -static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*); -static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*); - - -/****** Global Data ********************************************************** - * Note: All data must be explicitly initialized!!! - */ - -/* private data */ -static char drvname[] = "wanpipe"; -static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; -static int ncards; -static sdla_t* card_array; /* adapter data space */ - -/* Wanpipe's own workqueue, used for all API's. - * All protocol specific tasks will be inserted - * into the "wanpipe_wq" workqueue. - - * The kernel workqueue mechanism will execute - * all pending tasks in the "wanpipe_wq" workqueue. - */ - -struct workqueue_struct *wanpipe_wq; -DECLARE_WORK(wanpipe_work, NULL, NULL); - -static int wanpipe_bh_critical; - -/******* Kernel Loadable Module Entry Points ********************************/ - -/*============================================================================ - * Module 'insert' entry point. - * o print announcement - * o allocate adapter data space - * o initialize static data - * o register all cards with WAN router - * o calibrate SDLA shared memory access delay. - * - * Return: 0 Ok - * < 0 error. - * Context: process - */ - -static int __init wanpipe_init(void) -{ - int cnt, err = 0; - - printk(KERN_INFO "%s v%u.%u %s\n", - fullname, DRV_VERSION, DRV_RELEASE, copyright); - - wanpipe_wq = create_workqueue("wanpipe_wq"); - if (!wanpipe_wq) - return -ENOMEM; - - /* Probe for wanpipe cards and return the number found */ - printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n"); - ncards = wanpipe_hw_probe(); - if (ncards){ - printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards); - }else{ - printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n"); - destroy_workqueue(wanpipe_wq); - return -ENODEV; - } - - /* Verify number of cards and allocate adapter data space */ - card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); - if (card_array == NULL) { - destroy_workqueue(wanpipe_wq); - return -ENOMEM; - } - - memset(card_array, 0, sizeof(sdla_t) * ncards); - - /* Register adapters with WAN router */ - for (cnt = 0; cnt < ncards; ++ cnt) { - sdla_t* card = &card_array[cnt]; - struct wan_device* wandev = &card->wandev; - - card->next = NULL; - sprintf(card->devname, "%s%d", drvname, cnt + 1); - wandev->magic = ROUTER_MAGIC; - wandev->name = card->devname; - wandev->private = card; - wandev->enable_tx_int = 0; - wandev->setup = &setup; - wandev->shutdown = &shutdown; - wandev->ioctl = &ioctl; - err = register_wan_device(wandev); - if (err) { - printk(KERN_INFO - "%s: %s registration failed with error %d!\n", - drvname, card->devname, err); - break; - } - } - if (cnt){ - ncards = cnt; /* adjust actual number of cards */ - }else { - kfree(card_array); - destroy_workqueue(wanpipe_wq); - printk(KERN_INFO "IN Init Module: NO Cards registered\n"); - err = -ENODEV; - } - - return err; -} - -/*============================================================================ - * Module 'remove' entry point. - * o unregister all adapters from the WAN router - * o release all remaining system resources - */ -static void __exit wanpipe_cleanup(void) -{ - int i; - - if (!ncards) - return; - - for (i = 0; i < ncards; ++i) { - sdla_t* card = &card_array[i]; - unregister_wan_device(card->devname); - } - destroy_workqueue(wanpipe_wq); - kfree(card_array); - - printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n"); -} - -module_init(wanpipe_init); -module_exit(wanpipe_cleanup); - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Setup/configure WAN link driver. - * o check adapter state - * o make sure firmware is present in configuration - * o make sure I/O port and IRQ are specified - * o make sure I/O region is available - * o allocate interrupt vector - * o setup SDLA hardware - * o call appropriate routine to perform protocol-specific initialization - * o mark I/O region as used - * o if this is the first active card, then schedule background task - * - * This function is called when router handles ROUTER_SETUP IOCTL. The - * configuration structure is in kernel memory (including extended data, if - * any). - */ - -static int setup(struct wan_device* wandev, wandev_conf_t* conf) -{ - sdla_t* card; - int err = 0; - int irq=0; - - /* Sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){ - printk(KERN_INFO - "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n", - wandev->name, - (unsigned int)wandev,(unsigned int)wandev->private, - (unsigned int)conf); - return -EFAULT; - } - - printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name); - - card = wandev->private; - if (wandev->state != WAN_UNCONFIGURED){ - printk(KERN_INFO "%s: failed sdlamain setup, busy!\n", - wandev->name); - return -EBUSY; /* already configured */ - } - - printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name); - - /* Initialize the counters for each wandev - * Used for counting number of times new_if and - * del_if get called. - */ - wandev->del_if_cnt = 0; - wandev->new_if_cnt = 0; - wandev->config_id = conf->config_id; - - if (!conf->data_size || (conf->data == NULL)) { - printk(KERN_INFO - "%s: firmware not found in configuration data!\n", - wandev->name); - return -EINVAL; - } - - /* Check for resource conflicts and setup the - * card for piggibacking if necessary */ - if(!conf->S514_CPU_no[0]) { - if ((err=check_s508_conflicts(card,conf,&irq)) != 0){ - return err; - } - }else { - if ((err=check_s514_conflicts(card,conf,&irq)) != 0){ - return err; - } - } - - /* If the current card has already been configured - * or it's a piggyback card, do not try to allocate - * resources. - */ - if (!card->wandev.piggyback && !card->configured){ - - /* Configure hardware, load firmware, etc. */ - memset(&card->hw, 0, sizeof(sdlahw_t)); - - /* for an S514 adapter, pass the CPU number and the slot number read */ - /* from 'router.conf' to the 'sdla_setup()' function via the 'port' */ - /* parameter */ - if (conf->S514_CPU_no[0]){ - - card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0]; - card->hw.S514_slot_no = conf->PCI_slot_no; - card->hw.auto_pci_cfg = conf->auto_pci_cfg; - - if (card->hw.auto_pci_cfg == WANOPT_YES){ - printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n", - card->devname, card->hw.S514_cpu_no[0]); - }else{ - printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n", - card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no); - } - - }else{ - /* 508 Card io port and irq initialization */ - card->hw.port = conf->ioport; - card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; - } - - - /* Compute the virtual address of the card in kernel space */ - if(conf->maddr){ - card->hw.dpmbase = phys_to_virt(conf->maddr); - }else{ - card->hw.dpmbase = (void *)conf->maddr; - } - - card->hw.dpmsize = SDLA_WINDOWSIZE; - - /* set the adapter type if using an S514 adapter */ - card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; - card->hw.pclk = conf->hw_opt[1]; - - err = sdla_setup(&card->hw, conf->data, conf->data_size); - if (err){ - printk(KERN_INFO "%s: Hardware setup Failed %i\n", - card->devname,err); - return err; - } - - if(card->hw.type != SDLA_S514) - irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ - else - irq = card->hw.irq; - - /* request an interrupt vector - note that interrupts may be shared */ - /* when using the S514 PCI adapter */ - - if(request_irq(irq, sdla_isr, - (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, - wandev->name, card)){ - - printk(KERN_INFO "%s: Can't reserve IRQ %d!\n", wandev->name, irq); - return -EINVAL; - } - - }else{ - printk(KERN_INFO "%s: Card Configured %lu or Piggybacking %i!\n", - wandev->name,card->configured,card->wandev.piggyback); - } - - - if (!card->configured){ - - /* Initialize the Spin lock */ - printk(KERN_INFO "%s: Initializing for SMP\n",wandev->name); - - /* Piggyback spin lock has already been initialized, - * in check_s514/s508_conflicts() */ - if (!card->wandev.piggyback){ - spin_lock_init(&card->wandev.lock); - } - - /* Intialize WAN device data space */ - wandev->irq = irq; - wandev->dma = 0; - if(card->hw.type != SDLA_S514){ - wandev->ioport = card->hw.port; - }else{ - wandev->S514_cpu_no[0] = card->hw.S514_cpu_no[0]; - wandev->S514_slot_no = card->hw.S514_slot_no; - } - wandev->maddr = (unsigned long)card->hw.dpmbase; - wandev->msize = card->hw.dpmsize; - wandev->hw_opt[0] = card->hw.type; - wandev->hw_opt[1] = card->hw.pclk; - wandev->hw_opt[2] = card->hw.memory; - wandev->hw_opt[3] = card->hw.fwid; - } - - /* Protocol-specific initialization */ - switch (card->hw.fwid) { - - case SFID_X25_502: - case SFID_X25_508: - printk(KERN_INFO "%s: Starting X.25 Protocol Init.\n", - card->devname); - err = wpx_init(card, conf); - break; - case SFID_FR502: - case SFID_FR508: - printk(KERN_INFO "%s: Starting Frame Relay Protocol Init.\n", - card->devname); - err = wpf_init(card, conf); - break; - case SFID_PPP502: - case SFID_PPP508: - printk(KERN_INFO "%s: Starting PPP Protocol Init.\n", - card->devname); - err = wpp_init(card, conf); - break; - - case SFID_CHDLC508: - case SFID_CHDLC514: - if (conf->ft1){ - printk(KERN_INFO "%s: Starting FT1 CSU/DSU Config Driver.\n", - card->devname); - err = wpft1_init(card, conf); - break; - - }else if (conf->config_id == WANCONFIG_MPPP){ - printk(KERN_INFO "%s: Starting Multi-Port PPP Protocol Init.\n", - card->devname); - err = wsppp_init(card,conf); - break; - - }else{ - printk(KERN_INFO "%s: Starting CHDLC Protocol Init.\n", - card->devname); - err = wpc_init(card, conf); - break; - } - default: - printk(KERN_INFO "%s: Error, Firmware is not supported %X %X!\n", - wandev->name,card->hw.fwid,SFID_CHDLC508); - err = -EPROTONOSUPPORT; - } - - if (err != 0){ - if (err == -EPROTONOSUPPORT){ - printk(KERN_INFO - "%s: Error, Protocol selected has not been compiled!\n", - card->devname); - printk(KERN_INFO - "%s: Re-configure the kernel and re-build the modules!\n", - card->devname); - } - - release_hw(card); - wandev->state = WAN_UNCONFIGURED; - return err; - } - - - /* Reserve I/O region and schedule background task */ - if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) - if (!request_region(card->hw.port, card->hw.io_range, - wandev->name)) { - printk(KERN_WARNING "port 0x%04x busy\n", card->hw.port); - release_hw(card); - wandev->state = WAN_UNCONFIGURED; - return -EBUSY; - } - - /* Only use the polling routine for the X25 protocol */ - - card->wandev.critical=0; - return 0; -} - -/*================================================================== - * configure_s508_card - * - * For a S508 adapter, check for a possible configuration error in that - * we are loading an adapter in the same IO port as a previously loaded S508 - * card. - */ - -static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int *irq) -{ - unsigned long smp_flags; - int i; - - if (conf->ioport <= 0) { - printk(KERN_INFO - "%s: can't configure without I/O port address!\n", - card->wandev.name); - return -EINVAL; - } - - if (conf->irq <= 0) { - printk(KERN_INFO "%s: can't configure without IRQ!\n", - card->wandev.name); - return -EINVAL; - } - - if (test_bit(0,&card->configured)) - return 0; - - - /* Check for already loaded card with the same IO port and IRQ - * If found, copy its hardware configuration and use its - * resources (i.e. piggybacking) - */ - - for (i = 0; i < ncards; i++) { - sdla_t *nxt_card = &card_array[i]; - - /* Skip the current card ptr */ - if (nxt_card == card) - continue; - - - /* Find a card that is already configured with the - * same IO Port */ - if ((nxt_card->hw.type == SDLA_S508) && - (nxt_card->hw.port == conf->ioport) && - (nxt_card->next == NULL)){ - - /* We found a card the card that has same configuration - * as us. This means, that we must setup this card in - * piggibacking mode. However, only CHDLC and MPPP protocol - * support this setup */ - - if ((conf->config_id == WANCONFIG_CHDLC || - conf->config_id == WANCONFIG_MPPP) && - (nxt_card->wandev.config_id == WANCONFIG_CHDLC || - nxt_card->wandev.config_id == WANCONFIG_MPPP)){ - - *irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - - /* The master could already be running, we must - * set this as a critical area */ - lock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); - - nxt_card->next = card; - card->next = nxt_card; - - card->wandev.piggyback = WANOPT_YES; - - /* We must initialise the piggiback spin lock here - * since isr will try to lock card->next if it - * exists */ - spin_lock_init(&card->wandev.lock); - - unlock_adapter_irq(&nxt_card->wandev.lock, &smp_flags); - break; - }else{ - /* Trying to run piggibacking with a wrong protocol */ - printk(KERN_INFO "%s: ERROR: Resource busy, ioport: 0x%x\n" - "%s: This protocol doesn't support\n" - "%s: multi-port operation!\n", - card->devname,nxt_card->hw.port, - card->devname,card->devname); - return -EEXIST; - } - } - } - - - /* Make sure I/O port region is available only if we are the - * master device. If we are running in piggybacking mode, - * we will use the resources of the master card. */ - if (!card->wandev.piggyback) { - struct resource *rr = - request_region(conf->ioport, SDLA_MAXIORANGE, "sdlamain"); - release_region(conf->ioport, SDLA_MAXIORANGE); - - if (!rr) { - printk(KERN_INFO - "%s: I/O region 0x%X - 0x%X is in use!\n", - card->wandev.name, conf->ioport, - conf->ioport + SDLA_MAXIORANGE - 1); - return -EINVAL; - } - } - - return 0; -} - -/*================================================================== - * configure_s514_card - * - * For a S514 adapter, check for a possible configuration error in that - * we are loading an adapter in the same slot as a previously loaded S514 - * card. - */ - - -static int check_s514_conflicts(sdla_t* card,wandev_conf_t* conf, int *irq) -{ - unsigned long smp_flags; - int i; - - if (test_bit(0,&card->configured)) - return 0; - - - /* Check for already loaded card with the same IO port and IRQ - * If found, copy its hardware configuration and use its - * resources (i.e. piggybacking) - */ - - for (i = 0; i < ncards; i ++) { - - sdla_t* nxt_card = &card_array[i]; - if(nxt_card == card) - continue; - - if((nxt_card->hw.type == SDLA_S514) && - (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && - (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& - (nxt_card->next == NULL)){ - - - if ((conf->config_id == WANCONFIG_CHDLC || - conf->config_id == WANCONFIG_MPPP) && - (nxt_card->wandev.config_id == WANCONFIG_CHDLC || - nxt_card->wandev.config_id == WANCONFIG_MPPP)){ - - *irq = nxt_card->hw.irq; - memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); - - /* The master could already be running, we must - * set this as a critical area */ - lock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); - nxt_card->next = card; - card->next = nxt_card; - - card->wandev.piggyback = WANOPT_YES; - - /* We must initialise the piggiback spin lock here - * since isr will try to lock card->next if it - * exists */ - spin_lock_init(&card->wandev.lock); - - unlock_adapter_irq(&nxt_card->wandev.lock,&smp_flags); - - }else{ - /* Trying to run piggibacking with a wrong protocol */ - printk(KERN_INFO "%s: ERROR: Resource busy: CPU %c PCISLOT %i\n" - "%s: This protocol doesn't support\n" - "%s: multi-port operation!\n", - card->devname, - conf->S514_CPU_no[0],conf->PCI_slot_no, - card->devname,card->devname); - return -EEXIST; - } - } - } - - return 0; -} - - - -/*============================================================================ - * Shut down WAN link driver. - * o shut down adapter hardware - * o release system resources. - * - * This function is called by the router when device is being unregistered or - * when it handles ROUTER_DOWN IOCTL. - */ -static int shutdown(struct wan_device* wandev) -{ - sdla_t *card; - int err=0; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)){ - return -EFAULT; - } - - if (wandev->state == WAN_UNCONFIGURED){ - return 0; - } - - card = wandev->private; - - if (card->tty_opt){ - if (card->tty_open){ - printk(KERN_INFO - "%s: Shutdown Failed: TTY is still open\n", - card->devname); - return -EBUSY; - } - } - - wandev->state = WAN_UNCONFIGURED; - - set_bit(PERI_CRIT,(void*)&wandev->critical); - - /* In case of piggibacking, make sure that - * we never try to shutdown both devices at the same - * time, because they depend on one another */ - - if (card->disable_comm){ - card->disable_comm(card); - } - - /* Release Resources */ - release_hw(card); - - /* only free the allocated I/O range if not an S514 adapter */ - if (wandev->hw_opt[0] != SDLA_S514 && !card->configured){ - release_region(card->hw.port, card->hw.io_range); - } - - if (!card->configured){ - memset(&card->hw, 0, sizeof(sdlahw_t)); - if (card->next){ - memset(&card->next->hw, 0, sizeof(sdlahw_t)); - } - } - - - clear_bit(PERI_CRIT,(void*)&wandev->critical); - return err; -} - -static void release_hw (sdla_t *card) -{ - sdla_t *nxt_card; - - - /* Check if next device exists */ - if (card->next){ - nxt_card = card->next; - /* If next device is down then release resources */ - if (nxt_card->wandev.state == WAN_UNCONFIGURED){ - if (card->wandev.piggyback){ - /* If this device is piggyback then use - * information of the master device - */ - printk(KERN_INFO "%s: Piggyback shutting down\n",card->devname); - sdla_down(&card->next->hw); - free_irq(card->wandev.irq, card->next); - card->configured = 0; - card->next->configured = 0; - card->wandev.piggyback = 0; - }else{ - /* Master device shutting down */ - printk(KERN_INFO "%s: Master shutting down\n",card->devname); - sdla_down(&card->hw); - free_irq(card->wandev.irq, card); - card->configured = 0; - card->next->configured = 0; - } - }else{ - printk(KERN_INFO "%s: Device still running %i\n", - nxt_card->devname,nxt_card->wandev.state); - - card->configured = 1; - } - }else{ - printk(KERN_INFO "%s: Master shutting down\n",card->devname); - sdla_down(&card->hw); - free_irq(card->wandev.irq, card); - card->configured = 0; - } - return; -} - - -/*============================================================================ - * Driver I/O control. - * o verify arguments - * o perform requested action - * - * This function is called when router handles one of the reserved user - * IOCTLs. Note that 'arg' stil points to user address space. - */ -static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg) -{ - sdla_t* card; - int err; - - /* sanity checks */ - if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - card = wandev->private; - - if(card->hw.type != SDLA_S514){ - disable_irq(card->hw.irq); - } - - if (test_bit(SEND_CRIT, (void*)&wandev->critical)) { - return -EAGAIN; - } - - switch (cmd) { - case WANPIPE_DUMP: - err = ioctl_dump(wandev->private, (void*)arg); - break; - - case WANPIPE_EXEC: - err = ioctl_exec(wandev->private, (void*)arg, cmd); - break; - default: - err = -EINVAL; - } - - return err; -} - -/****** Driver IOCTL Handlers ***********************************************/ - -/*============================================================================ - * Dump adapter memory to user buffer. - * o verify request structure - * o copy request structure to kernel data space - * o verify length/offset - * o verify user buffer - * o copy adapter memory image to user buffer - * - * Note: when dumping memory, this routine switches curent dual-port memory - * vector, so care must be taken to avoid racing conditions. - */ -static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) -{ - sdla_dump_t dump; - unsigned winsize; - unsigned long oldvec; /* DPM window vector */ - unsigned long smp_flags; - int err = 0; - - if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) - return -EFAULT; - - if ((dump.magic != WANPIPE_MAGIC) || - (dump.offset + dump.length > card->hw.memory)) - return -EINVAL; - - winsize = card->hw.dpmsize; - - if(card->hw.type != SDLA_S514) { - - lock_adapter_irq(&card->wandev.lock, &smp_flags); - - oldvec = card->hw.vector; - while (dump.length) { - /* current offset */ - unsigned pos = dump.offset % winsize; - /* current vector */ - unsigned long vec = dump.offset - pos; - unsigned len = (dump.length > (winsize - pos)) ? - (winsize - pos) : dump.length; - /* relocate window */ - if (sdla_mapmem(&card->hw, vec) != 0) { - err = -EIO; - break; - } - - if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + pos, len)){ - - unlock_adapter_irq(&card->wandev.lock, &smp_flags); - return -EFAULT; - } - - dump.length -= len; - dump.offset += len; - dump.ptr = (char*)dump.ptr + len; - } - - sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ - unlock_adapter_irq(&card->wandev.lock, &smp_flags); - - }else { - - if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + dump.offset, dump.length)){ - return -EFAULT; - } - } - - return err; -} - -/*============================================================================ - * Execute adapter firmware command. - * o verify request structure - * o copy request structure to kernel data space - * o call protocol-specific 'exec' function - */ -static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int cmd) -{ - sdla_exec_t exec; - int err=0; - - if (card->exec == NULL && cmd == WANPIPE_EXEC){ - return -ENODEV; - } - - if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) - return -EFAULT; - - if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) - return -EINVAL; - - switch (cmd) { - case WANPIPE_EXEC: - err = card->exec(card, exec.cmd, exec.data); - break; - } - return err; -} - -/******* Miscellaneous ******************************************************/ - -/*============================================================================ - * SDLA Interrupt Service Routine. - * o acknowledge SDLA hardware interrupt. - * o call protocol-specific interrupt service routine, if any. - */ -STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs) -{ -#define card ((sdla_t*)dev_id) - - if(card->hw.type == SDLA_S514) { /* handle interrrupt on S514 */ - u32 int_status; - unsigned char CPU_no = card->hw.S514_cpu_no[0]; - unsigned char card_found_for_IRQ; - u8 IRQ_count = 0; - - for(;;) { - - read_S514_int_stat(&card->hw, &int_status); - - /* check if the interrupt is for this device */ - if(!((unsigned char)int_status & - (IRQ_CPU_A | IRQ_CPU_B))) - return IRQ_HANDLED; - - /* if the IRQ is for both CPUs on the same adapter, */ - /* then alter the interrupt status so as to handle */ - /* one CPU at a time */ - if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B)) - == (IRQ_CPU_A | IRQ_CPU_B)) { - int_status &= (CPU_no == S514_CPU_A) ? - ~IRQ_CPU_B : ~IRQ_CPU_A; - } - - card_found_for_IRQ = 0; - - /* check to see that the CPU number for this device */ - /* corresponds to the interrupt status read */ - switch (CPU_no) { - case S514_CPU_A: - if((unsigned char)int_status & - IRQ_CPU_A) - card_found_for_IRQ = 1; - break; - - case S514_CPU_B: - if((unsigned char)int_status & - IRQ_CPU_B) - card_found_for_IRQ = 1; - break; - } - - /* exit if the interrupt is for another CPU on the */ - /* same IRQ */ - if(!card_found_for_IRQ) - return IRQ_HANDLED; - - if (!card || - (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){ - printk(KERN_INFO - "Received IRQ %d for CPU #%c\n", - irq, CPU_no); - printk(KERN_INFO - "IRQ for unconfigured adapter\n"); - S514_intack(&card->hw, int_status); - return IRQ_HANDLED; - } - - if (card->in_isr) { - printk(KERN_INFO - "%s: interrupt re-entrancy on IRQ %d\n", - card->devname, card->wandev.irq); - S514_intack(&card->hw, int_status); - return IRQ_HANDLED; - } - - spin_lock(&card->wandev.lock); - if (card->next){ - spin_lock(&card->next->wandev.lock); - } - - S514_intack(&card->hw, int_status); - if (card->isr) - card->isr(card); - - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock(&card->wandev.lock); - - /* handle a maximum of two interrupts (one for each */ - /* CPU on the adapter) before returning */ - if((++ IRQ_count) == 2) - return IRQ_HANDLED; - } - } - - else { /* handle interrupt on S508 adapter */ - - if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured)) - return IRQ_HANDLED; - - if (card->in_isr) { - printk(KERN_INFO - "%s: interrupt re-entrancy on IRQ %d!\n", - card->devname, card->wandev.irq); - return IRQ_HANDLED; - } - - spin_lock(&card->wandev.lock); - if (card->next){ - spin_lock(&card->next->wandev.lock); - } - - sdla_intack(&card->hw); - if (card->isr) - card->isr(card); - - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock(&card->wandev.lock); - - } - return IRQ_HANDLED; -#undef card -} - -/*============================================================================ - * This routine is called by the protocol-specific modules when network - * interface is being open. The only reason we need this, is because we - * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void wanpipe_open (sdla_t* card) -{ - ++card->open_cnt; -} - -/*============================================================================ - * This routine is called by the protocol-specific modules when network - * interface is being closed. The only reason we need this, is because we - * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's - * defined more than once into the same kernel module. - */ -void wanpipe_close (sdla_t* card) -{ - --card->open_cnt; -} - -/*============================================================================ - * Set WAN device state. - */ -void wanpipe_set_state (sdla_t* card, int state) -{ - if (card->wandev.state != state) { - switch (state) { - case WAN_CONNECTED: - printk (KERN_INFO "%s: link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: link disconnected!\n", - card->devname); - break; - } - card->wandev.state = state; - } - card->state_tick = jiffies; -} - -sdla_t * wanpipe_find_card (char *name) -{ - int cnt; - for (cnt = 0; cnt < ncards; ++ cnt) { - sdla_t* card = &card_array[cnt]; - if (!strcmp(card->devname,name)) - return card; - } - return NULL; -} - -sdla_t * wanpipe_find_card_num (int num) -{ - if (num < 1 || num > ncards) - return NULL; - num--; - return &card_array[num]; -} - -/* - * @work_pointer: work_struct to be done; - * should already have PREPARE_WORK() or - * INIT_WORK() done on it by caller; - */ -void wanpipe_queue_work (struct work_struct *work_pointer) -{ - if (test_and_set_bit(1, (void*)&wanpipe_bh_critical)) - printk(KERN_INFO "CRITICAL IN QUEUING WORK\n"); - - queue_work(wanpipe_wq, work_pointer); - clear_bit(1,(void*)&wanpipe_bh_critical); -} - -void wakeup_sk_bh(struct net_device *dev) -{ - wanpipe_common_t *chan = dev->priv; - - if (test_bit(0,&chan->common_critical)) - return; - - if (chan->sk && chan->tx_timer){ - chan->tx_timer->expires=jiffies+1; - add_timer(chan->tx_timer); - } -} - -int change_dev_flags(struct net_device *dev, unsigned flags) -{ - struct ifreq if_info; - mm_segment_t fs = get_fs(); - int err; - - memset(&if_info, 0, sizeof(if_info)); - strcpy(if_info.ifr_name, dev->name); - if_info.ifr_flags = flags; - - set_fs(get_ds()); /* get user space block */ - err = devinet_ioctl(SIOCSIFFLAGS, &if_info); - set_fs(fs); - - return err; -} - -unsigned long get_ip_address(struct net_device *dev, int option) -{ - - struct in_ifaddr *ifaddr; - struct in_device *in_dev; - unsigned long addr = 0; - - rcu_read_lock(); - if ((in_dev = __in_dev_get_rcu(dev)) == NULL){ - goto out; - } - - if ((ifaddr = in_dev->ifa_list)== NULL ){ - goto out; - } - - switch (option){ - - case WAN_LOCAL_IP: - addr = ifaddr->ifa_local; - break; - - case WAN_POINTOPOINT_IP: - addr = ifaddr->ifa_address; - break; - - case WAN_NETMASK_IP: - addr = ifaddr->ifa_mask; - break; - - case WAN_BROADCAST_IP: - addr = ifaddr->ifa_broadcast; - break; - default: - break; - } - -out: - rcu_read_unlock(); - return addr; -} - -void add_gateway(sdla_t *card, struct net_device *dev) -{ - mm_segment_t oldfs; - struct rtentry route; - int res; - - memset((char*)&route,0,sizeof(struct rtentry)); - - ((struct sockaddr_in *) - &(route.rt_dst))->sin_addr.s_addr = 0; - ((struct sockaddr_in *) - &(route.rt_dst))->sin_family = AF_INET; - - ((struct sockaddr_in *) - &(route.rt_genmask))->sin_addr.s_addr = 0; - ((struct sockaddr_in *) - &(route.rt_genmask)) ->sin_family = AF_INET; - - - route.rt_flags = 0; - route.rt_dev = dev->name; - - oldfs = get_fs(); - set_fs(get_ds()); - res = ip_rt_ioctl(SIOCADDRT,&route); - set_fs(oldfs); - - if (res == 0){ - printk(KERN_INFO "%s: Gateway added for %s\n", - card->devname,dev->name); - } - - return; -} - -MODULE_LICENSE("GPL"); - -/****** End *********************************************************/ diff --git a/drivers/net/wan/wanpipe_multppp.c b/drivers/net/wan/wanpipe_multppp.c deleted file mode 100644 index 812a1183c502..000000000000 --- a/drivers/net/wan/wanpipe_multppp.c +++ /dev/null @@ -1,2358 +0,0 @@ -/***************************************************************************** -* wanpipe_multppp.c Multi-Port PPP driver module. -* -* Authors: Nenad Corbic -* -* Copyright: (c) 1995-2001 Sangoma Technologies Inc. -* -* 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. -* ============================================================================ -* Dec 15 2000 Updated for 2.4.X kernel -* Nov 15 2000 Fixed the SyncPPP support for kernels 2.2.16 and higher. -* The pppstruct has changed. -* Jul 13 2000 Using the kernel Syncppp module on top of RAW Wanpipe CHDLC -* module. -*****************************************************************************/ - -#include -#include /* printk(), and other useful stuff */ -#include /* offsetof(), etc. */ -#include /* return codes */ -#include /* inline memset(), etc. */ -#include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ -#include /* WANPIPE common user API definitions */ -#include /* ARPHRD_* defines */ -#include /* time_after() macro */ - -#include /* sockaddr_in */ -#include -#include -#include /* htons(), etc. */ -#include -#include - -#include /* CHDLC firmware API definitions */ -#include /* CHDLC (async) API definitions */ - -#include /* Socket Driver common area */ -#include - - -#include -#include - -#include - - -/****** Defines & Macros ****************************************************/ - -#ifdef _DEBUG_ -#define STATIC -#else -#define STATIC static -#endif - -/* reasons for enabling the timer interrupt on the adapter */ -#define TMR_INT_ENABLED_UDP 0x01 -#define TMR_INT_ENABLED_UPDATE 0x02 -#define TMR_INT_ENABLED_CONFIG 0x04 - -#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ -#define CHDLC_HDR_LEN 1 - -#define IFF_POINTTOPOINT 0x10 - -#define CHDLC_API 0x01 - -#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) -#define MAX_BH_BUFF 10 - -#define CRC_LENGTH 2 -#define PPP_HEADER_LEN 4 - -/******Data Structures*****************************************************/ - -/* This structure is placed in the private data area of the device structure. - * The card structure used to occupy the private area but now the following - * structure will incorporate the card structure along with CHDLC specific data - */ - -typedef struct chdlc_private_area -{ - void *if_ptr; /* General Pointer used by SPPP */ - wanpipe_common_t common; - sdla_t *card; - int TracingEnabled; /* For enabling Tracing */ - unsigned long curr_trace_addr; /* Used for Tracing */ - unsigned long start_trace_addr; - unsigned long end_trace_addr; - unsigned long base_addr_trace_buffer; - unsigned long end_addr_trace_buffer; - unsigned short number_trace_elements; - unsigned available_buffer_space; - unsigned long router_start_time; - unsigned char route_status; - unsigned char route_removed; - unsigned long tick_counter; /* For 5s timeout counter */ - unsigned long router_up_time; - u32 IP_address; /* IP addressing */ - u32 IP_netmask; - unsigned char mc; /* Mulitcast support on/off */ - unsigned short udp_pkt_lgth; /* udp packet processing */ - char udp_pkt_src; - char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; - unsigned short timer_int_enabled; - char update_comms_stats; /* updating comms stats */ - - //FIXME: add driver stats as per frame relay! - -} chdlc_private_area_t; - -/* Route Status options */ -#define NO_ROUTE 0x00 -#define ADD_ROUTE 0x01 -#define ROUTE_ADDED 0x02 -#define REMOVE_ROUTE 0x03 - - -/* variable for keeping track of enabling/disabling FT1 monitor status */ -static int rCount = 0; - -/* variable for tracking how many interfaces to open for WANPIPE on the - two ports */ - -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); - -/****** Function Prototypes *************************************************/ -/* WAN link driver entry points. These are called by the WAN router module. */ -static int update(struct wan_device* wandev); -static int new_if(struct wan_device* wandev, struct net_device* dev, - wanif_conf_t* conf); -static int del_if(struct wan_device* wandev, struct net_device* dev); - -/* Network device interface */ -static int if_init(struct net_device* dev); -static int if_open(struct net_device* dev); -static int if_close(struct net_device* dev); -static int if_send(struct sk_buff* skb, struct net_device* dev); -static struct net_device_stats* if_stats(struct net_device* dev); - -static void if_tx_timeout(struct net_device *dev); - -/* CHDLC Firmware interface functions */ -static int chdlc_configure (sdla_t* card, void* data); -static int chdlc_comm_enable (sdla_t* card); -static int chdlc_comm_disable (sdla_t* card); -static int chdlc_read_version (sdla_t* card, char* str); -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); -static int chdlc_send (sdla_t* card, void* data, unsigned len); -static int chdlc_read_comm_err_stats (sdla_t* card); -static int chdlc_read_op_stats (sdla_t* card); -static int config_chdlc (sdla_t *card); - - -/* Miscellaneous CHDLC Functions */ -static int set_chdlc_config (sdla_t* card); -static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev); -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); -static int process_chdlc_exception(sdla_t *card); -static int process_global_exception(sdla_t *card); -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area); -static void port_set_state (sdla_t *card, int); - -/* Interrupt handlers */ -static void wsppp_isr (sdla_t* card); -static void rx_intr (sdla_t* card); -static void timer_intr(sdla_t *); - -/* Miscellaneous functions */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ); -static int intr_test( sdla_t* card); -static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area); -static unsigned short calc_checksum (char *, int); -static void s508_lock (sdla_t *card, unsigned long *smp_flags); -static void s508_unlock (sdla_t *card, unsigned long *smp_flags); -static void send_ppp_term_request(struct net_device *dev); - - -static int Intr_test_counter; -/****** Public Functions ****************************************************/ - -/*============================================================================ - * Cisco HDLC protocol initialization routine. - * - * This routine is called by the main WANPIPE module during setup. At this - * point adapter is completely initialized and firmware is running. - * o read firmware version (to make sure it's alive) - * o configure adapter - * o initialize protocol-specific fields of the adapter data space. - * - * Return: 0 o.k. - * < 0 failure. - */ -int wsppp_init (sdla_t* card, wandev_conf_t* conf) -{ - unsigned char port_num; - int err; - unsigned long max_permitted_baud = 0; - SHARED_MEMORY_INFO_STRUCT *flags; - - union - { - char str[80]; - } u; - volatile CHDLC_MAILBOX_STRUCT* mb; - CHDLC_MAILBOX_STRUCT* mb1; - unsigned long timeout; - - /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_MPPP) { - printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); - return -EINVAL; - } - - /* Find out which Port to use */ - if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ - if (card->next){ - - if (conf->comm_port != card->next->u.c.comm_port){ - card->u.c.comm_port = conf->comm_port; - }else{ - printk(KERN_ERR "%s: ERROR - %s port used!\n", - card->wandev.name, PORT(conf->comm_port)); - return -EINVAL; - } - }else{ - card->u.c.comm_port = conf->comm_port; - } - }else{ - printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", - card->wandev.name); - return -EINVAL; - } - - - /* Initialize protocol-specific fields */ - if(card->hw.type != SDLA_S514){ - - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase; - }else{ - card->mbox = (void *) card->hw.dpmbase + - SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; - } - }else{ - /* for a S514 adapter, set a pointer to the actual mailbox in the */ - /* allocated virtual memory area */ - if (card->u.c.comm_port == WANOPT_PRI){ - card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; - }else{ - card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; - } - } - - mb = mb1 = card->mbox; - - if (!card->configured){ - - /* The board will place an 'I' in the return code to indicate that it is - ready to accept commands. We expect this to be completed in less - than 1 second. */ - - timeout = jiffies + 1 * HZ; - while (mb->return_code != 'I') /* Wait 1s for board to initialize */ - if (time_after(jiffies, timeout)) break; - - if (mb->return_code != 'I') { - printk(KERN_INFO - "%s: Initialization not completed by adapter\n", - card->devname); - printk(KERN_INFO "Please contact Sangoma representative.\n"); - return -EIO; - } - } - - /* Read firmware version. Note that when adapter initializes, it - * clears the mailbox, so it may appear that the first command was - * executed successfully when in fact it was merely erased. To work - * around this, we execute the first command twice. - */ - - if (chdlc_read_version(card, u.str)) - return -EIO; - - printk(KERN_INFO "%s: Running Raw CHDLC firmware v%s\n" - "%s: for Multi-Port PPP protocol.\n", - card->devname,u.str,card->devname); - - card->isr = &wsppp_isr; - card->poll = NULL; - card->exec = NULL; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.udp_port = conf->udp_port; - - card->wandev.new_if_cnt = 0; - - /* reset the number of times the 'update()' proc has been called */ - card->u.c.update_call_count = 0; - - card->wandev.ttl = conf->ttl; - card->wandev.interface = conf->interface; - - if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& - card->hw.type != SDLA_S514){ - printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", - card->devname, PORT(card->u.c.comm_port)); - return -EIO; - } - - - card->wandev.clocking = conf->clocking; - - port_num = card->u.c.comm_port; - - /* Setup Port Bps */ - - if(card->wandev.clocking) { - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - /* For Primary Port 0 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - PRI_MAX_BAUD_RATE_S514 : - PRI_MAX_BAUD_RATE_S508; - } - else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - max_permitted_baud = - (card->hw.type == SDLA_S514) ? - SEC_MAX_BAUD_RATE_S514 : - SEC_MAX_BAUD_RATE_S508; - } - - if(conf->bps > max_permitted_baud) { - conf->bps = max_permitted_baud; - printk(KERN_INFO "%s: Baud too high!\n", - card->wandev.name); - printk(KERN_INFO "%s: Baud rate set to %lu bps\n", - card->wandev.name, max_permitted_baud); - } - - card->wandev.bps = conf->bps; - }else{ - card->wandev.bps = 0; - } - - /* Setup the Port MTU */ - if((port_num == WANOPT_PRI) || card->u.c.receive_only) { - - /* For Primary Port 0 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } else if(port_num == WANOPT_SEC) { - /* For Secondary Port 1 */ - card->wandev.mtu = - (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? - min_t(unsigned int, conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : - CHDLC_DFLT_DATA_LEN; - } - - /* Add on a PPP Header */ - card->wandev.mtu += PPP_HEADER_LEN; - - /* Set up the interrupt status area */ - /* Read the CHDLC Configuration and obtain: - * Ptr to shared memory infor struct - * Use this pointer to calculate the value of card->u.c.flags ! - */ - mb1->buffer_length = 0; - mb1->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; - if(err != COMMAND_OK) { - clear_bit(1, (void*)&card->wandev.critical); - - if(card->hw.type != SDLA_S514) - enable_irq(card->hw.irq); - - chdlc_error(card, err, mb1); - return -EIO; - } - - if(card->hw.type == SDLA_S514){ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct)); - }else{ - card->u.c.flags = (void *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> - ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); - } - - flags = card->u.c.flags; - - /* This is for the ports link state */ - card->wandev.state = WAN_DUALPORT; - card->u.c.state = WAN_DISCONNECTED; - - - if (!card->wandev.piggyback){ - err = intr_test(card); - - if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { - printk(KERN_ERR "%s: Interrupt test failed (%i)\n", - card->devname, Intr_test_counter); - printk(KERN_ERR "%s: Please choose another interrupt\n", - card->devname); - return -EIO; - } - - printk(KERN_INFO "%s: Interrupt test passed (%i)\n", - card->devname, Intr_test_counter); - } - - - if (chdlc_set_intr_mode(card, APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return -EIO; - } - - /* Mask the Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - - printk(KERN_INFO "\n"); - - return 0; -} - -/******* WAN Device Driver Entry Points *************************************/ - -/*============================================================================ - * Update device status & statistics - * This procedure is called when updating the PROC file system and returns - * various communications statistics. These statistics are accumulated from 3 - * different locations: - * 1) The 'if_stats' recorded for the device. - * 2) Communication error statistics on the adapter. - * 3) CHDLC operational statistics on the adapter. - * The board level statistics are read during a timer interrupt. Note that we - * read the error and operational statistics during consecitive timer ticks so - * as to minimize the time that we are inside the interrupt handler. - * - */ -static int update(struct wan_device* wandev) -{ - sdla_t* card = wandev->private; - struct net_device* dev; - volatile chdlc_private_area_t* chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags; - unsigned long timeout; - - /* sanity checks */ - if((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT; - - if(wandev->state == WAN_UNCONFIGURED) - return -ENODEV; - - /* more sanity checks */ - if(!card->u.c.flags) - return -ENODEV; - - if((dev=card->wandev.dev) == NULL) - return -ENODEV; - - if((chdlc_priv_area=dev->priv) == NULL) - return -ENODEV; - - flags = card->u.c.flags; - - if(chdlc_priv_area->update_comms_stats){ - return -EAGAIN; - } - - /* we will need 2 timer interrupts to complete the */ - /* reading of the statistics */ - chdlc_priv_area->update_comms_stats = 2; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; - - /* wait a maximum of 1 second for the statistics to be updated */ - timeout = jiffies + 1 * HZ; - for(;;) { - if(chdlc_priv_area->update_comms_stats == 0) - break; - if (time_after(jiffies, timeout)){ - chdlc_priv_area->update_comms_stats = 0; - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - return -EAGAIN; - } - } - - return 0; -} - - -/*============================================================================ - * Create new logical channel. - * This routine is called by the router when ROUTER_IFNEW IOCTL is being - * handled. - * o parse media- and hardware-specific configuration - * o make sure that a new channel can be created - * o allocate resources, if necessary - * o prepare network device structure for registaration. - * - * Return: 0 o.k. - * < 0 failure (channel will not be created) - */ -static int new_if(struct wan_device* wandev, struct net_device* pdev, - wanif_conf_t* conf) -{ - - struct ppp_device *pppdev = (struct ppp_device *)pdev; - struct net_device *dev = NULL; - struct sppp *sp; - sdla_t* card = wandev->private; - chdlc_private_area_t* chdlc_priv_area; - - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { - printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); - return -EINVAL; - } - - /* allocate and initialize private data */ - chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); - - if(chdlc_priv_area == NULL) - return -ENOMEM; - - memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); - - chdlc_priv_area->card = card; - - /* initialize data */ - strcpy(card->u.c.if_name, conf->name); - - if(card->wandev.new_if_cnt > 0) { - kfree(chdlc_priv_area); - return -EEXIST; - } - - card->wandev.new_if_cnt++; - - chdlc_priv_area->TracingEnabled = 0; - - //We don't need this any more - chdlc_priv_area->route_status = NO_ROUTE; - chdlc_priv_area->route_removed = 0; - - printk(KERN_INFO "%s: Firmware running in HDLC STREAMING Mode\n", - wandev->name); - - /* Setup wanpipe as a router (WANPIPE) or as an API */ - if( strcmp(conf->usedby, "WANPIPE") == 0) { - printk(KERN_INFO "%s: Driver running in WANPIPE mode!\n", - wandev->name); - card->u.c.usedby = WANPIPE; - } else { - printk(KERN_INFO - "%s: API Mode is not supported for SyncPPP!\n", - wandev->name); - kfree(chdlc_priv_area); - return -EINVAL; - } - - /* Get Multicast Information */ - chdlc_priv_area->mc = conf->mc; - - - chdlc_priv_area->if_ptr = pppdev; - - /* prepare network device data space for registration */ - - strcpy(dev->name,card->u.c.if_name); - - /* Attach PPP protocol layer to pppdev - * The sppp_attach() will initilize the dev structure - * and setup ppp layer protocols. - * All we have to do is to bind in: - * if_open(), if_close(), if_send() and get_stats() functions. - */ - sppp_attach(pppdev); - dev = pppdev->dev; - sp = &pppdev->sppp; - - /* Enable PPP Debugging */ - // FIXME Fix this up somehow - //sp->pp_flags |= PP_DEBUG; - sp->pp_flags &= ~PP_CISCO; - - dev->init = &if_init; - dev->priv = chdlc_priv_area; - - return 0; -} - - - - -/*============================================================================ - * Delete logical channel. - */ -static int del_if(struct wan_device* wandev, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - unsigned long smp_lock; - - /* Detach the PPP layer */ - printk(KERN_INFO "%s: Detaching SyncPPP Module from %s\n", - wandev->name,dev->name); - - lock_adapter_irq(&wandev->lock,&smp_lock); - - sppp_detach(dev); - chdlc_priv_area->if_ptr=NULL; - - chdlc_set_intr_mode(card, 0); - if (card->u.c.comm_enabled) - chdlc_comm_disable(card); - unlock_adapter_irq(&wandev->lock,&smp_lock); - - port_set_state(card, WAN_DISCONNECTED); - - return 0; -} - - -/****** Network Device Interface ********************************************/ - -/*============================================================================ - * Initialize Linux network interface. - * - * This routine is called only once for each interface, during Linux network - * interface registration. Returning anything but zero will fail interface - * registration. - */ -static int if_init(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct wan_device* wandev = &card->wandev; - - /* NOTE: Most of the dev initialization was - * done in sppp_attach(), called by new_if() - * function. All we have to do here is - * to link four major routines below. - */ - - /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; - dev->tx_timeout = &if_tx_timeout; - dev->watchdog_timeo = TX_TIMEOUT; - - - /* Initialize hardware parameters */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; - - /* Set transmit buffer queue length - * If we over fill this queue the packets will - * be droped by the kernel. - * sppp_attach() sets this to 10, but - * 100 will give us more room at low speeds. - */ - dev->tx_queue_len = 100; - - return 0; -} - - -/*============================================================================ - * Handle transmit timeout event from netif watchdog - */ -static void if_tx_timeout(struct net_device *dev) -{ - chdlc_private_area_t* chan = dev->priv; - sdla_t *card = chan->card; - - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this - * is only used as a last resort. - */ - - ++card->wandev.stats.collisions; - - printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name); - netif_wake_queue (dev); -} - - -/*============================================================================ - * Open network interface. - * o enable communications and interrupts. - * o prevent module from unloading by incrementing use count - * - * Return 0 if O.k. or errno. - */ -static int if_open(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - struct timeval tv; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - /* Only one open per interface is allowed */ - if (netif_running(dev)) - return -EBUSY; - - /* Start PPP Layer */ - if (sppp_open(dev)){ - return -EIO; - } - - do_gettimeofday(&tv); - chdlc_priv_area->router_start_time = tv.tv_sec; - - netif_start_queue(dev); - - wanpipe_open(card); - - chdlc_priv_area->timer_int_enabled |= TMR_INT_ENABLED_CONFIG; - flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; - return 0; -} - -/*============================================================================ - * Close network interface. - * o if this is the last close, then disable communications and interrupts. - * o reset flags. - */ -static int if_close(struct net_device* dev) -{ - chdlc_private_area_t* chdlc_priv_area = dev->priv; - sdla_t* card = chdlc_priv_area->card; - - /* Stop the PPP Layer */ - sppp_close(dev); - netif_stop_queue(dev); - - wanpipe_close(card); - - return 0; -} - -/*============================================================================ - * Send a packet on a network interface. - * o set tbusy flag (marks start of the transmission) to block a timer-based - * transmit from overlapping. - * o check link state. If link is not up, then drop the packet. - * o execute adapter send command. - * o free socket buffer - * - * Return: 0 complete (socket buffer must be freed) - * non-0 packet may be re-transmitted (tbusy must be set) - * - * Notes: - * 1. This routine is called either by the protocol stack or by the "net - * bottom half" (with interrupts enabled). - * 2. Setting tbusy flag will inhibit further transmit requests from the - * protocol stack and can be used for flow control with protocol layer. - */ -static int if_send(struct sk_buff* skb, struct net_device* dev) -{ - chdlc_private_area_t *chdlc_priv_area = dev->priv; - sdla_t *card = chdlc_priv_area->card; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; - int udp_type = 0; - unsigned long smp_flags; - int err=0; - - netif_stop_queue(dev); - - - if (skb == NULL){ - /* If we get here, some higher layer thinks we've missed an - * tx-done interrupt. - */ - printk(KERN_INFO "%s: Received NULL skb buffer! interface %s got kicked!\n", - card->devname, dev->name); - - netif_wake_queue(dev); - return 0; - } - - if (ntohs(skb->protocol) != htons(PVC_PROT)){ - /* check the udp packet type */ - - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_CPIPE_TYPE){ - if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, - chdlc_priv_area)){ - chdlc_int->interrupt_permission |= - APP_INT_ON_TIMER; - } - netif_start_queue(dev); - return 0; - } - } - - /* Lock the 508 Card: SMP is supported */ - if(card->hw.type != SDLA_S514){ - s508_lock(card,&smp_flags); - } - - if (test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)){ - - printk(KERN_INFO "%s: Critical in if_send: %lx\n", - card->wandev.name,card->wandev.critical); - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_crit_exit; - } - - if (card->wandev.state != WAN_CONNECTED){ - ++card->wandev.stats.tx_dropped; - netif_start_queue(dev); - goto if_send_crit_exit; - } - - if (chdlc_send(card, skb->data, skb->len)){ - netif_stop_queue(dev); - - }else{ - ++card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += skb->len; - dev->trans_start = jiffies; - netif_start_queue(dev); - } - -if_send_crit_exit: - if (!(err=netif_queue_stopped(dev))){ - dev_kfree_skb_any(skb); - }else{ - chdlc_priv_area->tick_counter = jiffies; - chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; - } - - clear_bit(SEND_CRIT, (void*)&card->wandev.critical); - if(card->hw.type != SDLA_S514){ - s508_unlock(card,&smp_flags); - } - - return err; -} - - -/*============================================================================ - * Reply to UDP Management system. - * Return length of reply. - */ -static int reply_udp( unsigned char *data, unsigned int mbox_len ) -{ - - unsigned short len, udp_length, temp, ip_length; - unsigned long ip_temp; - int even_bound = 0; - chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; - - /* Set length of packet */ - len = sizeof(ip_pkt_t)+ - sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* fill in UDP reply */ - c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; - - /* fill in UDP length */ - udp_length = sizeof(udp_pkt_t)+ - sizeof(wp_mgmt_t)+ - sizeof(cblock_t)+ - sizeof(trace_info_t)+ - mbox_len; - - /* put it on an even boundary */ - if ( udp_length & 0x0001 ) { - udp_length += 1; - len += 1; - even_bound = 1; - } - - temp = (udp_length<<8)|(udp_length>>8); - c_udp_pkt->udp_pkt.udp_length = temp; - - /* swap UDP ports */ - temp = c_udp_pkt->udp_pkt.udp_src_port; - c_udp_pkt->udp_pkt.udp_src_port = - c_udp_pkt->udp_pkt.udp_dst_port; - c_udp_pkt->udp_pkt.udp_dst_port = temp; - - /* add UDP pseudo header */ - temp = 0x1100; - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; - temp = (udp_length<<8)|(udp_length>>8); - *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; - - - /* calculate UDP checksum */ - c_udp_pkt->udp_pkt.udp_checksum = 0; - c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); - - /* fill in IP length */ - ip_length = len; - temp = (ip_length<<8)|(ip_length>>8); - c_udp_pkt->ip_pkt.total_length = temp; - - /* swap IP addresses */ - ip_temp = c_udp_pkt->ip_pkt.ip_src_address; - c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; - c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; - - /* fill in IP checksum */ - c_udp_pkt->ip_pkt.hdr_checksum = 0; - c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); - - return len; - -} /* reply_udp */ - -unsigned short calc_checksum (char *data, int len) -{ - unsigned short temp; - unsigned long sum=0; - int i; - - for( i = 0; i > 16 ) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - - temp = (unsigned short)sum; - temp = ~temp; - - if( temp == 0 ) - temp = 0xffff; - - return temp; -} - - -/*============================================================================ - * Get ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. - */ -static struct net_device_stats* if_stats(struct net_device* dev) -{ - sdla_t *my_card; - chdlc_private_area_t* chdlc_priv_area; - - /* Shutdown bug fix. In del_if() we kill - * dev->priv pointer. This function, gets - * called after del_if(), thus check - * if pointer has been deleted */ - if ((chdlc_priv_area=dev->priv) == NULL) - return NULL; - - my_card = chdlc_priv_area->card; - return &my_card->wandev.stats; -} - - -/****** Cisco HDLC Firmware Interface Functions *******************************/ - -/*============================================================================ - * Read firmware code version. - * Put code version as ASCII string in str. - */ -static int chdlc_read_version (sdla_t* card, char* str) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int len; - char err; - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - } - else if (str) { /* is not null */ - len = mb->buffer_length; - memcpy(str, mb->data, len); - str[len] = '\0'; - } - return (err); -} - -/*----------------------------------------------------------------------------- - * Configure CHDLC firmware. - */ -static int chdlc_configure (sdla_t* card, void* data) -{ - int err; - CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; - int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); - - mailbox->buffer_length = data_length; - memcpy(mailbox->data, data, data_length); - mailbox->command = SET_CHDLC_CONFIGURATION; - err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) chdlc_error (card, err, mailbox); - - return err; -} - - -/*============================================================================ - * Set interrupt mode -- HDLC Version. - */ - -static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_INT_TRIGGERS_STRUCT* int_data = - (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; - int err; - - int_data->CHDLC_interrupt_triggers = mode; - int_data->IRQ = card->hw.irq; - int_data->interrupt_timer = 1; - - mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); - mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error (card, err, mb); - return err; -} - - -/*============================================================================ - * Enable communications. - */ - -static int chdlc_comm_enable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = ENABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card, err, mb); - else - card->u.c.comm_enabled=1; - - return err; -} - -/*============================================================================ - * Disable communications and Drop the Modem lines (DCD and RTS). - */ -static int chdlc_comm_disable (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = DISABLE_CHDLC_COMMUNICATIONS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - - return err; -} - -/*============================================================================ - * Read communication error statistics. - */ -static int chdlc_read_comm_err_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_COMMS_ERROR_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Read CHDLC operational statistics. - */ -static int chdlc_read_op_stats (sdla_t* card) -{ - int err; - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_OPERATIONAL_STATS; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) - chdlc_error(card,err,mb); - return err; -} - - -/*============================================================================ - * Update communications error and general packet statistics. - */ -static int update_comms_stats(sdla_t* card, - chdlc_private_area_t* chdlc_priv_area) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - COMMS_ERROR_STATS_STRUCT* err_stats; - CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; - - /* on the first timer interrupt, read the comms error statistics */ - if(chdlc_priv_area->update_comms_stats == 2) { - if(chdlc_read_comm_err_stats(card)) - return 1; - err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_over_errors = - err_stats->Rx_overrun_err_count; - card->wandev.stats.rx_crc_errors = - err_stats->CRC_err_count; - card->wandev.stats.rx_frame_errors = - err_stats->Rx_abort_count; - card->wandev.stats.rx_fifo_errors = - err_stats->Rx_dis_pri_bfrs_full_count; - card->wandev.stats.rx_missed_errors = - card->wandev.stats.rx_fifo_errors; - card->wandev.stats.tx_aborted_errors = - err_stats->sec_Tx_abort_count; - } - - /* on the second timer interrupt, read the operational statistics */ - else { - if(chdlc_read_op_stats(card)) - return 1; - op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; - card->wandev.stats.rx_length_errors = - (op_stats->Rx_Data_discard_short_count + - op_stats->Rx_Data_discard_long_count); - } - - return 0; -} - -/*============================================================================ - * Send packet. - * Return: 0 - o.k. - * 1 - no transmit buffers available - */ -static int chdlc_send (sdla_t* card, void* data, unsigned len) -{ - CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; - - if (txbuf->opp_flag) - return 1; - - sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); - - txbuf->frame_length = len; - txbuf->opp_flag = 1; /* start transmission */ - - /* Update transmit buffer control fields */ - card->u.c.txbuf = ++txbuf; - - if ((void*)txbuf > card->u.c.txbuf_last) - card->u.c.txbuf = card->u.c.txbuf_base; - - return 0; -} - -/****** Firmware Error Handler **********************************************/ - -/*============================================================================ - * Firmware error handler. - * This routine is called whenever firmware command returns non-zero - * return code. - * - * Return zero if previous command has to be cancelled. - */ -static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) -{ - unsigned cmd = mb->command; - - switch (err) { - - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - - case S514_BOTH_PORTS_SAME_CLK_MODE: - if(cmd == SET_CHDLC_CONFIGURATION) { - printk(KERN_INFO - "%s: Configure both ports for the same clock source\n", - card->devname); - break; - } - - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", - card->devname, cmd, err); - } - - return 0; -} - -/****** Interrupt Handlers **************************************************/ - -/*============================================================================ - * Cisco HDLC interrupt service routine. - */ -STATIC void wsppp_isr (sdla_t* card) -{ - struct net_device* dev; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - int i; - sdla_t *my_card; - - - /* Check for which port the interrupt has been generated - * Since Secondary Port is piggybacking on the Primary - * the check must be done here. - */ - - flags = card->u.c.flags; - if (!flags->interrupt_info_struct.interrupt_type){ - /* Check for a second port (piggybacking) */ - if((my_card = card->next)){ - flags = my_card->u.c.flags; - if (flags->interrupt_info_struct.interrupt_type){ - card = my_card; - card->isr(card); - return; - } - } - } - - dev = card->wandev.dev; - card->in_isr = 1; - flags = card->u.c.flags; - - /* If we get an interrupt with no network device, stop the interrupts - * and issue an error */ - if ((!dev || !dev->priv) && flags->interrupt_info_struct.interrupt_type != - COMMAND_COMPLETE_APP_INT_PEND){ - goto isr_done; - } - - - /* if critical due to peripheral operations - * ie. update() or getstats() then reset the interrupt and - * wait for the board to retrigger. - */ - if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { - flags->interrupt_info_struct. - interrupt_type = 0; - goto isr_done; - } - - - /* On a 508 Card, if critical due to if_send - * Major Error !!! - */ - if(card->hw.type != SDLA_S514) { - if(test_bit(0, (void*)&card->wandev.critical)) { - printk(KERN_INFO "%s: Critical while in ISR: %lx\n", - card->devname, card->wandev.critical); - goto isr_done; - } - } - - switch(flags->interrupt_info_struct.interrupt_type) { - - case RX_APP_INT_PEND: /* 0x01: receive interrupt */ - rx_intr(card); - break; - - case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TX_FRAME; - - netif_wake_queue(dev); - break; - - case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ - ++ Intr_test_counter; - break; - - case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ - process_chdlc_exception(card); - break; - - case GLOBAL_EXCEP_COND_APP_INT_PEND: - process_global_exception(card); - break; - - case TIMER_APP_INT_PEND: - timer_intr(card); - break; - - default: - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, - flags->interrupt_info_struct.interrupt_type); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - break; - } - -isr_done: - card->in_isr = 0; - flags->interrupt_info_struct.interrupt_type = 0; -} - -/*============================================================================ - * Receive interrupt handler. - */ -static void rx_intr (sdla_t* card) -{ - struct net_device *dev; - chdlc_private_area_t *chdlc_priv_area; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; - struct sk_buff *skb; - unsigned len; - unsigned addr = rxbuf->ptr_data_bfr; - void *buf; - int i,udp_type; - - if (rxbuf->opp_flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned)rxbuf, rxbuf->opp_flag); - printk(KERN_INFO "Code name: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codename[i]); - printk(KERN_INFO "\nCode version: "); - for(i = 0; i < 4; i ++) - printk(KERN_INFO "%c", - flags->global_info_struct.codeversion[i]); - printk(KERN_INFO "\n"); - - - /* Bug Fix: Mar 6 2000 - * If we get a corrupted mailbox, it measn that driver - * is out of sync with the firmware. There is no recovery. - * If we don't turn off all interrupts for this card - * the machine will crash. - */ - printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); - printk(KERN_INFO "Please contact Sangoma Technologies !\n"); - chdlc_set_intr_mode(card,0); - return; - } - - dev = card->wandev.dev; - - if (!dev){ - goto rx_exit; - } - - if (!netif_running(dev)){ - goto rx_exit; - } - - chdlc_priv_area = dev->priv; - - if (rxbuf->error_flag){ - goto rx_exit; - } - /* Take off two CRC bytes */ - - if (rxbuf->frame_length < 7 || rxbuf->frame_length > 1506 ){ - goto rx_exit; - } - - len = rxbuf->frame_length - CRC_LENGTH; - - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - - if (skb == NULL) { - if (net_ratelimit()){ - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - ++card->wandev.stats.rx_dropped; - goto rx_exit; - } - - /* Copy data to the socket buffer */ - if((addr + len) > card->u.c.rx_top + 1) { - unsigned tmp = card->u.c.rx_top - addr + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.c.rx_base; - len -= tmp; - } - - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - - skb->protocol = htons(ETH_P_WAN_PPP); - - card->wandev.stats.rx_packets ++; - card->wandev.stats.rx_bytes += skb->len; - udp_type = udp_pkt_type( skb, card ); - - if(udp_type == UDP_CPIPE_TYPE) { - if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, - card, skb, dev, chdlc_priv_area)) { - flags->interrupt_info_struct. - interrupt_permission |= - APP_INT_ON_TIMER; - } - }else{ - /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; - netif_rx(skb); - dev->last_rx = jiffies; - } - -rx_exit: - /* Release buffer element and calculate a pointer to the next one */ - rxbuf->opp_flag = 0x00; - card->u.c.rxmb = ++ rxbuf; - if((void*)rxbuf > card->u.c.rxbuf_last){ - card->u.c.rxmb = card->u.c.rxbuf_base; - } -} - -/*============================================================================ - * Timer interrupt handler. - * The timer interrupt is used for two purposes: - * 1) Processing udp calls from 'cpipemon'. - * 2) Reading board-level statistics for updating the proc file system. - */ -void timer_intr(sdla_t *card) -{ - struct net_device* dev; - chdlc_private_area_t* chdlc_priv_area = NULL; - SHARED_MEMORY_INFO_STRUCT* flags = NULL; - - dev = card->wandev.dev; - chdlc_priv_area = dev->priv; - - if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { - if (!config_chdlc(card)){ - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; - } - } - - /* process a udp call if pending */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { - process_udp_mgmt_pkt(card, dev, - chdlc_priv_area); - chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; - } - - - /* read the communications statistics if required */ - if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { - update_comms_stats(card, chdlc_priv_area); - if(!(-- chdlc_priv_area->update_comms_stats)) { - chdlc_priv_area->timer_int_enabled &= - ~TMR_INT_ENABLED_UPDATE; - } - } - - /* only disable the timer interrupt if there are no udp or statistic */ - /* updates pending */ - if(!chdlc_priv_area->timer_int_enabled) { - flags = card->u.c.flags; - flags->interrupt_info_struct.interrupt_permission &= - ~APP_INT_ON_TIMER; - } -} - -/*------------------------------------------------------------------------------ - Miscellaneous Functions - - set_chdlc_config() used to set configuration options on the board -------------------------------------------------------------------------------*/ - -static int set_chdlc_config(sdla_t* card) -{ - - CHDLC_CONFIGURATION_STRUCT cfg; - - memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); - - if(card->wandev.clocking) - cfg.baud_rate = card->wandev.bps; - - cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? - INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; - - cfg.modem_config_options = 0; - //API OPTIONS - cfg.CHDLC_API_options = DISCARD_RX_ERROR_FRAMES; - cfg.modem_status_timer = 100; - cfg.CHDLC_protocol_options = HDLC_STREAMING_MODE; - cfg.percent_data_buffer_for_Tx = 50; - cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | - CHDLC_RX_DATA_BYTE_COUNT_STAT); - cfg.max_CHDLC_data_field_length = card->wandev.mtu; - - cfg.transmit_keepalive_timer = 0; - cfg.receive_keepalive_timer = 0; - cfg.keepalive_error_tolerance = 0; - cfg.SLARP_request_timer = 0; - - cfg.IP_address = 0; - cfg.IP_netmask = 0; - - return chdlc_configure(card, &cfg); -} - -/*============================================================================ - * Process global exception condition - */ -static int process_global_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mbox = card->mbox; - int err; - - mbox->buffer_length = 0; - mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; - err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; - - if(err != CMD_TIMEOUT ){ - - switch(mbox->return_code) { - - case EXCEP_MODEM_STATUS_CHANGE: - - printk(KERN_INFO "%s: Modem status change\n", - card->devname); - - switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { - case (DCD_HIGH): - printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); - break; - case (CTS_HIGH): - printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); - break; - case ((DCD_HIGH | CTS_HIGH)): - printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); - break; - default: - printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); - break; - } - - if (!(mbox->data[0] & DCD_HIGH) || !(mbox->data[0] & DCD_HIGH)){ - //printk(KERN_INFO "Sending TERM Request Manually !\n"); - send_ppp_term_request(card->wandev.dev); - } - break; - - case EXCEP_TRC_DISABLED: - printk(KERN_INFO "%s: Line trace disabled\n", - card->devname); - break; - - case EXCEP_IRQ_TIMEOUT: - printk(KERN_INFO "%s: IRQ timeout occurred\n", - card->devname); - break; - - default: - printk(KERN_INFO "%s: Global exception %x\n", - card->devname, mbox->return_code); - break; - } - } - return 0; -} - - -/*============================================================================ - * Process chdlc exception condition - */ -static int process_chdlc_exception(sdla_t *card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_EXCEPTION_CONDITION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if(err != CMD_TIMEOUT) { - - switch (err) { - - case EXCEP_LINK_ACTIVE: - port_set_state(card, WAN_CONNECTED); - break; - - case EXCEP_LINK_INACTIVE_MODEM: - port_set_state(card, WAN_DISCONNECTED); - break; - - case EXCEP_LOOPBACK_CONDITION: - printk(KERN_INFO "%s: Loopback Condition Detected.\n", - card->devname); - break; - - case NO_CHDLC_EXCEP_COND_TO_REPORT: - printk(KERN_INFO "%s: No exceptions reported.\n", - card->devname); - break; - default: - printk(KERN_INFO "%s: Exception Condition %x!\n", - card->devname,err); - break; - } - - } - return 0; -} - - -/*============================================================================= - * Store a UDP management packet for later processing. - */ - -static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, - struct sk_buff *skb, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area ) -{ - int udp_pkt_stored = 0; - - if(!chdlc_priv_area->udp_pkt_lgth && - (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { - chdlc_priv_area->udp_pkt_lgth = skb->len; - chdlc_priv_area->udp_pkt_src = udp_pkt_src; - memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); - chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; - udp_pkt_stored = 1; - } - - if(udp_pkt_src == UDP_PKT_FRM_STACK) - dev_kfree_skb_any(skb); - else - dev_kfree_skb_any(skb); - - return(udp_pkt_stored); -} - - -/*============================================================================= - * Process UDP management packet. - */ - -static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, - chdlc_private_area_t* chdlc_priv_area ) -{ - unsigned char *buf; - unsigned int frames, len; - struct sk_buff *new_skb; - unsigned short buffer_length, real_len; - unsigned long data_ptr; - unsigned data_length; - int udp_mgmt_req_valid = 1; - CHDLC_MAILBOX_STRUCT *mb = card->mbox; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - chdlc_udp_pkt_t *chdlc_udp_pkt; - struct timeval tv; - int err; - char ut_char; - - chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - - switch(chdlc_udp_pkt->cblock.command) { - case READ_GLOBAL_STATISTICS: - case READ_MODEM_STATUS: - case READ_CHDLC_LINK_STATUS: - case CPIPE_ROUTER_UP_TIME: - case READ_COMMS_ERROR_STATS: - case READ_CHDLC_OPERATIONAL_STATS: - - /* These two commands are executed for - * each request */ - case READ_CHDLC_CONFIGURATION: - case READ_CHDLC_CODE_VERSION: - udp_mgmt_req_valid = 1; - break; - default: - udp_mgmt_req_valid = 0; - break; - } - } - - if(!udp_mgmt_req_valid) { - - /* set length to 0 */ - chdlc_udp_pkt->cblock.buffer_length = 0; - - /* set return code */ - chdlc_udp_pkt->cblock.return_code = 0xCD; - - if (net_ratelimit()){ - printk(KERN_INFO - "%s: Warning, Illegal UDP command attempted from network: %x\n", - card->devname,chdlc_udp_pkt->cblock.command); - } - - } else { - unsigned long trace_status_cfg_addr = 0; - TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; - TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; - - switch(chdlc_udp_pkt->cblock.command) { - - case CPIPE_ENABLE_TRACING: - if (!chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_ACTIVE; - /* Trace delay mode is not used because it slows - down transfer and results in a standoff situation - when there is a lot of data */ - - /* Configure the Trace based on user inputs */ - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= - chdlc_udp_pkt->data[0]; - - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_deactivation_timer = 4000; - - - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - card->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - /* Get the base address of the trace element list */ - mb->buffer_length = 0; - mb->command = READ_TRACE_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if (err != COMMAND_OK) { - chdlc_error(card,err,mb); - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = err; - mb->buffer_length = 0; - break; - } - - trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) - mb->data) -> ptr_trace_stat_el_cfg_struct; - - sdla_peek(&card->hw, trace_status_cfg_addr, - &trace_cfg_struct, sizeof(trace_cfg_struct)); - - chdlc_priv_area->start_trace_addr = trace_cfg_struct. - base_addr_trace_status_elements; - - chdlc_priv_area->number_trace_elements = - trace_cfg_struct.number_trace_status_elements; - - chdlc_priv_area->end_trace_addr = (unsigned long) - ((TRACE_STATUS_ELEMENT_STRUCT *) - chdlc_priv_area->start_trace_addr + - (chdlc_priv_area->number_trace_elements - 1)); - - chdlc_priv_area->base_addr_trace_buffer = - trace_cfg_struct.base_addr_trace_buffer; - - chdlc_priv_area->end_addr_trace_buffer = - trace_cfg_struct.end_addr_trace_buffer; - - chdlc_priv_area->curr_trace_addr = - trace_cfg_struct.next_trace_element_to_use; - - chdlc_priv_area->available_buffer_space = 2000 - - sizeof(ip_pkt_t) - - sizeof(udp_pkt_t) - - sizeof(wp_mgmt_t) - - sizeof(cblock_t) - - sizeof(trace_info_t); - } - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - chdlc_priv_area->TracingEnabled = 1; - break; - - - case CPIPE_DISABLE_TRACING: - if (chdlc_priv_area->TracingEnabled) { - - /* OPERATE_DATALINE_MONITOR */ - mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); - mb->command = SET_TRACE_CONFIGURATION; - ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> - trace_config = TRACE_INACTIVE; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - } - - chdlc_priv_area->TracingEnabled = 0; - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 0; - break; - - - case CPIPE_GET_TRACE_INFO: - - if (!chdlc_priv_area->TracingEnabled) { - chdlc_udp_pkt->cblock.return_code = 1; - mb->buffer_length = 0; - break; - } - - chdlc_udp_pkt->trace_info.ismoredata = 0x00; - buffer_length = 0; /* offset of packet already occupied */ - - for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ - - trace_pkt_t *trace_pkt = (trace_pkt_t *) - &chdlc_udp_pkt->data[buffer_length]; - - sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, - (unsigned char *)&trace_element_struct, - sizeof(TRACE_STATUS_ELEMENT_STRUCT)); - - if (trace_element_struct.opp_flag == 0x00) { - break; - } - - /* get pointer to real data */ - data_ptr = trace_element_struct.ptr_data_bfr; - - /* See if there is actual data on the trace buffer */ - if (data_ptr){ - data_length = trace_element_struct.trace_length; - }else{ - data_length = 0; - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - - if( (chdlc_priv_area->available_buffer_space - buffer_length) - < ( sizeof(trace_pkt_t) + data_length) ) { - - /* indicate there are more frames on board & exit */ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - break; - } - - trace_pkt->status = trace_element_struct.trace_type; - - trace_pkt->time_stamp = - trace_element_struct.trace_time_stamp; - - trace_pkt->real_length = - trace_element_struct.trace_length; - - /* see if we can fit the frame into the user buffer */ - real_len = trace_pkt->real_length; - - if (data_ptr == 0) { - trace_pkt->data_avail = 0x00; - } else { - unsigned tmp = 0; - - /* get the data from circular buffer - must check for end of buffer */ - trace_pkt->data_avail = 0x01; - - if ((data_ptr + real_len) > - chdlc_priv_area->end_addr_trace_buffer + 1){ - - tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; - sdla_peek(&card->hw, data_ptr, - trace_pkt->data,tmp); - data_ptr = chdlc_priv_area->base_addr_trace_buffer; - } - - sdla_peek(&card->hw, data_ptr, - &trace_pkt->data[tmp], real_len - tmp); - } - - /* zero the opp flag to show we got the frame */ - ut_char = 0x00; - sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); - - /* now move onto the next frame */ - chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); - - /* check if we went over the last address */ - if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { - chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; - } - - if(trace_pkt->data_avail == 0x01) { - buffer_length += real_len - 1; - } - - /* for the header */ - buffer_length += sizeof(trace_pkt_t); - - } /* For Loop */ - - if (frames == chdlc_priv_area->number_trace_elements){ - chdlc_udp_pkt->trace_info.ismoredata = 0x01; - } - chdlc_udp_pkt->trace_info.num_frames = frames; - - mb->buffer_length = buffer_length; - chdlc_udp_pkt->cblock.buffer_length = buffer_length; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - - break; - - - case CPIPE_FT1_READ_STATUS: - ((unsigned char *)chdlc_udp_pkt->data )[0] = - flags->FT1_info_struct.parallel_port_A_input; - - ((unsigned char *)chdlc_udp_pkt->data )[1] = - flags->FT1_info_struct.parallel_port_B_input; - - chdlc_udp_pkt->cblock.return_code = COMMAND_OK; - mb->buffer_length = 2; - break; - - case CPIPE_ROUTER_UP_TIME: - do_gettimeofday( &tv ); - chdlc_priv_area->router_up_time = tv.tv_sec - - chdlc_priv_area->router_start_time; - *(unsigned long *)&chdlc_udp_pkt->data = - chdlc_priv_area->router_up_time; - mb->buffer_length = sizeof(unsigned long); - break; - - case FT1_MONITOR_STATUS_CTRL: - /* Enable FT1 MONITOR STATUS */ - if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || - (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { - - if( rCount++ != 0 ) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - - /* Disable FT1 MONITOR STATUS */ - if( chdlc_udp_pkt->data[0] == 0) { - - if( --rCount != 0) { - chdlc_udp_pkt->cblock. - return_code = COMMAND_OK; - mb->buffer_length = 1; - break; - } - } - - default: - /* it's a board command */ - mb->command = chdlc_udp_pkt->cblock.command; - mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; - if (mb->buffer_length) { - memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> - data, mb->buffer_length); - } - /* run the command on the board */ - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - if (err != COMMAND_OK) { - break; - } - - /* copy the result back to our buffer */ - memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); - - if (mb->buffer_length) { - memcpy(&chdlc_udp_pkt->data, &mb->data, - mb->buffer_length); - } - - } /* end of switch */ - } /* end of else */ - - /* Fill UDP TTL */ - chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; - - len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); - - if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { - if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { - ++ card->wandev.stats.tx_packets; - card->wandev.stats.tx_bytes += len; - } - } else { - - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - /* copy data into new_skb */ - - buf = skb_put(new_skb, len); - memcpy(buf, chdlc_priv_area->udp_pkt_data, len); - - /* Decapsulate pkt and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - dev->last_rx = jiffies; - } else { - - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - } - } - - chdlc_priv_area->udp_pkt_lgth = 0; - - return 0; -} - -/*============================================================================ - * Initialize Receive and Transmit Buffers. - */ - -static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; - CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; - char err; - - mb->buffer_length = 0; - mb->command = READ_CHDLC_CONFIGURATION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - - if(err != COMMAND_OK) { - chdlc_error(card,err,mb); - return; - } - - if(card->hw.type == SDLA_S514) { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct)); - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - tx_config->base_addr_Tx_status_elements); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *) - card->u.c.txbuf_base + - (tx_config->number_Tx_status_elements - 1); - - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - rx_config->base_addr_Rx_status_elements); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *) - card->u.c.rxbuf_base + - (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - tx_config->next_Tx_status_element_to_use); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - rx_config->next_Rx_status_element_to_use); - } - else { - tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + - (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> - ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); - - /* Setup Head and Tails for buffers */ - card->u.c.txbuf_base = (void *)(card->hw.dpmbase + - (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.txbuf_last = - (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base - + (tx_config->number_Tx_status_elements - 1); - card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + - (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); - card->u.c.rxbuf_last = - (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base - + (rx_config->number_Rx_status_elements - 1); - - /* Set up next pointer to be used */ - card->u.c.txbuf = (void *)(card->hw.dpmbase + - (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); - card->u.c.rxmb = (void *)(card->hw.dpmbase + - (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); - } - - /* Setup Actual Buffer Start and end addresses */ - card->u.c.rx_base = rx_config->base_addr_Rx_buffer; - card->u.c.rx_top = rx_config->end_addr_Rx_buffer; - -} - -/*============================================================================= - * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR - * _TEST_COUNTER times. - */ -static int intr_test( sdla_t* card) -{ - CHDLC_MAILBOX_STRUCT* mb = card->mbox; - int err,i; - - Intr_test_counter = 0; - - /* The critical flag is unset because during initialization (if_open) - * we want the interrupts to be enabled so that when the wpc_isr is - * called it does not exit due to critical flag set. - */ - - err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); - - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { - mb->buffer_length = 0; - mb->command = READ_CHDLC_CODE_VERSION; - err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; - } - } - else { - return err; - } - - err = chdlc_set_intr_mode(card, 0); - - if (err != CMD_OK) - return err; - - return 0; -} - -/*============================================================================== - * Determine what type of UDP call it is. CPIPEAB ? - */ -static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) -{ - chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; - - if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && - (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && - (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && - (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { - return UDP_CPIPE_TYPE; - } - else return UDP_INVALID_TYPE; -} - -/*============================================================================ - * Set PORT state. - */ -static void port_set_state (sdla_t *card, int state) -{ - struct net_device *dev = card->wandev.dev; - chdlc_private_area_t *chdlc_priv_area = dev->priv; - - if (card->u.c.state != state) - { - switch (state) - { - case WAN_CONNECTED: - printk (KERN_INFO "%s: HDLC link connected!\n", - card->devname); - break; - - case WAN_CONNECTING: - printk (KERN_INFO "%s: HDLC link connecting...\n", - card->devname); - break; - - case WAN_DISCONNECTED: - printk (KERN_INFO "%s: HDLC link disconnected!\n", - card->devname); - break; - } - - card->wandev.state = card->u.c.state = state; - chdlc_priv_area->common.state = state; - } -} - -void s508_lock (sdla_t *card, unsigned long *smp_flags) -{ - spin_lock_irqsave(&card->wandev.lock, *smp_flags); - if (card->next){ - /* It is ok to use spin_lock here, since we - * already turned off interrupts */ - spin_lock(&card->next->wandev.lock); - } -} - -void s508_unlock (sdla_t *card, unsigned long *smp_flags) -{ - if (card->next){ - spin_unlock(&card->next->wandev.lock); - } - spin_unlock_irqrestore(&card->wandev.lock, *smp_flags); -} - - - -/*=========================================================================== - * config_chdlc - * - * Configure the chdlc protocol and enable communications. - * - * The if_open() function binds this function to the poll routine. - * Therefore, this function will run every time the chdlc interface - * is brought up. We cannot run this function from the if_open - * because if_open does not have access to the remote IP address. - * - * If the communications are not enabled, proceed to configure - * the card and enable communications. - * - * If the communications are enabled, it means that the interface - * was shutdown by ether the user or driver. In this case, we - * have to check that the IP addresses have not changed. If - * the IP addresses have changed, we have to reconfigure the firmware - * and update the changed IP addresses. Otherwise, just exit. - * - */ - -static int config_chdlc (sdla_t *card) -{ - struct net_device *dev = card->wandev.dev; - SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; - - if (card->u.c.comm_enabled){ - chdlc_comm_disable(card); - port_set_state(card, WAN_DISCONNECTED); - } - - if (set_chdlc_config(card)) { - printk(KERN_INFO "%s: CHDLC Configuration Failed!\n", - card->devname); - return 0; - } - init_chdlc_tx_rx_buff(card, dev); - - /* Set interrupt mode and mask */ - if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | - APP_INT_ON_GLOBAL_EXCEP_COND | - APP_INT_ON_TX_FRAME | - APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ - printk (KERN_INFO "%s: Failed to set interrupt triggers!\n", - card->devname); - return 0; - } - - - /* Mask the Transmit and Timer interrupt */ - flags->interrupt_info_struct.interrupt_permission &= - ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); - - - if (chdlc_comm_enable(card) != 0) { - printk(KERN_INFO "%s: Failed to enable chdlc communications!\n", - card->devname); - flags->interrupt_info_struct.interrupt_permission = 0; - card->u.c.comm_enabled=0; - chdlc_set_intr_mode(card,0); - return 0; - } - - /* Initialize Rx/Tx buffer control fields */ - port_set_state(card, WAN_CONNECTING); - return 0; -} - - -static void send_ppp_term_request(struct net_device *dev) -{ - struct sk_buff *new_skb; - unsigned char *buf; - - if ((new_skb = dev_alloc_skb(8)) != NULL) { - /* copy data into new_skb */ - - buf = skb_put(new_skb, 8); - sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07); - - /* Decapsulate pkt and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_WAN_PPP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - - netif_rx(new_skb); - dev->last_rx = jiffies; - } -} - - -MODULE_LICENSE("GPL"); - -/****** End ****************************************************************/ diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index fd17aa8491b6..bad09ebdb50b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -309,7 +309,10 @@ config APPLE_AIRPORT Say Y here to support the Airport 802.11b wireless Ethernet hardware built into the Macintosh iBook and other recent PowerPC-based Macintosh machines. This is essentially a Lucent Orinoco card with - a non-standard interface + a non-standard interface. + + This driver does not support the Airport Extreme (802.11b/g). Use + the BCM43xx driver for Airport Extreme cards. config PLX_HERMES tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)" @@ -353,7 +356,7 @@ config PCI_HERMES config ATMEL tristate "Atmel at76c50x chipset 802.11b support" - depends on NET_RADIO + depends on NET_RADIO && (PCI || PCMCIA) select FW_LOADER select CRC32 ---help--- @@ -401,6 +404,7 @@ config PCMCIA_HERMES config PCMCIA_SPECTRUM tristate "Symbol Spectrum24 Trilogy PCMCIA card support" depends on NET_RADIO && PCMCIA && HERMES + select FW_LOADER ---help--- This is a driver for 802.11b cards using RAM-loadable Symbol @@ -500,6 +504,7 @@ config PRISM54 will be called prism54.ko. source "drivers/net/wireless/hostap/Kconfig" +source "drivers/net/wireless/bcm43xx/Kconfig" # yes, this works even when no drivers are selected config NET_WIRELESS diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 3a6f7ba326ca..c86779879361 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o obj-$(CONFIG_PRISM54) += prism54/ obj-$(CONFIG_HOSTAP) += hostap/ +obj-$(CONFIG_BCM43XX) += bcm43xx/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index a496460ce224..af0cbb6c5c0c 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -80,8 +80,8 @@ MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards"); event handler. */ -static void airo_config(dev_link_t *link); -static void airo_release(dev_link_t *link); +static int airo_config(struct pcmcia_device *link); +static void airo_release(struct pcmcia_device *link); /* The attach() and detach() entry points are used to create and destroy @@ -101,10 +101,10 @@ static void airo_detach(struct pcmcia_device *p_dev); /* A linked list of "instances" of the aironet device. Each actual PCMCIA card corresponds to one device instance, and is described - by one dev_link_t structure (defined in ds.h). + by one struct pcmcia_device structure (defined in ds.h). You may not want to use a linked list for this -- for example, the - memory card driver uses an array of dev_link_t pointers, where minor + memory card driver uses an array of struct pcmcia_device pointers, where minor device numbers are used to derive the corresponding array index. */ @@ -114,7 +114,7 @@ static void airo_detach(struct pcmcia_device *p_dev); example, ethernet cards, modems). In other cases, there may be many actual or logical devices (SCSI adapters, memory cards with multiple partitions). The dev_node_t structures need to be kept - in a linked list starting at the 'dev' field of a dev_link_t + in a linked list starting at the 'dev' field of a struct pcmcia_device structure. We allocate them in the card's private data structure, because they generally shouldn't be allocated dynamically. @@ -141,24 +141,16 @@ typedef struct local_info_t { ======================================================================*/ -static int airo_attach(struct pcmcia_device *p_dev) +static int airo_probe(struct pcmcia_device *p_dev) { - dev_link_t *link; local_info_t *local; DEBUG(0, "airo_attach()\n"); - /* Initialize the dev_link_t structure */ - link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) { - printk(KERN_ERR "airo_cs: no memory for new device\n"); - return -ENOMEM; - } - /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = NULL; + p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.Handler = NULL; /* General socket configuration defaults can go here. In this @@ -167,26 +159,18 @@ static int airo_attach(struct pcmcia_device *p_dev) and attributes of IO windows) are fixed by the nature of the device, and can be hard-wired here. */ - link->conf.Attributes = 0; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; + p_dev->conf.Attributes = 0; + p_dev->conf.IntType = INT_MEMORY_AND_IO; /* Allocate space for private device-specific data */ local = kzalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) { printk(KERN_ERR "airo_cs: no memory for new device\n"); - kfree (link); return -ENOMEM; } - link->priv = local; + p_dev->priv = local; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - airo_config(link); - - return 0; + return airo_config(p_dev); } /* airo_attach */ /*====================================================================== @@ -198,14 +182,11 @@ static int airo_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void airo_detach(struct pcmcia_device *p_dev) +static void airo_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - DEBUG(0, "airo_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) - airo_release(link); + airo_release(link); if ( ((local_info_t*)link->priv)->eth_dev ) { stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 ); @@ -213,7 +194,6 @@ static void airo_detach(struct pcmcia_device *p_dev) ((local_info_t*)link->priv)->eth_dev = NULL; kfree(link->priv); - kfree(link); } /* airo_detach */ /*====================================================================== @@ -227,9 +207,8 @@ static void airo_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void airo_config(dev_link_t *link) +static int airo_config(struct pcmcia_device *link) { - client_handle_t handle; tuple_t tuple; cisparse_t parse; local_info_t *dev; @@ -237,8 +216,7 @@ static void airo_config(dev_link_t *link) u_char buf[64]; win_req_t req; memreq_t map; - - handle = link->handle; + dev = link->priv; DEBUG(0, "airo_config(0x%p)\n", link); @@ -252,15 +230,12 @@ static void airo_config(dev_link_t *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - - /* Configure card */ - link->state |= DEV_CONFIG; - + /* In this loop, we scan the CIS for configuration table entries, each of which describes a valid card configuration, including @@ -274,12 +249,12 @@ static void airo_config(dev_link_t *link) will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; @@ -294,16 +269,11 @@ static void airo_config(dev_link_t *link) /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1<conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; - else if (dflt.vcc.present & (1<conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; - if (cfg->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; /* Do we need to allocate an interrupt? */ @@ -329,12 +299,12 @@ static void airo_config(dev_link_t *link) } /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; /* Now set up a common memory window, if needed. There is room - in the dev_link_t structure for one memory window handle, + in the struct pcmcia_device structure for one memory window handle, but if the base addresses need to be saved, or if multiple windows are needed, the info should go in the private data structure for this device. @@ -350,7 +320,7 @@ static void airo_config(dev_link_t *link) req.Base = mem->win[0].host_addr; req.Size = mem->win[0].len; req.AccessSpeed = 0; - if (pcmcia_request_window(&link->handle, &req, &link->win) != 0) + if (pcmcia_request_window(&link, &req, &link->win) != 0) goto next_entry; map.Page = 0; map.CardOffset = mem->win[0].card_addr; if (pcmcia_map_mem_page(link->win, &map) != 0) @@ -360,7 +330,7 @@ static void airo_config(dev_link_t *link) break; next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } /* @@ -369,33 +339,32 @@ static void airo_config(dev_link_t *link) irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); ((local_info_t*)link->priv)->eth_dev = init_airo_card( link->irq.AssignedIRQ, - link->io.BasePort1, 1, &handle_to_dev(handle) ); + link->io.BasePort1, 1, &handle_to_dev(link) ); if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed; /* At this point, the dev_node_t structure(s) need to be - initialized and arranged in a linked list at link->dev. + initialized and arranged in a linked list at link->dev_node. */ strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); dev->node.major = dev->node.minor = 0; - link->dev = &dev->node; + link->dev_node = &dev->node; /* Finally, report what we've done */ - printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", - dev->node.dev_name, link->conf.ConfigIndex, - link->conf.Vcc/10, link->conf.Vcc%10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + printk(KERN_INFO "%s: index 0x%02x: ", + dev->node.dev_name, link->conf.ConfigIndex); + if (link->conf.Vpp) + printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); if (link->conf.Attributes & CONF_ENABLE_IRQ) printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) @@ -408,14 +377,12 @@ static void airo_config(dev_link_t *link) printk(", mem 0x%06lx-0x%06lx", req.Base, req.Base+req.Size-1); printk("\n"); - - link->state &= ~DEV_CONFIG_PENDING; - return; - + return 0; + cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); airo_release(link); - + return -ENODEV; } /* airo_config */ /*====================================================================== @@ -426,51 +393,26 @@ static void airo_config(dev_link_t *link) ======================================================================*/ -static void airo_release(dev_link_t *link) +static void airo_release(struct pcmcia_device *link) { DEBUG(0, "airo_release(0x%p)\n", link); - - /* Unlink the device chain */ - link->dev = NULL; - - /* - In a normal driver, additional code may be needed to release - other kernel data structures associated with this device. - */ - - /* Don't bother checking to see if these succeed or not */ - if (link->win) - pcmcia_release_window(link->win); - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - if (link->irq.AssignedIRQ) - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } -static int airo_suspend(struct pcmcia_device *p_dev) +static int airo_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); local_info_t *local = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - netif_device_detach(local->eth_dev); - pcmcia_release_configuration(link->handle); - } + netif_device_detach(local->eth_dev); return 0; } -static int airo_resume(struct pcmcia_device *p_dev) +static int airo_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); local_info_t *local = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); + if (link->open) { reset_airo_card(local->eth_dev); netif_device_attach(local->eth_dev); } @@ -492,7 +434,7 @@ static struct pcmcia_driver airo_driver = { .drv = { .name = "airo_cs", }, - .probe = airo_attach, + .probe = airo_probe, .remove = airo_detach, .id_table = airo_ids, .suspend = airo_suspend, diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index d6f4a5a3e55a..26bf1127524d 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -91,8 +91,8 @@ MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards"); event handler. */ -static void atmel_config(dev_link_t *link); -static void atmel_release(dev_link_t *link); +static int atmel_config(struct pcmcia_device *link); +static void atmel_release(struct pcmcia_device *link); /* The attach() and detach() entry points are used to create and destroy @@ -112,10 +112,10 @@ static void atmel_detach(struct pcmcia_device *p_dev); /* A linked list of "instances" of the atmelnet device. Each actual PCMCIA card corresponds to one device instance, and is described - by one dev_link_t structure (defined in ds.h). + by one struct pcmcia_device structure (defined in ds.h). You may not want to use a linked list for this -- for example, the - memory card driver uses an array of dev_link_t pointers, where minor + memory card driver uses an array of struct pcmcia_device pointers, where minor device numbers are used to derive the corresponding array index. */ @@ -125,7 +125,7 @@ static void atmel_detach(struct pcmcia_device *p_dev); example, ethernet cards, modems). In other cases, there may be many actual or logical devices (SCSI adapters, memory cards with multiple partitions). The dev_node_t structures need to be kept - in a linked list starting at the 'dev' field of a dev_link_t + in a linked list starting at the 'dev' field of a struct pcmcia_device structure. We allocate them in the card's private data structure, because they generally shouldn't be allocated dynamically. @@ -152,24 +152,16 @@ typedef struct local_info_t { ======================================================================*/ -static int atmel_attach(struct pcmcia_device *p_dev) +static int atmel_probe(struct pcmcia_device *p_dev) { - dev_link_t *link; local_info_t *local; DEBUG(0, "atmel_attach()\n"); - /* Initialize the dev_link_t structure */ - link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) { - printk(KERN_ERR "atmel_cs: no memory for new device\n"); - return -ENOMEM; - } - /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = NULL; + p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.Handler = NULL; /* General socket configuration defaults can go here. In this @@ -178,26 +170,18 @@ static int atmel_attach(struct pcmcia_device *p_dev) and attributes of IO windows) are fixed by the nature of the device, and can be hard-wired here. */ - link->conf.Attributes = 0; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; + p_dev->conf.Attributes = 0; + p_dev->conf.IntType = INT_MEMORY_AND_IO; /* Allocate space for private device-specific data */ local = kzalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) { printk(KERN_ERR "atmel_cs: no memory for new device\n"); - kfree (link); return -ENOMEM; } - link->priv = local; + p_dev->priv = local; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - atmel_config(link); - - return 0; + return atmel_config(p_dev); } /* atmel_attach */ /*====================================================================== @@ -209,17 +193,13 @@ static int atmel_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void atmel_detach(struct pcmcia_device *p_dev) +static void atmel_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - DEBUG(0, "atmel_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) - atmel_release(link); + atmel_release(link); kfree(link->priv); - kfree(link); } /*====================================================================== @@ -236,19 +216,17 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) /* Call-back function to interrogate PCMCIA-specific information about the current existance of the card */ static int card_present(void *arg) -{ - dev_link_t *link = (dev_link_t *)arg; - if (link->state & DEV_SUSPEND) - return 0; - else if (link->state & DEV_PRESENT) +{ + struct pcmcia_device *link = (struct pcmcia_device *)arg; + + if (pcmcia_dev_present(link)) return 1; - + return 0; } -static void atmel_config(dev_link_t *link) +static int atmel_config(struct pcmcia_device *link) { - client_handle_t handle; tuple_t tuple; cisparse_t parse; local_info_t *dev; @@ -256,9 +234,8 @@ static void atmel_config(dev_link_t *link) u_char buf[64]; struct pcmcia_device_id *did; - handle = link->handle; dev = link->priv; - did = handle_to_dev(handle).driver_data; + did = handle_to_dev(link).driver_data; DEBUG(0, "atmel_config(0x%p)\n", link); @@ -272,15 +249,12 @@ static void atmel_config(dev_link_t *link) registers. */ tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - - /* Configure card */ - link->state |= DEV_CONFIG; - + /* In this loop, we scan the CIS for configuration table entries, each of which describes a valid card configuration, including @@ -294,12 +268,12 @@ static void atmel_config(dev_link_t *link) will only use the CIS to fill in implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; @@ -314,16 +288,11 @@ static void atmel_config(dev_link_t *link) /* Use power settings for Vcc and Vpp if present */ /* Note that the CIS values need to be rescaled */ - if (cfg->vcc.present & (1<conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; - else if (dflt.vcc.present & (1<conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; - if (cfg->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; /* Do we need to allocate an interrupt? */ @@ -349,14 +318,14 @@ static void atmel_config(dev_link_t *link) } /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; /* If we got this far, we're cool! */ break; next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } /* @@ -365,14 +334,14 @@ static void atmel_config(dev_link_t *link) irq structure is initialized. */ if (link->conf.Attributes & CONF_ENABLE_IRQ) - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); if (link->irq.AssignedIRQ == 0) { printk(KERN_ALERT @@ -384,7 +353,7 @@ static void atmel_config(dev_link_t *link) init_atmel_card(link->irq.AssignedIRQ, link->io.BasePort1, did ? did->driver_info : ATMEL_FW_TYPE_NONE, - &handle_to_dev(handle), + &handle_to_dev(link), card_present, link); if (!((local_info_t*)link->priv)->eth_dev) @@ -393,18 +362,18 @@ static void atmel_config(dev_link_t *link) /* At this point, the dev_node_t structure(s) need to be - initialized and arranged in a linked list at link->dev. + initialized and arranged in a linked list at link->dev_node. */ strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); dev->node.major = dev->node.minor = 0; - link->dev = &dev->node; - - link->state &= ~DEV_CONFIG_PENDING; - return; - + link->dev_node = &dev->node; + + return 0; + cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); atmel_release(link); + return -ENODEV; } /*====================================================================== @@ -415,53 +384,34 @@ static void atmel_config(dev_link_t *link) ======================================================================*/ -static void atmel_release(dev_link_t *link) +static void atmel_release(struct pcmcia_device *link) { struct net_device *dev = ((local_info_t*)link->priv)->eth_dev; - + DEBUG(0, "atmel_release(0x%p)\n", link); - - /* Unlink the device chain */ - link->dev = NULL; - - if (dev) + + if (dev) stop_atmel_card(dev); - ((local_info_t*)link->priv)->eth_dev = NULL; - - /* Don't bother checking to see if these succeed or not */ - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - if (link->irq.AssignedIRQ) - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + ((local_info_t*)link->priv)->eth_dev = NULL; + + pcmcia_disable_device(link); } -static int atmel_suspend(struct pcmcia_device *dev) +static int atmel_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); local_info_t *local = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - netif_device_detach(local->eth_dev); - pcmcia_release_configuration(link->handle); - } + netif_device_detach(local->eth_dev); return 0; } -static int atmel_resume(struct pcmcia_device *dev) +static int atmel_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); local_info_t *local = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - atmel_open(local->eth_dev); - netif_device_attach(local->eth_dev); - } + atmel_open(local->eth_dev); + netif_device_attach(local->eth_dev); return 0; } @@ -515,7 +465,7 @@ static struct pcmcia_driver atmel_driver = { .drv = { .name = "atmel_cs", }, - .probe = atmel_attach, + .probe = atmel_probe, .remove = atmel_detach, .id_table = atmel_ids, .suspend = atmel_suspend, diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig new file mode 100644 index 000000000000..418465600a77 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/Kconfig @@ -0,0 +1,62 @@ +config BCM43XX + tristate "Broadcom BCM43xx wireless support" + depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL + select FW_LOADER + ---help--- + This is an experimental driver for the Broadcom 43xx wireless chip, + found in the Apple Airport Extreme and various other devices. + +config BCM43XX_DEBUG + bool "Broadcom BCM43xx debugging (RECOMMENDED)" + depends on BCM43XX + default y + ---help--- + Broadcom 43xx debugging messages. + Say Y, because the driver is still very experimental and + this will help you get it running. + +config BCM43XX_DMA + bool +config BCM43XX_PIO + bool + +choice + prompt "BCM43xx data transfer mode" + depends on BCM43XX + default BCM43XX_DMA_AND_PIO_MODE + +config BCM43XX_DMA_AND_PIO_MODE + bool "DMA + PIO" + select BCM43XX_DMA + select BCM43XX_PIO + ---help--- + Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) + data transfer modes. + The actually used mode is selectable through the module + parameter "pio". If the module parameter is pio=0, DMA is used. + Otherwise PIO is used. DMA is default. + + If unsure, choose this option. + +config BCM43XX_DMA_MODE + bool "DMA (Direct Memory Access) only" + select BCM43XX_DMA + ---help--- + Only include Direct Memory Access (DMA). + This reduces the size of the driver module, by omitting the PIO code. + +config BCM43XX_PIO_MODE + bool "PIO (Programmed I/O) only" + select BCM43XX_PIO + ---help--- + Only include Programmed I/O (PIO). + This reduces the size of the driver module, by omitting the DMA code. + Please note that PIO transfers are slow (compared to DMA). + + Also note that not all devices of the 43xx series support PIO. + The 4306 (Apple Airport Extreme and others) supports PIO, while + the 4318 is known to _not_ support PIO. + + Only use PIO, if DMA does not work for you. + +endchoice diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile new file mode 100644 index 000000000000..bb5220c629d2 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -0,0 +1,12 @@ +obj-$(CONFIG_BCM43XX) += bcm43xx.o +bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o + +bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o +bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o + +bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ + bcm43xx_radio.o bcm43xx_phy.o \ + bcm43xx_power.o bcm43xx_wx.o \ + bcm43xx_leds.o bcm43xx_ethtool.o \ + bcm43xx_xmit.o bcm43xx_sysfs.o \ + $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h new file mode 100644 index 000000000000..dcadd295de4f --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -0,0 +1,926 @@ +#ifndef BCM43xx_H_ +#define BCM43xx_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "bcm43xx_debugfs.h" +#include "bcm43xx_leds.h" +#include "bcm43xx_sysfs.h" + + +#define PFX KBUILD_MODNAME ": " + +#define BCM43xx_SWITCH_CORE_MAX_RETRIES 50 +#define BCM43xx_IRQWAIT_MAX_RETRIES 50 + +#define BCM43xx_IO_SIZE 8192 + +/* Active Core PCI Configuration Register. */ +#define BCM43xx_PCICFG_ACTIVE_CORE 0x80 +/* SPROM control register. */ +#define BCM43xx_PCICFG_SPROMCTL 0x88 +/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */ +#define BCM43xx_PCICFG_ICR 0x94 + +/* MMIO offsets */ +#define BCM43xx_MMIO_DMA1_REASON 0x20 +#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x24 +#define BCM43xx_MMIO_DMA2_REASON 0x28 +#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x2C +#define BCM43xx_MMIO_DMA3_REASON 0x30 +#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x34 +#define BCM43xx_MMIO_DMA4_REASON 0x38 +#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x3C +#define BCM43xx_MMIO_STATUS_BITFIELD 0x120 +#define BCM43xx_MMIO_STATUS2_BITFIELD 0x124 +#define BCM43xx_MMIO_GEN_IRQ_REASON 0x128 +#define BCM43xx_MMIO_GEN_IRQ_MASK 0x12C +#define BCM43xx_MMIO_RAM_CONTROL 0x130 +#define BCM43xx_MMIO_RAM_DATA 0x134 +#define BCM43xx_MMIO_PS_STATUS 0x140 +#define BCM43xx_MMIO_RADIO_HWENABLED_HI 0x158 +#define BCM43xx_MMIO_SHM_CONTROL 0x160 +#define BCM43xx_MMIO_SHM_DATA 0x164 +#define BCM43xx_MMIO_SHM_DATA_UNALIGNED 0x166 +#define BCM43xx_MMIO_XMITSTAT_0 0x170 +#define BCM43xx_MMIO_XMITSTAT_1 0x174 +#define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ +#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ +#define BCM43xx_MMIO_DMA1_BASE 0x200 +#define BCM43xx_MMIO_DMA2_BASE 0x220 +#define BCM43xx_MMIO_DMA3_BASE 0x240 +#define BCM43xx_MMIO_DMA4_BASE 0x260 +#define BCM43xx_MMIO_PIO1_BASE 0x300 +#define BCM43xx_MMIO_PIO2_BASE 0x310 +#define BCM43xx_MMIO_PIO3_BASE 0x320 +#define BCM43xx_MMIO_PIO4_BASE 0x330 +#define BCM43xx_MMIO_PHY_VER 0x3E0 +#define BCM43xx_MMIO_PHY_RADIO 0x3E2 +#define BCM43xx_MMIO_ANTENNA 0x3E8 +#define BCM43xx_MMIO_CHANNEL 0x3F0 +#define BCM43xx_MMIO_CHANNEL_EXT 0x3F4 +#define BCM43xx_MMIO_RADIO_CONTROL 0x3F6 +#define BCM43xx_MMIO_RADIO_DATA_HIGH 0x3F8 +#define BCM43xx_MMIO_RADIO_DATA_LOW 0x3FA +#define BCM43xx_MMIO_PHY_CONTROL 0x3FC +#define BCM43xx_MMIO_PHY_DATA 0x3FE +#define BCM43xx_MMIO_MACFILTER_CONTROL 0x420 +#define BCM43xx_MMIO_MACFILTER_DATA 0x422 +#define BCM43xx_MMIO_RADIO_HWENABLED_LO 0x49A +#define BCM43xx_MMIO_GPIO_CONTROL 0x49C +#define BCM43xx_MMIO_GPIO_MASK 0x49E +#define BCM43xx_MMIO_TSF_0 0x632 /* core rev < 3 only */ +#define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */ +#define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */ +#define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */ +#define BCM43xx_MMIO_POWERUP_DELAY 0x6A8 + +/* SPROM offsets. */ +#define BCM43xx_SPROM_BASE 0x1000 +#define BCM43xx_SPROM_BOARDFLAGS2 0x1c +#define BCM43xx_SPROM_IL0MACADDR 0x24 +#define BCM43xx_SPROM_ET0MACADDR 0x27 +#define BCM43xx_SPROM_ET1MACADDR 0x2a +#define BCM43xx_SPROM_ETHPHY 0x2d +#define BCM43xx_SPROM_BOARDREV 0x2e +#define BCM43xx_SPROM_PA0B0 0x2f +#define BCM43xx_SPROM_PA0B1 0x30 +#define BCM43xx_SPROM_PA0B2 0x31 +#define BCM43xx_SPROM_WL0GPIO0 0x32 +#define BCM43xx_SPROM_WL0GPIO2 0x33 +#define BCM43xx_SPROM_MAXPWR 0x34 +#define BCM43xx_SPROM_PA1B0 0x35 +#define BCM43xx_SPROM_PA1B1 0x36 +#define BCM43xx_SPROM_PA1B2 0x37 +#define BCM43xx_SPROM_IDL_TSSI_TGT 0x38 +#define BCM43xx_SPROM_BOARDFLAGS 0x39 +#define BCM43xx_SPROM_ANTENNA_GAIN 0x3a +#define BCM43xx_SPROM_VERSION 0x3f + +/* BCM43xx_SPROM_BOARDFLAGS values */ +#define BCM43xx_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ +#define BCM43xx_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ +#define BCM43xx_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */ +#define BCM43xx_BFL_RSSI 0x0008 /* software calculates nrssi slope. */ +#define BCM43xx_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */ +#define BCM43xx_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */ +#define BCM43xx_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */ +#define BCM43xx_BFL_ENETADM 0x0080 /* has ADMtek switch */ +#define BCM43xx_BFL_ENETVLAN 0x0100 /* can do vlan */ +#define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ +#define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */ +#define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */ +#define BCM43xx_BFL_EXTLNA 0x1000 /* has an external LNA */ +#define BCM43xx_BFL_HGPA 0x2000 /* had high gain PA */ +#define BCM43xx_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ +#define BCM43xx_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ + +/* GPIO register offset, in both ChipCommon and PCI core. */ +#define BCM43xx_GPIO_CONTROL 0x6c + +/* SHM Routing */ +#define BCM43xx_SHM_SHARED 0x0001 +#define BCM43xx_SHM_WIRELESS 0x0002 +#define BCM43xx_SHM_PCM 0x0003 +#define BCM43xx_SHM_HWMAC 0x0004 +#define BCM43xx_SHM_UCODE 0x0300 + +/* MacFilter offsets. */ +#define BCM43xx_MACFILTER_SELF 0x0000 +#define BCM43xx_MACFILTER_ASSOC 0x0003 + +/* Chipcommon registers. */ +#define BCM43xx_CHIPCOMMON_CAPABILITIES 0x04 +#define BCM43xx_CHIPCOMMON_PLLONDELAY 0xB0 +#define BCM43xx_CHIPCOMMON_FREFSELDELAY 0xB4 +#define BCM43xx_CHIPCOMMON_SLOWCLKCTL 0xB8 +#define BCM43xx_CHIPCOMMON_SYSCLKCTL 0xC0 + +/* PCI core specific registers. */ +#define BCM43xx_PCICORE_BCAST_ADDR 0x50 +#define BCM43xx_PCICORE_BCAST_DATA 0x54 +#define BCM43xx_PCICORE_SBTOPCI2 0x108 + +/* SBTOPCI2 values. */ +#define BCM43xx_SBTOPCI2_PREFETCH 0x4 +#define BCM43xx_SBTOPCI2_BURST 0x8 + +/* Chipcommon capabilities. */ +#define BCM43xx_CAPABILITIES_PCTL 0x00040000 +#define BCM43xx_CAPABILITIES_PLLMASK 0x00030000 +#define BCM43xx_CAPABILITIES_PLLSHIFT 16 +#define BCM43xx_CAPABILITIES_FLASHMASK 0x00000700 +#define BCM43xx_CAPABILITIES_FLASHSHIFT 8 +#define BCM43xx_CAPABILITIES_EXTBUSPRESENT 0x00000040 +#define BCM43xx_CAPABILITIES_UARTGPIO 0x00000020 +#define BCM43xx_CAPABILITIES_UARTCLOCKMASK 0x00000018 +#define BCM43xx_CAPABILITIES_UARTCLOCKSHIFT 3 +#define BCM43xx_CAPABILITIES_MIPSBIGENDIAN 0x00000004 +#define BCM43xx_CAPABILITIES_NRUARTSMASK 0x00000003 + +/* PowerControl */ +#define BCM43xx_PCTL_IN 0xB0 +#define BCM43xx_PCTL_OUT 0xB4 +#define BCM43xx_PCTL_OUTENABLE 0xB8 +#define BCM43xx_PCTL_XTAL_POWERUP 0x40 +#define BCM43xx_PCTL_PLL_POWERDOWN 0x80 + +/* PowerControl Clock Modes */ +#define BCM43xx_PCTL_CLK_FAST 0x00 +#define BCM43xx_PCTL_CLK_SLOW 0x01 +#define BCM43xx_PCTL_CLK_DYNAMIC 0x02 + +#define BCM43xx_PCTL_FORCE_SLOW 0x0800 +#define BCM43xx_PCTL_FORCE_PLL 0x1000 +#define BCM43xx_PCTL_DYN_XTAL 0x2000 + +/* COREIDs */ +#define BCM43xx_COREID_CHIPCOMMON 0x800 +#define BCM43xx_COREID_ILINE20 0x801 +#define BCM43xx_COREID_SDRAM 0x803 +#define BCM43xx_COREID_PCI 0x804 +#define BCM43xx_COREID_MIPS 0x805 +#define BCM43xx_COREID_ETHERNET 0x806 +#define BCM43xx_COREID_V90 0x807 +#define BCM43xx_COREID_USB11_HOSTDEV 0x80a +#define BCM43xx_COREID_IPSEC 0x80b +#define BCM43xx_COREID_PCMCIA 0x80d +#define BCM43xx_COREID_EXT_IF 0x80f +#define BCM43xx_COREID_80211 0x812 +#define BCM43xx_COREID_MIPS_3302 0x816 +#define BCM43xx_COREID_USB11_HOST 0x817 +#define BCM43xx_COREID_USB11_DEV 0x818 +#define BCM43xx_COREID_USB20_HOST 0x819 +#define BCM43xx_COREID_USB20_DEV 0x81a +#define BCM43xx_COREID_SDIO_HOST 0x81b + +/* Core Information Registers */ +#define BCM43xx_CIR_BASE 0xf00 +#define BCM43xx_CIR_SBTPSFLAG (BCM43xx_CIR_BASE + 0x18) +#define BCM43xx_CIR_SBIMSTATE (BCM43xx_CIR_BASE + 0x90) +#define BCM43xx_CIR_SBINTVEC (BCM43xx_CIR_BASE + 0x94) +#define BCM43xx_CIR_SBTMSTATELOW (BCM43xx_CIR_BASE + 0x98) +#define BCM43xx_CIR_SBTMSTATEHIGH (BCM43xx_CIR_BASE + 0x9c) +#define BCM43xx_CIR_SBIMCONFIGLOW (BCM43xx_CIR_BASE + 0xa8) +#define BCM43xx_CIR_SB_ID_HI (BCM43xx_CIR_BASE + 0xfc) + +/* Mask to get the Backplane Flag Number from SBTPSFLAG. */ +#define BCM43xx_BACKPLANE_FLAG_NR_MASK 0x3f + +/* SBIMCONFIGLOW values/masks. */ +#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK 0x00000007 +#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT 0 +#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK 0x00000070 +#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT 4 +#define BCM43xx_SBIMCONFIGLOW_CONNID_MASK 0x00ff0000 +#define BCM43xx_SBIMCONFIGLOW_CONNID_SHIFT 16 + +/* sbtmstatelow state flags */ +#define BCM43xx_SBTMSTATELOW_RESET 0x01 +#define BCM43xx_SBTMSTATELOW_REJECT 0x02 +#define BCM43xx_SBTMSTATELOW_CLOCK 0x10000 +#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 + +/* sbtmstatehigh state flags */ +#define BCM43xx_SBTMSTATEHIGH_SERROR 0x1 +#define BCM43xx_SBTMSTATEHIGH_BUSY 0x4 + +/* sbimstate flags */ +#define BCM43xx_SBIMSTATE_IB_ERROR 0x20000 +#define BCM43xx_SBIMSTATE_TIMEOUT 0x40000 + +/* PHYVersioning */ +#define BCM43xx_PHYTYPE_A 0x00 +#define BCM43xx_PHYTYPE_B 0x01 +#define BCM43xx_PHYTYPE_G 0x02 + +/* PHYRegisters */ +#define BCM43xx_PHY_ILT_A_CTRL 0x0072 +#define BCM43xx_PHY_ILT_A_DATA1 0x0073 +#define BCM43xx_PHY_ILT_A_DATA2 0x0074 +#define BCM43xx_PHY_G_LO_CONTROL 0x0810 +#define BCM43xx_PHY_ILT_G_CTRL 0x0472 +#define BCM43xx_PHY_ILT_G_DATA1 0x0473 +#define BCM43xx_PHY_ILT_G_DATA2 0x0474 +#define BCM43xx_PHY_A_PCTL 0x007B +#define BCM43xx_PHY_G_PCTL 0x0029 +#define BCM43xx_PHY_A_CRS 0x0029 +#define BCM43xx_PHY_RADIO_BITFIELD 0x0401 +#define BCM43xx_PHY_G_CRS 0x0429 +#define BCM43xx_PHY_NRSSILT_CTRL 0x0803 +#define BCM43xx_PHY_NRSSILT_DATA 0x0804 + +/* RadioRegisters */ +#define BCM43xx_RADIOCTL_ID 0x01 + +/* StatusBitField */ +#define BCM43xx_SBF_MAC_ENABLED 0x00000001 +#define BCM43xx_SBF_2 0x00000002 /*FIXME: fix name*/ +#define BCM43xx_SBF_CORE_READY 0x00000004 +#define BCM43xx_SBF_400 0x00000400 /*FIXME: fix name*/ +#define BCM43xx_SBF_4000 0x00004000 /*FIXME: fix name*/ +#define BCM43xx_SBF_8000 0x00008000 /*FIXME: fix name*/ +#define BCM43xx_SBF_XFER_REG_BYTESWAP 0x00010000 +#define BCM43xx_SBF_MODE_NOTADHOC 0x00020000 +#define BCM43xx_SBF_MODE_AP 0x00040000 +#define BCM43xx_SBF_RADIOREG_LOCK 0x00080000 +#define BCM43xx_SBF_MODE_MONITOR 0x00400000 +#define BCM43xx_SBF_MODE_PROMISC 0x01000000 +#define BCM43xx_SBF_PS1 0x02000000 +#define BCM43xx_SBF_PS2 0x04000000 +#define BCM43xx_SBF_NO_SSID_BCAST 0x08000000 +#define BCM43xx_SBF_TIME_UPDATE 0x10000000 +#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/ + +/* MicrocodeFlagsBitfield (addr + lo-word values?)*/ +#define BCM43xx_UCODEFLAGS_OFFSET 0x005E + +#define BCM43xx_UCODEFLAG_AUTODIV 0x0001 +#define BCM43xx_UCODEFLAG_UNKBGPHY 0x0002 +#define BCM43xx_UCODEFLAG_UNKBPHY 0x0004 +#define BCM43xx_UCODEFLAG_UNKGPHY 0x0020 +#define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040 +#define BCM43xx_UCODEFLAG_JAPAN 0x0080 + +/* Generic-Interrupt reasons. */ +#define BCM43xx_IRQ_READY (1 << 0) +#define BCM43xx_IRQ_BEACON (1 << 1) +#define BCM43xx_IRQ_PS (1 << 2) +#define BCM43xx_IRQ_REG124 (1 << 5) +#define BCM43xx_IRQ_PMQ (1 << 6) +#define BCM43xx_IRQ_PIO_WORKAROUND (1 << 8) +#define BCM43xx_IRQ_XMIT_ERROR (1 << 11) +#define BCM43xx_IRQ_RX (1 << 15) +#define BCM43xx_IRQ_SCAN (1 << 16) +#define BCM43xx_IRQ_NOISE (1 << 18) +#define BCM43xx_IRQ_XMIT_STATUS (1 << 29) + +#define BCM43xx_IRQ_ALL 0xffffffff +#define BCM43xx_IRQ_INITIAL (BCM43xx_IRQ_PS | \ + BCM43xx_IRQ_REG124 | \ + BCM43xx_IRQ_PMQ | \ + BCM43xx_IRQ_XMIT_ERROR | \ + BCM43xx_IRQ_RX | \ + BCM43xx_IRQ_SCAN | \ + BCM43xx_IRQ_NOISE | \ + BCM43xx_IRQ_XMIT_STATUS) + + +/* Initial default iw_mode */ +#define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA + +/* Bus type PCI. */ +#define BCM43xx_BUSTYPE_PCI 0 +/* Bus type Silicone Backplane Bus. */ +#define BCM43xx_BUSTYPE_SB 1 +/* Bus type PCMCIA. */ +#define BCM43xx_BUSTYPE_PCMCIA 2 + +/* Threshold values. */ +#define BCM43xx_MIN_RTS_THRESHOLD 1U +#define BCM43xx_MAX_RTS_THRESHOLD 2304U +#define BCM43xx_DEFAULT_RTS_THRESHOLD BCM43xx_MAX_RTS_THRESHOLD + +#define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT 7 +#define BCM43xx_DEFAULT_LONG_RETRY_LIMIT 4 + +/* Max size of a security key */ +#define BCM43xx_SEC_KEYSIZE 16 +/* Security algorithms. */ +enum { + BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ + BCM43xx_SEC_ALGO_WEP, + BCM43xx_SEC_ALGO_UNKNOWN, + BCM43xx_SEC_ALGO_AES, + BCM43xx_SEC_ALGO_WEP104, + BCM43xx_SEC_ALGO_TKIP, +}; + +#ifdef assert +# undef assert +#endif +#ifdef CONFIG_BCM43XX_DEBUG +#define assert(expr) \ + do { \ + if (unlikely(!(expr))) { \ + printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", \ + #expr, __FILE__, __LINE__, __FUNCTION__); \ + } \ + } while (0) +#else +#define assert(expr) do { /* nothing */ } while (0) +#endif + +/* rate limited printk(). */ +#ifdef printkl +# undef printkl +#endif +#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0) +/* rate limited printk() for debugging */ +#ifdef dprintkl +# undef dprintkl +#endif +#ifdef CONFIG_BCM43XX_DEBUG +# define dprintkl printkl +#else +# define dprintkl(f, x...) do { /* nothing */ } while (0) +#endif + +/* Helper macro for if branches. + * An if branch marked with this macro is only taken in DEBUG mode. + * Example: + * if (DEBUG_ONLY(foo == bar)) { + * do something + * } + * In DEBUG mode, the branch will be taken if (foo == bar). + * In non-DEBUG mode, the branch will never be taken. + */ +#ifdef DEBUG_ONLY +# undef DEBUG_ONLY +#endif +#ifdef CONFIG_BCM43XX_DEBUG +# define DEBUG_ONLY(x) (x) +#else +# define DEBUG_ONLY(x) 0 +#endif + +/* debugging printk() */ +#ifdef dprintk +# undef dprintk +#endif +#ifdef CONFIG_BCM43XX_DEBUG +# define dprintk(f, x...) do { printk(f ,##x); } while (0) +#else +# define dprintk(f, x...) do { /* nothing */ } while (0) +#endif + + +struct net_device; +struct pci_dev; +struct bcm43xx_dmaring; +struct bcm43xx_pioqueue; + +struct bcm43xx_initval { + u16 offset; + u16 size; + u32 value; +} __attribute__((__packed__)); + +/* Values for bcm430x_sprominfo.locale */ +enum { + BCM43xx_LOCALE_WORLD = 0, + BCM43xx_LOCALE_THAILAND, + BCM43xx_LOCALE_ISRAEL, + BCM43xx_LOCALE_JORDAN, + BCM43xx_LOCALE_CHINA, + BCM43xx_LOCALE_JAPAN, + BCM43xx_LOCALE_USA_CANADA_ANZ, + BCM43xx_LOCALE_EUROPE, + BCM43xx_LOCALE_USA_LOW, + BCM43xx_LOCALE_JAPAN_HIGH, + BCM43xx_LOCALE_ALL, + BCM43xx_LOCALE_NONE, +}; + +#define BCM43xx_SPROM_SIZE 64 /* in 16-bit words. */ +struct bcm43xx_sprominfo { + u16 boardflags2; + u8 il0macaddr[6]; + u8 et0macaddr[6]; + u8 et1macaddr[6]; + u8 et0phyaddr:5; + u8 et1phyaddr:5; + u8 et0mdcport:1; + u8 et1mdcport:1; + u8 boardrev; + u8 locale:4; + u8 antennas_aphy:2; + u8 antennas_bgphy:2; + u16 pa0b0; + u16 pa0b1; + u16 pa0b2; + u8 wl0gpio0; + u8 wl0gpio1; + u8 wl0gpio2; + u8 wl0gpio3; + u8 maxpower_aphy; + u8 maxpower_bgphy; + u16 pa1b0; + u16 pa1b1; + u16 pa1b2; + u8 idle_tssi_tgt_aphy; + u8 idle_tssi_tgt_bgphy; + u16 boardflags; + u16 antennagain_aphy; + u16 antennagain_bgphy; +}; + +/* Value pair to measure the LocalOscillator. */ +struct bcm43xx_lopair { + s8 low; + s8 high; + u8 used:1; +}; +#define BCM43xx_LO_COUNT (14*4) + +struct bcm43xx_phyinfo { + /* Hardware Data */ + u8 version; + u8 type; + u8 rev; + u16 antenna_diversity; + u16 savedpctlreg; + u16 minlowsig[2]; + u16 minlowsigpos[2]; + u8 connected:1, + calibrated:1, + is_locked:1, /* used in bcm43xx_phy_{un}lock() */ + dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */ + /* LO Measurement Data. + * Use bcm43xx_get_lopair() to get a value. + */ + struct bcm43xx_lopair *_lo_pairs; + + /* TSSI to dBm table in use */ + const s8 *tssi2dbm; + /* idle TSSI value */ + s8 idle_tssi; + + /* Values from bcm43xx_calc_loopback_gain() */ + u16 loopback_gain[2]; + + /* PHY lock for core.rev < 3 + * This lock is only used by bcm43xx_phy_{un}lock() + */ + spinlock_t lock; +}; + + +struct bcm43xx_radioinfo { + u16 manufact; + u16 version; + u8 revision; + + /* Desired TX power in dBm Q5.2 */ + u16 txpower_desired; + /* TX Power control values. */ + union { + /* B/G PHY */ + struct { + u16 baseband_atten; + u16 radio_atten; + u16 txctl1; + u16 txctl2; + }; + /* A PHY */ + struct { + u16 txpwr_offset; + }; + }; + + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define BCM43xx_INTERFSTACK_SIZE 26 + u32 interfstack[BCM43xx_INTERFSTACK_SIZE]; + + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + /* current channel */ + u8 channel; + u8 initial_channel; + + u16 lofcal; + + u16 initval; + + u8 enabled:1; + /* ACI (adjacent channel interference) flags. */ + u8 aci_enable:1, + aci_wlan_automatic:1, + aci_hw_rssi:1; +}; + +/* Data structures for DMA transmission, per 80211 core. */ +struct bcm43xx_dma { + struct bcm43xx_dmaring *tx_ring0; + struct bcm43xx_dmaring *tx_ring1; + struct bcm43xx_dmaring *tx_ring2; + struct bcm43xx_dmaring *tx_ring3; + struct bcm43xx_dmaring *rx_ring0; + struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */ +}; + +/* Data structures for PIO transmission, per 80211 core. */ +struct bcm43xx_pio { + struct bcm43xx_pioqueue *queue0; + struct bcm43xx_pioqueue *queue1; + struct bcm43xx_pioqueue *queue2; + struct bcm43xx_pioqueue *queue3; +}; + +#define BCM43xx_MAX_80211_CORES 2 + +#ifdef CONFIG_BCM947XX +#define core_offset(bcm) (bcm)->current_core_offset +#else +#define core_offset(bcm) 0 +#endif + +/* Generic information about a core. */ +struct bcm43xx_coreinfo { + u8 available:1, + enabled:1, + initialized:1; + /** core_id ID number */ + u16 id; + /** core_rev revision number */ + u8 rev; + /** Index number for _switch_core() */ + u8 index; +}; + +/* Additional information for each 80211 core. */ +struct bcm43xx_coreinfo_80211 { + /* PHY device. */ + struct bcm43xx_phyinfo phy; + /* Radio device. */ + struct bcm43xx_radioinfo radio; + union { + /* DMA context. */ + struct bcm43xx_dma dma; + /* PIO context. */ + struct bcm43xx_pio pio; + }; +}; + +/* Context information for a noise calculation (Link Quality). */ +struct bcm43xx_noise_calculation { + struct bcm43xx_coreinfo *core_at_start; + u8 channel_at_start; + u8 calculation_running:1; + u8 nr_samples; + s8 samples[8][4]; +}; + +struct bcm43xx_stats { + u8 link_quality; + u8 noise; + struct iw_statistics wstats; + /* Store the last TX/RX times here for updating the leds. */ + unsigned long last_tx; + unsigned long last_rx; +}; + +struct bcm43xx_key { + u8 enabled:1; + u8 algorithm; +}; + +struct bcm43xx_private { + struct bcm43xx_sysfs sysfs; + + struct ieee80211_device *ieee; + struct ieee80211softmac_device *softmac; + + struct net_device *net_dev; + struct pci_dev *pci_dev; + unsigned int irq; + + void __iomem *mmio_addr; + unsigned int mmio_len; + + /* Do not use the lock directly. Use the bcm43xx_lock* helper + * functions, to be MMIO-safe. */ + spinlock_t _lock; + + /* Driver status flags. */ + u32 initialized:1, /* init_board() succeed */ + was_initialized:1, /* for PCI suspend/resume. */ + shutting_down:1, /* free_board() in progress */ + __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ + bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ + reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ + powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ + short_preamble:1, /* TRUE, if short preamble is enabled. */ + firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ + + struct bcm43xx_stats stats; + + /* Bus type we are connected to. + * This is currently always BCM43xx_BUSTYPE_PCI + */ + u8 bustype; + + u16 board_vendor; + u16 board_type; + u16 board_revision; + + u16 chip_id; + u8 chip_rev; + u8 chip_package; + + struct bcm43xx_sprominfo sprom; +#define BCM43xx_NR_LEDS 4 + struct bcm43xx_led leds[BCM43xx_NR_LEDS]; + + /* The currently active core. */ + struct bcm43xx_coreinfo *current_core; +#ifdef CONFIG_BCM947XX + /** current core memory offset */ + u32 current_core_offset; +#endif + struct bcm43xx_coreinfo *active_80211_core; + /* coreinfo structs for all possible cores follow. + * Note that a core might not exist. + * So check the coreinfo flags before using it. + */ + struct bcm43xx_coreinfo core_chipcommon; + struct bcm43xx_coreinfo core_pci; + struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; + /* Additional information, specific to the 80211 cores. */ + struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; + /* Index of the current 80211 core. If current_core is not + * an 80211 core, this is -1. + */ + int current_80211_core_idx; + /* Number of available 80211 cores. */ + int nr_80211_available; + + u32 chipcommon_capabilities; + + /* Reason code of the last interrupt. */ + u32 irq_reason; + u32 dma_reason[4]; + /* saved irq enable/disable state bitfield. */ + u32 irq_savedstate; + /* Link Quality calculation context. */ + struct bcm43xx_noise_calculation noisecalc; + + /* Threshold values. */ + //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. + u32 rts_threshold; + + /* Interrupt Service Routine tasklet (bottom-half) */ + struct tasklet_struct isr_tasklet; + + /* Periodic tasks */ + struct timer_list periodic_tasks; + unsigned int periodic_state; + + struct work_struct restart_work; + + /* Informational stuff. */ + char nick[IW_ESSID_MAX_SIZE + 1]; + + /* encryption/decryption */ + u16 security_offset; + struct bcm43xx_key key[54]; + u8 default_key_idx; + + /* Firmware. */ + const struct firmware *ucode; + const struct firmware *pcm; + const struct firmware *initvals0; + const struct firmware *initvals1; + + /* Debugging stuff follows. */ +#ifdef CONFIG_BCM43XX_DEBUG + struct bcm43xx_dfsentry *dfsentry; +#endif +}; + +/* bcm43xx_(un)lock() protect struct bcm43xx_private. + * Note that _NO_ MMIO writes are allowed. If you want to + * write to the device through MMIO in the critical section, use + * the *_mmio lock functions. + * MMIO read-access is allowed, though. + */ +#define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags) +#define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags) +/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO. + * MMIO write-access to the device is allowed. + * All MMIO writes are flushed on unlock, so it is guaranteed to not + * interfere with other threads writing MMIO registers. + */ +#define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags) +#define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0) + +static inline +struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) +{ + return ieee80211softmac_priv(dev); +} + + +/* Helper function, which returns a boolean. + * TRUE, if PIO is used; FALSE, if DMA is used. + */ +#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) +static inline +int bcm43xx_using_pio(struct bcm43xx_private *bcm) +{ + return bcm->__using_pio; +} +#elif defined(CONFIG_BCM43XX_DMA) +static inline +int bcm43xx_using_pio(struct bcm43xx_private *bcm) +{ + return 0; +} +#elif defined(CONFIG_BCM43XX_PIO) +static inline +int bcm43xx_using_pio(struct bcm43xx_private *bcm) +{ + return 1; +} +#else +# error "Using neither DMA nor PIO? Confused..." +#endif + +/* Helper functions to access data structures private to the 80211 cores. + * Note that we _must_ have an 80211 core mapped when calling + * any of these functions. + */ +static inline +struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) +{ + assert(bcm43xx_using_pio(bcm)); + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio); +} +static inline +struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) +{ + assert(!bcm43xx_using_pio(bcm)); + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma); +} +static inline +struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) +{ + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy); +} +static inline +struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) +{ + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); +} + +/* Are we running in init_board() context? */ +static inline +int bcm43xx_is_initializing(struct bcm43xx_private *bcm) +{ + if (bcm->initialized) + return 0; + if (bcm->shutting_down) + return 0; + return 1; +} + +static inline +struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, + u16 radio_attenuation, + u16 baseband_attenuation) +{ + return phy->_lo_pairs + (radio_attenuation + 14 * (baseband_attenuation / 2)); +} + + +static inline +u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset) +{ + return ioread16(bcm->mmio_addr + core_offset(bcm) + offset); +} + +static inline +void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value) +{ + iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset); +} + +static inline +u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset) +{ + return ioread32(bcm->mmio_addr + core_offset(bcm) + offset); +} + +static inline +void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value) +{ + iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset); +} + +static inline +int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value) +{ + return pci_read_config_word(bcm->pci_dev, offset, value); +} + +static inline +int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value) +{ + return pci_read_config_dword(bcm->pci_dev, offset, value); +} + +static inline +int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value) +{ + return pci_write_config_word(bcm->pci_dev, offset, value); +} + +static inline +int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value) +{ + return pci_write_config_dword(bcm->pci_dev, offset, value); +} + +/** Limit a value between two limits */ +#ifdef limit_value +# undef limit_value +#endif +#define limit_value(value, min, max) \ + ({ \ + typeof(value) __value = (value); \ + typeof(value) __min = (min); \ + typeof(value) __max = (max); \ + if (__value < __min) \ + __value = __min; \ + else if (__value > __max) \ + __value = __max; \ + __value; \ + }) + +/** Helpers to print MAC addresses. */ +#define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \ + ((u8*)(x))[2], ((u8*)(x))[3], \ + ((u8*)(x))[4], ((u8*)(x))[5] + +#endif /* BCM43xx_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c new file mode 100644 index 000000000000..d2c3401e9b70 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -0,0 +1,499 @@ +/* + + Broadcom BCM43xx wireless driver + + debugfs driver debugging code + + Copyright (c) 2005 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + + + +#include +#include +#include +#include +#include +#include + +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_debugfs.h" +#include "bcm43xx_dma.h" +#include "bcm43xx_pio.h" +#include "bcm43xx_xmit.h" + +#define REALLY_BIG_BUFFER_SIZE (1024*256) + +static struct bcm43xx_debugfs fs; +static char really_big_buffer[REALLY_BIG_BUFFER_SIZE]; +static DECLARE_MUTEX(big_buffer_sem); + + +static ssize_t write_file_dummy(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return count; +} + +static int open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->u.generic_ip; + return 0; +} + +#define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x) + +static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + struct net_device *net_dev; + struct pci_dev *pci_dev; + unsigned long flags; + u16 tmp16; + int i; + + down(&big_buffer_sem); + + bcm43xx_lock_mmio(bcm, flags); + if (!bcm->initialized) { + fappend("Board not initialized.\n"); + goto out; + } + net_dev = bcm->net_dev; + pci_dev = bcm->pci_dev; + + /* This is where the information is written to the "devinfo" file */ + fappend("*** %s devinfo ***\n", net_dev->name); + fappend("vendor: 0x%04x device: 0x%04x\n", + pci_dev->vendor, pci_dev->device); + fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n", + pci_dev->subsystem_vendor, pci_dev->subsystem_device); + fappend("IRQ: %d\n", bcm->irq); + fappend("mmio_addr: 0x%p mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len); + fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev); + if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16))) + fappend("Radio disabled by hardware!\n"); + if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4))) + fappend("Radio disabled by hardware!\n"); + fappend("board_vendor: 0x%04x board_type: 0x%04x\n", bcm->board_vendor, + bcm->board_type); + + fappend("\nCores:\n"); +#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \ + "rev: 0x%02x, index: 0x%02x\n", \ + (info).available \ + ? "available" : "nonavailable", \ + (info).enabled \ + ? "enabled" : "disabled", \ + (info).id, (info).rev, (info).index) + fappend_core("CHIPCOMMON", bcm->core_chipcommon); + fappend_core("PCI", bcm->core_pci); + fappend_core("first 80211", bcm->core_80211[0]); + fappend_core("second 80211", bcm->core_80211[1]); +#undef fappend_core + tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + fappend("LEDs: "); + for (i = 0; i < BCM43xx_NR_LEDS; i++) + fappend("%d ", !!(tmp16 & (1 << i))); + fappend("\n"); + +out: + bcm43xx_unlock_mmio(bcm, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + + down(&big_buffer_sem); + + /* This is where the information is written to the "driver" file */ + fappend(KBUILD_MODNAME " driver\n"); + fappend("Compiled at: %s %s\n", __DATE__, __TIME__); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + + down(&big_buffer_sem); + bcm43xx_lock_mmio(bcm, flags); + if (!bcm->initialized) { + fappend("Board not initialized.\n"); + goto out; + } + + /* This is where the information is written to the "sprom_dump" file */ + fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); + +out: + bcm43xx_unlock_mmio(bcm, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t tsf_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + u64 tsf; + + down(&big_buffer_sem); + bcm43xx_lock_mmio(bcm, flags); + if (!bcm->initialized) { + fappend("Board not initialized.\n"); + goto out; + } + bcm43xx_tsf_read(bcm, &tsf); + fappend("0x%08x%08x\n", + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(tsf & 0xFFFFFFFFULL)); + +out: + bcm43xx_unlock_mmio(bcm, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + ssize_t buf_size; + ssize_t res; + unsigned long flags; + u64 tsf; + + buf_size = min(count, sizeof (really_big_buffer) - 1); + down(&big_buffer_sem); + if (copy_from_user(buf, user_buf, buf_size)) { + res = -EFAULT; + goto out_up; + } + bcm43xx_lock_mmio(bcm, flags); + if (!bcm->initialized) { + printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); + res = -EFAULT; + goto out_unlock; + } + if (sscanf(buf, "%lli", &tsf) != 1) { + printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n"); + res = -EINVAL; + goto out_unlock; + } + bcm43xx_tsf_write(bcm, tsf); + res = buf_size; + +out_unlock: + bcm43xx_unlock_mmio(bcm, flags); +out_up: + up(&big_buffer_sem); + return res; +} + +static ssize_t txstat_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + struct bcm43xx_dfsentry *e; + struct bcm43xx_xmitstatus *status; + int i, cnt, j = 0; + + down(&big_buffer_sem); + bcm43xx_lock(bcm, flags); + + fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", + BCM43xx_NR_LOGGED_XMITSTATUS); + e = bcm->dfsentry; + if (e->xmitstatus_printing == 0) { + /* At the beginning, make a copy of all data to avoid + * concurrency, as this function is called multiple + * times for big logs. Without copying, the data might + * change between reads. This would result in total trash. + */ + e->xmitstatus_printing = 1; + e->saved_xmitstatus_ptr = e->xmitstatus_ptr; + e->saved_xmitstatus_cnt = e->xmitstatus_cnt; + memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer, + BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer))); + } + i = e->saved_xmitstatus_ptr - 1; + if (i < 0) + i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; + cnt = e->saved_xmitstatus_cnt; + while (cnt) { + status = e->xmitstatus_print_buffer + i; + fappend("0x%02x: cookie: 0x%04x, flags: 0x%02x, " + "cnt1: 0x%02x, cnt2: 0x%02x, seq: 0x%04x, " + "unk: 0x%04x\n", j, + status->cookie, status->flags, + status->cnt1, status->cnt2, status->seq, + status->unknown); + j++; + cnt--; + i--; + if (i < 0) + i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; + } + + bcm43xx_unlock(bcm, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + bcm43xx_lock(bcm, flags); + if (*ppos == pos) { + /* Done. Drop the copied data. */ + e->xmitstatus_printing = 0; + } + bcm43xx_unlock(bcm, flags); + up(&big_buffer_sem); + return res; +} + +#undef fappend + + +static struct file_operations devinfo_fops = { + .read = devinfo_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + +static struct file_operations spromdump_fops = { + .read = spromdump_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + +static struct file_operations drvinfo_fops = { + .read = drvinfo_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + +static struct file_operations tsf_fops = { + .read = tsf_read_file, + .write = tsf_write_file, + .open = open_file_generic, +}; + +static struct file_operations txstat_fops = { + .read = txstat_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + + +void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dfsentry *e; + char devdir[IFNAMSIZ]; + + assert(bcm); + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) { + printk(KERN_ERR PFX "out of memory\n"); + return; + } + e->bcm = bcm; + e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS + * sizeof(*(e->xmitstatus_buffer)), + GFP_KERNEL); + if (!e->xmitstatus_buffer) { + printk(KERN_ERR PFX "out of memory\n"); + kfree(e); + return; + } + e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS + * sizeof(*(e->xmitstatus_buffer)), + GFP_KERNEL); + if (!e->xmitstatus_print_buffer) { + printk(KERN_ERR PFX "out of memory\n"); + kfree(e); + return; + } + + + bcm->dfsentry = e; + + strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir)); + e->subdir = debugfs_create_dir(devdir, fs.root); + e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir, + bcm, &devinfo_fops); + if (!e->dentry_devinfo) + printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir); + e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir, + bcm, &spromdump_fops); + if (!e->dentry_spromdump) + printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir); + e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir, + bcm, &tsf_fops); + if (!e->dentry_tsf) + printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir); + e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir, + bcm, &txstat_fops); + if (!e->dentry_txstat) + printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); +} + +void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dfsentry *e; + + if (!bcm) + return; + + e = bcm->dfsentry; + assert(e); + debugfs_remove(e->dentry_spromdump); + debugfs_remove(e->dentry_devinfo); + debugfs_remove(e->dentry_tsf); + debugfs_remove(e->dentry_txstat); + debugfs_remove(e->subdir); + kfree(e->xmitstatus_buffer); + kfree(e->xmitstatus_print_buffer); + kfree(e); +} + +void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ + struct bcm43xx_dfsentry *e; + struct bcm43xx_xmitstatus *savedstatus; + + /* This is protected by bcm->_lock */ + e = bcm->dfsentry; + assert(e); + savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr; + memcpy(savedstatus, status, sizeof(*status)); + e->xmitstatus_ptr++; + if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS) + e->xmitstatus_ptr = 0; + if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS) + e->xmitstatus_cnt++; +} + +void bcm43xx_debugfs_init(void) +{ + memset(&fs, 0, sizeof(fs)); + fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!fs.root) + printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n"); + fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops); + if (!fs.dentry_driverinfo) + printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n"); +} + +void bcm43xx_debugfs_exit(void) +{ + debugfs_remove(fs.dentry_driverinfo); + debugfs_remove(fs.root); +} + +void bcm43xx_printk_dump(const char *data, + size_t size, + const char *description) +{ + size_t i; + char c; + + printk(KERN_INFO PFX "Data dump (%s, %u bytes):", + description, size); + for (i = 0; i < size; i++) { + c = data[i]; + if (i % 8 == 0) + printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff); + else + printk("0x%02x, ", c & 0xff); + } + printk("\n"); +} + +void bcm43xx_printk_bitdump(const unsigned char *data, + size_t bytes, int msb_to_lsb, + const char *description) +{ + size_t i; + int j; + const unsigned char *d; + + printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***", + description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB"); + for (i = 0; i < bytes; i++) { + d = data + i; + if (i % 8 == 0) + printk("\n" KERN_INFO PFX "0x%08x: ", i); + if (msb_to_lsb) { + for (j = 7; j >= 0; j--) { + if (*d & (1 << j)) + printk("1"); + else + printk("0"); + } + } else { + for (j = 0; j < 8; j++) { + if (*d & (1 << j)) + printk("1"); + else + printk("0"); + } + } + printk(" "); + } + printk("\n"); +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h new file mode 100644 index 000000000000..50ce267f794d --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h @@ -0,0 +1,117 @@ +#ifndef BCM43xx_DEBUGFS_H_ +#define BCM43xx_DEBUGFS_H_ + +struct bcm43xx_private; +struct bcm43xx_xmitstatus; + +#ifdef CONFIG_BCM43XX_DEBUG + +#include +#include + +struct dentry; + +/* limited by the size of the "really_big_buffer" */ +#define BCM43xx_NR_LOGGED_XMITSTATUS 100 + +struct bcm43xx_dfsentry { + struct dentry *subdir; + struct dentry *dentry_devinfo; + struct dentry *dentry_spromdump; + struct dentry *dentry_tsf; + struct dentry *dentry_txstat; + + struct bcm43xx_private *bcm; + + /* saved xmitstatus. */ + struct bcm43xx_xmitstatus *xmitstatus_buffer; + int xmitstatus_ptr; + int xmitstatus_cnt; + /* We need a seperate buffer while printing to avoid + * concurrency issues. (New xmitstatus can arrive + * while we are printing). + */ + struct bcm43xx_xmitstatus *xmitstatus_print_buffer; + int saved_xmitstatus_ptr; + int saved_xmitstatus_cnt; + int xmitstatus_printing; +}; + +struct bcm43xx_debugfs { + struct dentry *root; + struct dentry *dentry_driverinfo; +}; + +void bcm43xx_debugfs_init(void); +void bcm43xx_debugfs_exit(void); +void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm); +void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm); +void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status); + +/* Debug helper: Dump binary data through printk. */ +void bcm43xx_printk_dump(const char *data, + size_t size, + const char *description); +/* Debug helper: Dump bitwise binary data through printk. */ +void bcm43xx_printk_bitdump(const unsigned char *data, + size_t bytes, int msb_to_lsb, + const char *description); +#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \ + do { \ + bcm43xx_printk_bitdump((const unsigned char *)(pointer), \ + sizeof(*(pointer)), \ + (msb_to_lsb), \ + (description)); \ + } while (0) + +#else /* CONFIG_BCM43XX_DEBUG*/ + +static inline +void bcm43xx_debugfs_init(void) { } +static inline +void bcm43xx_debugfs_exit(void) { } +static inline +void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { } +static inline +void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) { } +static inline +void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) { } + +static inline +void bcm43xx_printk_dump(const char *data, + size_t size, + const char *description) +{ +} +static inline +void bcm43xx_printk_bitdump(const unsigned char *data, + size_t bytes, int msb_to_lsb, + const char *description) +{ +} +#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) do { /* nothing */ } while (0) + +#endif /* CONFIG_BCM43XX_DEBUG*/ + +/* Ugly helper macros to make incomplete code more verbose on runtime */ +#ifdef TODO +# undef TODO +#endif +#define TODO() \ + do { \ + printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + } while (0) + +#ifdef FIXME +# undef FIXME +#endif +#define FIXME() \ + do { \ + printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + } while (0) + +#endif /* BCM43xx_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c new file mode 100644 index 000000000000..c3681b8f09b4 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -0,0 +1,968 @@ +/* + + Broadcom BCM43xx wireless driver + + DMA ringbuffer and descriptor allocation/management + + Copyright (c) 2005 Michael Buesch + + Some code in this file is derived from the b44.c driver + Copyright (C) 2002 David S. Miller + Copyright (C) Pekka Pietikainen + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_dma.h" +#include "bcm43xx_main.h" +#include "bcm43xx_debugfs.h" +#include "bcm43xx_power.h" +#include "bcm43xx_xmit.h" + +#include +#include +#include +#include + + +static inline int free_slots(struct bcm43xx_dmaring *ring) +{ + return (ring->nr_slots - ring->used_slots); +} + +static inline int next_slot(struct bcm43xx_dmaring *ring, int slot) +{ + assert(slot >= -1 && slot <= ring->nr_slots - 1); + if (slot == ring->nr_slots - 1) + return 0; + return slot + 1; +} + +static inline int prev_slot(struct bcm43xx_dmaring *ring, int slot) +{ + assert(slot >= 0 && slot <= ring->nr_slots - 1); + if (slot == 0) + return ring->nr_slots - 1; + return slot - 1; +} + +/* Request a slot for usage. */ +static inline +int request_slot(struct bcm43xx_dmaring *ring) +{ + int slot; + + assert(ring->tx); + assert(!ring->suspended); + assert(free_slots(ring) != 0); + + slot = next_slot(ring, ring->current_slot); + ring->current_slot = slot; + ring->used_slots++; + + /* Check the number of available slots and suspend TX, + * if we are running low on free slots. + */ + if (unlikely(free_slots(ring) < ring->suspend_mark)) { + netif_stop_queue(ring->bcm->net_dev); + ring->suspended = 1; + } +#ifdef CONFIG_BCM43XX_DEBUG + if (ring->used_slots > ring->max_used_slots) + ring->max_used_slots = ring->used_slots; +#endif /* CONFIG_BCM43XX_DEBUG*/ + + return slot; +} + +/* Return a slot to the free slots. */ +static inline +void return_slot(struct bcm43xx_dmaring *ring, int slot) +{ + assert(ring->tx); + + ring->used_slots--; + + /* Check if TX is suspended and check if we have + * enough free slots to resume it again. + */ + if (unlikely(ring->suspended)) { + if (free_slots(ring) >= ring->resume_mark) { + ring->suspended = 0; + netif_wake_queue(ring->bcm->net_dev); + } + } +} + +static inline +dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring, + unsigned char *buf, + size_t len, + int tx) +{ + dma_addr_t dmaaddr; + + if (tx) { + dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, + buf, len, + DMA_TO_DEVICE); + } else { + dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, + buf, len, + DMA_FROM_DEVICE); + } + + return dmaaddr; +} + +static inline +void unmap_descbuffer(struct bcm43xx_dmaring *ring, + dma_addr_t addr, + size_t len, + int tx) +{ + if (tx) { + dma_unmap_single(&ring->bcm->pci_dev->dev, + addr, len, + DMA_TO_DEVICE); + } else { + dma_unmap_single(&ring->bcm->pci_dev->dev, + addr, len, + DMA_FROM_DEVICE); + } +} + +static inline +void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + assert(!ring->tx); + + dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline +void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + assert(!ring->tx); + + dma_sync_single_for_device(&ring->bcm->pci_dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +/* Unmap and free a descriptor buffer. */ +static inline +void free_descriptor_buffer(struct bcm43xx_dmaring *ring, + struct bcm43xx_dmadesc *desc, + struct bcm43xx_dmadesc_meta *meta, + int irq_context) +{ + assert(meta->skb); + if (irq_context) + dev_kfree_skb_irq(meta->skb); + else + dev_kfree_skb(meta->skb); + meta->skb = NULL; +} + +static int alloc_ringmemory(struct bcm43xx_dmaring *ring) +{ + struct device *dev = &(ring->bcm->pci_dev->dev); + + ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, + &(ring->dmabase), GFP_KERNEL); + if (!ring->vbase) { + printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); + return -ENOMEM; + } + if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G " + "(0x%08x, len: %lu)\n", + ring->dmabase, BCM43xx_DMA_RINGMEMSIZE); + dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, + ring->vbase, ring->dmabase); + return -ENOMEM; + } + assert(!(ring->dmabase & 0x000003FF)); + memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE); + + return 0; +} + +static void free_ringmemory(struct bcm43xx_dmaring *ring) +{ + struct device *dev = &(ring->bcm->pci_dev->dev); + + dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, + ring->vbase, ring->dmabase); +} + +/* Reset the RX DMA channel */ +int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, + u16 mmio_base) +{ + int i; + u32 value; + + bcm43xx_write32(bcm, + mmio_base + BCM43xx_DMA_RX_CONTROL, + 0x00000000); + for (i = 0; i < 1000; i++) { + value = bcm43xx_read32(bcm, + mmio_base + BCM43xx_DMA_RX_STATUS); + value &= BCM43xx_DMA_RXSTAT_STAT_MASK; + if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n"); + return -ENODEV; + } + + return 0; +} + +/* Reset the RX DMA channel */ +int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, + u16 mmio_base) +{ + int i; + u32 value; + + for (i = 0; i < 1000; i++) { + value = bcm43xx_read32(bcm, + mmio_base + BCM43xx_DMA_TX_STATUS); + value &= BCM43xx_DMA_TXSTAT_STAT_MASK; + if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED || + value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT || + value == BCM43xx_DMA_TXSTAT_STAT_STOPPED) + break; + udelay(10); + } + bcm43xx_write32(bcm, + mmio_base + BCM43xx_DMA_TX_CONTROL, + 0x00000000); + for (i = 0; i < 1000; i++) { + value = bcm43xx_read32(bcm, + mmio_base + BCM43xx_DMA_TX_STATUS); + value &= BCM43xx_DMA_TXSTAT_STAT_MASK; + if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n"); + return -ENODEV; + } + /* ensure the reset is completed. */ + udelay(300); + + return 0; +} + +static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, + struct bcm43xx_dmadesc *desc, + struct bcm43xx_dmadesc_meta *meta, + gfp_t gfp_flags) +{ + struct bcm43xx_rxhdr *rxhdr; + dma_addr_t dmaaddr; + u32 desc_addr; + u32 desc_ctl; + const int slot = (int)(desc - ring->vbase); + struct sk_buff *skb; + + assert(slot >= 0 && slot < ring->nr_slots); + assert(!ring->tx); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); + if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) { + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb_any(skb); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G " + "(0x%08x, len: %u)\n", + dmaaddr, ring->rx_buffersize); + return -ENOMEM; + } + meta->skb = skb; + meta->dmaaddr = dmaaddr; + skb->dev = ring->bcm->net_dev; + desc_addr = (u32)(dmaaddr + ring->memoffset); + desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK & + (u32)(ring->rx_buffersize - ring->frameoffset)); + if (slot == ring->nr_slots - 1) + desc_ctl |= BCM43xx_DMADTOR_DTABLEEND; + set_desc_addr(desc, desc_addr); + set_desc_ctl(desc, desc_ctl); + + rxhdr = (struct bcm43xx_rxhdr *)(skb->data); + rxhdr->frame_length = 0; + rxhdr->flags1 = 0; + + return 0; +} + +/* Allocate the initial descbuffers. + * This is used for an RX ring only. + */ +static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) +{ + int i, err = -ENOMEM; + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->vbase + i; + meta = ring->meta + i; + + err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); + if (err) + goto err_unwind; + } + ring->used_slots = ring->nr_slots; + err = 0; +out: + return err; + +err_unwind: + for (i--; i >= 0; i--) { + desc = ring->vbase + i; + meta = ring->meta + i; + + unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb(meta->skb); + } + goto out; +} + +/* Do initial setup of the DMA controller. + * Reset the controller, write the ring busaddress + * and switch the "enable" bit on. + */ +static int dmacontroller_setup(struct bcm43xx_dmaring *ring) +{ + int err = 0; + u32 value; + + if (ring->tx) { + /* Set Transmit Control register to "transmit enable" */ + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, + BCM43xx_DMA_TXCTRL_ENABLE); + /* Set Transmit Descriptor ring address. */ + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, + ring->dmabase + ring->memoffset); + } else { + err = alloc_initial_descbuffers(ring); + if (err) + goto out; + /* Set Receive Control "receive enable" and frame offset */ + value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT); + value |= BCM43xx_DMA_RXCTRL_ENABLE; + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value); + /* Set Receive Descriptor ring address. */ + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, + ring->dmabase + ring->memoffset); + /* Init the descriptor pointer. */ + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200); + } + +out: + return err; +} + +/* Shutdown the DMA controller. */ +static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) +{ + if (ring->tx) { + bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); + /* Zero out Transmit Descriptor ring address. */ + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0); + } else { + bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); + /* Zero out Receive Descriptor ring address. */ + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0); + } +} + +static void free_all_descbuffers(struct bcm43xx_dmaring *ring) +{ + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + int i; + + if (!ring->used_slots) + return; + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->vbase + i; + meta = ring->meta + i; + + if (!meta->skb) { + assert(ring->tx); + continue; + } + if (ring->tx) { + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); + } else { + unmap_descbuffer(ring, meta->dmaaddr, + ring->rx_buffersize, 0); + } + free_descriptor_buffer(ring, desc, meta, 0); + } +} + +/* Main initialization function. */ +static +struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, + u16 dma_controller_base, + int nr_descriptor_slots, + int tx) +{ + struct bcm43xx_dmaring *ring; + int err; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto out; + + ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots, + GFP_KERNEL); + if (!ring->meta) + goto err_kfree_ring; + + ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET; +#ifdef CONFIG_BCM947XX + if (bcm->pci_dev->bus->number == 0) + ring->memoffset = 0; +#endif + + ring->bcm = bcm; + ring->nr_slots = nr_descriptor_slots; + ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100; + ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100; + assert(ring->suspend_mark < ring->resume_mark); + ring->mmio_base = dma_controller_base; + if (tx) { + ring->tx = 1; + ring->current_slot = -1; + } else { + switch (dma_controller_base) { + case BCM43xx_MMIO_DMA1_BASE: + ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE; + ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET; + break; + case BCM43xx_MMIO_DMA4_BASE: + ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE; + ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET; + break; + default: + assert(0); + } + } + + err = alloc_ringmemory(ring); + if (err) + goto err_kfree_meta; + err = dmacontroller_setup(ring); + if (err) + goto err_free_ringmemory; + +out: + return ring; + +err_free_ringmemory: + free_ringmemory(ring); +err_kfree_meta: + kfree(ring->meta); +err_kfree_ring: + kfree(ring); + ring = NULL; + goto out; +} + +/* Main cleanup function. */ +static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) +{ + if (!ring) + return; + + dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n", + ring->mmio_base, + (ring->tx) ? "TX" : "RX", + ring->max_used_slots, ring->nr_slots); + /* Device IRQs are disabled prior entering this function, + * so no need to take care of concurrency with rx handler stuff. + */ + dmacontroller_cleanup(ring); + free_all_descbuffers(ring); + free_ringmemory(ring); + + kfree(ring->meta); + kfree(ring); +} + +void bcm43xx_dma_free(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dma *dma; + + if (bcm43xx_using_pio(bcm)) + return; + dma = bcm43xx_current_dma(bcm); + + bcm43xx_destroy_dmaring(dma->rx_ring1); + dma->rx_ring1 = NULL; + bcm43xx_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; +} + +int bcm43xx_dma_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); + struct bcm43xx_dmaring *ring; + int err = -ENOMEM; + + /* setup TX DMA channels. */ + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto out; + dma->tx_ring0 = ring; + + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto err_destroy_tx0; + dma->tx_ring1 = ring; + + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto err_destroy_tx1; + dma->tx_ring2 = ring; + + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto err_destroy_tx2; + dma->tx_ring3 = ring; + + /* setup RX DMA channels. */ + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, + BCM43xx_RXRING_SLOTS, 0); + if (!ring) + goto err_destroy_tx3; + dma->rx_ring0 = ring; + + if (bcm->current_core->rev < 5) { + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, + BCM43xx_RXRING_SLOTS, 0); + if (!ring) + goto err_destroy_rx0; + dma->rx_ring1 = ring; + } + + dprintk(KERN_INFO PFX "DMA initialized\n"); + err = 0; +out: + return err; + +err_destroy_rx0: + bcm43xx_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; +err_destroy_tx3: + bcm43xx_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; +err_destroy_tx2: + bcm43xx_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; +err_destroy_tx1: + bcm43xx_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; +err_destroy_tx0: + bcm43xx_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; + goto out; +} + +/* Generate a cookie for the TX header. */ +static u16 generate_cookie(struct bcm43xx_dmaring *ring, + int slot) +{ + u16 cookie = 0x0000; + + /* Use the upper 4 bits of the cookie as + * DMA controller ID and store the slot number + * in the lower 12 bits + */ + switch (ring->mmio_base) { + default: + assert(0); + case BCM43xx_MMIO_DMA1_BASE: + break; + case BCM43xx_MMIO_DMA2_BASE: + cookie = 0x1000; + break; + case BCM43xx_MMIO_DMA3_BASE: + cookie = 0x2000; + break; + case BCM43xx_MMIO_DMA4_BASE: + cookie = 0x3000; + break; + } + assert(((u16)slot & 0xF000) == 0x0000); + cookie |= (u16)slot; + + return cookie; +} + +/* Inspect a cookie and find out to which controller/slot it belongs. */ +static +struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, + u16 cookie, int *slot) +{ + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); + struct bcm43xx_dmaring *ring = NULL; + + switch (cookie & 0xF000) { + case 0x0000: + ring = dma->tx_ring0; + break; + case 0x1000: + ring = dma->tx_ring1; + break; + case 0x2000: + ring = dma->tx_ring2; + break; + case 0x3000: + ring = dma->tx_ring3; + break; + default: + assert(0); + } + *slot = (cookie & 0x0FFF); + assert(*slot >= 0 && *slot < ring->nr_slots); + + return ring; +} + +static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, + int slot) +{ + /* Everything is ready to start. Buffers are DMA mapped and + * associated with slots. + * "slot" is the last slot of the new frame we want to transmit. + * Close your seat belts now, please. + */ + wmb(); + slot = next_slot(ring, slot); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); +} + +static int dma_tx_fragment(struct bcm43xx_dmaring *ring, + struct sk_buff *skb, + u8 cur_frag) +{ + int slot; + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + u32 desc_ctl; + u32 desc_addr; + + assert(skb_shinfo(skb)->nr_frags == 0); + + slot = request_slot(ring); + desc = ring->vbase + slot; + meta = ring->meta + slot; + + /* Add a device specific TX header. */ + assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); + /* Reserve enough headroom for the device tx header. */ + __skb_push(skb, sizeof(struct bcm43xx_txhdr)); + /* Now calculate and add the tx header. + * The tx header includes the PLCP header. + */ + bcm43xx_generate_txhdr(ring->bcm, + (struct bcm43xx_txhdr *)skb->data, + skb->data + sizeof(struct bcm43xx_txhdr), + skb->len - sizeof(struct bcm43xx_txhdr), + (cur_frag == 0), + generate_cookie(ring, slot)); + + meta->skb = skb; + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { + return_slot(ring, slot); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G " + "(0x%08x, len: %u)\n", + meta->dmaaddr, skb->len); + return -ENOMEM; + } + + desc_addr = (u32)(meta->dmaaddr + ring->memoffset); + desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND; + desc_ctl |= BCM43xx_DMADTOR_COMPIRQ; + desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK & + (u32)(meta->skb->len - ring->frameoffset)); + if (slot == ring->nr_slots - 1) + desc_ctl |= BCM43xx_DMADTOR_DTABLEEND; + + set_desc_ctl(desc, desc_ctl); + set_desc_addr(desc, desc_addr); + /* Now transfer the whole frame. */ + dmacontroller_poke_tx(ring, slot); + + return 0; +} + +int bcm43xx_dma_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + /* We just received a packet from the kernel network subsystem. + * Add headers and DMA map the memory. Poke + * the device to send the stuff. + * Note that this is called from atomic context. + */ + struct bcm43xx_dmaring *ring = bcm43xx_current_dma(bcm)->tx_ring1; + u8 i; + struct sk_buff *skb; + + assert(ring->tx); + if (unlikely(free_slots(ring) < txb->nr_frags)) { + /* The queue should be stopped, + * if we are low on free slots. + * If this ever triggers, we have to lower the suspend_mark. + */ + dprintkl(KERN_ERR PFX "Out of DMA descriptor slots!\n"); + return -ENOMEM; + } + + for (i = 0; i < txb->nr_frags; i++) { + skb = txb->fragments[i]; + /* Take skb from ieee80211_txb_free */ + txb->fragments[i] = NULL; + dma_tx_fragment(ring, skb, i); + //TODO: handle failure of dma_tx_fragment + } + ieee80211_txb_free(txb); + + return 0; +} + +void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ + struct bcm43xx_dmaring *ring; + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + int is_last_fragment; + int slot; + + ring = parse_cookie(bcm, status->cookie, &slot); + assert(ring); + assert(ring->tx); + assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART); + while (1) { + assert(slot >= 0 && slot < ring->nr_slots); + desc = ring->vbase + slot; + meta = ring->meta + slot; + + is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND); + unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); + free_descriptor_buffer(ring, desc, meta, 1); + /* Everything belonging to the slot is unmapped + * and freed, so we can return it. + */ + return_slot(ring, slot); + + if (is_last_fragment) + break; + slot = next_slot(ring, slot); + } + bcm->stats.last_tx = jiffies; +} + +static void dma_rx(struct bcm43xx_dmaring *ring, + int *slot) +{ + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + struct bcm43xx_rxhdr *rxhdr; + struct sk_buff *skb; + u16 len; + int err; + dma_addr_t dmaaddr; + + desc = ring->vbase + *slot; + meta = ring->meta + *slot; + + sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); + skb = meta->skb; + + if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) { + /* We received an xmit status. */ + struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data; + struct bcm43xx_xmitstatus stat; + + stat.cookie = le16_to_cpu(hw->cookie); + stat.flags = hw->flags; + stat.cnt1 = hw->cnt1; + stat.cnt2 = hw->cnt2; + stat.seq = le16_to_cpu(hw->seq); + stat.unknown = le16_to_cpu(hw->unknown); + + bcm43xx_debugfs_log_txstat(ring->bcm, &stat); + bcm43xx_dma_handle_xmitstatus(ring->bcm, &stat); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize); + + return; + } + rxhdr = (struct bcm43xx_rxhdr *)skb->data; + len = le16_to_cpu(rxhdr->frame_length); + if (len == 0) { + int i = 0; + + do { + udelay(2); + barrier(); + len = le16_to_cpu(rxhdr->frame_length); + } while (len == 0 && i++ < 5); + if (unlikely(len == 0)) { + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + goto drop; + } + } + if (unlikely(len > ring->rx_buffersize)) { + /* The data did not fit into one descriptor buffer + * and is split over multiple buffers. + * This should never happen, as we try to allocate buffers + * big enough. So simply ignore this packet. + */ + int cnt = 0; + s32 tmp = len; + + while (1) { + desc = ring->vbase + *slot; + meta = ring->meta + *slot; + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); + *slot = next_slot(ring, *slot); + cnt++; + tmp -= ring->rx_buffersize; + if (tmp <= 0) + break; + } + printkl(KERN_ERR PFX "DMA RX buffer too small " + "(len: %u, buffer: %u, nr-dropped: %d)\n", + len, ring->rx_buffersize, cnt); + goto drop; + } + len -= IEEE80211_FCS_LEN; + + dmaaddr = meta->dmaaddr; + err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); + if (unlikely(err)) { + dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n"); + sync_descbuffer_for_device(ring, dmaaddr, + ring->rx_buffersize); + goto drop; + } + + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + skb_put(skb, len + ring->frameoffset); + skb_pull(skb, ring->frameoffset); + + err = bcm43xx_rx(ring->bcm, skb, rxhdr); + if (err) { + dev_kfree_skb_irq(skb); + goto drop; + } + +drop: + return; +} + +void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) +{ + u32 status; + u16 descptr; + int slot, current_slot; +#ifdef CONFIG_BCM43XX_DEBUG + int used_slots = 0; +#endif + + assert(!ring->tx); + status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS); + descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK); + current_slot = descptr / sizeof(struct bcm43xx_dmadesc); + assert(current_slot >= 0 && current_slot < ring->nr_slots); + + slot = ring->current_slot; + for ( ; slot != current_slot; slot = next_slot(ring, slot)) { + dma_rx(ring, &slot); +#ifdef CONFIG_BCM43XX_DEBUG + if (++used_slots > ring->max_used_slots) + ring->max_used_slots = used_slots; +#endif + } + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); + ring->current_slot = slot; +} + +void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring) +{ + assert(ring->tx); + bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, + bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) + | BCM43xx_DMA_TXCTRL_SUSPEND); +} + +void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) +{ + assert(ring->tx); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, + bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) + & ~BCM43xx_DMA_TXCTRL_SUSPEND); + bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1); +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h new file mode 100644 index 000000000000..2d520e4b0276 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -0,0 +1,218 @@ +#ifndef BCM43xx_DMA_H_ +#define BCM43xx_DMA_H_ + +#include +#include +#include +#include +#include + + +/* DMA-Interrupt reasons. */ +#define BCM43xx_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ + | (1 << 14) | (1 << 15)) +#define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13) +#define BCM43xx_DMAIRQ_RX_DONE (1 << 16) + +/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */ +#define BCM43xx_DMA_TX_CONTROL 0x00 +#define BCM43xx_DMA_TX_DESC_RING 0x04 +#define BCM43xx_DMA_TX_DESC_INDEX 0x08 +#define BCM43xx_DMA_TX_STATUS 0x0c +#define BCM43xx_DMA_RX_CONTROL 0x10 +#define BCM43xx_DMA_RX_DESC_RING 0x14 +#define BCM43xx_DMA_RX_DESC_INDEX 0x18 +#define BCM43xx_DMA_RX_STATUS 0x1c + +/* DMA controller channel control word values. */ +#define BCM43xx_DMA_TXCTRL_ENABLE (1 << 0) +#define BCM43xx_DMA_TXCTRL_SUSPEND (1 << 1) +#define BCM43xx_DMA_TXCTRL_LOOPBACK (1 << 2) +#define BCM43xx_DMA_TXCTRL_FLUSH (1 << 4) +#define BCM43xx_DMA_RXCTRL_ENABLE (1 << 0) +#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK 0x000000fe +#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT 1 +#define BCM43xx_DMA_RXCTRL_PIO (1 << 8) +/* DMA controller channel status word values. */ +#define BCM43xx_DMA_TXSTAT_DPTR_MASK 0x00000fff +#define BCM43xx_DMA_TXSTAT_STAT_MASK 0x0000f000 +#define BCM43xx_DMA_TXSTAT_STAT_DISABLED 0x00000000 +#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE 0x00001000 +#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT 0x00002000 +#define BCM43xx_DMA_TXSTAT_STAT_STOPPED 0x00003000 +#define BCM43xx_DMA_TXSTAT_STAT_SUSP 0x00004000 +#define BCM43xx_DMA_TXSTAT_ERROR_MASK 0x000f0000 +#define BCM43xx_DMA_TXSTAT_FLUSHED (1 << 20) +#define BCM43xx_DMA_RXSTAT_DPTR_MASK 0x00000fff +#define BCM43xx_DMA_RXSTAT_STAT_MASK 0x0000f000 +#define BCM43xx_DMA_RXSTAT_STAT_DISABLED 0x00000000 +#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE 0x00001000 +#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT 0x00002000 +#define BCM43xx_DMA_RXSTAT_STAT_RESERVED 0x00003000 +#define BCM43xx_DMA_RXSTAT_STAT_ERRORS 0x00004000 +#define BCM43xx_DMA_RXSTAT_ERROR_MASK 0x000f0000 + +/* DMA descriptor control field values. */ +#define BCM43xx_DMADTOR_BYTECNT_MASK 0x00001fff +#define BCM43xx_DMADTOR_DTABLEEND (1 << 28) /* End of descriptor table */ +#define BCM43xx_DMADTOR_COMPIRQ (1 << 29) /* IRQ on completion request */ +#define BCM43xx_DMADTOR_FRAMEEND (1 << 30) +#define BCM43xx_DMADTOR_FRAMESTART (1 << 31) + +/* Misc DMA constants */ +#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE +#define BCM43xx_DMA_BUSADDRMAX 0x3FFFFFFF +#define BCM43xx_DMA_DMABUSADDROFFSET (1 << 30) +#define BCM43xx_DMA1_RX_FRAMEOFFSET 30 +#define BCM43xx_DMA4_RX_FRAMEOFFSET 0 + +/* DMA engine tuning knobs */ +#define BCM43xx_TXRING_SLOTS 512 +#define BCM43xx_RXRING_SLOTS 64 +#define BCM43xx_DMA1_RXBUFFERSIZE (2304 + 100) +#define BCM43xx_DMA4_RXBUFFERSIZE 16 +/* Suspend the tx queue, if less than this percent slots are free. */ +#define BCM43xx_TXSUSPEND_PERCENT 20 +/* Resume the tx queue, if more than this percent slots are free. */ +#define BCM43xx_TXRESUME_PERCENT 50 + + + +#ifdef CONFIG_BCM43XX_DMA + + +struct sk_buff; +struct bcm43xx_private; +struct bcm43xx_xmitstatus; + + +struct bcm43xx_dmadesc { + __le32 _control; + __le32 _address; +} __attribute__((__packed__)); + +/* Macros to access the bcm43xx_dmadesc struct */ +#define get_desc_ctl(desc) le32_to_cpu((desc)->_control) +#define set_desc_ctl(desc, ctl) do { (desc)->_control = cpu_to_le32(ctl); } while (0) +#define get_desc_addr(desc) le32_to_cpu((desc)->_address) +#define set_desc_addr(desc, addr) do { (desc)->_address = cpu_to_le32(addr); } while (0) + +struct bcm43xx_dmadesc_meta { + /* The kernel DMA-able buffer. */ + struct sk_buff *skb; + /* DMA base bus-address of the descriptor buffer. */ + dma_addr_t dmaaddr; +}; + +struct bcm43xx_dmaring { + struct bcm43xx_private *bcm; + /* Kernel virtual base address of the ring memory. */ + struct bcm43xx_dmadesc *vbase; + /* DMA memory offset */ + dma_addr_t memoffset; + /* (Unadjusted) DMA base bus-address of the ring memory. */ + dma_addr_t dmabase; + /* Meta data about all descriptors. */ + struct bcm43xx_dmadesc_meta *meta; + /* Number of descriptor slots in the ring. */ + int nr_slots; + /* Number of used descriptor slots. */ + int used_slots; + /* Currently used slot in the ring. */ + int current_slot; + /* Marks to suspend/resume the queue. */ + int suspend_mark; + int resume_mark; + /* Frameoffset in octets. */ + u32 frameoffset; + /* Descriptor buffer size. */ + u16 rx_buffersize; + /* The MMIO base register of the DMA controller, this + * ring is posted to. + */ + u16 mmio_base; + u8 tx:1, /* TRUE, if this is a TX ring. */ + suspended:1; /* TRUE, if transfers are suspended on this ring. */ +#ifdef CONFIG_BCM43XX_DEBUG + /* Maximum number of used slots. */ + int max_used_slots; +#endif /* CONFIG_BCM43XX_DEBUG*/ +}; + + +static inline +u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring, + u16 offset) +{ + return bcm43xx_read32(ring->bcm, ring->mmio_base + offset); +} + +static inline +void bcm43xx_dma_write(struct bcm43xx_dmaring *ring, + u16 offset, u32 value) +{ + bcm43xx_write32(ring->bcm, ring->mmio_base + offset, value); +} + + +int bcm43xx_dma_init(struct bcm43xx_private *bcm); +void bcm43xx_dma_free(struct bcm43xx_private *bcm); + +int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base); +int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base); + +void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring); +void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring); + +void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status); + +int bcm43xx_dma_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb); +void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); + + +#else /* CONFIG_BCM43XX_DMA */ + + +static inline +int bcm43xx_dma_init(struct bcm43xx_private *bcm) +{ + return 0; +} +static inline +void bcm43xx_dma_free(struct bcm43xx_private *bcm) +{ +} +static inline +int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base) +{ + return 0; +} +static inline +int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base) +{ + return 0; +} +static inline +int bcm43xx_dma_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return 0; +} +static inline +void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ +} +static inline +void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) +{ +} + +#endif /* CONFIG_BCM43XX_DMA */ +#endif /* BCM43xx_DMA_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c new file mode 100644 index 000000000000..b3ffcf501311 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c @@ -0,0 +1,50 @@ +/* + + Broadcom BCM43xx wireless driver + + ethtool support + + Copyright (c) 2006 Jason Lunz + + Some code in this file is derived from the 8139too.c driver + Copyright (C) 2002 Jeff Garzik + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_ethtool.h" + +#include +#include +#include +#include + + +static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(dev); + + strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); + strncpy(info->version, UTS_RELEASE, sizeof(info->version)); + strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN); +} + +struct ethtool_ops bcm43xx_ethtool_ops = { + .get_drvinfo = bcm43xx_get_drvinfo, + .get_link = ethtool_op_get_link, +}; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h new file mode 100644 index 000000000000..813704991f62 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h @@ -0,0 +1,8 @@ +#ifndef BCM43xx_ETHTOOL_H_ +#define BCM43xx_ETHTOOL_H_ + +#include + +extern struct ethtool_ops bcm43xx_ethtool_ops; + +#endif /* BCM43xx_ETHTOOL_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c new file mode 100644 index 000000000000..ad8e569d1faf --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c @@ -0,0 +1,337 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_ilt.h" +#include "bcm43xx_phy.h" + + +/**** Initial Internal Lookup Tables ****/ + +const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE] = { + 0xFEB93FFD, 0xFEC63FFD, /* 0 */ + 0xFED23FFD, 0xFEDF3FFD, + 0xFEEC3FFE, 0xFEF83FFE, + 0xFF053FFE, 0xFF113FFE, + 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */ + 0xFF373FFF, 0xFF443FFF, + 0xFF503FFF, 0xFF5D3FFF, + 0xFF693FFF, 0xFF763FFF, + 0xFF824000, 0xFF8F4000, /* 16 */ + 0xFF9B4000, 0xFFA84000, + 0xFFB54000, 0xFFC14000, + 0xFFCE4000, 0xFFDA4000, + 0xFFE74000, 0xFFF34000, /* 24 */ + 0x00004000, 0x000D4000, + 0x00194000, 0x00264000, + 0x00324000, 0x003F4000, + 0x004B4000, 0x00584000, /* 32 */ + 0x00654000, 0x00714000, + 0x007E4000, 0x008A3FFF, + 0x00973FFF, 0x00A33FFF, + 0x00B03FFF, 0x00BC3FFF, /* 40 */ + 0x00C93FFF, 0x00D63FFF, + 0x00E23FFE, 0x00EF3FFE, + 0x00FB3FFE, 0x01083FFE, + 0x01143FFE, 0x01213FFD, /* 48 */ + 0x012E3FFD, 0x013A3FFD, + 0x01473FFD, +}; + +const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE] = { + 0xDB93CB87, 0xD666CF64, /* 0 */ + 0xD1FDD358, 0xCDA6D826, + 0xCA38DD9F, 0xC729E2B4, + 0xC469E88E, 0xC26AEE2B, + 0xC0DEF46C, 0xC073FA62, /* 8 */ + 0xC01D00D5, 0xC0760743, + 0xC1560D1E, 0xC2E51369, + 0xC4ED18FF, 0xC7AC1ED7, + 0xCB2823B2, 0xCEFA28D9, /* 16 */ + 0xD2F62D3F, 0xD7BB3197, + 0xDCE53568, 0xE1FE3875, + 0xE7D13B35, 0xED663D35, + 0xF39B3EC4, 0xF98E3FA7, /* 24 */ + 0x00004000, 0x06723FA7, + 0x0C653EC4, 0x129A3D35, + 0x182F3B35, 0x1E023875, + 0x231B3568, 0x28453197, /* 32 */ + 0x2D0A2D3F, 0x310628D9, + 0x34D823B2, 0x38541ED7, + 0x3B1318FF, 0x3D1B1369, + 0x3EAA0D1E, 0x3F8A0743, /* 40 */ + 0x3FE300D5, 0x3F8DFA62, + 0x3F22F46C, 0x3D96EE2B, + 0x3B97E88E, 0x38D7E2B4, + 0x35C8DD9F, 0x325AD826, /* 48 */ + 0x2E03D358, 0x299ACF64, + 0x246DCB87, +}; + +const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE] = { + 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */ + 0x0202, 0x0282, 0x0302, 0x0382, + 0x0402, 0x0482, 0x0502, 0x0582, + 0x05E2, 0x0662, 0x06E2, 0x0762, + 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */ + 0x09C2, 0x0A22, 0x0AA2, 0x0B02, + 0x0B82, 0x0BE2, 0x0C62, 0x0CC2, + 0x0D42, 0x0DA2, 0x0E02, 0x0E62, + 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */ + 0x1062, 0x10C2, 0x1122, 0x1182, + 0x11E2, 0x1242, 0x12A2, 0x12E2, + 0x1342, 0x13A2, 0x1402, 0x1442, + 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */ + 0x15E2, 0x1622, 0x1662, 0x16C1, + 0x1701, 0x1741, 0x1781, 0x17E1, + 0x1821, 0x1861, 0x18A1, 0x18E1, + 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */ + 0x1A21, 0x1A61, 0x1AA1, 0x1AC1, + 0x1B01, 0x1B41, 0x1B81, 0x1BA1, + 0x1BE1, 0x1C21, 0x1C41, 0x1C81, + 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */ + 0x1D61, 0x1DA1, 0x1DC1, 0x1E01, + 0x1E21, 0x1E61, 0x1E81, 0x1EA1, + 0x1EE1, 0x1F01, 0x1F21, 0x1F41, + 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */ + 0x2001, 0x2041, 0x2061, 0x2081, + 0x20A1, 0x20C1, 0x20E1, 0x2101, + 0x2121, 0x2141, 0x2161, 0x2181, + 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */ + 0x2221, 0x2241, 0x2261, 0x2281, + 0x22A1, 0x22C1, 0x22C1, 0x22E1, + 0x2301, 0x2321, 0x2341, 0x2361, + 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */ + 0x23E1, 0x23E1, 0x2401, 0x2421, + 0x2441, 0x2441, 0x2461, 0x2481, + 0x2481, 0x24A1, 0x24C1, 0x24C1, + 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */ + 0x2541, 0x2541, 0x2561, 0x2561, + 0x2581, 0x25A1, 0x25A1, 0x25C1, + 0x25C1, 0x25E1, 0x2601, 0x2601, + 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */ + 0x2661, 0x2661, 0x2681, 0x2681, + 0x26A1, 0x26A1, 0x26C1, 0x26C1, + 0x26E1, 0x26E1, 0x2701, 0x2701, + 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */ + 0x2760, 0x2760, 0x2780, 0x2780, + 0x2780, 0x27A0, 0x27A0, 0x27C0, + 0x27C0, 0x27E0, 0x27E0, 0x27E0, + 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */ + 0x2820, 0x2840, 0x2840, 0x2840, + 0x2860, 0x2860, 0x2880, 0x2880, + 0x2880, 0x28A0, 0x28A0, 0x28A0, + 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */ + 0x28E0, 0x28E0, 0x2900, 0x2900, + 0x2900, 0x2920, 0x2920, 0x2920, + 0x2940, 0x2940, 0x2940, 0x2960, + 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */ + 0x2980, 0x2980, 0x29A0, 0x29A0, + 0x29A0, 0x29A0, 0x29C0, 0x29C0, + 0x29C0, 0x29E0, 0x29E0, 0x29E0, + 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */ + 0x2A00, 0x2A20, 0x2A20, 0x2A20, + 0x2A20, 0x2A40, 0x2A40, 0x2A40, + 0x2A40, 0x2A60, 0x2A60, 0x2A60, +}; + +const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE] = { + 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */ + 0x05A9, 0x0669, 0x0709, 0x0789, + 0x0829, 0x08A9, 0x0929, 0x0989, + 0x0A09, 0x0A69, 0x0AC9, 0x0B29, + 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */ + 0x0D09, 0x0D69, 0x0DA9, 0x0E09, + 0x0E69, 0x0EA9, 0x0F09, 0x0F49, + 0x0FA9, 0x0FE9, 0x1029, 0x1089, + 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */ + 0x11E9, 0x1229, 0x1289, 0x12C9, + 0x1309, 0x1349, 0x1389, 0x13C9, + 0x1409, 0x1449, 0x14A9, 0x14E9, + 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */ + 0x1629, 0x1669, 0x16A9, 0x16E8, + 0x1728, 0x1768, 0x17A8, 0x17E8, + 0x1828, 0x1868, 0x18A8, 0x18E8, + 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */ + 0x1A28, 0x1A68, 0x1AA8, 0x1AE8, + 0x1B28, 0x1B68, 0x1BA8, 0x1BE8, + 0x1C28, 0x1C68, 0x1CA8, 0x1CE8, + 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */ + 0x1E48, 0x1E88, 0x1EC8, 0x1F08, + 0x1F48, 0x1F88, 0x1FE8, 0x2028, + 0x2068, 0x20A8, 0x2108, 0x2148, + 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */ + 0x22C8, 0x2308, 0x2348, 0x23A8, + 0x23E8, 0x2448, 0x24A8, 0x24E8, + 0x2548, 0x25A8, 0x2608, 0x2668, + 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */ + 0x2847, 0x28C7, 0x2947, 0x29A7, + 0x2A27, 0x2AC7, 0x2B47, 0x2BE7, + 0x2CA7, 0x2D67, 0x2E47, 0x2F67, + 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */ + 0x3806, 0x38A6, 0x3946, 0x39E6, + 0x3A66, 0x3AE6, 0x3B66, 0x3BC6, + 0x3C45, 0x3CA5, 0x3D05, 0x3D85, + 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */ + 0x3F45, 0x3FA5, 0x4005, 0x4045, + 0x40A5, 0x40E5, 0x4145, 0x4185, + 0x41E5, 0x4225, 0x4265, 0x42C5, + 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */ + 0x4424, 0x4464, 0x44C4, 0x4504, + 0x4544, 0x4584, 0x45C4, 0x4604, + 0x4644, 0x46A4, 0x46E4, 0x4724, + 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */ + 0x4864, 0x48A4, 0x48E4, 0x4924, + 0x4964, 0x49A4, 0x49E4, 0x4A24, + 0x4A64, 0x4AA4, 0x4AE4, 0x4B23, + 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */ + 0x4C63, 0x4CA3, 0x4CE3, 0x4D23, + 0x4D63, 0x4DA3, 0x4DE3, 0x4E23, + 0x4E63, 0x4EA3, 0x4EE3, 0x4F23, + 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */ + 0x5083, 0x50C3, 0x5103, 0x5143, + 0x5183, 0x51E2, 0x5222, 0x5262, + 0x52A2, 0x52E2, 0x5342, 0x5382, + 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */ + 0x5502, 0x5542, 0x55A2, 0x55E2, + 0x5642, 0x5682, 0x56E2, 0x5722, + 0x5782, 0x57E1, 0x5841, 0x58A1, + 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */ + 0x5AA1, 0x5B01, 0x5B81, 0x5BE1, + 0x5C61, 0x5D01, 0x5D80, 0x5E20, + 0x5EE0, 0x5FA0, 0x6080, 0x61C0, +}; + +const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE] = { + 0x0001, 0x0001, 0x0001, 0xFFFE, + 0xFFFE, 0x3FFF, 0x1000, 0x0393, +}; + +const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE] = { + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, +}; + +const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE] = { + 0x013C, 0x01F5, 0x031A, 0x0631, + 0x0001, 0x0001, 0x0001, 0x0001, +}; + +const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE] = { + 0x5484, 0x3C40, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE] = { + 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ + 0x2F2D, 0x2A2A, 0x2527, 0x1F21, + 0x1A1D, 0x1719, 0x1616, 0x1414, + 0x1414, 0x1400, 0x1414, 0x1614, + 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */ + 0x2A27, 0x2F2A, 0x332D, 0x3B35, + 0x5140, 0x6C62, 0x0077, +}; + +const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE] = { + 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ + 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, + 0x969B, 0x9195, 0x8F8F, 0x8A8A, + 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, + 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */ + 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7, + 0xCBC0, 0xD8D4, 0x00DD, +}; + +const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE] = { + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA400, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0x00A4, +}; + +const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE] = { + 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */ + 0x0067, 0x0063, 0x005E, 0x0059, + 0x0054, 0x0050, 0x004B, 0x0046, + 0x0042, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x0000, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x0042, 0x0046, 0x004B, 0x0050, + 0x0054, 0x0059, 0x005E, 0x0063, + 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */ + 0x007A, +}; + +const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = { + 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */ + 0x00D6, 0x00D4, 0x00D2, 0x00CF, + 0x00CD, 0x00CA, 0x00C7, 0x00C4, + 0x00C1, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x0000, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00C1, 0x00C4, 0x00C7, 0x00CA, + 0x00CD, 0x00CF, 0x00D2, 0x00D4, + 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */ + 0x00DE, +}; + +/**** Helper functions to access the device Internal Lookup Tables ****/ + +void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val) +{ + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + mmiowb(); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + mmiowb(); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val); + } +} + +u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset) +{ + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); + } +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h new file mode 100644 index 000000000000..464521abf73c --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h @@ -0,0 +1,32 @@ +#ifndef BCM43xx_ILT_H_ +#define BCM43xx_ILT_H_ + +#define BCM43xx_ILT_ROTOR_SIZE 53 +extern const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE]; +#define BCM43xx_ILT_RETARD_SIZE 53 +extern const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE]; +#define BCM43xx_ILT_FINEFREQA_SIZE 256 +extern const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE]; +#define BCM43xx_ILT_FINEFREQG_SIZE 256 +extern const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE]; +#define BCM43xx_ILT_NOISEA2_SIZE 8 +extern const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE]; +#define BCM43xx_ILT_NOISEA3_SIZE 8 +extern const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE]; +#define BCM43xx_ILT_NOISEG1_SIZE 8 +extern const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE]; +#define BCM43xx_ILT_NOISEG2_SIZE 8 +extern const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE]; +#define BCM43xx_ILT_NOISESCALEG_SIZE 27 +extern const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE]; +extern const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE]; +extern const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE]; +#define BCM43xx_ILT_SIGMASQR_SIZE 53 +extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE]; +extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE]; + + +void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val); +u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset); + +#endif /* BCM43xx_ILT_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c new file mode 100644 index 000000000000..4b2c02c0b31e --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -0,0 +1,293 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx_leds.h" +#include "bcm43xx.h" + +#include + + +static void bcm43xx_led_changestate(struct bcm43xx_led *led) +{ + struct bcm43xx_private *bcm = led->bcm; + const int index = bcm43xx_led_index(led); + const u16 mask = (1 << index); + u16 ledctl; + + assert(index >= 0 && index < BCM43xx_NR_LEDS); + assert(led->blink_interval); + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +static void bcm43xx_led_blink(unsigned long d) +{ + struct bcm43xx_led *led = (struct bcm43xx_led *)d; + struct bcm43xx_private *bcm = led->bcm; + unsigned long flags; + + bcm43xx_lock_mmio(bcm, flags); + if (led->blink_interval) { + bcm43xx_led_changestate(led); + mod_timer(&led->blink_timer, jiffies + led->blink_interval); + } + bcm43xx_unlock_mmio(bcm, flags); +} + +static void bcm43xx_led_blink_start(struct bcm43xx_led *led, + unsigned long interval) +{ + if (led->blink_interval) + return; + led->blink_interval = interval; + bcm43xx_led_changestate(led); + led->blink_timer.expires = jiffies + interval; + add_timer(&led->blink_timer); +} + +static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync) +{ + struct bcm43xx_private *bcm = led->bcm; + const int index = bcm43xx_led_index(led); + u16 ledctl; + + if (!led->blink_interval) + return; + if (unlikely(sync)) + del_timer_sync(&led->blink_timer); + else + del_timer(&led->blink_timer); + led->blink_interval = 0; + + /* Make sure the LED is turned off. */ + assert(index >= 0 && index < BCM43xx_NR_LEDS); + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + if (led->activelow) + ledctl |= (1 << index); + else + ledctl &= ~(1 << index); + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm, + struct bcm43xx_led *led, + int led_index) +{ + /* This function is called, if the behaviour (and activelow) + * information for a LED is missing in the SPROM. + * We hardcode the behaviour values for various devices here. + * Note that the BCM43xx_LED_TEST_XXX behaviour values can + * be used to figure out which led is mapped to which index. + */ + + switch (led_index) { + case 0: + led->behaviour = BCM43xx_LED_ACTIVITY; + if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) + led->behaviour = BCM43xx_LED_RADIO_ALL; + break; + case 1: + led->behaviour = BCM43xx_LED_RADIO_B; + if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK) + led->behaviour = BCM43xx_LED_ASSOC; + break; + case 2: + led->behaviour = BCM43xx_LED_RADIO_A; + break; + case 3: + led->behaviour = BCM43xx_LED_OFF; + break; + default: + assert(0); + } +} + +int bcm43xx_leds_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_led *led; + u8 sprom[4]; + int i; + + sprom[0] = bcm->sprom.wl0gpio0; + sprom[1] = bcm->sprom.wl0gpio1; + sprom[2] = bcm->sprom.wl0gpio2; + sprom[3] = bcm->sprom.wl0gpio3; + + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + led->bcm = bcm; + setup_timer(&led->blink_timer, + bcm43xx_led_blink, + (unsigned long)led); + + if (sprom[i] == 0xFF) { + bcm43xx_led_init_hardcoded(bcm, led, i); + } else { + led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR; + led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW); + } + } + + return 0; +} + +void bcm43xx_leds_exit(struct bcm43xx_private *bcm) +{ + struct bcm43xx_led *led; + int i; + + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + bcm43xx_led_blink_stop(led, 1); + } + bcm43xx_leds_switch_all(bcm, 0); +} + +void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) +{ + struct bcm43xx_led *led; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES; + int i, turn_on; + unsigned long interval = 0; + u16 ledctl; + + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + + turn_on = 0; + switch (led->behaviour) { + case BCM43xx_LED_INACTIVE: + continue; + case BCM43xx_LED_OFF: + break; + case BCM43xx_LED_ON: + turn_on = 1; + break; + case BCM43xx_LED_ACTIVITY: + turn_on = activity; + break; + case BCM43xx_LED_RADIO_ALL: + turn_on = radio->enabled; + break; + case BCM43xx_LED_RADIO_A: + turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A); + break; + case BCM43xx_LED_RADIO_B: + turn_on = (radio->enabled && + (phy->type == BCM43xx_PHYTYPE_B || + phy->type == BCM43xx_PHYTYPE_G)); + break; + case BCM43xx_LED_MODE_BG: + if (phy->type == BCM43xx_PHYTYPE_G && + 1/*FIXME: using G rates.*/) + turn_on = 1; + break; + case BCM43xx_LED_TRANSFER: + if (transferring) + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); + else + bcm43xx_led_blink_stop(led, 0); + continue; + case BCM43xx_LED_APTRANSFER: + if (bcm->ieee->iw_mode == IW_MODE_MASTER) { + if (transferring) { + interval = BCM43xx_LEDBLINK_FAST; + turn_on = 1; + } + } else { + turn_on = 1; + if (0/*TODO: not assoc*/) + interval = BCM43xx_LEDBLINK_SLOW; + else if (transferring) + interval = BCM43xx_LEDBLINK_FAST; + else + turn_on = 0; + } + if (turn_on) + bcm43xx_led_blink_start(led, interval); + else + bcm43xx_led_blink_stop(led, 0); + continue; + case BCM43xx_LED_WEIRD: + //TODO + break; + case BCM43xx_LED_ASSOC: + if (bcm->softmac->associated) + turn_on = 1; + break; +#ifdef CONFIG_BCM43XX_DEBUG + case BCM43xx_LED_TEST_BLINKSLOW: + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW); + continue; + case BCM43xx_LED_TEST_BLINKMEDIUM: + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); + continue; + case BCM43xx_LED_TEST_BLINKFAST: + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST); + continue; +#endif /* CONFIG_BCM43XX_DEBUG */ + default: + assert(0); + }; + + if (led->activelow) + turn_on = !turn_on; + if (turn_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) +{ + struct bcm43xx_led *led; + u16 ledctl; + int i; + int bit_on; + + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + if (led->behaviour == BCM43xx_LED_INACTIVE) + continue; + if (on) + bit_on = led->activelow ? 0 : 1; + else + bit_on = led->activelow ? 1 : 0; + if (bit_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h new file mode 100644 index 000000000000..d3716cf3aebc --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h @@ -0,0 +1,56 @@ +#ifndef BCM43xx_LEDS_H_ +#define BCM43xx_LEDS_H_ + +#include +#include + + +struct bcm43xx_led { + u8 behaviour:7; + u8 activelow:1; + + struct bcm43xx_private *bcm; + struct timer_list blink_timer; + unsigned long blink_interval; +}; +#define bcm43xx_led_index(led) ((int)((led) - (led)->bcm->leds)) + +/* Delay between state changes when blinking in jiffies */ +#define BCM43xx_LEDBLINK_SLOW (HZ / 1) +#define BCM43xx_LEDBLINK_MEDIUM (HZ / 4) +#define BCM43xx_LEDBLINK_FAST (HZ / 8) + +#define BCM43xx_LED_XFER_THRES (HZ / 100) + +#define BCM43xx_LED_BEHAVIOUR 0x7F +#define BCM43xx_LED_ACTIVELOW 0x80 +enum { /* LED behaviour values */ + BCM43xx_LED_OFF, + BCM43xx_LED_ON, + BCM43xx_LED_ACTIVITY, + BCM43xx_LED_RADIO_ALL, + BCM43xx_LED_RADIO_A, + BCM43xx_LED_RADIO_B, + BCM43xx_LED_MODE_BG, + BCM43xx_LED_TRANSFER, + BCM43xx_LED_APTRANSFER, + BCM43xx_LED_WEIRD,//FIXME + BCM43xx_LED_ASSOC, + BCM43xx_LED_INACTIVE, + + /* Behaviour values for testing. + * With these values it is easier to figure out + * the real behaviour of leds, in case the SPROM + * is missing information. + */ + BCM43xx_LED_TEST_BLINKSLOW, + BCM43xx_LED_TEST_BLINKMEDIUM, + BCM43xx_LED_TEST_BLINKFAST, +}; + +int bcm43xx_leds_init(struct bcm43xx_private *bcm); +void bcm43xx_leds_exit(struct bcm43xx_private *bcm); +void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity); +void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on); + +#endif /* BCM43xx_LEDS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c new file mode 100644 index 000000000000..c37371fc9e01 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -0,0 +1,3973 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_debugfs.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_phy.h" +#include "bcm43xx_dma.h" +#include "bcm43xx_pio.h" +#include "bcm43xx_power.h" +#include "bcm43xx_wx.h" +#include "bcm43xx_ethtool.h" +#include "bcm43xx_xmit.h" + + +MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); +MODULE_AUTHOR("Martin Langer"); +MODULE_AUTHOR("Stefano Brivio"); +MODULE_AUTHOR("Michael Buesch"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_BCM947XX +extern char *nvram_get(char *name); +#endif + +#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) +static int modparam_pio; +module_param_named(pio, modparam_pio, int, 0444); +MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); +#elif defined(CONFIG_BCM43XX_DMA) +# define modparam_pio 0 +#elif defined(CONFIG_BCM43XX_PIO) +# define modparam_pio 1 +#endif + +static int modparam_bad_frames_preempt; +module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); +MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption"); + +static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT; +module_param_named(short_retry, modparam_short_retry, int, 0444); +MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); + +static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT; +module_param_named(long_retry, modparam_long_retry, int, 0444); +MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); + +static int modparam_locale = -1; +module_param_named(locale, modparam_locale, int, 0444); +MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)"); + +static int modparam_noleds; +module_param_named(noleds, modparam_noleds, int, 0444); +MODULE_PARM_DESC(noleds, "Turn off all LED activity"); + +#ifdef CONFIG_BCM43XX_DEBUG +static char modparam_fwpostfix[64]; +module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444); +MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); +#else +# define modparam_fwpostfix "" +#endif /* CONFIG_BCM43XX_DEBUG*/ + + +/* If you want to debug with just a single device, enable this, + * where the string is the pci device ID (as given by the kernel's + * pci_name function) of the device to be used. + */ +//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0" + +/* If you want to enable printing of each MMIO access, enable this. */ +//#define DEBUG_ENABLE_MMIO_PRINT + +/* If you want to enable printing of MMIO access within + * ucode/pcm upload, initvals write, enable this. + */ +//#define DEBUG_ENABLE_UCODE_MMIO_PRINT + +/* If you want to enable printing of PCI Config Space access, enable this */ +//#define DEBUG_ENABLE_PCILOG + + +/* Detailed list maintained at: + * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices + */ + static struct pci_device_id bcm43xx_pci_tbl[] = { + /* Broadcom 4303 802.11b */ + { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* Broadcom 4307 802.11b */ + { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* Broadcom 4318 802.11b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* Broadcom 4306 802.11b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* Broadcom 4306 802.11a */ +// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* Broadcom 4309 802.11a/b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + /* Broadcom 43XG 802.11b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#ifdef CONFIG_BCM947XX + /* SB bus on BCM947xx */ + { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + { 0 }, +}; +MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl); + +static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val) +{ + u32 status; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP)) + val = swab32(val); + + bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset); + mmiowb(); + bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val); +} + +static inline +void bcm43xx_shm_control_word(struct bcm43xx_private *bcm, + u16 routing, u16 offset) +{ + u32 control; + + /* "offset" is the WORD offset. */ + + control = routing; + control <<= 16; + control |= offset; + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control); +} + +u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, + u16 routing, u16 offset) +{ + u32 ret; + + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); + ret <<= 16; + bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); + ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); + + return ret; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA); + + return ret; +} + +u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, + u16 routing, u16 offset) +{ + u16 ret; + + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); + + return ret; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); + + return ret; +} + +void bcm43xx_shm_write32(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u32 value) +{ + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, + (value >> 16) & 0xffff); + mmiowb(); + bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, + value & 0xffff); + return; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + mmiowb(); + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value); +} + +void bcm43xx_shm_write16(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u16 value) +{ + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, + value); + return; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value); +} + +void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf) +{ + /* We need to be careful. As we read the TSF from multiple + * registers, we should take care of register overflows. + * In theory, the whole tsf read process should be atomic. + * We try to be atomic here, by restaring the read process, + * if any of the high registers changed (overflew). + */ + if (bcm->current_core->rev >= 3) { + u32 low, high, high2; + + do { + high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); + low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW); + high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); + } while (unlikely(high != high2)); + + *tsf = high; + *tsf <<= 32; + *tsf |= low; + } else { + u64 tmp; + u16 v0, v1, v2, v3; + u16 test1, test2, test3; + + do { + v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); + v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); + v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); + v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0); + + test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); + test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); + test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); + } while (v3 != test3 || v2 != test2 || v1 != test1); + + *tsf = v3; + *tsf <<= 48; + tmp = v2; + tmp <<= 32; + *tsf |= tmp; + tmp = v1; + tmp <<= 16; + *tsf |= tmp; + *tsf |= v0; + } +} + +void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) +{ + u32 status; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status |= BCM43xx_SBF_TIME_UPDATE; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + mmiowb(); + + /* Be careful with the in-progress timer. + * First zero out the low register, so we have a full + * register-overflow duration to complete the operation. + */ + if (bcm->current_core->rev >= 3) { + u32 lo = (tsf & 0x00000000FFFFFFFFULL); + u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; + + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0); + mmiowb(); + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi); + mmiowb(); + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo); + } else { + u16 v0 = (tsf & 0x000000000000FFFFULL); + u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; + u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; + u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; + + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0); + } + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status &= ~BCM43xx_SBF_TIME_UPDATE; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); +} + +static +void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, + u16 offset, + const u8 *mac) +{ + u16 data; + + offset |= 0x0020; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset); + + data = mac[0]; + data |= mac[1] << 8; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); + data = mac[2]; + data |= mac[3] << 8; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); + data = mac[4]; + data |= mac[5] << 8; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); +} + +static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, + u16 offset) +{ + const u8 zero_addr[ETH_ALEN] = { 0 }; + + bcm43xx_macfilter_set(bcm, offset, zero_addr); +} + +static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) +{ + const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr); + const u8 *bssid = (const u8 *)(bcm->ieee->bssid); + u8 mac_bssid[ETH_ALEN * 2]; + int i; + + memcpy(mac_bssid, mac, ETH_ALEN); + memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); + + /* Write our MAC address and BSSID to template ram */ + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) + bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i))); + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) + bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i))); + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) + bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i))); +} + +//FIXME: Well, we should probably call them from somewhere. +#if 0 +static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) +{ + /* slot_time is in usec. */ + if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G) + return; + bcm43xx_write16(bcm, 0x684, 510 + slot_time); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time); +} + +static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm) +{ + bcm43xx_set_slot_time(bcm, 9); +} + +static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) +{ + bcm43xx_set_slot_time(bcm, 20); +} +#endif + +/* FIXME: To get the MAC-filter working, we need to implement the + * following functions (and rename them :) + */ +#if 0 +static void bcm43xx_disassociate(struct bcm43xx_private *bcm) +{ + bcm43xx_mac_suspend(bcm); + bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); + + bcm43xx_ram_write(bcm, 0x0026, 0x0000); + bcm43xx_ram_write(bcm, 0x0028, 0x0000); + bcm43xx_ram_write(bcm, 0x007E, 0x0000); + bcm43xx_ram_write(bcm, 0x0080, 0x0000); + bcm43xx_ram_write(bcm, 0x047E, 0x0000); + bcm43xx_ram_write(bcm, 0x0480, 0x0000); + + if (bcm->current_core->rev < 3) { + bcm43xx_write16(bcm, 0x0610, 0x8000); + bcm43xx_write16(bcm, 0x060E, 0x0000); + } else + bcm43xx_write32(bcm, 0x0188, 0x80000000); + + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); + + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G && + ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate)) + bcm43xx_short_slot_timing_enable(bcm); + + bcm43xx_mac_enable(bcm); +} + +static void bcm43xx_associate(struct bcm43xx_private *bcm, + const u8 *mac) +{ + memcpy(bcm->ieee->bssid, mac, ETH_ALEN); + + bcm43xx_mac_suspend(bcm); + bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac); + bcm43xx_write_mac_bssid_templates(bcm); + bcm43xx_mac_enable(bcm); +} +#endif + +/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask) +{ + u32 old_mask; + + old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask); + + return old_mask; +} + +/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask) +{ + u32 old_mask; + + old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask); + + return old_mask; +} + +/* Make sure we don't receive more data from the device. */ +static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) +{ + u32 old; + unsigned long flags; + + bcm43xx_lock_mmio(bcm, flags); + if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) { + bcm43xx_unlock_mmio(bcm, flags); + return -EBUSY; + } + old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + tasklet_disable(&bcm->isr_tasklet); + bcm43xx_unlock_mmio(bcm, flags); + if (oldstate) + *oldstate = old; + + return 0; +} + +static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u32 radio_id; + u16 manufact; + u16 version; + u8 revision; + s8 i; + + if (bcm->chip_id == 0x4317) { + if (bcm->chip_rev == 0x00) + radio_id = 0x3205017F; + else if (bcm->chip_rev == 0x01) + radio_id = 0x4205017F; + else + radio_id = 0x5205017F; + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); + radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH); + radio_id <<= 16; + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); + radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); + } + + manufact = (radio_id & 0x00000FFF); + version = (radio_id & 0x0FFFF000) >> 12; + revision = (radio_id & 0xF0000000) >> 28; + + dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n", + radio_id, manufact, version, revision); + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f)) + goto err_unsupported_radio; + break; + case BCM43xx_PHYTYPE_B: + if ((version & 0xFFF0) != 0x2050) + goto err_unsupported_radio; + break; + case BCM43xx_PHYTYPE_G: + if (version != 0x2050) + goto err_unsupported_radio; + break; + } + + radio->manufact = manufact; + radio->version = version; + radio->revision = revision; + + /* Set default attenuation values. */ + radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); + radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); + radio->txctl1 = bcm43xx_default_txctl1(bcm); + radio->txctl2 = 0xFFFF; + if (phy->type == BCM43xx_PHYTYPE_A) + radio->txpower_desired = bcm->sprom.maxpower_aphy; + else + radio->txpower_desired = bcm->sprom.maxpower_bgphy; + + /* Initialize the in-memory nrssi Lookup Table. */ + for (i = 0; i < 64; i++) + radio->nrssi_lt[i] = i; + + return 0; + +err_unsupported_radio: + printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n"); + return -ENODEV; +} + +static const char * bcm43xx_locale_iso(u8 locale) +{ + /* ISO 3166-1 country codes. + * Note that there aren't ISO 3166-1 codes for + * all or locales. (Not all locales are countries) + */ + switch (locale) { + case BCM43xx_LOCALE_WORLD: + case BCM43xx_LOCALE_ALL: + return "XX"; + case BCM43xx_LOCALE_THAILAND: + return "TH"; + case BCM43xx_LOCALE_ISRAEL: + return "IL"; + case BCM43xx_LOCALE_JORDAN: + return "JO"; + case BCM43xx_LOCALE_CHINA: + return "CN"; + case BCM43xx_LOCALE_JAPAN: + case BCM43xx_LOCALE_JAPAN_HIGH: + return "JP"; + case BCM43xx_LOCALE_USA_CANADA_ANZ: + case BCM43xx_LOCALE_USA_LOW: + return "US"; + case BCM43xx_LOCALE_EUROPE: + return "EU"; + case BCM43xx_LOCALE_NONE: + return " "; + } + assert(0); + return " "; +} + +static const char * bcm43xx_locale_string(u8 locale) +{ + switch (locale) { + case BCM43xx_LOCALE_WORLD: + return "World"; + case BCM43xx_LOCALE_THAILAND: + return "Thailand"; + case BCM43xx_LOCALE_ISRAEL: + return "Israel"; + case BCM43xx_LOCALE_JORDAN: + return "Jordan"; + case BCM43xx_LOCALE_CHINA: + return "China"; + case BCM43xx_LOCALE_JAPAN: + return "Japan"; + case BCM43xx_LOCALE_USA_CANADA_ANZ: + return "USA/Canada/ANZ"; + case BCM43xx_LOCALE_EUROPE: + return "Europe"; + case BCM43xx_LOCALE_USA_LOW: + return "USAlow"; + case BCM43xx_LOCALE_JAPAN_HIGH: + return "JapanHigh"; + case BCM43xx_LOCALE_ALL: + return "All"; + case BCM43xx_LOCALE_NONE: + return "None"; + } + assert(0); + return ""; +} + +static inline u8 bcm43xx_crc8(u8 crc, u8 data) +{ + static const u8 t[] = { + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, + }; + return t[crc ^ data]; +} + +static u8 bcm43xx_sprom_crc(const u16 *sprom) +{ + int word; + u8 crc = 0xFF; + + for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) { + crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF); + crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8); + } + crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF); + crc ^= 0xFF; + + return crc; +} + +int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom) +{ + int i; + u8 crc, expected_crc; + + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) + sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); + /* CRC-8 check. */ + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum " + "(0x%02X, expected: 0x%02X)\n", + crc, expected_crc); + return -EINVAL; + } + + return 0; +} + +int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom) +{ + int i, err; + u8 crc, expected_crc; + u32 spromctl; + + /* CRC-8 validation of the input data. */ + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n"); + return -EINVAL; + } + + printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl); + if (err) + goto err_ctlreg; + spromctl |= 0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + /* We must burn lots of CPU cycles here, but that does not + * really matter as one does not write the SPROM every other minute... + */ + printk(KERN_INFO PFX "[ 0%%"); + mdelay(500); + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + if (i == 16) + printk("25%%"); + else if (i == 32) + printk("50%%"); + else if (i == 48) + printk("75%%"); + else if (i % 2) + printk("."); + bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); + mmiowb(); + mdelay(20); + } + spromctl &= ~0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + mdelay(500); + printk("100%% ]\n"); + printk(KERN_INFO PFX "SPROM written.\n"); + bcm43xx_controller_restart(bcm, "SPROM update"); + + return 0; +err_ctlreg: + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + return -ENODEV; +} + +static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) +{ + u16 value; + u16 *sprom; +#ifdef CONFIG_BCM947XX + char *c; +#endif + + sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16), + GFP_KERNEL); + if (!sprom) { + printk(KERN_ERR PFX "sprom_extract OOM\n"); + return -ENOMEM; + } +#ifdef CONFIG_BCM947XX + sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2")); + sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags")); + + if ((c = nvram_get("il0macaddr")) != NULL) + e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR])); + + if ((c = nvram_get("et1macaddr")) != NULL) + e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR])); + + sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0")); + sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1")); + sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2")); + + sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0")); + sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1")); + sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2")); + + sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev")); +#else + bcm43xx_sprom_read(bcm, sprom); +#endif + + /* boardflags2 */ + value = sprom[BCM43xx_SPROM_BOARDFLAGS2]; + bcm->sprom.boardflags2 = value; + + /* il0macaddr */ + value = sprom[BCM43xx_SPROM_IL0MACADDR + 0]; + *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_IL0MACADDR + 1]; + *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_IL0MACADDR + 2]; + *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value); + + /* et0macaddr */ + value = sprom[BCM43xx_SPROM_ET0MACADDR + 0]; + *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET0MACADDR + 1]; + *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET0MACADDR + 2]; + *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value); + + /* et1macaddr */ + value = sprom[BCM43xx_SPROM_ET1MACADDR + 0]; + *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET1MACADDR + 1]; + *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET1MACADDR + 2]; + *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value); + + /* ethernet phy settings */ + value = sprom[BCM43xx_SPROM_ETHPHY]; + bcm->sprom.et0phyaddr = (value & 0x001F); + bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5; + bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14; + bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15; + + /* boardrev, antennas, locale */ + value = sprom[BCM43xx_SPROM_BOARDREV]; + bcm->sprom.boardrev = (value & 0x00FF); + bcm->sprom.locale = (value & 0x0F00) >> 8; + bcm->sprom.antennas_aphy = (value & 0x3000) >> 12; + bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14; + if (modparam_locale != -1) { + if (modparam_locale >= 0 && modparam_locale <= 11) { + bcm->sprom.locale = modparam_locale; + printk(KERN_WARNING PFX "Operating with modified " + "LocaleCode %u (%s)\n", + bcm->sprom.locale, + bcm43xx_locale_string(bcm->sprom.locale)); + } else { + printk(KERN_WARNING PFX "Module parameter \"locale\" " + "invalid value. (0 - 11)\n"); + } + } + + /* pa0b* */ + value = sprom[BCM43xx_SPROM_PA0B0]; + bcm->sprom.pa0b0 = value; + value = sprom[BCM43xx_SPROM_PA0B1]; + bcm->sprom.pa0b1 = value; + value = sprom[BCM43xx_SPROM_PA0B2]; + bcm->sprom.pa0b2 = value; + + /* wl0gpio* */ + value = sprom[BCM43xx_SPROM_WL0GPIO0]; + if (value == 0x0000) + value = 0xFFFF; + bcm->sprom.wl0gpio0 = value & 0x00FF; + bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8; + value = sprom[BCM43xx_SPROM_WL0GPIO2]; + if (value == 0x0000) + value = 0xFFFF; + bcm->sprom.wl0gpio2 = value & 0x00FF; + bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8; + + /* maxpower */ + value = sprom[BCM43xx_SPROM_MAXPWR]; + bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8; + bcm->sprom.maxpower_bgphy = value & 0x00FF; + + /* pa1b* */ + value = sprom[BCM43xx_SPROM_PA1B0]; + bcm->sprom.pa1b0 = value; + value = sprom[BCM43xx_SPROM_PA1B1]; + bcm->sprom.pa1b1 = value; + value = sprom[BCM43xx_SPROM_PA1B2]; + bcm->sprom.pa1b2 = value; + + /* idle tssi target */ + value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT]; + bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF; + bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8; + + /* boardflags */ + value = sprom[BCM43xx_SPROM_BOARDFLAGS]; + if (value == 0xFFFF) + value = 0x0000; + bcm->sprom.boardflags = value; + /* boardflags workarounds */ + if (bcm->board_vendor == PCI_VENDOR_ID_DELL && + bcm->chip_id == 0x4301 && + bcm->board_revision == 0x74) + bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST; + if (bcm->board_vendor == PCI_VENDOR_ID_APPLE && + bcm->board_type == 0x4E && + bcm->board_revision > 0x40) + bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL; + + /* antenna gain */ + value = sprom[BCM43xx_SPROM_ANTENNA_GAIN]; + if (value == 0x0000 || value == 0xFFFF) + value = 0x0202; + /* convert values to Q5.2 */ + bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4; + bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4; + + kfree(sprom); + + return 0; +} + +static void bcm43xx_geo_init(struct bcm43xx_private *bcm) +{ + struct ieee80211_geo geo; + struct ieee80211_channel *chan; + int have_a = 0, have_bg = 0; + int i; + u8 channel; + struct bcm43xx_phyinfo *phy; + const char *iso_country; + + memset(&geo, 0, sizeof(geo)); + for (i = 0; i < bcm->nr_80211_available; i++) { + phy = &(bcm->core_80211_ext[i].phy); + switch (phy->type) { + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + have_bg = 1; + break; + case BCM43xx_PHYTYPE_A: + have_a = 1; + break; + default: + assert(0); + } + } + iso_country = bcm43xx_locale_iso(bcm->sprom.locale); + + if (have_a) { + for (i = 0, channel = 0; channel < 201; channel++) { + chan = &geo.a[i++]; + chan->freq = bcm43xx_channel_to_freq_a(channel); + chan->channel = channel; + } + geo.a_channels = i; + } + if (have_bg) { + for (i = 0, channel = 1; channel < 15; channel++) { + chan = &geo.bg[i++]; + chan->freq = bcm43xx_channel_to_freq_bg(channel); + chan->channel = channel; + } + geo.bg_channels = i; + } + memcpy(geo.name, iso_country, 2); + if (0 /*TODO: Outdoor use only */) + geo.name[2] = 'O'; + else if (0 /*TODO: Indoor use only */) + geo.name[2] = 'I'; + else + geo.name[2] = ' '; + geo.name[3] = '\0'; + + ieee80211_set_geo(bcm->ieee, &geo); +} + +/* DummyTransmission function, as documented on + * http://bcm-specs.sipsolutions.net/DummyTransmission + */ +void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + unsigned int i, max_loop; + u16 value = 0; + u32 buffer[5] = { + 0x00000000, + 0x0000D400, + 0x00000000, + 0x00000001, + 0x00000000, + }; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + max_loop = 0x1E; + buffer[0] = 0xCC010200; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + max_loop = 0xFA; + buffer[0] = 0x6E840B00; + break; + default: + assert(0); + return; + } + + for (i = 0; i < 5; i++) + bcm43xx_ram_write(bcm, i * 4, buffer[i]); + + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ + + bcm43xx_write16(bcm, 0x0568, 0x0000); + bcm43xx_write16(bcm, 0x07C0, 0x0000); + bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); + bcm43xx_write16(bcm, 0x0508, 0x0000); + bcm43xx_write16(bcm, 0x050A, 0x0000); + bcm43xx_write16(bcm, 0x054C, 0x0000); + bcm43xx_write16(bcm, 0x056A, 0x0014); + bcm43xx_write16(bcm, 0x0568, 0x0826); + bcm43xx_write16(bcm, 0x0500, 0x0000); + bcm43xx_write16(bcm, 0x0502, 0x0030); + + if (radio->version == 0x2050 && radio->revision <= 0x5) + bcm43xx_radio_write16(bcm, 0x0051, 0x0017); + for (i = 0x00; i < max_loop; i++) { + value = bcm43xx_read16(bcm, 0x050E); + if (value & 0x0080) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = bcm43xx_read16(bcm, 0x050E); + if (value & 0x0400) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = bcm43xx_read16(bcm, 0x0690); + if (!(value & 0x0100)) + break; + udelay(10); + } + if (radio->version == 0x2050 && radio->revision <= 0x5) + bcm43xx_radio_write16(bcm, 0x0051, 0x0037); +} + +static void key_write(struct bcm43xx_private *bcm, + u8 index, u8 algorithm, const u16 *key) +{ + unsigned int i, basic_wep = 0; + u32 offset; + u16 value; + + /* Write associated key information */ + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2), + ((index << 4) | (algorithm & 0x0F))); + + /* The first 4 WEP keys need extra love */ + if (((algorithm == BCM43xx_SEC_ALGO_WEP) || + (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4)) + basic_wep = 1; + + /* Write key payload, 8 little endian words */ + offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE); + for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) { + value = cpu_to_le16(key[i]); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + offset + (i * 2), value); + + if (!basic_wep) + continue; + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE, + value); + } +} + +static void keymac_write(struct bcm43xx_private *bcm, + u8 index, const u32 *addr) +{ + /* for keys 0-3 there is no associated mac address */ + if (index < 4) + return; + + index -= 4; + if (bcm->current_core->rev >= 5) { + bcm43xx_shm_write32(bcm, + BCM43xx_SHM_HWMAC, + index * 2, + cpu_to_be32(*addr)); + bcm43xx_shm_write16(bcm, + BCM43xx_SHM_HWMAC, + (index * 2) + 1, + cpu_to_be16(*((u16 *)(addr + 1)))); + } else { + if (index < 8) { + TODO(); /* Put them in the macaddress filter */ + } else { + TODO(); + /* Put them BCM43xx_SHM_SHARED, stating index 0x0120. + Keep in mind to update the count of keymacs in 0x003E as well! */ + } + } +} + +static int bcm43xx_key_write(struct bcm43xx_private *bcm, + u8 index, u8 algorithm, + const u8 *_key, int key_len, + const u8 *mac_addr) +{ + u8 key[BCM43xx_SEC_KEYSIZE] = { 0 }; + + if (index >= ARRAY_SIZE(bcm->key)) + return -EINVAL; + if (key_len > ARRAY_SIZE(key)) + return -EINVAL; + if (algorithm < 1 || algorithm > 5) + return -EINVAL; + + memcpy(key, _key, key_len); + key_write(bcm, index, algorithm, (const u16 *)key); + keymac_write(bcm, index, (const u32 *)mac_addr); + + bcm->key[index].algorithm = algorithm; + + return 0; +} + +static void bcm43xx_clear_keys(struct bcm43xx_private *bcm) +{ + static const u32 zero_mac[2] = { 0 }; + unsigned int i,j, nr_keys = 54; + u16 offset; + + if (bcm->current_core->rev < 5) + nr_keys = 16; + assert(nr_keys <= ARRAY_SIZE(bcm->key)); + + for (i = 0; i < nr_keys; i++) { + bcm->key[i].enabled = 0; + /* returns for i < 4 immediately */ + keymac_write(bcm, i, zero_mac); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + 0x100 + (i * 2), 0x0000); + for (j = 0; j < 8; j++) { + offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + offset, 0x0000); + } + } + dprintk(KERN_INFO PFX "Keys cleared\n"); +} + +/* Lowlevel core-switch function. This is only to be used in + * bcm43xx_switch_core() and bcm43xx_probe_cores() + */ +static int _switch_core(struct bcm43xx_private *bcm, int core) +{ + int err; + int attempts = 0; + u32 current_core; + + assert(core >= 0); + while (1) { + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, + (core * 0x1000) + 0x18000000); + if (unlikely(err)) + goto error; + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, + ¤t_core); + if (unlikely(err)) + goto error; + current_core = (current_core - 0x18000000) / 0x1000; + if (current_core == core) + break; + + if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) + goto error; + udelay(10); + } +#ifdef CONFIG_BCM947XX + if (bcm->pci_dev->bus->number == 0) + bcm->current_core_offset = 0x1000 * core; + else + bcm->current_core_offset = 0; +#endif + + return 0; +error: + printk(KERN_ERR PFX "Failed to switch to core %d\n", core); + return -ENODEV; +} + +int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core) +{ + int err; + + if (unlikely(!new_core)) + return 0; + if (!new_core->available) + return -ENODEV; + if (bcm->current_core == new_core) + return 0; + err = _switch_core(bcm, new_core->index); + if (unlikely(err)) + goto out; + + bcm->current_core = new_core; + bcm->current_80211_core_idx = -1; + if (new_core->id == BCM43xx_COREID_80211) + bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0])); + +out: + return err; +} + +static int bcm43xx_core_enabled(struct bcm43xx_private *bcm) +{ + u32 value; + + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET + | BCM43xx_SBTMSTATELOW_REJECT; + + return (value == BCM43xx_SBTMSTATELOW_CLOCK); +} + +/* disable current core */ +static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags) +{ + u32 sbtmstatelow; + u32 sbtmstatehigh; + int i; + + /* fetch sbtmstatelow from core information registers */ + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + + /* core is already in reset */ + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET) + goto out; + + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) { + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | + BCM43xx_SBTMSTATELOW_REJECT; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + + for (i = 0; i < 1000; i++) { + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n"); + return -EBUSY; + } + + for (i = 0; i < 1000; i++) { + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n"); + return -EBUSY; + } + + sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | + BCM43xx_SBTMSTATELOW_REJECT | + BCM43xx_SBTMSTATELOW_RESET | + BCM43xx_SBTMSTATELOW_CLOCK | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(10); + } + + sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET | + BCM43xx_SBTMSTATELOW_REJECT | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + +out: + bcm->current_core->enabled = 0; + + return 0; +} + +/* enable (reset) current core */ +static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags) +{ + u32 sbtmstatelow; + u32 sbtmstatehigh; + u32 sbimstate; + int err; + + err = bcm43xx_core_disable(bcm, core_flags); + if (err) + goto out; + + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | + BCM43xx_SBTMSTATELOW_RESET | + BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) { + sbtmstatehigh = 0x00000000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh); + } + + sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE); + if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) { + sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT); + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate); + } + + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | + BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + bcm->current_core->enabled = 1; + assert(err == 0); +out: + return err; +} + +/* http://bcm-specs.sipsolutions.net/80211CoreReset */ +void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) +{ + u32 flags = 0x00040000; + + if ((bcm43xx_core_enabled(bcm)) && + !bcm43xx_using_pio(bcm)) { +//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here? +#ifndef CONFIG_BCM947XX + /* reset all used DMA controllers. */ + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE); + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE); + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); + bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); + if (bcm->current_core->rev < 5) + bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); +#endif + } + if (bcm->shutting_down) { + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); + } else { + if (connect_phy) + flags |= 0x20000000; + bcm43xx_phy_connect(bcm, connect_phy); + bcm43xx_core_enable(bcm, flags); + bcm43xx_write16(bcm, 0x03E6, 0x0000); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + | BCM43xx_SBF_400); + } +} + +static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm) +{ + bcm43xx_radio_turn_off(bcm); + bcm43xx_write16(bcm, 0x03E6, 0x00F4); + bcm43xx_core_disable(bcm, 0); +} + +/* Mark the current 80211 core inactive. + * "active_80211_core" is the other 80211 core, which is used. + */ +static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, + struct bcm43xx_coreinfo *active_80211_core) +{ + u32 sbtmstatelow; + struct bcm43xx_coreinfo *old_core; + int err = 0; + + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_radio_turn_off(bcm); + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow &= ~0x200a0000; + sbtmstatelow |= 0xa0000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow &= ~0xa0000; + sbtmstatelow |= 0x80000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) { + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, active_80211_core); + if (err) + goto out; + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow &= ~0x20000000; + sbtmstatelow |= 0x20000000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + err = bcm43xx_switch_core(bcm, old_core); + } + +out: + return err; +} + +static void handle_irq_transmit_status(struct bcm43xx_private *bcm) +{ + u32 v0, v1; + u16 tmp; + struct bcm43xx_xmitstatus stat; + + while (1) { + v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); + if (!v0) + break; + v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); + + stat.cookie = (v0 >> 16) & 0x0000FFFF; + tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1)); + stat.flags = tmp & 0xFF; + stat.cnt1 = (tmp & 0x0F00) >> 8; + stat.cnt2 = (tmp & 0xF000) >> 12; + stat.seq = (u16)(v1 & 0xFFFF); + stat.unknown = (u16)((v1 >> 16) & 0xFF); + + bcm43xx_debugfs_log_txstat(bcm, &stat); + + if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE) + continue; + if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) { + //TODO: packet was not acked (was lost) + } + //TODO: There are more (unknown) flags to test. see bcm43xx_main.h + + if (bcm43xx_using_pio(bcm)) + bcm43xx_pio_handle_xmitstatus(bcm, &stat); + else + bcm43xx_dma_handle_xmitstatus(bcm, &stat); + } +} + +static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) +{ + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4)); + assert(bcm->noisecalc.core_at_start == bcm->current_core); + assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel); +} + +static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) +{ + /* Top half of Link Quality calculation. */ + + if (bcm->noisecalc.calculation_running) + return; + bcm->noisecalc.core_at_start = bcm->current_core; + bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel; + bcm->noisecalc.calculation_running = 1; + bcm->noisecalc.nr_samples = 0; + + bcm43xx_generate_noise_sample(bcm); +} + +static void handle_irq_noise(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 tmp; + u8 noise[4]; + u8 i, j; + s32 average; + + /* Bottom half of Link Quality calculation. */ + + assert(bcm->noisecalc.calculation_running); + if (bcm->noisecalc.core_at_start != bcm->current_core || + bcm->noisecalc.channel_at_start != radio->channel) + goto drop_calculation; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408); + noise[0] = (tmp & 0x00FF); + noise[1] = (tmp & 0xFF00) >> 8; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A); + noise[2] = (tmp & 0x00FF); + noise[3] = (tmp & 0xFF00) >> 8; + if (noise[0] == 0x7F || noise[1] == 0x7F || + noise[2] == 0x7F || noise[3] == 0x7F) + goto generate_new; + + /* Get the noise samples. */ + assert(bcm->noisecalc.nr_samples <= 8); + i = bcm->noisecalc.nr_samples; + noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]]; + bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]]; + bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]]; + bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]]; + bcm->noisecalc.nr_samples++; + if (bcm->noisecalc.nr_samples == 8) { + /* Calculate the Link Quality by the noise samples. */ + average = 0; + for (i = 0; i < 8; i++) { + for (j = 0; j < 4; j++) + average += bcm->noisecalc.samples[i][j]; + } + average /= (8 * 4); + average *= 125; + average += 64; + average /= 128; + + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C); + tmp = (tmp / 128) & 0x1F; + if (tmp >= 8) + average += 2; + else + average -= 25; + if (tmp == 8) + average -= 72; + else + average -= 48; + +/* FIXME: This is wrong, but people want fancy stats. well... */ +bcm->stats.noise = average; + if (average > -65) + bcm->stats.link_quality = 0; + else if (average > -75) + bcm->stats.link_quality = 1; + else if (average > -85) + bcm->stats.link_quality = 2; + else + bcm->stats.link_quality = 3; +// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average); +drop_calculation: + bcm->noisecalc.calculation_running = 0; + return; + } +generate_new: + bcm43xx_generate_noise_sample(bcm); +} + +static void handle_irq_ps(struct bcm43xx_private *bcm) +{ + if (bcm->ieee->iw_mode == IW_MODE_MASTER) { + ///TODO: PS TBTT + } else { + if (1/*FIXME: the last PSpoll frame was sent successfully */) + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); + } + if (bcm->ieee->iw_mode == IW_MODE_ADHOC) + bcm->reg124_set_0x4 = 1; + //FIXME else set to false? +} + +static void handle_irq_reg124(struct bcm43xx_private *bcm) +{ + if (!bcm->reg124_set_0x4) + return; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) + | 0x4); + //FIXME: reset reg124_set_0x4 to false? +} + +static void handle_irq_pmq(struct bcm43xx_private *bcm) +{ + u32 tmp; + + //TODO: AP mode. + + while (1) { + tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS); + if (!(tmp & 0x00000008)) + break; + } + /* 16bit write is odd, but correct. */ + bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002); +} + +static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm, + u16 ram_offset, u16 shm_size_offset) +{ + u32 value; + u16 size = 0; + + /* Timestamp. */ + //FIXME: assumption: The chip sets the timestamp + value = 0; + bcm43xx_ram_write(bcm, ram_offset++, value); + bcm43xx_ram_write(bcm, ram_offset++, value); + size += 8; + + /* Beacon Interval / Capability Information */ + value = 0x0000;//FIXME: Which interval? + value |= (1 << 0) << 16; /* ESS */ + value |= (1 << 2) << 16; /* CF Pollable */ //FIXME? + value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME? + if (!bcm->ieee->open_wep) + value |= (1 << 4) << 16; /* Privacy */ + bcm43xx_ram_write(bcm, ram_offset++, value); + size += 4; + + /* SSID */ + //TODO + + /* FH Parameter Set */ + //TODO + + /* DS Parameter Set */ + //TODO + + /* CF Parameter Set */ + //TODO + + /* TIM */ + //TODO + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size); +} + +static void handle_irq_beacon(struct bcm43xx_private *bcm) +{ + u32 status; + + bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON; + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD); + + if ((status & 0x1) && (status & 0x2)) { + /* ACK beacon IRQ. */ + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, + BCM43xx_IRQ_BEACON); + bcm->irq_savedstate |= BCM43xx_IRQ_BEACON; + return; + } + if (!(status & 0x1)) { + bcm43xx_generate_beacon_template(bcm, 0x68, 0x18); + status |= 0x1; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); + } + if (!(status & 0x2)) { + bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A); + status |= 0x2; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); + } +} + +/* Interrupt handler bottom-half */ +static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) +{ + u32 reason; + u32 dma_reason[4]; + int activity = 0; + unsigned long flags; + +#ifdef CONFIG_BCM43XX_DEBUG + u32 _handled = 0x00000000; +# define bcmirq_handled(irq) do { _handled |= (irq); } while (0) +#else +# define bcmirq_handled(irq) do { /* nothing */ } while (0) +#endif /* CONFIG_BCM43XX_DEBUG*/ + + bcm43xx_lock_mmio(bcm, flags); + reason = bcm->irq_reason; + dma_reason[0] = bcm->dma_reason[0]; + dma_reason[1] = bcm->dma_reason[1]; + dma_reason[2] = bcm->dma_reason[2]; + dma_reason[3] = bcm->dma_reason[3]; + + if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) { + /* TX error. We get this when Template Ram is written in wrong endianess + * in dummy_tx(). We also get this if something is wrong with the TX header + * on DMA or PIO queues. + * Maybe we get this in other error conditions, too. + */ + printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n"); + bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR); + } + if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) | + (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) | + (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) | + (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) { + printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: " + "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3]); + bcm43xx_controller_restart(bcm, "DMA error"); + bcm43xx_unlock_mmio(bcm, flags); + return; + } + if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | + (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) | + (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) | + (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) { + printkl(KERN_ERR PFX "DMA error: " + "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3]); + } + + if (reason & BCM43xx_IRQ_PS) { + handle_irq_ps(bcm); + bcmirq_handled(BCM43xx_IRQ_PS); + } + + if (reason & BCM43xx_IRQ_REG124) { + handle_irq_reg124(bcm); + bcmirq_handled(BCM43xx_IRQ_REG124); + } + + if (reason & BCM43xx_IRQ_BEACON) { + if (bcm->ieee->iw_mode == IW_MODE_MASTER) + handle_irq_beacon(bcm); + bcmirq_handled(BCM43xx_IRQ_BEACON); + } + + if (reason & BCM43xx_IRQ_PMQ) { + handle_irq_pmq(bcm); + bcmirq_handled(BCM43xx_IRQ_PMQ); + } + + if (reason & BCM43xx_IRQ_SCAN) { + /*TODO*/ + //bcmirq_handled(BCM43xx_IRQ_SCAN); + } + + if (reason & BCM43xx_IRQ_NOISE) { + handle_irq_noise(bcm); + bcmirq_handled(BCM43xx_IRQ_NOISE); + } + + /* Check the DMA reason registers for received data. */ + assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); + assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); + if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { + if (bcm43xx_using_pio(bcm)) + bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0); + else + bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0); + /* We intentionally don't set "activity" to 1, here. */ + } + if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { + if (bcm43xx_using_pio(bcm)) + bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3); + else + bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1); + activity = 1; + } + bcmirq_handled(BCM43xx_IRQ_RX); + + if (reason & BCM43xx_IRQ_XMIT_STATUS) { + handle_irq_transmit_status(bcm); + activity = 1; + //TODO: In AP mode, this also causes sending of powersave responses. + bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); + } + + /* IRQ_PIO_WORKAROUND is handled in the top-half. */ + bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND); +#ifdef CONFIG_BCM43XX_DEBUG + if (unlikely(reason & ~_handled)) { + printkl(KERN_WARNING PFX + "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, " + "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + reason, (reason & ~_handled), + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3]); + } +#endif +#undef bcmirq_handled + + if (!modparam_noleds) + bcm43xx_leds_update(bcm, activity); + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); + bcm43xx_unlock_mmio(bcm, flags); +} + +static void pio_irq_workaround(struct bcm43xx_private *bcm, + u16 base, int queueidx) +{ + u16 rxctl; + + rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL); + if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE) + bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE; + else + bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE; +} + +static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason) +{ + if (bcm43xx_using_pio(bcm) && + (bcm->current_core->rev < 3) && + (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { + /* Apply a PIO specific workaround to the dma_reasons */ + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0); + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1); + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2); + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3); + } + + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason); + + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, + bcm->dma_reason[0]); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON, + bcm->dma_reason[1]); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON, + bcm->dma_reason[2]); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON, + bcm->dma_reason[3]); +} + +/* Interrupt handler top-half */ +static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + irqreturn_t ret = IRQ_HANDLED; + struct bcm43xx_private *bcm = dev_id; + u32 reason; + + if (!bcm) + return IRQ_NONE; + + spin_lock(&bcm->_lock); + + reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (reason == 0xffffffff) { + /* irq not for us (shared irq) */ + ret = IRQ_NONE; + goto out; + } + reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + if (!reason) + goto out; + + bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) + & 0x0001dc00; + bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) + & 0x0000dc00; + bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) + & 0x0000dc00; + bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) + & 0x0001dc00; + + bcm43xx_interrupt_ack(bcm, reason); + + /* Only accept IRQs, if we are initialized properly. + * This avoids an RX race while initializing. + * We should probably not enable IRQs before we are initialized + * completely, but some careful work is needed to fix this. I think it + * is best to stay with this cheap workaround for now... . + */ + if (likely(bcm->initialized)) { + /* disable all IRQs. They are enabled again in the bottom half. */ + bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + /* save the reason code and call our bottom half. */ + bcm->irq_reason = reason; + tasklet_schedule(&bcm->isr_tasklet); + } + +out: + mmiowb(); + spin_unlock(&bcm->_lock); + + return ret; +} + +static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) +{ + if (bcm->firmware_norelease && !force) + return; /* Suspending or controller reset. */ + release_firmware(bcm->ucode); + bcm->ucode = NULL; + release_firmware(bcm->pcm); + bcm->pcm = NULL; + release_firmware(bcm->initvals0); + bcm->initvals0 = NULL; + release_firmware(bcm->initvals1); + bcm->initvals1 = NULL; +} + +static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u8 rev = bcm->current_core->rev; + int err = 0; + int nr; + char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; + + if (!bcm->ucode) { + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", + (rev >= 5 ? 5 : rev), + modparam_fwpostfix); + err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: Microcode \"%s\" not available or load failed.\n", + buf); + goto error; + } + } + + if (!bcm->pcm) { + snprintf(buf, ARRAY_SIZE(buf), + "bcm43xx_pcm%d%s.fw", + (rev < 5 ? 4 : 5), + modparam_fwpostfix); + err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: PCM \"%s\" not available or load failed.\n", + buf); + goto error; + } + } + + if (!bcm->initvals0) { + if (rev == 2 || rev == 4) { + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + nr = 3; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + nr = 1; + break; + default: + goto err_noinitval; + } + + } else if (rev >= 5) { + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + nr = 7; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + nr = 5; + break; + default: + goto err_noinitval; + } + } else + goto err_noinitval; + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", + nr, modparam_fwpostfix); + + err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: InitVals \"%s\" not available or load failed.\n", + buf); + goto error; + } + if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { + printk(KERN_ERR PFX "InitVals fileformat error.\n"); + goto error; + } + } + + if (!bcm->initvals1) { + if (rev >= 5) { + u32 sbtmstatehigh; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (sbtmstatehigh & 0x00010000) + nr = 9; + else + nr = 10; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + nr = 6; + break; + default: + goto err_noinitval; + } + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", + nr, modparam_fwpostfix); + + err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: InitVals \"%s\" not available or load failed.\n", + buf); + goto error; + } + if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { + printk(KERN_ERR PFX "InitVals fileformat error.\n"); + goto error; + } + } + } + +out: + return err; +error: + bcm43xx_release_firmware(bcm, 1); + goto out; +err_noinitval: + printk(KERN_ERR PFX "Error: No InitVals available!\n"); + err = -ENOENT; + goto error; +} + +static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) +{ + const u32 *data; + unsigned int i, len; + + /* Upload Microcode. */ + data = (u32 *)(bcm->ucode->data); + len = bcm->ucode->size / sizeof(u32); + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); + for (i = 0; i < len; i++) { + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } + + /* Upload PCM data. */ + data = (u32 *)(bcm->pcm->data); + len = bcm->pcm->size / sizeof(u32); + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); + for (i = 0; i < len; i++) { + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } +} + +static int bcm43xx_write_initvals(struct bcm43xx_private *bcm, + const struct bcm43xx_initval *data, + const unsigned int len) +{ + u16 offset, size; + u32 value; + unsigned int i; + + for (i = 0; i < len; i++) { + offset = be16_to_cpu(data[i].offset); + size = be16_to_cpu(data[i].size); + value = be32_to_cpu(data[i].value); + + if (unlikely(offset >= 0x1000)) + goto err_format; + if (size == 2) { + if (unlikely(value & 0xFFFF0000)) + goto err_format; + bcm43xx_write16(bcm, offset, (u16)value); + } else if (size == 4) { + bcm43xx_write32(bcm, offset, value); + } else + goto err_format; + } + + return 0; + +err_format: + printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. " + "Please fix your bcm43xx firmware files.\n"); + return -EPROTO; +} + +static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) +{ + int err; + + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, + bcm->initvals0->size / sizeof(struct bcm43xx_initval)); + if (err) + goto out; + if (bcm->initvals1) { + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, + bcm->initvals1->size / sizeof(struct bcm43xx_initval)); + if (err) + goto out; + } +out: + return err; +} + +static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) +{ + int res; + unsigned int i; + u32 data; + + bcm->irq = bcm->pci_dev->irq; +#ifdef CONFIG_BCM947XX + if (bcm->pci_dev->bus->number == 0) { + struct pci_dev *d = NULL; + /* FIXME: we will probably need more device IDs here... */ + d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL); + if (d != NULL) { + bcm->irq = d->irq; + } + } +#endif + res = request_irq(bcm->irq, bcm43xx_interrupt_handler, + SA_SHIRQ, KBUILD_MODNAME, bcm); + if (res) { + printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); + return -ENODEV; + } + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); + i = 0; + while (1) { + data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (data == BCM43xx_IRQ_READY) + break; + i++; + if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { + printk(KERN_ERR PFX "Card IRQ register not responding. " + "Giving up.\n"); + free_irq(bcm->irq, bcm); + return -ENODEV; + } + udelay(10); + } + // dummy read + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + + return 0; +} + +/* Switch to the core used to write the GPIO register. + * This is either the ChipCommon, or the PCI core. + */ +static int switch_to_gpio_core(struct bcm43xx_private *bcm) +{ + int err; + + /* Where to find the GPIO register depends on the chipset. + * If it has a ChipCommon, its register at offset 0x6c is the GPIO + * control register. Otherwise the register at offset 0x6c in the + * PCI core is the GPIO control register. + */ + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) { + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (unlikely(err == -ENODEV)) { + printk(KERN_ERR PFX "gpio error: " + "Neither ChipCommon nor PCI core available!\n"); + } + } + + return err; +} + +/* Initialize the GPIOs + * http://bcm-specs.sipsolutions.net/GPIO + */ +static int bcm43xx_gpio_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_coreinfo *old_core; + int err; + u32 mask, set; + + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & 0xFFFF3FFF); + + bcm43xx_leds_switch_all(bcm, 0); + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F); + + mask = 0x0000001F; + set = 0x0000000F; + if (bcm->chip_id == 0x4301) { + mask |= 0x0060; + set |= 0x0060; + } + if (0 /* FIXME: conditional unknown */) { + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) + | 0x0100); + mask |= 0x0180; + set |= 0x0180; + } + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) + | 0x0200); + mask |= 0x0200; + set |= 0x0200; + } + if (bcm->current_core->rev >= 2) + mask |= 0x0010; /* FIXME: This is redundant. */ + + old_core = bcm->current_core; + err = switch_to_gpio_core(bcm); + if (err) + goto out; + bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, + (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set); + err = bcm43xx_switch_core(bcm, old_core); +out: + return err; +} + +/* Turn off all GPIO stuff. Call this on module unload, for example. */ +static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm) +{ + struct bcm43xx_coreinfo *old_core; + int err; + + old_core = bcm->current_core; + err = switch_to_gpio_core(bcm); + if (err) + return err; + bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000); + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + + return 0; +} + +/* http://bcm-specs.sipsolutions.net/EnableMac */ +void bcm43xx_mac_enable(struct bcm43xx_private *bcm) +{ + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + | BCM43xx_SBF_MAC_ENABLED); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); +} + +/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) +{ + int i; + u32 tmp; + + bcm43xx_power_saving_ctl_bits(bcm, -1, 1); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & ~BCM43xx_SBF_MAC_ENABLED); + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ + for (i = 100000; i; i--) { + tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (tmp & BCM43xx_IRQ_READY) + return; + udelay(10); + } + printkl(KERN_ERR PFX "MAC suspend failed\n"); +} + +void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, + int iw_mode) +{ + unsigned long flags; + struct net_device *net_dev = bcm->net_dev; + u32 status; + u16 value; + + spin_lock_irqsave(&bcm->ieee->lock, flags); + bcm->ieee->iw_mode = iw_mode; + spin_unlock_irqrestore(&bcm->ieee->lock, flags); + if (iw_mode == IW_MODE_MONITOR) + net_dev->type = ARPHRD_IEEE80211; + else + net_dev->type = ARPHRD_ETHER; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + /* Reset status to infrastructured mode */ + status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR); + status &= ~BCM43xx_SBF_MODE_PROMISC; + status |= BCM43xx_SBF_MODE_NOTADHOC; + +/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */ +status |= BCM43xx_SBF_MODE_PROMISC; + + switch (iw_mode) { + case IW_MODE_MONITOR: + status |= BCM43xx_SBF_MODE_MONITOR; + status |= BCM43xx_SBF_MODE_PROMISC; + break; + case IW_MODE_ADHOC: + status &= ~BCM43xx_SBF_MODE_NOTADHOC; + break; + case IW_MODE_MASTER: + status |= BCM43xx_SBF_MODE_AP; + break; + case IW_MODE_SECOND: + case IW_MODE_REPEAT: + TODO(); /* TODO */ + break; + case IW_MODE_INFRA: + /* nothing to be done here... */ + break; + default: + dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode); + } + if (net_dev->flags & IFF_PROMISC) + status |= BCM43xx_SBF_MODE_PROMISC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + + value = 0x0002; + if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { + if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3) + value = 0x0064; + else + value = 0x0032; + } + bcm43xx_write16(bcm, 0x0612, value); +} + +/* This is the opposite of bcm43xx_chip_init() */ +static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) +{ + bcm43xx_radio_turn_off(bcm); + if (!modparam_noleds) + bcm43xx_leds_exit(bcm); + bcm43xx_gpio_cleanup(bcm); + free_irq(bcm->irq, bcm); + bcm43xx_release_firmware(bcm, 0); +} + +/* Initialize the chip + * http://bcm-specs.sipsolutions.net/ChipInit + */ +static int bcm43xx_chip_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + int err; + int tmp; + u32 value32; + u16 value16; + + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + BCM43xx_SBF_CORE_READY + | BCM43xx_SBF_400); + + err = bcm43xx_request_firmware(bcm); + if (err) + goto out; + bcm43xx_upload_microcode(bcm); + + err = bcm43xx_initialize_irq(bcm); + if (err) + goto err_release_fw; + + err = bcm43xx_gpio_init(bcm); + if (err) + goto err_free_irq; + + err = bcm43xx_upload_initvals(bcm); + if (err) + goto err_gpio_cleanup; + bcm43xx_radio_turn_on(bcm); + + bcm43xx_write16(bcm, 0x03E6, 0x0000); + err = bcm43xx_phy_init(bcm); + if (err) + goto err_radio_off; + + /* Select initial Interference Mitigation. */ + tmp = radio->interfmode; + radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; + bcm43xx_radio_set_interference_mitigation(bcm, tmp); + + bcm43xx_phy_set_antenna_diversity(bcm); + bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT); + if (phy->type == BCM43xx_PHYTYPE_B) { + value16 = bcm43xx_read16(bcm, 0x005E); + value16 |= 0x0004; + bcm43xx_write16(bcm, 0x005E, value16); + } + bcm43xx_write32(bcm, 0x0100, 0x01000000); + if (bcm->current_core->rev < 5) + bcm43xx_write32(bcm, 0x010C, 0x01000000); + + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= BCM43xx_SBF_MODE_NOTADHOC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= 0x100000; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + + if (bcm43xx_using_pio(bcm)) { + bcm43xx_write32(bcm, 0x0210, 0x00000100); + bcm43xx_write32(bcm, 0x0230, 0x00000100); + bcm43xx_write32(bcm, 0x0250, 0x00000100); + bcm43xx_write32(bcm, 0x0270, 0x00000100); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000); + } + + /* Probe Response Timeout value */ + /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000); + + /* Initially set the wireless operation mode. */ + bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode); + + if (bcm->current_core->rev < 3) { + bcm43xx_write16(bcm, 0x060E, 0x0000); + bcm43xx_write16(bcm, 0x0610, 0x8000); + bcm43xx_write16(bcm, 0x0604, 0x0000); + bcm43xx_write16(bcm, 0x0606, 0x0200); + } else { + bcm43xx_write32(bcm, 0x0188, 0x80000000); + bcm43xx_write32(bcm, 0x018C, 0x02000000); + } + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00); + + value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + value32 |= 0x00100000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32); + + bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm)); + + assert(err == 0); + dprintk(KERN_INFO PFX "Chip initialized\n"); +out: + return err; + +err_radio_off: + bcm43xx_radio_turn_off(bcm); +err_gpio_cleanup: + bcm43xx_gpio_cleanup(bcm); +err_free_irq: + free_irq(bcm->irq, bcm); +err_release_fw: + bcm43xx_release_firmware(bcm, 1); + goto out; +} + +/* Validate chip access + * http://bcm-specs.sipsolutions.net/ValidateChipAccess */ +static int bcm43xx_validate_chip(struct bcm43xx_private *bcm) +{ + u32 value; + u32 shm_backup; + + shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA); + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) + goto error; + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55); + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) + goto error; + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup); + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + if ((value | 0x80000000) != 0x80000400) + goto error; + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (value != 0x00000000) + goto error; + + return 0; +error: + printk(KERN_ERR PFX "Failed to validate the chipaccess\n"); + return -ENODEV; +} + +static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) +{ + /* Initialize a "phyinfo" structure. The structure is already + * zeroed out. + */ + phy->antenna_diversity = 0xFFFF; + phy->savedpctlreg = 0xFFFF; + phy->minlowsig[0] = 0xFFFF; + phy->minlowsig[1] = 0xFFFF; + spin_lock_init(&phy->lock); +} + +static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) +{ + /* Initialize a "radioinfo" structure. The structure is already + * zeroed out. + */ + radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; + radio->channel = 0xFF; + radio->initial_channel = 0xFF; + radio->lofcal = 0xFFFF; + radio->initval = 0xFFFF; + radio->nrssi[0] = -1000; + radio->nrssi[1] = -1000; +} + +static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) +{ + int err, i; + int current_core; + u32 core_vendor, core_id, core_rev; + u32 sb_id_hi, chip_id_32 = 0; + u16 pci_device, chip_id_16; + u8 core_count; + + memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo) + * BCM43xx_MAX_80211_CORES); + memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) + * BCM43xx_MAX_80211_CORES); + bcm->current_80211_core_idx = -1; + bcm->nr_80211_available = 0; + bcm->current_core = NULL; + bcm->active_80211_core = NULL; + + /* map core 0 */ + err = _switch_core(bcm, 0); + if (err) + goto out; + + /* fetch sb_id_hi from core information registers */ + sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); + + core_id = (sb_id_hi & 0xFFF0) >> 4; + core_rev = (sb_id_hi & 0xF); + core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; + + /* if present, chipcommon is always core 0; read the chipid from it */ + if (core_id == BCM43xx_COREID_CHIPCOMMON) { + chip_id_32 = bcm43xx_read32(bcm, 0); + chip_id_16 = chip_id_32 & 0xFFFF; + bcm->core_chipcommon.available = 1; + bcm->core_chipcommon.id = core_id; + bcm->core_chipcommon.rev = core_rev; + bcm->core_chipcommon.index = 0; + /* While we are at it, also read the capabilities. */ + bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES); + } else { + /* without a chipCommon, use a hard coded table. */ + pci_device = bcm->pci_dev->device; + if (pci_device == 0x4301) + chip_id_16 = 0x4301; + else if ((pci_device >= 0x4305) && (pci_device <= 0x4307)) + chip_id_16 = 0x4307; + else if ((pci_device >= 0x4402) && (pci_device <= 0x4403)) + chip_id_16 = 0x4402; + else if ((pci_device >= 0x4610) && (pci_device <= 0x4615)) + chip_id_16 = 0x4610; + else if ((pci_device >= 0x4710) && (pci_device <= 0x4715)) + chip_id_16 = 0x4710; +#ifdef CONFIG_BCM947XX + else if ((pci_device >= 0x4320) && (pci_device <= 0x4325)) + chip_id_16 = 0x4309; +#endif + else { + printk(KERN_ERR PFX "Could not determine Chip ID\n"); + return -ENODEV; + } + } + + /* ChipCommon with Core Rev >=4 encodes number of cores, + * otherwise consult hardcoded table */ + if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) { + core_count = (chip_id_32 & 0x0F000000) >> 24; + } else { + switch (chip_id_16) { + case 0x4610: + case 0x4704: + case 0x4710: + core_count = 9; + break; + case 0x4310: + core_count = 8; + break; + case 0x5365: + core_count = 7; + break; + case 0x4306: + core_count = 6; + break; + case 0x4301: + case 0x4307: + core_count = 5; + break; + case 0x4402: + core_count = 3; + break; + default: + /* SOL if we get here */ + assert(0); + core_count = 1; + } + } + + bcm->chip_id = chip_id_16; + bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16; + bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20; + + dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n", + bcm->chip_id, bcm->chip_rev); + dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count); + if (bcm->core_chipcommon.available) { + dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", + core_id, core_rev, core_vendor, + bcm43xx_core_enabled(bcm) ? "enabled" : "disabled"); + } + + if (bcm->core_chipcommon.available) + current_core = 1; + else + current_core = 0; + for ( ; current_core < core_count; current_core++) { + struct bcm43xx_coreinfo *core; + struct bcm43xx_coreinfo_80211 *ext_80211; + + err = _switch_core(bcm, current_core); + if (err) + goto out; + /* Gather information */ + /* fetch sb_id_hi from core information registers */ + sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); + + /* extract core_id, core_rev, core_vendor */ + core_id = (sb_id_hi & 0xFFF0) >> 4; + core_rev = (sb_id_hi & 0xF); + core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; + + dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", + current_core, core_id, core_rev, core_vendor, + bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" ); + + core = NULL; + switch (core_id) { + case BCM43xx_COREID_PCI: + core = &bcm->core_pci; + if (core->available) { + printk(KERN_WARNING PFX "Multiple PCI cores found.\n"); + continue; + } + break; + case BCM43xx_COREID_80211: + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + core = &(bcm->core_80211[i]); + ext_80211 = &(bcm->core_80211_ext[i]); + if (!core->available) + break; + core = NULL; + } + if (!core) { + printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n", + BCM43xx_MAX_80211_CORES); + continue; + } + if (i != 0) { + /* More than one 80211 core is only supported + * by special chips. + * There are chips with two 80211 cores, but with + * dangling pins on the second core. Be careful + * and ignore these cores here. + */ + if (bcm->pci_dev->device != 0x4324) { + dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n"); + continue; + } + } + switch (core_rev) { + case 2: + case 4: + case 5: + case 6: + case 7: + case 9: + break; + default: + printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n", + core_rev); + err = -ENODEV; + goto out; + } + bcm->nr_80211_available++; + bcm43xx_init_struct_phyinfo(&ext_80211->phy); + bcm43xx_init_struct_radioinfo(&ext_80211->radio); + break; + case BCM43xx_COREID_CHIPCOMMON: + printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n"); + break; + } + if (core) { + core->available = 1; + core->id = core_id; + core->rev = core_rev; + core->index = current_core; + } + } + + if (!bcm->core_80211[0].available) { + printk(KERN_ERR PFX "Error: No 80211 core found!\n"); + err = -ENODEV; + goto out; + } + + err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]); + + assert(err == 0); +out: + return err; +} + +static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm) +{ + const u8 *mac = (const u8*)(bcm->net_dev->dev_addr); + u8 *bssid = bcm->ieee->bssid; + + switch (bcm->ieee->iw_mode) { + case IW_MODE_ADHOC: + random_ether_addr(bssid); + break; + case IW_MODE_MASTER: + case IW_MODE_INFRA: + case IW_MODE_REPEAT: + case IW_MODE_SECOND: + case IW_MODE_MONITOR: + memcpy(bssid, mac, ETH_ALEN); + break; + default: + assert(0); + } +} + +static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm, + u16 rate, + int is_ofdm) +{ + u16 offset; + + if (is_ofdm) { + offset = 0x480; + offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2; + } + else { + offset = 0x4C0; + offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2; + } + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20, + bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset)); +} + +static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm) +{ + switch (bcm43xx_current_phy(bcm)->type) { + case BCM43xx_PHYTYPE_A: + case BCM43xx_PHYTYPE_G: + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1); + case BCM43xx_PHYTYPE_B: + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0); + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0); + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0); + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0); + break; + default: + assert(0); + } +} + +static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) +{ + bcm43xx_chip_cleanup(bcm); + bcm43xx_pio_free(bcm); + bcm43xx_dma_free(bcm); + + bcm->current_core->initialized = 0; +} + +/* http://bcm-specs.sipsolutions.net/80211Init */ +static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u32 ucodeflags; + int err; + u32 sbimconfiglow; + u8 limit; + + if (bcm->chip_rev < 5) { + sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); + sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; + sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; + if (bcm->bustype == BCM43xx_BUSTYPE_PCI) + sbimconfiglow |= 0x32; + else if (bcm->bustype == BCM43xx_BUSTYPE_SB) + sbimconfiglow |= 0x53; + else + assert(0); + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow); + } + + bcm43xx_phy_calibrate(bcm); + err = bcm43xx_chip_init(bcm); + if (err) + goto out; + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev); + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET); + + if (0 /*FIXME: which condition has to be used here? */) + ucodeflags |= 0x00000010; + + /* HW decryption needs to be set now */ + ucodeflags |= 0x40000000; + + if (phy->type == BCM43xx_PHYTYPE_G) { + ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; + if (phy->rev == 1) + ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY; + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) + ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL; + } else if (phy->type == BCM43xx_PHYTYPE_B) { + ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; + if (phy->rev >= 2 && radio->version == 0x2050) + ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY; + } + + if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET)) { + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, ucodeflags); + } + + /* Short/Long Retry Limit. + * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. + */ + limit = limit_value(modparam_short_retry, 0, 0xF); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit); + limit = limit_value(modparam_long_retry, 0, 0xF); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit); + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2); + + bcm43xx_rate_memory_init(bcm); + + /* Minimum Contention Window */ + if (phy->type == BCM43xx_PHYTYPE_B) + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f); + else + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f); + /* Maximum Contention Window */ + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); + + bcm43xx_gen_bssid(bcm); + bcm43xx_write_mac_bssid_templates(bcm); + + if (bcm->current_core->rev >= 5) + bcm43xx_write16(bcm, 0x043C, 0x000C); + + if (bcm43xx_using_pio(bcm)) + err = bcm43xx_pio_init(bcm); + else + err = bcm43xx_dma_init(bcm); + if (err) + goto err_chip_cleanup; + bcm43xx_write16(bcm, 0x0612, 0x0050); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); + + bcm43xx_mac_enable(bcm); + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); + + bcm->current_core->initialized = 1; +out: + return err; + +err_chip_cleanup: + bcm43xx_chip_cleanup(bcm); + goto out; +} + +static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm) +{ + int err; + u16 pci_status; + + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto out; + bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); + bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); + +out: + return err; +} + +static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm) +{ + bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); + bcm43xx_pctl_set_crystal(bcm, 0); +} + +static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, + u32 address, + u32 data) +{ + bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address); + bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data); +} + +static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm) +{ + int err; + struct bcm43xx_coreinfo *old_core; + + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (err) + goto out; + + bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); + + bcm43xx_switch_core(bcm, old_core); + assert(err == 0); +out: + return err; +} + +/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable. + * To enable core 0, pass a core_mask of 1<<0 + */ +static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, + u32 core_mask) +{ + u32 backplane_flag_nr; + u32 value; + struct bcm43xx_coreinfo *old_core; + int err = 0; + + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG); + backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK; + + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (err) + goto out; + + if (bcm->core_pci.rev < 6) { + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC); + value |= (1 << backplane_flag_nr); + bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value); + } else { + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value); + if (err) { + printk(KERN_ERR PFX "Error: ICR setup failure!\n"); + goto out_switch_back; + } + value |= core_mask << 8; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value); + if (err) { + printk(KERN_ERR PFX "Error: ICR setup failure!\n"); + goto out_switch_back; + } + } + + value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); + value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST; + bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); + + if (bcm->core_pci.rev < 5) { + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); + value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT) + & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; + value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT) + & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value); + err = bcm43xx_pcicore_commit_settings(bcm); + assert(err == 0); + } + +out_switch_back: + err = bcm43xx_switch_core(bcm, old_core); +out: + return err; +} + +static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) +{ + ieee80211softmac_start(bcm->net_dev); +} + +static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2) + return; + + bcm43xx_mac_suspend(bcm); + bcm43xx_phy_lo_g_measure(bcm); + bcm43xx_mac_enable(bcm); +} + +static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm) +{ + bcm43xx_phy_lo_mark_all_unused(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_mac_suspend(bcm); + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_mac_enable(bcm); + } +} + +static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm) +{ + /* Update device statistics. */ + bcm43xx_calculate_link_quality(bcm); +} + +static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + if (phy->type == BCM43xx_PHYTYPE_G) { + //TODO: update_aci_moving_average + if (radio->aci_enable && radio->aci_wlan_automatic) { + bcm43xx_mac_suspend(bcm); + if (!radio->aci_enable && 1 /*TODO: not scanning? */) { + if (0 /*TODO: bunch of conditions*/) { + bcm43xx_radio_set_interference_mitigation(bcm, + BCM43xx_RADIO_INTERFMODE_MANUALWLAN); + } + } else if (1/*TODO*/) { + /* + if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) { + bcm43xx_radio_set_interference_mitigation(bcm, + BCM43xx_RADIO_INTERFMODE_NONE); + } + */ + } + bcm43xx_mac_enable(bcm); + } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN && + phy->rev == 1) { + //TODO: implement rev1 workaround + } + } + bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? + //TODO for APHY (temperature?) +} + +static void bcm43xx_periodic_task_handler(unsigned long d) +{ + struct bcm43xx_private *bcm = (struct bcm43xx_private *)d; + unsigned long flags; + unsigned int state; + + bcm43xx_lock_mmio(bcm, flags); + + assert(bcm->initialized); + state = bcm->periodic_state; + if (state % 8 == 0) + bcm43xx_periodic_every120sec(bcm); + if (state % 4 == 0) + bcm43xx_periodic_every60sec(bcm); + if (state % 2 == 0) + bcm43xx_periodic_every30sec(bcm); + bcm43xx_periodic_every15sec(bcm); + bcm->periodic_state = state + 1; + + mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15)); + + bcm43xx_unlock_mmio(bcm, flags); +} + +static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) +{ + del_timer_sync(&bcm->periodic_tasks); +} + +static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) +{ + struct timer_list *timer = &(bcm->periodic_tasks); + + assert(bcm->initialized); + setup_timer(timer, + bcm43xx_periodic_task_handler, + (unsigned long)bcm); + timer->expires = jiffies; + add_timer(timer); +} + +static void bcm43xx_security_init(struct bcm43xx_private *bcm) +{ + bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, + 0x0056) * 2; + bcm43xx_clear_keys(bcm); +} + +/* This is the opposite of bcm43xx_init_board() */ +static void bcm43xx_free_board(struct bcm43xx_private *bcm) +{ + int i, err; + unsigned long flags; + + bcm43xx_sysfs_unregister(bcm); + + bcm43xx_periodic_tasks_delete(bcm); + + bcm43xx_lock(bcm, flags); + bcm->initialized = 0; + bcm->shutting_down = 1; + bcm43xx_unlock(bcm, flags); + + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + if (!bcm->core_80211[i].available) + continue; + if (!bcm->core_80211[i].initialized) + continue; + + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); + assert(err == 0); + bcm43xx_wireless_core_cleanup(bcm); + } + + bcm43xx_pctl_set_crystal(bcm, 0); + + bcm43xx_lock(bcm, flags); + bcm->shutting_down = 0; + bcm43xx_unlock(bcm, flags); +} + +static int bcm43xx_init_board(struct bcm43xx_private *bcm) +{ + int i, err; + int connect_phy; + unsigned long flags; + + might_sleep(); + + bcm43xx_lock(bcm, flags); + bcm->initialized = 0; + bcm->shutting_down = 0; + bcm43xx_unlock(bcm, flags); + + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto out; + err = bcm43xx_pctl_init(bcm); + if (err) + goto err_crystal_off; + err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); + if (err) + goto err_crystal_off; + + tasklet_enable(&bcm->isr_tasklet); + for (i = 0; i < bcm->nr_80211_available; i++) { + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); + assert(err != -ENODEV); + if (err) + goto err_80211_unwind; + + /* Enable the selected wireless core. + * Connect PHY only on the first core. + */ + if (!bcm43xx_core_enabled(bcm)) { + if (bcm->nr_80211_available == 1) { + connect_phy = bcm43xx_current_phy(bcm)->connected; + } else { + if (i == 0) + connect_phy = 1; + else + connect_phy = 0; + } + bcm43xx_wireless_core_reset(bcm, connect_phy); + } + + if (i != 0) + bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); + + err = bcm43xx_wireless_core_init(bcm); + if (err) + goto err_80211_unwind; + + if (i != 0) { + bcm43xx_mac_suspend(bcm); + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_radio_turn_off(bcm); + } + } + bcm->active_80211_core = &bcm->core_80211[0]; + if (bcm->nr_80211_available >= 2) { + bcm43xx_switch_core(bcm, &bcm->core_80211[0]); + bcm43xx_mac_enable(bcm); + } + bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); + bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); + dprintk(KERN_INFO PFX "80211 cores initialized\n"); + bcm43xx_security_init(bcm); + bcm43xx_softmac_init(bcm); + + bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); + + if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { + bcm43xx_mac_suspend(bcm); + bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0); + bcm43xx_mac_enable(bcm); + } + + /* Initialization of the board is done. Flag it as such. */ + bcm43xx_lock(bcm, flags); + bcm->initialized = 1; + bcm43xx_unlock(bcm, flags); + + bcm43xx_periodic_tasks_setup(bcm); + bcm43xx_sysfs_register(bcm); + //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though... + + assert(err == 0); +out: + return err; + +err_80211_unwind: + tasklet_disable(&bcm->isr_tasklet); + /* unwind all 80211 initialization */ + for (i = 0; i < bcm->nr_80211_available; i++) { + if (!bcm->core_80211[i].initialized) + continue; + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_wireless_core_cleanup(bcm); + } +err_crystal_off: + bcm43xx_pctl_set_crystal(bcm, 0); + goto out; +} + +static void bcm43xx_detach_board(struct bcm43xx_private *bcm) +{ + struct pci_dev *pci_dev = bcm->pci_dev; + int i; + + bcm43xx_chipset_detach(bcm); + /* Do _not_ access the chip, after it is detached. */ + iounmap(bcm->mmio_addr); + + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); + + /* Free allocated structures/fields */ + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + kfree(bcm->core_80211_ext[i].phy._lo_pairs); + if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) + kfree(bcm->core_80211_ext[i].phy.tssi2dbm); + } +} + +static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 value; + u8 phy_version; + u8 phy_type; + u8 phy_rev; + int phy_rev_ok = 1; + void *p; + + value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); + + phy_version = (value & 0xF000) >> 12; + phy_type = (value & 0x0F00) >> 8; + phy_rev = (value & 0x000F); + + dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n", + phy_version, phy_type, phy_rev); + + switch (phy_type) { + case BCM43xx_PHYTYPE_A: + if (phy_rev >= 4) + phy_rev_ok = 0; + /*FIXME: We need to switch the ieee->modulation, etc.. flags, + * if we switch 80211 cores after init is done. + * As we do not implement on the fly switching between + * wireless cores, I will leave this as a future task. + */ + bcm->ieee->modulation = IEEE80211_OFDM_MODULATION; + bcm->ieee->mode = IEEE_A; + bcm->ieee->freq_band = IEEE80211_52GHZ_BAND | + IEEE80211_24GHZ_BAND; + break; + case BCM43xx_PHYTYPE_B: + if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7) + phy_rev_ok = 0; + bcm->ieee->modulation = IEEE80211_CCK_MODULATION; + bcm->ieee->mode = IEEE_B; + bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; + break; + case BCM43xx_PHYTYPE_G: + if (phy_rev > 7) + phy_rev_ok = 0; + bcm->ieee->modulation = IEEE80211_OFDM_MODULATION | + IEEE80211_CCK_MODULATION; + bcm->ieee->mode = IEEE_G; + bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; + break; + default: + printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n", + phy_type); + return -ENODEV; + }; + if (!phy_rev_ok) { + printk(KERN_WARNING PFX "Invalid PHY Revision %x\n", + phy_rev); + } + + phy->version = phy_version; + phy->type = phy_type; + phy->rev = phy_rev; + if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) { + p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT, + GFP_KERNEL); + if (!p) + return -ENOMEM; + phy->_lo_pairs = p; + } + + return 0; +} + +static int bcm43xx_attach_board(struct bcm43xx_private *bcm) +{ + struct pci_dev *pci_dev = bcm->pci_dev; + struct net_device *net_dev = bcm->net_dev; + int err; + int i; + unsigned long mmio_start, mmio_flags, mmio_len; + u32 coremask; + + err = pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err); + goto out; + } + mmio_start = pci_resource_start(pci_dev, 0); + mmio_flags = pci_resource_flags(pci_dev, 0); + mmio_len = pci_resource_len(pci_dev, 0); + if (!(mmio_flags & IORESOURCE_MEM)) { + printk(KERN_ERR PFX + "%s, region #0 not an MMIO resource, aborting\n", + pci_name(pci_dev)); + err = -ENODEV; + goto err_pci_disable; + } + err = pci_request_regions(pci_dev, KBUILD_MODNAME); + if (err) { + printk(KERN_ERR PFX + "could not access PCI resources (%i)\n", err); + goto err_pci_disable; + } + /* enable PCI bus-mastering */ + pci_set_master(pci_dev); + bcm->mmio_addr = ioremap(mmio_start, mmio_len); + if (!bcm->mmio_addr) { + printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", + pci_name(pci_dev)); + err = -EIO; + goto err_pci_release; + } + bcm->mmio_len = mmio_len; + net_dev->base_addr = (unsigned long)bcm->mmio_addr; + + bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, + &bcm->board_vendor); + bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, + &bcm->board_type); + bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, + &bcm->board_revision); + + err = bcm43xx_chipset_attach(bcm); + if (err) + goto err_iounmap; + err = bcm43xx_pctl_init(bcm); + if (err) + goto err_chipset_detach; + err = bcm43xx_probe_cores(bcm); + if (err) + goto err_chipset_detach; + + /* Attach all IO cores to the backplane. */ + coremask = 0; + for (i = 0; i < bcm->nr_80211_available; i++) + coremask |= (1 << bcm->core_80211[i].index); + //FIXME: Also attach some non80211 cores? + err = bcm43xx_setup_backplane_pci_connection(bcm, coremask); + if (err) { + printk(KERN_ERR PFX "Backplane->PCI connection failed!\n"); + goto err_chipset_detach; + } + + err = bcm43xx_sprom_extract(bcm); + if (err) + goto err_chipset_detach; + err = bcm43xx_leds_init(bcm); + if (err) + goto err_chipset_detach; + + for (i = 0; i < bcm->nr_80211_available; i++) { + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); + assert(err != -ENODEV); + if (err) + goto err_80211_unwind; + + /* Enable the selected wireless core. + * Connect PHY only on the first core. + */ + bcm43xx_wireless_core_reset(bcm, (i == 0)); + + err = bcm43xx_read_phyinfo(bcm); + if (err && (i == 0)) + goto err_80211_unwind; + + err = bcm43xx_read_radioinfo(bcm); + if (err && (i == 0)) + goto err_80211_unwind; + + err = bcm43xx_validate_chip(bcm); + if (err && (i == 0)) + goto err_80211_unwind; + + bcm43xx_radio_turn_off(bcm); + err = bcm43xx_phy_init_tssi2dbm_table(bcm); + if (err) + goto err_80211_unwind; + bcm43xx_wireless_core_disable(bcm); + } + bcm43xx_pctl_set_crystal(bcm, 0); + + /* Set the MAC address in the networking subsystem */ + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) + memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); + else + memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); + + bcm43xx_geo_init(bcm); + + snprintf(bcm->nick, IW_ESSID_MAX_SIZE, + "Broadcom %04X", bcm->chip_id); + + assert(err == 0); +out: + return err; + +err_80211_unwind: + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + kfree(bcm->core_80211_ext[i].phy._lo_pairs); + if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) + kfree(bcm->core_80211_ext[i].phy.tssi2dbm); + } +err_chipset_detach: + bcm43xx_chipset_detach(bcm); +err_iounmap: + iounmap(bcm->mmio_addr); +err_pci_release: + pci_release_regions(pci_dev); +err_pci_disable: + pci_disable_device(pci_dev); + goto out; +} + +/* Do the Hardware IO operations to send the txb */ +static inline int bcm43xx_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + int err = -ENODEV; + + if (bcm43xx_using_pio(bcm)) + err = bcm43xx_pio_tx(bcm, txb); + else + err = bcm43xx_dma_tx(bcm, txb); + + return err; +} + +static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, + u8 channel) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; + unsigned long flags; + + bcm43xx_lock_mmio(bcm, flags); + if (bcm->initialized) { + bcm43xx_mac_suspend(bcm); + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_mac_enable(bcm); + } else { + radio = bcm43xx_current_radio(bcm); + radio->initial_channel = channel; + } + bcm43xx_unlock_mmio(bcm, flags); +} + +/* set_security() callback in struct ieee80211_device */ +static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, + struct ieee80211_security *sec) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct ieee80211_security *secinfo = &bcm->ieee->sec; + unsigned long flags; + int keyidx; + + dprintk(KERN_INFO PFX "set security called\n"); + + bcm43xx_lock_mmio(bcm, flags); + + for (keyidx = 0; keyidxflags & (1<encode_alg[keyidx] = sec->encode_alg[keyidx]; + secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx]; + memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN); + } + + if (sec->flags & SEC_ACTIVE_KEY) { + secinfo->active_key = sec->active_key; + dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key); + } + if (sec->flags & SEC_UNICAST_GROUP) { + secinfo->unicast_uses_group = sec->unicast_uses_group; + dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group); + } + if (sec->flags & SEC_LEVEL) { + secinfo->level = sec->level; + dprintk(KERN_INFO PFX " .level = %d\n", sec->level); + } + if (sec->flags & SEC_ENABLED) { + secinfo->enabled = sec->enabled; + dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled); + } + if (sec->flags & SEC_ENCRYPT) { + secinfo->encrypt = sec->encrypt; + dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt); + } + if (bcm->initialized && !bcm->ieee->host_encrypt) { + if (secinfo->enabled) { + /* upload WEP keys to hardware */ + char null_address[6] = { 0 }; + u8 algorithm = 0; + for (keyidx = 0; keyidxflags & (1<encode_alg[keyidx]) { + case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break; + case SEC_ALG_WEP: + algorithm = BCM43xx_SEC_ALGO_WEP; + if (secinfo->key_sizes[keyidx] == 13) + algorithm = BCM43xx_SEC_ALGO_WEP104; + break; + case SEC_ALG_TKIP: + FIXME(); + algorithm = BCM43xx_SEC_ALGO_TKIP; + break; + case SEC_ALG_CCMP: + FIXME(); + algorithm = BCM43xx_SEC_ALGO_AES; + break; + default: + assert(0); + break; + } + bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]); + bcm->key[keyidx].enabled = 1; + bcm->key[keyidx].algorithm = algorithm; + } + } else + bcm43xx_clear_keys(bcm); + } + bcm43xx_unlock_mmio(bcm, flags); +} + +/* hard_start_xmit() callback in struct ieee80211_device */ +static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, + struct net_device *net_dev, + int pri) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = -ENODEV; + unsigned long flags; + + bcm43xx_lock_mmio(bcm, flags); + if (likely(bcm->initialized)) + err = bcm43xx_tx(bcm, txb); + bcm43xx_unlock_mmio(bcm, flags); + + return err; +} + +static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev) +{ + return &(bcm43xx_priv(net_dev)->ieee->stats); +} + +static void bcm43xx_net_tx_timeout(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + bcm43xx_lock_mmio(bcm, flags); + bcm43xx_controller_restart(bcm, "TX timeout"); + bcm43xx_unlock_mmio(bcm, flags); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void bcm43xx_net_poll_controller(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + local_irq_save(flags); + bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); + local_irq_restore(flags); +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +static int bcm43xx_net_open(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + return bcm43xx_init_board(bcm); +} + +static int bcm43xx_net_stop(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + ieee80211softmac_stop(net_dev); + bcm43xx_disable_interrupts_sync(bcm, NULL); + bcm43xx_free_board(bcm); + + return 0; +} + +static int bcm43xx_init_private(struct bcm43xx_private *bcm, + struct net_device *net_dev, + struct pci_dev *pci_dev) +{ + int err; + + bcm->ieee = netdev_priv(net_dev); + bcm->softmac = ieee80211_priv(net_dev); + bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; + + bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; + bcm->pci_dev = pci_dev; + bcm->net_dev = net_dev; + bcm->bad_frames_preempt = modparam_bad_frames_preempt; + spin_lock_init(&bcm->_lock); + tasklet_init(&bcm->isr_tasklet, + (void (*)(unsigned long))bcm43xx_interrupt_tasklet, + (unsigned long)bcm); + tasklet_disable_nosync(&bcm->isr_tasklet); + if (modparam_pio) { + bcm->__using_pio = 1; + } else { + err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK); + err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK); + if (err) { +#ifdef CONFIG_BCM43XX_PIO + printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); + bcm->__using_pio = 1; +#else + printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " + "Recompile the driver with PIO support, please.\n"); + return -ENODEV; +#endif /* CONFIG_BCM43XX_PIO */ + } + } + bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; + + /* default to sw encryption for now */ + bcm->ieee->host_build_iv = 0; + bcm->ieee->host_encrypt = 1; + bcm->ieee->host_decrypt = 1; + + bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE; + bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr); + bcm->ieee->set_security = bcm43xx_ieee80211_set_security; + bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit; + + return 0; +} + +static int __devinit bcm43xx_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *net_dev; + struct bcm43xx_private *bcm; + int err; + +#ifdef CONFIG_BCM947XX + if ((pdev->bus->number == 0) && (pdev->device != 0x0800)) + return -ENODEV; +#endif + +#ifdef DEBUG_SINGLE_DEVICE_ONLY + if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY)) + return -ENODEV; +#endif + + net_dev = alloc_ieee80211softmac(sizeof(*bcm)); + if (!net_dev) { + printk(KERN_ERR PFX + "could not allocate ieee80211 device %s\n", + pci_name(pdev)); + err = -ENOMEM; + goto out; + } + /* initialize the net_device struct */ + SET_MODULE_OWNER(net_dev); + SET_NETDEV_DEV(net_dev, &pdev->dev); + + net_dev->open = bcm43xx_net_open; + net_dev->stop = bcm43xx_net_stop; + net_dev->get_stats = bcm43xx_net_get_stats; + net_dev->tx_timeout = bcm43xx_net_tx_timeout; +#ifdef CONFIG_NET_POLL_CONTROLLER + net_dev->poll_controller = bcm43xx_net_poll_controller; +#endif + net_dev->wireless_handlers = &bcm43xx_wx_handlers_def; + net_dev->irq = pdev->irq; + SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops); + + /* initialize the bcm43xx_private struct */ + bcm = bcm43xx_priv(net_dev); + memset(bcm, 0, sizeof(*bcm)); + err = bcm43xx_init_private(bcm, net_dev, pdev); + if (err) + goto err_free_netdev; + + pci_set_drvdata(pdev, net_dev); + + err = bcm43xx_attach_board(bcm); + if (err) + goto err_free_netdev; + + err = register_netdev(net_dev); + if (err) { + printk(KERN_ERR PFX "Cannot register net device, " + "aborting.\n"); + err = -ENOMEM; + goto err_detach_board; + } + + bcm43xx_debugfs_add_device(bcm); + + assert(err == 0); +out: + return err; + +err_detach_board: + bcm43xx_detach_board(bcm); +err_free_netdev: + free_ieee80211softmac(net_dev); + goto out; +} + +static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) +{ + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + bcm43xx_debugfs_remove_device(bcm); + unregister_netdev(net_dev); + bcm43xx_detach_board(bcm); + assert(bcm->ucode == NULL); + free_ieee80211softmac(net_dev); +} + +/* Hard-reset the chip. Do not call this directly. + * Use bcm43xx_controller_restart() + */ +static void bcm43xx_chip_reset(void *_bcm) +{ + struct bcm43xx_private *bcm = _bcm; + struct net_device *net_dev = bcm->net_dev; + struct pci_dev *pci_dev = bcm->pci_dev; + int err; + int was_initialized = bcm->initialized; + + netif_stop_queue(bcm->net_dev); + tasklet_disable(&bcm->isr_tasklet); + + bcm->firmware_norelease = 1; + if (was_initialized) + bcm43xx_free_board(bcm); + bcm->firmware_norelease = 0; + bcm43xx_detach_board(bcm); + err = bcm43xx_init_private(bcm, net_dev, pci_dev); + if (err) + goto failure; + err = bcm43xx_attach_board(bcm); + if (err) + goto failure; + if (was_initialized) { + err = bcm43xx_init_board(bcm); + if (err) + goto failure; + } + netif_wake_queue(bcm->net_dev); + printk(KERN_INFO PFX "Controller restarted\n"); + + return; +failure: + printk(KERN_ERR PFX "Controller restart failed\n"); +} + +/* Hard-reset the chip. + * This can be called from interrupt or process context. + * Make sure to _not_ re-enable device interrupts after this has been called. +*/ +void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) +{ + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ + printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); + INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); + schedule_work(&bcm->restart_work); +} + +#ifdef CONFIG_PM + +static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int try_to_shutdown = 0, err; + + dprintk(KERN_INFO PFX "Suspending...\n"); + + bcm43xx_lock(bcm, flags); + bcm->was_initialized = bcm->initialized; + if (bcm->initialized) + try_to_shutdown = 1; + bcm43xx_unlock(bcm, flags); + + netif_device_detach(net_dev); + if (try_to_shutdown) { + ieee80211softmac_stop(net_dev); + err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); + if (unlikely(err)) { + dprintk(KERN_ERR PFX "Suspend failed.\n"); + return -EAGAIN; + } + bcm->firmware_norelease = 1; + bcm43xx_free_board(bcm); + bcm->firmware_norelease = 0; + } + bcm43xx_chipset_detach(bcm); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + dprintk(KERN_INFO PFX "Device suspended.\n"); + + return 0; +} + +static int bcm43xx_resume(struct pci_dev *pdev) +{ + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = 0; + + dprintk(KERN_INFO PFX "Resuming...\n"); + + pci_set_power_state(pdev, 0); + pci_enable_device(pdev); + pci_restore_state(pdev); + + bcm43xx_chipset_attach(bcm); + if (bcm->was_initialized) { + bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; + err = bcm43xx_init_board(bcm); + } + if (err) { + printk(KERN_ERR PFX "Resume failed!\n"); + return err; + } + + netif_device_attach(net_dev); + + /*FIXME: This should be handled by softmac instead. */ + schedule_work(&bcm->softmac->associnfo.work); + + dprintk(KERN_INFO PFX "Device resumed.\n"); + + return 0; +} + +#endif /* CONFIG_PM */ + +static struct pci_driver bcm43xx_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = bcm43xx_pci_tbl, + .probe = bcm43xx_init_one, + .remove = __devexit_p(bcm43xx_remove_one), +#ifdef CONFIG_PM + .suspend = bcm43xx_suspend, + .resume = bcm43xx_resume, +#endif /* CONFIG_PM */ +}; + +static int __init bcm43xx_init(void) +{ + printk(KERN_INFO KBUILD_MODNAME " driver\n"); + bcm43xx_debugfs_init(); + return pci_register_driver(&bcm43xx_pci_driver); +} + +static void __exit bcm43xx_exit(void) +{ + pci_unregister_driver(&bcm43xx_pci_driver); + bcm43xx_debugfs_exit(); +} + +module_init(bcm43xx_init) +module_exit(bcm43xx_exit) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h new file mode 100644 index 000000000000..eca79a38594a --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -0,0 +1,168 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_MAIN_H_ +#define BCM43xx_MAIN_H_ + +#include "bcm43xx.h" + +#ifdef CONFIG_BCM947XX +#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0) + +static inline void e_aton(char *str, char *dest) +{ + int i = 0; + u16 *d = (u16 *) dest; + + for (;;) { + dest[i++] = (char) simple_strtoul(str, NULL, 16); + str += 2; + if (!*str++ || i == 6) + break; + } + for (i = 0; i < 3; i++) + d[i] = cpu_to_be16(d[i]); +} +#endif + +#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] +#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) +/* Magic helper macro to pad structures. Ignore those above. It's magic. */ +#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) + + +/* Lightweight function to convert a frequency (in Mhz) to a channel number. */ +static inline +u8 bcm43xx_freq_to_channel_a(int freq) +{ + return ((freq - 5000) / 5); +} +static inline +u8 bcm43xx_freq_to_channel_bg(int freq) +{ + u8 channel; + + if (freq == 2484) + channel = 14; + else + channel = (freq - 2407) / 5; + + return channel; +} +static inline +u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, + int freq) +{ + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) + return bcm43xx_freq_to_channel_a(freq); + return bcm43xx_freq_to_channel_bg(freq); +} + +/* Lightweight function to convert a channel number to a frequency (in Mhz). */ +static inline +int bcm43xx_channel_to_freq_a(u8 channel) +{ + return (5000 + (5 * channel)); +} +static inline +int bcm43xx_channel_to_freq_bg(u8 channel) +{ + int freq; + + if (channel == 14) + freq = 2484; + else + freq = 2407 + (5 * channel); + + return freq; +} +static inline +int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, + u8 channel) +{ + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) + return bcm43xx_channel_to_freq_a(channel); + return bcm43xx_channel_to_freq_bg(channel); +} + +/* Lightweight function to check if a channel number is valid. + * Note that this does _NOT_ check for geographical restrictions! + */ +static inline +int bcm43xx_is_valid_channel_a(u8 channel) +{ + return (channel <= 200); +} +static inline +int bcm43xx_is_valid_channel_bg(u8 channel) +{ + return (channel >= 1 && channel <= 14); +} +static inline +int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, + u8 channel) +{ + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) + return bcm43xx_is_valid_channel_a(channel); + return bcm43xx_is_valid_channel_bg(channel); +} + +void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); +void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf); + +void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, + int iw_mode); + +u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, + u16 routing, u16 offset); +u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, + u16 routing, u16 offset); +void bcm43xx_shm_write32(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u32 value); +void bcm43xx_shm_write16(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u16 value); + +void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm); + +int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); + +void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); + +void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); +void bcm43xx_mac_enable(struct bcm43xx_private *bcm); + +void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); + +int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); +int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom); + +#endif /* BCM43xx_MAIN_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c new file mode 100644 index 000000000000..0a66f43ca0c0 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -0,0 +1,2345 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include + +#include "bcm43xx.h" +#include "bcm43xx_phy.h" +#include "bcm43xx_main.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_ilt.h" +#include "bcm43xx_power.h" + + +static const s8 bcm43xx_tssi2dbm_b_table[] = { + 0x4D, 0x4C, 0x4B, 0x4A, + 0x4A, 0x49, 0x48, 0x47, + 0x47, 0x46, 0x45, 0x45, + 0x44, 0x43, 0x42, 0x42, + 0x41, 0x40, 0x3F, 0x3E, + 0x3D, 0x3C, 0x3B, 0x3A, + 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x32, 0x31, + 0x30, 0x2F, 0x2D, 0x2C, + 0x2B, 0x29, 0x28, 0x26, + 0x25, 0x23, 0x21, 0x1F, + 0x1D, 0x1A, 0x17, 0x14, + 0x10, 0x0C, 0x06, 0x00, + -7, -7, -7, -7, + -7, -7, -7, -7, + -7, -7, -7, -7, +}; + +static const s8 bcm43xx_tssi2dbm_g_table[] = { + 77, 77, 77, 76, + 76, 76, 75, 75, + 74, 74, 73, 73, + 73, 72, 72, 71, + 71, 70, 70, 69, + 68, 68, 67, 67, + 66, 65, 65, 64, + 63, 63, 62, 61, + 60, 59, 58, 57, + 56, 55, 54, 53, + 52, 50, 49, 47, + 45, 43, 40, 37, + 33, 28, 22, 14, + 5, -7, -20, -20, + -20, -20, -20, -20, + -20, -20, -20, -20, +}; + +static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); + + +void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + assert(irqs_disabled()); + if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) { + phy->is_locked = 0; + return; + } + if (bcm->current_core->rev < 3) { + bcm43xx_mac_suspend(bcm); + spin_lock(&phy->lock); + } else { + if (bcm->ieee->iw_mode != IW_MODE_MASTER) + bcm43xx_power_saving_ctl_bits(bcm, -1, 1); + } + phy->is_locked = 1; +} + +void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + assert(irqs_disabled()); + if (bcm->current_core->rev < 3) { + if (phy->is_locked) { + spin_unlock(&phy->lock); + bcm43xx_mac_enable(bcm); + } + } else { + if (bcm->ieee->iw_mode != IW_MODE_MASTER) + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); + } + phy->is_locked = 0; +} + +u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset) +{ + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); + return bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_DATA); +} + +void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) +{ + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val); +} + +void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + unsigned long flags; + + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ + if (phy->calibrated) + return; + if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) { + /* We do not want to be preempted while calibrating + * the hardware. + */ + local_irq_save(flags); + + bcm43xx_wireless_core_reset(bcm, 0); + bcm43xx_phy_initg(bcm); + bcm43xx_wireless_core_reset(bcm, 1); + + local_irq_restore(flags); + } + phy->calibrated = 1; +} + +/* Connect the PHY + * http://bcm-specs.sipsolutions.net/SetPHY + */ +int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u32 flags; + + if (bcm->current_core->rev < 5) + goto out; + + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (connect) { + if (!(flags & 0x00010000)) + return -ENODEV; + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + flags |= (0x800 << 18); + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); + } else { + if (!(flags & 0x00020000)) + return -ENODEV; + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + flags &= ~(0x800 << 18); + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); + } +out: + phy->connected = connect; + if (connect) + dprintk(KERN_INFO PFX "PHY connected\n"); + else + dprintk(KERN_INFO PFX "PHY disconnected\n"); + + return 0; +} + +/* intialize B PHY power control + * as described in http://bcm-specs.sipsolutions.net/InitPowerControl + */ +static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0; + int must_reset_txpower = 0; + + assert(phy->type != BCM43xx_PHYTYPE_A); + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type == 0x0416)) + return; + + bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF); + bcm43xx_phy_write(bcm, 0x0028, 0x8018); + + if (phy->type == BCM43xx_PHYTYPE_G) { + if (!phy->connected) + return; + bcm43xx_phy_write(bcm, 0x047A, 0xC111); + } + if (phy->savedpctlreg != 0xFFFF) + return; + + if (phy->type == BCM43xx_PHYTYPE_B && + phy->rev >= 2 && + radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0076, + bcm43xx_radio_read16(bcm, 0x0076) | 0x0084); + } else { + saved_batt = radio->baseband_atten; + saved_ratt = radio->radio_atten; + saved_txctl1 = radio->txctl1; + if ((radio->revision >= 6) && (radio->revision <= 8) + && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) + bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0); + else + bcm43xx_radio_set_txpower_bg(bcm, 0xB, 9, 0); + must_reset_txpower = 1; + } + bcm43xx_dummy_transmission(bcm); + + phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_PCTL); + + if (must_reset_txpower) + bcm43xx_radio_set_txpower_bg(bcm, saved_batt, saved_ratt, saved_txctl1); + else + bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) & 0xFF7B); + bcm43xx_radio_clear_tssi(bcm); +} + +static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 offset = 0x0000; + + if (phy->rev == 1) + offset = 0x4C00; + + bcm43xx_ilt_write(bcm, offset, 0x00FE); + bcm43xx_ilt_write(bcm, offset + 1, 0x000D); + bcm43xx_ilt_write(bcm, offset + 2, 0x0013); + bcm43xx_ilt_write(bcm, offset + 3, 0x0019); + + if (phy->rev == 1) { + bcm43xx_ilt_write(bcm, 0x1800, 0x2710); + bcm43xx_ilt_write(bcm, 0x1801, 0x9B83); + bcm43xx_ilt_write(bcm, 0x1802, 0x9B83); + bcm43xx_ilt_write(bcm, 0x1803, 0x0F8D); + bcm43xx_phy_write(bcm, 0x0455, 0x0004); + } + + bcm43xx_phy_write(bcm, 0x04A5, (bcm43xx_phy_read(bcm, 0x04A5) & 0x00FF) | 0x5700); + bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xFF80) | 0x000F); + bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xC07F) | 0x2B80); + bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xF0FF) | 0x0300); + + bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0008); + + bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFF0) | 0x0008); + bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xF0FF) | 0x0600); + bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0700); + bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0100); + + if (phy->rev == 1) + bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x0007); + + bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xFF00) | 0x001C); + bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xC0FF) | 0x0200); + bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0xFF00) | 0x001C); + bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xFF00) | 0x0020); + bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xC0FF) | 0x0200); + bcm43xx_phy_write(bcm, 0x0482, (bcm43xx_phy_read(bcm, 0x0482) & 0xFF00) | 0x002E); + bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0x00FF) | 0x1A00); + bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0xFF00) | 0x0028); + bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0x00FF) | 0x2C00); + + if (phy->rev == 1) { + bcm43xx_phy_write(bcm, 0x0430, 0x092B); + bcm43xx_phy_write(bcm, 0x041B, (bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1) | 0x0002); + } else { + bcm43xx_phy_write(bcm, 0x041B, bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1); + bcm43xx_phy_write(bcm, 0x041F, 0x287A); + bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0xFFF0) | 0x0004); + } + + if (phy->rev > 2) { + bcm43xx_phy_write(bcm, 0x0422, 0x287A); + bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); + } + + bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874); + bcm43xx_phy_write(bcm, 0x048E, 0x1C00); + + if (phy->rev == 1) { + bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600); + bcm43xx_phy_write(bcm, 0x048B, 0x005E); + bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E); + bcm43xx_phy_write(bcm, 0x048D, 0x0002); + } + + bcm43xx_ilt_write(bcm, offset + 0x0800, 0); + bcm43xx_ilt_write(bcm, offset + 0x0801, 7); + bcm43xx_ilt_write(bcm, offset + 0x0802, 16); + bcm43xx_ilt_write(bcm, offset + 0x0803, 28); +} + +static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 i; + + assert(phy->type == BCM43xx_PHYTYPE_G); + if (phy->rev == 1) { + bcm43xx_phy_write(bcm, 0x0406, 0x4F19); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340); + bcm43xx_phy_write(bcm, 0x042C, 0x005A); + bcm43xx_phy_write(bcm, 0x0427, 0x001A); + + for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]); + for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + } else { + /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ + bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654); + + if (phy->rev == 2) { + bcm43xx_phy_write(bcm, 0x04C0, 0x1861); + bcm43xx_phy_write(bcm, 0x04C1, 0x0271); + } else if (phy->rev > 2) { + bcm43xx_phy_write(bcm, 0x04C0, 0x0098); + bcm43xx_phy_write(bcm, 0x04C1, 0x0070); + bcm43xx_phy_write(bcm, 0x04C9, 0x0080); + } + bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800); + + for (i = 0; i < 64; i++) + bcm43xx_ilt_write(bcm, 0x4000 + i, i); + for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]); + } + + if (phy->rev <= 2) + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); + else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); + else + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]); + + if (phy->rev == 2) + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + else if ((phy->rev > 2) && (phy->rev <= 7)) + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); + + if (phy->rev == 1) { + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + for (i = 0; i < 4; i++) { + bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x540C + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x5410 + i, 0x0020); + } + bcm43xx_phy_agcsetup(bcm); + + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type == 0x0416) && + (bcm->board_revision == 0x0017)) + return; + + bcm43xx_ilt_write(bcm, 0x5001, 0x0002); + bcm43xx_ilt_write(bcm, 0x5002, 0x0001); + } else { + for (i = 0; i <= 0x2F; i++) + bcm43xx_ilt_write(bcm, 0x1000 + i, 0x0820); + bcm43xx_phy_agcsetup(bcm); + bcm43xx_phy_read(bcm, 0x0400); /* dummy read */ + bcm43xx_phy_write(bcm, 0x0403, 0x1000); + bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); + + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type == 0x0416) && + (bcm->board_revision == 0x0017)) + return; + + bcm43xx_ilt_write(bcm, 0x0401, 0x0002); + bcm43xx_ilt_write(bcm, 0x0402, 0x0001); + } +} + +/* Initialize the noisescaletable for APHY */ +static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + int i; + + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400); + for (i = 0; i < 12; i++) { + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); + } + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6700); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2300); + for (i = 0; i < 11; i++) { + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); + } + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0067); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0023); +} + +static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 i; + + assert(phy->type == BCM43xx_PHYTYPE_A); + switch (phy->rev) { + case 2: + bcm43xx_phy_write(bcm, 0x008E, 0x3800); + bcm43xx_phy_write(bcm, 0x0035, 0x03FF); + bcm43xx_phy_write(bcm, 0x0036, 0x0400); + + bcm43xx_ilt_write(bcm, 0x3807, 0x0051); + + bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); + bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); + bcm43xx_ilt_write(bcm, 0x3C0C, 0x07BF); + bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); + + bcm43xx_phy_write(bcm, 0x0024, 0x4680); + bcm43xx_phy_write(bcm, 0x0020, 0x0003); + bcm43xx_phy_write(bcm, 0x001D, 0x0F40); + bcm43xx_phy_write(bcm, 0x001F, 0x1C00); + + bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); + bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF); + bcm43xx_phy_write(bcm, 0x008E, 0x58C1); + + bcm43xx_ilt_write(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write(bcm, 0x0807, 0x003A); + + bcm43xx_ilt_write(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write(bcm, 0x0006, 0x0019); + + bcm43xx_ilt_write(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write(bcm, 0x0406, 0x0007); + + for (i = 0; i < 16; i++) + bcm43xx_ilt_write(bcm, 0x4000 + i, (0x8 + i) & 0x000F); + + bcm43xx_ilt_write(bcm, 0x3003, 0x1044); + bcm43xx_ilt_write(bcm, 0x3004, 0x7201); + bcm43xx_ilt_write(bcm, 0x3006, 0x0040); + bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); + + for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]); + for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + bcm43xx_phy_init_noisescaletbl(bcm); + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + break; + case 3: + for (i = 0; i < 64; i++) + bcm43xx_ilt_write(bcm, 0x4000 + i, i); + + bcm43xx_ilt_write(bcm, 0x3807, 0x0051); + + bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); + bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); + bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); + + bcm43xx_phy_write(bcm, 0x0024, 0x4680); + bcm43xx_phy_write(bcm, 0x0020, 0x0003); + bcm43xx_phy_write(bcm, 0x001D, 0x0F40); + bcm43xx_phy_write(bcm, 0x001F, 0x1C00); + bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); + + bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); + for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]); + bcm43xx_phy_init_noisescaletbl(bcm); + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + + bcm43xx_phy_write(bcm, 0x0003, 0x1808); + + bcm43xx_ilt_write(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write(bcm, 0x0807, 0x003A); + + bcm43xx_ilt_write(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write(bcm, 0x0006, 0x0019); + + bcm43xx_ilt_write(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write(bcm, 0x0406, 0x0007); + + bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); + break; + default: + assert(0); + } +} + +/* Initialize APHY. This is also called for the GPHY in some cases. */ +static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 tval; + + if (phy->type == BCM43xx_PHYTYPE_A) { + bcm43xx_phy_setupa(bcm); + } else { + bcm43xx_phy_setupg(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) + bcm43xx_phy_write(bcm, 0x046E, 0x03CF); + return; + } + + bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) & 0xF83C) | 0x0340); + bcm43xx_phy_write(bcm, 0x0034, 0x0001); + + TODO();//TODO: RSSI AGC + bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) | (1 << 14)); + bcm43xx_radio_init2060(bcm); + + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) + && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) { + if (radio->lofcal == 0xFFFF) { + TODO();//TODO: LOF Cal + bcm43xx_radio_set_tx_iq(bcm); + } else + bcm43xx_radio_write16(bcm, 0x001E, radio->lofcal); + } + + bcm43xx_phy_write(bcm, 0x007A, 0xF111); + + if (phy->savedpctlreg == 0xFFFF) { + bcm43xx_radio_write16(bcm, 0x0019, 0x0000); + bcm43xx_radio_write16(bcm, 0x0017, 0x0020); + + tval = bcm43xx_ilt_read(bcm, 0x3001); + if (phy->rev == 1) { + bcm43xx_ilt_write(bcm, 0x3001, + (bcm43xx_ilt_read(bcm, 0x3001) & 0xFF87) + | 0x0058); + } else { + bcm43xx_ilt_write(bcm, 0x3001, + (bcm43xx_ilt_read(bcm, 0x3001) & 0xFFC3) + | 0x002C); + } + bcm43xx_dummy_transmission(bcm); + phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL); + bcm43xx_ilt_write(bcm, 0x3001, tval); + + bcm43xx_radio_set_txpower_a(bcm, 0x0018); + } + bcm43xx_radio_clear_tssi(bcm); +} + +static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 offset, val; + + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + bcm43xx_phy_write(bcm, 0x0026, 0x0000); + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_phy_write(bcm, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + bcm43xx_phy_write(bcm, 0x03E4, 0x3000); + if (radio->channel == 0xFF) + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + else + bcm43xx_radio_selectchannel(bcm, radio->channel, 0); + if (radio->version != 0x2050) { + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); + } + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + bcm43xx_radio_write16(bcm, 0x007A, 0x000F); + bcm43xx_phy_write(bcm, 0x0038, 0x0677); + bcm43xx_radio_init2050(bcm); + } + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); + bcm43xx_phy_write(bcm, 0x0032, 0x00CC); + bcm43xx_phy_write(bcm, 0x0035, 0x07C2); + bcm43xx_phy_lo_b_measure(bcm); + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); + if (radio->version != 0x2050) + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1000); + bcm43xx_phy_write(bcm, 0x002A, 0x88A3); + if (radio->version != 0x2050) + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + bcm43xx_phy_init_pctl(bcm); +} + +static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 offset, val; + + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + bcm43xx_phy_write(bcm, 0x0026, 0x0000); + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_phy_write(bcm, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + bcm43xx_phy_write(bcm, 0x03E4, 0x3000); + if (radio->channel == 0xFF) + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + else + bcm43xx_radio_selectchannel(bcm, radio->channel, 0); + if (radio->version != 0x2050) { + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); + } + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + bcm43xx_radio_write16(bcm, 0x007A, 0x000F); + bcm43xx_phy_write(bcm, 0x0038, 0x0677); + bcm43xx_radio_init2050(bcm); + } + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0032, 0x00E0); + bcm43xx_phy_write(bcm, 0x0035, 0x07C2); + + bcm43xx_phy_lo_b_measure(bcm); + + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1100); + bcm43xx_phy_write(bcm, 0x002A, 0x88A3); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + } + bcm43xx_phy_init_pctl(bcm); +} + +static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 offset; + + if (phy->version == 1 && + radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + | 0x0050); + } + if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type != 0x0416)) { + for (offset = 0x00A8 ; offset < 0x00C7; offset++) { + bcm43xx_phy_write(bcm, offset, + (bcm43xx_phy_read(bcm, offset) + 0x2020) + & 0x3F3F); + } + } + bcm43xx_phy_write(bcm, 0x0035, + (bcm43xx_phy_read(bcm, 0x0035) & 0xF0FF) + | 0x0700); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0038, 0x0667); + + if (phy->connected) { + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + | 0x0020); + bcm43xx_radio_write16(bcm, 0x0051, + bcm43xx_radio_read16(bcm, 0x0051) + | 0x0004); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 0x0000); + + bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | 0x0100); + bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x2000); + + bcm43xx_phy_write(bcm, 0x001C, 0x186A); + + bcm43xx_phy_write(bcm, 0x0013, (bcm43xx_phy_read(bcm, 0x0013) & 0x00FF) | 0x1900); + bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFFC0) | 0x0064); + bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) & 0xFF80) | 0x000A); + } + + if (bcm->bad_frames_preempt) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11)); + } + + if (phy->version == 1 && radio->version == 0x2050) { + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_phy_write(bcm, 0x0021, 0x3763); + bcm43xx_phy_write(bcm, 0x0022, 0x1BC3); + bcm43xx_phy_write(bcm, 0x0023, 0x06F9); + bcm43xx_phy_write(bcm, 0x0024, 0x037E); + } else + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + + if (phy->version == 1 && radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0020, 0x3E1C); + else + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + + if (phy->version == 0) + bcm43xx_write16(bcm, 0x03E4, 0x3000); + + /* Force to channel 7, even if not supported. */ + bcm43xx_radio_selectchannel(bcm, 7, 0); + + if (radio->version != 0x2050) { + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); + } + + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + } + + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + + bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007); + + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); + bcm43xx_phy_write(bcm, 0x88A3, 0x002A); + + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + + if (radio->version == 0x2050) + bcm43xx_radio_write16(bcm, 0x005D, 0x000D); + + bcm43xx_write16(bcm, 0x03E4, (bcm43xx_read16(bcm, 0x03E4) & 0xFFC0) | 0x0004); +} + +static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 offset, val; + + bcm43xx_phy_write(bcm, 0x003E, 0x817A); + bcm43xx_radio_write16(bcm, 0x007A, + (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058)); + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 3 || + radio->revision == 4 || + radio->revision == 5)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x001F); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x005B); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x0088); + bcm43xx_radio_write16(bcm, 0x005D, 0x0088); + bcm43xx_radio_write16(bcm, 0x005E, 0x0088); + bcm43xx_radio_write16(bcm, 0x007D, 0x0088); + } + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 6)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x008B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B5); + bcm43xx_radio_write16(bcm, 0x005D, 0x0088); + bcm43xx_radio_write16(bcm, 0x005E, 0x0088); + bcm43xx_radio_write16(bcm, 0x007D, 0x0088); + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); + } + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 7)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x00A8); + bcm43xx_radio_write16(bcm, 0x005C, 0x0075); + bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); + bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); + bcm43xx_radio_write16(bcm, 0x007D, 0x00E8); + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); + bcm43xx_radio_write16(bcm, 0x007B, 0x0000); + } + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 8)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x006B); + bcm43xx_radio_write16(bcm, 0x005C, 0x000F); + if (bcm->sprom.boardflags & 0x8000) { + bcm43xx_radio_write16(bcm, 0x005D, 0x00FA); + bcm43xx_radio_write16(bcm, 0x005E, 0x00D8); + } else { + bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); + bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); + } + bcm43xx_radio_write16(bcm, 0x0073, 0x0003); + bcm43xx_radio_write16(bcm, 0x007D, 0x00A8); + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + bcm43xx_phy_write(bcm, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == BCM43xx_PHYTYPE_G) { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0020); + bcm43xx_radio_write16(bcm, 0x0051, + bcm43xx_radio_read16(bcm, 0x0051) | 0x0004); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | 0x0100); + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) | 0x2000); + } + + /* Force to channel 7, even if not supported. */ + bcm43xx_radio_selectchannel(bcm, 7, 0); + + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + udelay(40); + bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002)); + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + if (radio->manufact == 0x17F && + radio->version == 0x2050 && + radio->revision <= 2) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + } + bcm43xx_radio_write16(bcm, 0x007A, + (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007); + + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + + bcm43xx_phy_write(bcm, 0x0014, 0x0200); + if (radio->version == 0x2050){ + if (radio->revision == 3 || + radio->revision == 4 || + radio->revision == 5) + bcm43xx_phy_write(bcm, 0x002A, 0x8AC0); + else + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); + } + bcm43xx_phy_write(bcm, 0x0038, 0x0668); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + if (radio->version == 0x2050) { + if (radio->revision == 3 || + radio->revision == 4 || + radio->revision == 5) + bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003); + else if (radio->revision <= 2) + bcm43xx_radio_write16(bcm, 0x005D, 0x000D); + } + + if (phy->rev == 4) + bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004); + else + bcm43xx_write16(bcm, 0x03E4, 0x0009); + if (phy->type == BCM43xx_PHYTYPE_B) { + bcm43xx_write16(bcm, 0x03E6, 0x8140); + bcm43xx_phy_write(bcm, 0x0016, 0x0410); + bcm43xx_phy_write(bcm, 0x0017, 0x0820); + bcm43xx_phy_write(bcm, 0x0062, 0x0007); + (void) bcm43xx_radio_calibrationvalue(bcm); + bcm43xx_phy_lo_b_measure(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + } + bcm43xx_phy_init_pctl(bcm); + } else + bcm43xx_write16(bcm, 0x03E6, 0x0); +} + +static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 backup_phy[15]; + u16 backup_radio[3]; + u16 backup_bband; + u16 i; + u16 loop1_cnt, loop1_done, loop1_omitted; + u16 loop2_done; + + backup_phy[0] = bcm43xx_phy_read(bcm, 0x0429); + backup_phy[1] = bcm43xx_phy_read(bcm, 0x0001); + backup_phy[2] = bcm43xx_phy_read(bcm, 0x0811); + backup_phy[3] = bcm43xx_phy_read(bcm, 0x0812); + backup_phy[4] = bcm43xx_phy_read(bcm, 0x0814); + backup_phy[5] = bcm43xx_phy_read(bcm, 0x0815); + backup_phy[6] = bcm43xx_phy_read(bcm, 0x005A); + backup_phy[7] = bcm43xx_phy_read(bcm, 0x0059); + backup_phy[8] = bcm43xx_phy_read(bcm, 0x0058); + backup_phy[9] = bcm43xx_phy_read(bcm, 0x000A); + backup_phy[10] = bcm43xx_phy_read(bcm, 0x0003); + backup_phy[11] = bcm43xx_phy_read(bcm, 0x080F); + backup_phy[12] = bcm43xx_phy_read(bcm, 0x0810); + backup_phy[13] = bcm43xx_phy_read(bcm, 0x002B); + backup_phy[14] = bcm43xx_phy_read(bcm, 0x0015); + bcm43xx_phy_read(bcm, 0x002D); /* dummy read */ + backup_bband = radio->baseband_atten; + backup_radio[0] = bcm43xx_radio_read16(bcm, 0x0052); + backup_radio[1] = bcm43xx_radio_read16(bcm, 0x0043); + backup_radio[2] = bcm43xx_radio_read16(bcm, 0x007A); + + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) & 0x3FFF); + bcm43xx_phy_write(bcm, 0x0001, + bcm43xx_phy_read(bcm, 0x0001) & 0x8000); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0002); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xFFFD); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0001); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xFFFE); + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0001); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0002); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFD); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) | 0x000C); + + bcm43xx_phy_write(bcm, 0x0811, + (bcm43xx_phy_read(bcm, 0x0811) + & 0xFFCF) | 0x0030); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) + & 0xFFCF) | 0x0010); + + bcm43xx_phy_write(bcm, 0x005A, 0x0780); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->version == 0) { + bcm43xx_phy_write(bcm, 0x0003, 0x0122); + } else { + bcm43xx_phy_write(bcm, 0x000A, + bcm43xx_phy_read(bcm, 0x000A) + | 0x2000); + } + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0004); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) + & 0xFF9F) | 0x0040); + if (radio->version == 0x2050 && radio->revision == 2) { + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + bcm43xx_radio_write16(bcm, 0x0043, + (bcm43xx_radio_read16(bcm, 0x0043) + & 0xFFF0) | 0x0009); + loop1_cnt = 9; + } else if (radio->revision == 8) { + bcm43xx_radio_write16(bcm, 0x0043, 0x000F); + loop1_cnt = 15; + } else + loop1_cnt = 0; + + bcm43xx_phy_set_baseband_attenuation(bcm, 11); + + if (phy->rev >= 3) + bcm43xx_phy_write(bcm, 0x080F, 0xC020); + else + bcm43xx_phy_write(bcm, 0x080F, 0x8020); + bcm43xx_phy_write(bcm, 0x0810, 0x0000); + + bcm43xx_phy_write(bcm, 0x002B, + (bcm43xx_phy_read(bcm, 0x002B) + & 0xFFC0) | 0x0001); + bcm43xx_phy_write(bcm, 0x002B, + (bcm43xx_phy_read(bcm, 0x002B) + & 0xC0FF) | 0x0800); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0100); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xCFFF); + if (bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA) { + if (phy->rev >= 7) { + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) + | 0x0800); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) + | 0x8000); + } + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + & 0x00F7); + + for (i = 0; i < loop1_cnt; i++) { + bcm43xx_radio_write16(bcm, 0x0043, loop1_cnt); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) + & 0xF0FF) | (i << 8)); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xA000); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) + break; + } + loop1_done = i; + loop1_omitted = loop1_cnt - loop1_done; + + loop2_done = 0; + if (loop1_done >= 8) { + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) + | 0x0030); + for (i = loop1_done - 8; i < 16; i++) { + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) + & 0xF0FF) | (i << 8)); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xA000); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) + break; + } + } + + bcm43xx_phy_write(bcm, 0x0814, backup_phy[4]); + bcm43xx_phy_write(bcm, 0x0815, backup_phy[5]); + bcm43xx_phy_write(bcm, 0x005A, backup_phy[6]); + bcm43xx_phy_write(bcm, 0x0059, backup_phy[7]); + bcm43xx_phy_write(bcm, 0x0058, backup_phy[8]); + bcm43xx_phy_write(bcm, 0x000A, backup_phy[9]); + bcm43xx_phy_write(bcm, 0x0003, backup_phy[10]); + bcm43xx_phy_write(bcm, 0x080F, backup_phy[11]); + bcm43xx_phy_write(bcm, 0x0810, backup_phy[12]); + bcm43xx_phy_write(bcm, 0x002B, backup_phy[13]); + bcm43xx_phy_write(bcm, 0x0015, backup_phy[14]); + + bcm43xx_phy_set_baseband_attenuation(bcm, backup_bband); + + bcm43xx_radio_write16(bcm, 0x0052, backup_radio[0]); + bcm43xx_radio_write16(bcm, 0x0043, backup_radio[1]); + bcm43xx_radio_write16(bcm, 0x007A, backup_radio[2]); + + bcm43xx_phy_write(bcm, 0x0811, backup_phy[2] | 0x0003); + udelay(10); + bcm43xx_phy_write(bcm, 0x0811, backup_phy[2]); + bcm43xx_phy_write(bcm, 0x0812, backup_phy[3]); + bcm43xx_phy_write(bcm, 0x0429, backup_phy[0]); + bcm43xx_phy_write(bcm, 0x0001, backup_phy[1]); + + phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11; + phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2; +} + +static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 tmp; + + if (phy->rev == 1) + bcm43xx_phy_initb5(bcm); + else if (phy->rev >= 2 && phy->rev <= 7) + bcm43xx_phy_initb6(bcm); + if (phy->rev >= 2 || phy->connected) + bcm43xx_phy_inita(bcm); + + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0814, 0x0000); + bcm43xx_phy_write(bcm, 0x0815, 0x0000); + if (phy->rev == 2) + bcm43xx_phy_write(bcm, 0x0811, 0x0000); + else if (phy->rev >= 3) + bcm43xx_phy_write(bcm, 0x0811, 0x0400); + bcm43xx_phy_write(bcm, 0x0015, 0x00C0); + if (phy->connected) { + tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; + if (tmp < 6) { + bcm43xx_phy_write(bcm, 0x04C2, 0x1816); + bcm43xx_phy_write(bcm, 0x04C3, 0x8006); + if (tmp != 3) { + bcm43xx_phy_write(bcm, 0x04CC, + (bcm43xx_phy_read(bcm, 0x04CC) + & 0x00FF) | 0x1F00); + } + } + } + } + if (phy->rev < 3 && phy->connected) + bcm43xx_phy_write(bcm, 0x047E, 0x0078); + if (phy->rev >= 6 && phy->rev <= 8) { + bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080); + bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004); + } + if (phy->rev >= 2 && phy->connected) + bcm43xx_calc_loopback_gain(bcm); + if (radio->revision != 8) { + if (radio->initval == 0xFFFF) + radio->initval = bcm43xx_radio_init2050(bcm); + else + bcm43xx_radio_write16(bcm, 0x0078, radio->initval); + } + if (radio->txctl2 == 0xFFFF) { + bcm43xx_phy_lo_g_measure(bcm); + } else { + if (radio->version == 0x2050 && radio->revision == 8) { + //FIXME + } else { + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) + & 0xFFF0) | radio->txctl1); + } + if (phy->rev >= 6) { + /* + bcm43xx_phy_write(bcm, 0x0036, + (bcm43xx_phy_read(bcm, 0x0036) + & 0xF000) | (FIXME << 12)); + */ + } + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) + bcm43xx_phy_write(bcm, 0x002E, 0x8075); + else + bcm43xx_phy_write(bcm, 0x003E, 0x807F); + if (phy->rev < 2) + bcm43xx_phy_write(bcm, 0x002F, 0x0101); + else + bcm43xx_phy_write(bcm, 0x002F, 0x0202); + } + if (phy->connected) { + bcm43xx_phy_lo_adjust(bcm, 0); + bcm43xx_phy_write(bcm, 0x080F, 0x8078); + } + + if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the limit_value() in nrssi_hw_update()) + */ + bcm43xx_nrssi_hw_update(bcm, 0xFFFF); + bcm43xx_calc_nrssi_threshold(bcm); + } else if (phy->connected) { + if (radio->nrssi[0] == -1000) { + assert(radio->nrssi[1] == -1000); + bcm43xx_calc_nrssi_slope(bcm); + } else { + assert(radio->nrssi[1] != -1000); + bcm43xx_calc_nrssi_threshold(bcm); + } + } + if (radio->revision == 8) + bcm43xx_phy_write(bcm, 0x0805, 0x3230); + bcm43xx_phy_init_pctl(bcm); + if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) { + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF); + bcm43xx_phy_write(bcm, 0x04C3, + bcm43xx_phy_read(bcm, 0x04C3) & 0x7FFF); + } +} + +static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) +{ + int i; + u16 ret = 0; + + for (i = 0; i < 10; i++){ + bcm43xx_phy_write(bcm, 0x0015, 0xAFA0); + udelay(1); + bcm43xx_phy_write(bcm, 0x0015, 0xEFA0); + udelay(10); + bcm43xx_phy_write(bcm, 0x0015, 0xFFA0); + udelay(40); + ret += bcm43xx_phy_read(bcm, 0x002C); + } + + return ret; +} + +void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 regstack[12] = { 0 }; + u16 mls; + u16 fval; + int i, j; + + regstack[0] = bcm43xx_phy_read(bcm, 0x0015); + regstack[1] = bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0; + + if (radio->version == 0x2053) { + regstack[2] = bcm43xx_phy_read(bcm, 0x000A); + regstack[3] = bcm43xx_phy_read(bcm, 0x002A); + regstack[4] = bcm43xx_phy_read(bcm, 0x0035); + regstack[5] = bcm43xx_phy_read(bcm, 0x0003); + regstack[6] = bcm43xx_phy_read(bcm, 0x0001); + regstack[7] = bcm43xx_phy_read(bcm, 0x0030); + + regstack[8] = bcm43xx_radio_read16(bcm, 0x0043); + regstack[9] = bcm43xx_radio_read16(bcm, 0x007A); + regstack[10] = bcm43xx_read16(bcm, 0x03EC); + regstack[11] = bcm43xx_radio_read16(bcm, 0x0052) & 0x00F0; + + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); + bcm43xx_write16(bcm, 0x03EC, 0x3F3F); + bcm43xx_phy_write(bcm, 0x0035, regstack[4] & 0xFF7F); + bcm43xx_radio_write16(bcm, 0x007A, regstack[9] & 0xFFF0); + } + bcm43xx_phy_write(bcm, 0x0015, 0xB000); + bcm43xx_phy_write(bcm, 0x002B, 0x0004); + + if (radio->version == 0x2053) { + bcm43xx_phy_write(bcm, 0x002B, 0x0203); + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); + } + + phy->minlowsig[0] = 0xFFFF; + + for (i = 0; i < 4; i++) { + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); + bcm43xx_phy_lo_b_r15_loop(bcm); + } + for (i = 0; i < 10; i++) { + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); + mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; + if (mls < phy->minlowsig[0]) { + phy->minlowsig[0] = mls; + phy->minlowsigpos[0] = i; + } + } + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | phy->minlowsigpos[0]); + + phy->minlowsig[1] = 0xFFFF; + + for (i = -4; i < 5; i += 2) { + for (j = -4; j < 5; j += 2) { + if (j < 0) + fval = (0x0100 * i) + j + 0x0100; + else + fval = (0x0100 * i) + j; + bcm43xx_phy_write(bcm, 0x002F, fval); + mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; + if (mls < phy->minlowsig[1]) { + phy->minlowsig[1] = mls; + phy->minlowsigpos[1] = fval; + } + } + } + phy->minlowsigpos[1] += 0x0101; + + bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]); + if (radio->version == 0x2053) { + bcm43xx_phy_write(bcm, 0x000A, regstack[2]); + bcm43xx_phy_write(bcm, 0x002A, regstack[3]); + bcm43xx_phy_write(bcm, 0x0035, regstack[4]); + bcm43xx_phy_write(bcm, 0x0003, regstack[5]); + bcm43xx_phy_write(bcm, 0x0001, regstack[6]); + bcm43xx_phy_write(bcm, 0x0030, regstack[7]); + + bcm43xx_radio_write16(bcm, 0x0043, regstack[8]); + bcm43xx_radio_write16(bcm, 0x007A, regstack[9]); + + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) & 0x000F) + | regstack[11]); + + bcm43xx_write16(bcm, 0x03EC, regstack[10]); + } + bcm43xx_phy_write(bcm, 0x0015, regstack[0]); +} + +static inline +u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x15, 0xE300); + control <<= 8; + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0); + udelay(5); + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B2); + udelay(2); + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B3); + udelay(4); + bcm43xx_phy_write(bcm, 0x0015, 0xF300); + udelay(8); + } else { + bcm43xx_phy_write(bcm, 0x0015, control | 0xEFA0); + udelay(2); + bcm43xx_phy_write(bcm, 0x0015, control | 0xEFE0); + udelay(4); + bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0); + udelay(8); + } + + return bcm43xx_phy_read(bcm, 0x002D); +} + +static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control) +{ + int i; + u32 ret = 0; + + for (i = 0; i < 8; i++) + ret += bcm43xx_phy_lo_g_deviation_subval(bcm, control); + + return ret; +} + +/* Write the LocalOscillator CONTROL */ +static inline +void bcm43xx_lo_write(struct bcm43xx_private *bcm, + struct bcm43xx_lopair *pair) +{ + u16 value; + + value = (u8)(pair->low); + value |= ((u8)(pair->high)) << 8; + +#ifdef CONFIG_BCM43XX_DEBUG + /* Sanity check. */ + if (pair->low < -8 || pair->low > 8 || + pair->high < -8 || pair->high > 8) { + printk(KERN_WARNING PFX + "WARNING: Writing invalid LOpair " + "(low: %d, high: %d, index: %lu)\n", + pair->low, pair->high, + (unsigned long)(pair - bcm43xx_current_phy(bcm)->_lo_pairs)); + dump_stack(); + } +#endif + + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, value); +} + +static inline +struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, + u16 baseband_attenuation, + u16 radio_attenuation, + u16 tx) +{ + static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + if (baseband_attenuation > 6) + baseband_attenuation = 6; + assert(radio_attenuation < 10); + + if (tx == 3) { + return bcm43xx_get_lopair(phy, + radio_attenuation, + baseband_attenuation); + } + return bcm43xx_get_lopair(phy, dict[radio_attenuation], baseband_attenuation); +} + +static inline +struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + return bcm43xx_find_lopair(bcm, + radio->baseband_atten, + radio->radio_atten, + radio->txctl1); +} + +/* Adjust B/G LO */ +void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed) +{ + struct bcm43xx_lopair *pair; + + if (fixed) { + /* Use fixed values. Only for initialization. */ + pair = bcm43xx_find_lopair(bcm, 2, 3, 0); + } else + pair = bcm43xx_current_lopair(bcm); + bcm43xx_lo_write(bcm, pair); +} + +static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 txctl2 = 0, i; + u32 smallest, tmp; + + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + udelay(10); + smallest = bcm43xx_phy_lo_g_singledeviation(bcm, 0); + for (i = 0; i < 16; i++) { + bcm43xx_radio_write16(bcm, 0x0052, i); + udelay(10); + tmp = bcm43xx_phy_lo_g_singledeviation(bcm, 0); + if (tmp < smallest) { + smallest = tmp; + txctl2 = i; + } + } + radio->txctl2 = txctl2; +} + +static +void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm, + const struct bcm43xx_lopair *in_pair, + struct bcm43xx_lopair *out_pair, + u16 r27) +{ + static const struct bcm43xx_lopair transitions[8] = { + { .high = 1, .low = 1, }, + { .high = 1, .low = 0, }, + { .high = 1, .low = -1, }, + { .high = 0, .low = -1, }, + { .high = -1, .low = -1, }, + { .high = -1, .low = 0, }, + { .high = -1, .low = 1, }, + { .high = 0, .low = 1, }, + }; + struct bcm43xx_lopair lowest_transition = { + .high = in_pair->high, + .low = in_pair->low, + }; + struct bcm43xx_lopair tmp_pair; + struct bcm43xx_lopair transition; + int i = 12; + int state = 0; + int found_lower; + int j, begin, end; + u32 lowest_deviation; + u32 tmp; + + /* Note that in_pair and out_pair can point to the same pair. Be careful. */ + + bcm43xx_lo_write(bcm, &lowest_transition); + lowest_deviation = bcm43xx_phy_lo_g_singledeviation(bcm, r27); + do { + found_lower = 0; + assert(state >= 0 && state <= 8); + if (state == 0) { + begin = 1; + end = 8; + } else if (state % 2 == 0) { + begin = state - 1; + end = state + 1; + } else { + begin = state - 2; + end = state + 2; + } + if (begin < 1) + begin += 8; + if (end > 8) + end -= 8; + + j = begin; + tmp_pair.high = lowest_transition.high; + tmp_pair.low = lowest_transition.low; + while (1) { + assert(j >= 1 && j <= 8); + transition.high = tmp_pair.high + transitions[j - 1].high; + transition.low = tmp_pair.low + transitions[j - 1].low; + if ((abs(transition.low) < 9) && (abs(transition.high) < 9)) { + bcm43xx_lo_write(bcm, &transition); + tmp = bcm43xx_phy_lo_g_singledeviation(bcm, r27); + if (tmp < lowest_deviation) { + lowest_deviation = tmp; + state = j; + found_lower = 1; + + lowest_transition.high = transition.high; + lowest_transition.low = transition.low; + } + } + if (j == end) + break; + if (j == 8) + j = 1; + else + j++; + } + } while (i-- && found_lower); + + out_pair->high = lowest_transition.high; + out_pair->low = lowest_transition.low; +} + +/* Set the baseband attenuation value on chip. */ +void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, + u16 baseband_attenuation) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 value; + + if (phy->version == 0) { + value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0); + value |= (baseband_attenuation & 0x000F); + bcm43xx_write16(bcm, 0x03E6, value); + return; + } + + if (phy->version > 1) { + value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C; + value |= (baseband_attenuation << 2) & 0x003C; + } else { + value = bcm43xx_phy_read(bcm, 0x0060) & ~0x0078; + value |= (baseband_attenuation << 3) & 0x0078; + } + bcm43xx_phy_write(bcm, 0x0060, value); +} + +/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ +void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) +{ + static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; + const int is_initializing = bcm43xx_is_initializing(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 h, i, oldi = 0, j; + struct bcm43xx_lopair control; + struct bcm43xx_lopair *tmp_control; + u16 tmp; + u16 regstack[16] = { 0 }; + u8 oldchannel; + + //XXX: What are these? + u8 r27 = 0, r31; + + oldchannel = radio->channel; + /* Setup */ + if (phy->connected) { + regstack[0] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); + regstack[1] = bcm43xx_phy_read(bcm, 0x0802); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); + } + regstack[3] = bcm43xx_read16(bcm, 0x03E2); + bcm43xx_write16(bcm, 0x03E2, regstack[3] | 0x8000); + regstack[4] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + regstack[5] = bcm43xx_phy_read(bcm, 0x15); + regstack[6] = bcm43xx_phy_read(bcm, 0x2A); + regstack[7] = bcm43xx_phy_read(bcm, 0x35); + regstack[8] = bcm43xx_phy_read(bcm, 0x60); + regstack[9] = bcm43xx_radio_read16(bcm, 0x43); + regstack[10] = bcm43xx_radio_read16(bcm, 0x7A); + regstack[11] = bcm43xx_radio_read16(bcm, 0x52); + if (phy->connected) { + regstack[12] = bcm43xx_phy_read(bcm, 0x0811); + regstack[13] = bcm43xx_phy_read(bcm, 0x0812); + regstack[14] = bcm43xx_phy_read(bcm, 0x0814); + regstack[15] = bcm43xx_phy_read(bcm, 0x0815); + } + bcm43xx_radio_selectchannel(bcm, 6, 0); + if (phy->connected) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); + bcm43xx_dummy_transmission(bcm); + } + bcm43xx_radio_write16(bcm, 0x0043, 0x0006); + + bcm43xx_phy_set_baseband_attenuation(bcm, 2); + + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x0000); + bcm43xx_phy_write(bcm, 0x002E, 0x007F); + bcm43xx_phy_write(bcm, 0x080F, 0x0078); + bcm43xx_phy_write(bcm, 0x0035, regstack[7] & ~(1 << 7)); + bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0); + bcm43xx_phy_write(bcm, 0x002B, 0x0203); + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003); + bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC); + bcm43xx_phy_write(bcm, 0x0811, 0x01B3); + bcm43xx_phy_write(bcm, 0x0812, 0x00B2); + } + if (is_initializing) + bcm43xx_phy_lo_g_measure_txctl2(bcm); + bcm43xx_phy_write(bcm, 0x080F, 0x8078); + + /* Measure */ + control.low = 0; + control.high = 0; + for (h = 0; h < 10; h++) { + /* Loop over each possible RadioAttenuation (0-9) */ + i = pairorder[h]; + if (is_initializing) { + if (i == 3) { + control.low = 0; + control.high = 0; + } else if (((i % 2 == 1) && (oldi % 2 == 1)) || + ((i % 2 == 0) && (oldi % 2 == 0))) { + tmp_control = bcm43xx_get_lopair(phy, oldi, 0); + memcpy(&control, tmp_control, sizeof(control)); + } else { + tmp_control = bcm43xx_get_lopair(phy, 3, 0); + memcpy(&control, tmp_control, sizeof(control)); + } + } + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp = i * 2 + j; + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + bcm43xx_radio_write16(bcm, 0x43, i); + bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); + udelay(10); + + bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + bcm43xx_radio_write16(bcm, 0x007A, tmp); + + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); + bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); + } + oldi = i; + } + /* Loop over each possible RadioAttenuation (10-13) */ + for (i = 10; i < 14; i++) { + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); + memcpy(&control, tmp_control, sizeof(control)); + tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger. + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + bcm43xx_radio_write16(bcm, 0x43, i - 9); + bcm43xx_radio_write16(bcm, 0x52, + radio->txctl2 + | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? + udelay(10); + + bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + bcm43xx_radio_write16(bcm, 0x7A, tmp); + + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); + bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); + } + } + + /* Restoration */ + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0015, 0xE300); + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0); + udelay(5); + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); + udelay(2); + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); + } else + bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); + bcm43xx_phy_lo_adjust(bcm, is_initializing); + bcm43xx_phy_write(bcm, 0x002E, 0x807F); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x002F, 0x0202); + else + bcm43xx_phy_write(bcm, 0x002F, 0x0101); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]); + bcm43xx_phy_write(bcm, 0x0015, regstack[5]); + bcm43xx_phy_write(bcm, 0x002A, regstack[6]); + bcm43xx_phy_write(bcm, 0x0035, regstack[7]); + bcm43xx_phy_write(bcm, 0x0060, regstack[8]); + bcm43xx_radio_write16(bcm, 0x0043, regstack[9]); + bcm43xx_radio_write16(bcm, 0x007A, regstack[10]); + regstack[11] &= 0x00F0; + regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F); + bcm43xx_radio_write16(bcm, 0x52, regstack[11]); + bcm43xx_write16(bcm, 0x03E2, regstack[3]); + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0811, regstack[12]); + bcm43xx_phy_write(bcm, 0x0812, regstack[13]); + bcm43xx_phy_write(bcm, 0x0814, regstack[14]); + bcm43xx_phy_write(bcm, 0x0815, regstack[15]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]); + bcm43xx_phy_write(bcm, 0x0802, regstack[1]); + } + bcm43xx_radio_selectchannel(bcm, oldchannel, 1); + +#ifdef CONFIG_BCM43XX_DEBUG + { + /* Sanity check for all lopairs. */ + for (i = 0; i < BCM43xx_LO_COUNT; i++) { + tmp_control = phy->_lo_pairs + i; + if (tmp_control->low < -8 || tmp_control->low > 8 || + tmp_control->high < -8 || tmp_control->high > 8) { + printk(KERN_WARNING PFX + "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n", + tmp_control->low, tmp_control->high, i); + } + } + } +#endif /* CONFIG_BCM43XX_DEBUG */ +} + +static +void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm) +{ + struct bcm43xx_lopair *pair; + + pair = bcm43xx_current_lopair(bcm); + pair->used = 1; +} + +void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_lopair *pair; + int i; + + for (i = 0; i < BCM43xx_LO_COUNT; i++) { + pair = phy->_lo_pairs + i; + pair->used = 0; + } +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + s8 dbm = 0; + s32 tmp; + + tmp = phy->idle_tssi; + tmp += tssi; + tmp -= phy->savedpctlreg; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + tmp += 0x80; + tmp = limit_value(tmp, 0x00, 0xFF); + dbm = phy->tssi2dbm[tmp]; + TODO(); //TODO: There's a FIXME on the specs + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + tmp = limit_value(tmp, 0x00, 0x3F); + dbm = phy->tssi2dbm[tmp]; + break; + default: + assert(0); + } + + return dbm; +} + +/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + if (phy->savedpctlreg == 0xFFFF) + return; + if ((bcm->board_type == 0x0416) && + (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)) + return; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: { + + TODO(); //TODO: Nothing for A PHYs yet :-/ + + break; + } + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: { + u16 tmp; + u16 txpower; + s8 v0, v1, v2, v3; + s8 average; + u8 max_pwr; + s16 desired_pwr, estimated_pwr, pwr_adjust; + s16 radio_att_delta, baseband_att_delta; + s16 radio_attenuation, baseband_attenuation; + unsigned long phylock_flags; + + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + tmp = 0; + + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) + return; + v0 = (v0 + 0x20) & 0x3F; + v1 = (v1 + 0x20) & 0x3F; + v2 = (v2 + 0x20) & 0x3F; + v3 = (v3 + 0x20) & 0x3F; + tmp = 1; + } + bcm43xx_radio_clear_tssi(bcm); + + average = (v0 + v1 + v2 + v3 + 2) / 4; + + if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8)) + average -= 13; + + estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average); + + max_pwr = bcm->sprom.maxpower_bgphy; + + if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) && + (phy->type == BCM43xx_PHYTYPE_G)) + max_pwr -= 0x3; + + /*TODO: + max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr) + where REG is the max power as per the regulatory domain + */ + + desired_pwr = limit_value(radio->txpower_desired, 0, max_pwr); + /* Check if we need to adjust the current power. */ + pwr_adjust = desired_pwr - estimated_pwr; + radio_att_delta = -(pwr_adjust + 7) >> 3; + baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); + if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { + bcm43xx_phy_lo_mark_current_used(bcm); + return; + } + + /* Calculate the new attenuation values. */ + baseband_attenuation = radio->baseband_atten; + baseband_attenuation += baseband_att_delta; + radio_attenuation = radio->radio_atten; + radio_attenuation += radio_att_delta; + + /* Get baseband and radio attenuation values into their permitted ranges. + * baseband 0-11, radio 0-9. + * Radio attenuation affects power level 4 times as much as baseband. + */ + if (radio_attenuation < 0) { + baseband_attenuation -= (4 * -radio_attenuation); + radio_attenuation = 0; + } else if (radio_attenuation > 9) { + baseband_attenuation += (4 * (radio_attenuation - 9)); + radio_attenuation = 9; + } else { + while (baseband_attenuation < 0 && radio_attenuation > 0) { + baseband_attenuation += 4; + radio_attenuation--; + } + while (baseband_attenuation > 11 && radio_attenuation < 9) { + baseband_attenuation -= 4; + radio_attenuation++; + } + } + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + + txpower = radio->txctl1; + if ((radio->version == 0x2050) && (radio->revision == 2)) { + if (radio_attenuation <= 1) { + if (txpower == 0) { + txpower = 3; + radio_attenuation += 2; + baseband_attenuation += 2; + } else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { + baseband_attenuation += 4 * (radio_attenuation - 2); + radio_attenuation = 2; + } + } else if (radio_attenuation > 4 && txpower != 0) { + txpower = 0; + if (baseband_attenuation < 3) { + radio_attenuation -= 3; + baseband_attenuation += 2; + } else { + radio_attenuation -= 2; + baseband_attenuation -= 2; + } + } + } + radio->txctl1 = txpower; + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + radio_attenuation = limit_value(radio_attenuation, 0, 9); + + bcm43xx_phy_lock(bcm, phylock_flags); + bcm43xx_radio_lock(bcm); + bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation, + radio_attenuation, txpower); + bcm43xx_phy_lo_mark_current_used(bcm); + bcm43xx_radio_unlock(bcm); + bcm43xx_phy_unlock(bcm, phylock_flags); + break; + } + default: + assert(0); + } +} + +static inline +s32 bcm43xx_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num/den; + else + return (num+den/2)/den; +} + +static inline +s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1, m2, f = 256, q, delta; + s8 i = 0; + + m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = bcm43xx_tssi2dbm_ad(f * 4096 - + bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; +} + +/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ +int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + s16 pab0, pab1, pab2; + u8 idx; + s8 *dyn_tssi2dbm; + + if (phy->type == BCM43xx_PHYTYPE_A) { + pab0 = (s16)(bcm->sprom.pa1b0); + pab1 = (s16)(bcm->sprom.pa1b1); + pab2 = (s16)(bcm->sprom.pa1b2); + } else { + pab0 = (s16)(bcm->sprom.pa0b0); + pab1 = (s16)(bcm->sprom.pa0b1); + pab2 = (s16)(bcm->sprom.pa0b2); + } + + if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) { + phy->idle_tssi = 0x34; + phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; + return 0; + } + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if (phy->type == BCM43xx_PHYTYPE_A) { + if ((s8)bcm->sprom.idle_tssi_tgt_aphy != 0 && + (s8)bcm->sprom.idle_tssi_tgt_aphy != -1) + phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_aphy); + else + phy->idle_tssi = 62; + } else { + if ((s8)bcm->sprom.idle_tssi_tgt_bgphy != 0 && + (s8)bcm->sprom.idle_tssi_tgt_bgphy != -1) + phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_bgphy); + else + phy->idle_tssi = 62; + } + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); + if (dyn_tssi2dbm == NULL) { + printk(KERN_ERR PFX "Could not allocate memory" + "for tssi2dbm table\n"); + return -ENOMEM; + } + for (idx = 0; idx < 64; idx++) + if (bcm43xx_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, pab1, pab2)) { + phy->tssi2dbm = NULL; + printk(KERN_ERR PFX "Could not generate " + "tssi2dBm table\n"); + return -ENODEV; + } + phy->tssi2dbm = dyn_tssi2dbm; + phy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + /* APHY needs a generated table. */ + phy->tssi2dbm = NULL; + printk(KERN_ERR PFX "Could not generate tssi2dBm " + "table (wrong SPROM info)!\n"); + return -ENODEV; + case BCM43xx_PHYTYPE_B: + phy->idle_tssi = 0x34; + phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; + break; + case BCM43xx_PHYTYPE_G: + phy->idle_tssi = 0x34; + phy->tssi2dbm = bcm43xx_tssi2dbm_g_table; + break; + } + } + + return 0; +} + +int bcm43xx_phy_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + int err = -ENODEV; + unsigned long flags; + + /* We do not want to be preempted while calibrating + * the hardware. + */ + local_irq_save(flags); + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + if (phy->rev == 2 || phy->rev == 3) { + bcm43xx_phy_inita(bcm); + err = 0; + } + break; + case BCM43xx_PHYTYPE_B: + switch (phy->rev) { + case 2: + bcm43xx_phy_initb2(bcm); + err = 0; + break; + case 4: + bcm43xx_phy_initb4(bcm); + err = 0; + break; + case 5: + bcm43xx_phy_initb5(bcm); + err = 0; + break; + case 6: + bcm43xx_phy_initb6(bcm); + err = 0; + break; + } + break; + case BCM43xx_PHYTYPE_G: + bcm43xx_phy_initg(bcm); + err = 0; + break; + } + local_irq_restore(flags); + if (err) + printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n"); + + return err; +} + +void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 antennadiv; + u16 offset; + u16 value; + u32 ucodeflags; + + antennadiv = phy->antenna_diversity; + + if (antennadiv == 0xFFFF) + antennadiv = 3; + assert(antennadiv <= 3); + + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + ucodeflags & ~BCM43xx_UCODEFLAG_AUTODIV); + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + case BCM43xx_PHYTYPE_G: + if (phy->type == BCM43xx_PHYTYPE_A) + offset = 0x0000; + else + offset = 0x0400; + + if (antennadiv == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + bcm43xx_phy_write(bcm, offset + 1, + (bcm43xx_phy_read(bcm, offset + 1) + & 0x7E7F) | value); + + if (antennadiv >= 2) { + if (antennadiv == 2) + value = (antennadiv << 7); + else + value = (0/*force0*/ << 7); + bcm43xx_phy_write(bcm, offset + 0x2B, + (bcm43xx_phy_read(bcm, offset + 0x2B) + & 0xFEFF) | value); + } + + if (phy->type == BCM43xx_PHYTYPE_G) { + if (antennadiv >= 2) + bcm43xx_phy_write(bcm, 0x048C, + bcm43xx_phy_read(bcm, 0x048C) + | 0x2000); + else + bcm43xx_phy_write(bcm, 0x048C, + bcm43xx_phy_read(bcm, 0x048C) + & ~0x2000); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0461, + bcm43xx_phy_read(bcm, 0x0461) + | 0x0010); + bcm43xx_phy_write(bcm, 0x04AD, + (bcm43xx_phy_read(bcm, 0x04AD) + & 0x00FF) | 0x0015); + if (phy->rev == 2) + bcm43xx_phy_write(bcm, 0x0427, 0x0008); + else + bcm43xx_phy_write(bcm, 0x0427, + (bcm43xx_phy_read(bcm, 0x0427) + & 0x00FF) | 0x0008); + } + else if (phy->rev >= 6) + bcm43xx_phy_write(bcm, 0x049B, 0x00DC); + } else { + if (phy->rev < 3) + bcm43xx_phy_write(bcm, 0x002B, + (bcm43xx_phy_read(bcm, 0x002B) + & 0x00FF) | 0x0024); + else { + bcm43xx_phy_write(bcm, 0x0061, + bcm43xx_phy_read(bcm, 0x0061) + | 0x0010); + if (phy->rev == 3) { + bcm43xx_phy_write(bcm, 0x0093, 0x001D); + bcm43xx_phy_write(bcm, 0x0027, 0x0008); + } else { + bcm43xx_phy_write(bcm, 0x0093, 0x003A); + bcm43xx_phy_write(bcm, 0x0027, + (bcm43xx_phy_read(bcm, 0x0027) + & 0x00FF) | 0x0008); + } + } + } + break; + case BCM43xx_PHYTYPE_B: + if (bcm->current_core->rev == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + bcm43xx_phy_write(bcm, 0x03E2, + (bcm43xx_phy_read(bcm, 0x03E2) + & 0xFE7F) | value); + break; + default: + assert(0); + } + + if (antennadiv >= 2) { + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + ucodeflags | BCM43xx_UCODEFLAG_AUTODIV); + } + + phy->antenna_diversity = antennadiv; +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h new file mode 100644 index 000000000000..1f321ef42be8 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h @@ -0,0 +1,74 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_PHY_H_ +#define BCM43xx_PHY_H_ + +#include + +struct bcm43xx_private; + +void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm); +#define bcm43xx_phy_lock(bcm, flags) \ + do { \ + local_irq_save(flags); \ + bcm43xx_raw_phy_lock(bcm); \ + } while (0) +void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm); +#define bcm43xx_phy_unlock(bcm, flags) \ + do { \ + bcm43xx_raw_phy_unlock(bcm); \ + local_irq_restore(flags); \ + } while (0) + +u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val); + +int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm); +int bcm43xx_phy_init(struct bcm43xx_private *bcm); + +void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm); +void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm); +int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect); + +void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm); +void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm); +void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm); + +/* Adjust the LocalOscillator to the saved values. + * "fixed" is only set to 1 once in initialization. Set to 0 otherwise. + */ +void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed); +void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm); + +void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, + u16 baseband_attenuation); + +#endif /* BCM43xx_PHY_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c new file mode 100644 index 000000000000..c59ddd40680d --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -0,0 +1,606 @@ +/* + + Broadcom BCM43xx wireless driver + + PIO Transmission + + Copyright (c) 2005 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_pio.h" +#include "bcm43xx_main.h" +#include "bcm43xx_xmit.h" + +#include + + +static void tx_start(struct bcm43xx_pioqueue *queue) +{ + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_INIT); +} + +static void tx_octet(struct bcm43xx_pioqueue *queue, + u8 octet) +{ + if (queue->need_workarounds) { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, + octet); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITEHI); + } else { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITEHI); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, + octet); + } +} + +static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr, + const u8 *packet, + unsigned int *pos) +{ + const u8 *source; + unsigned int i = *pos; + u16 ret; + + if (i < sizeof(*txhdr)) { + source = (const u8 *)txhdr; + } else { + source = packet; + i -= sizeof(*txhdr); + } + ret = le16_to_cpu( *((u16 *)(source + i)) ); + *pos += 2; + + return ret; +} + +static void tx_data(struct bcm43xx_pioqueue *queue, + struct bcm43xx_txhdr *txhdr, + const u8 *packet, + unsigned int octets) +{ + u16 data; + unsigned int i = 0; + + if (queue->need_workarounds) { + data = tx_get_next_word(txhdr, packet, &i); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + } + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITELO | + BCM43xx_PIO_TXCTL_WRITEHI); + while (i < octets - 1) { + data = tx_get_next_word(txhdr, packet, &i); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + } + if (octets % 2) + tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]); +} + +static void tx_complete(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb) +{ + if (queue->need_workarounds) { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, + skb->data[skb->len - 1]); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITEHI | + BCM43xx_PIO_TXCTL_COMPLETE); + } else { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_COMPLETE); + } +} + +static u16 generate_cookie(struct bcm43xx_pioqueue *queue, + int packetindex) +{ + u16 cookie = 0x0000; + + /* We use the upper 4 bits for the PIO + * controller ID and the lower 12 bits + * for the packet index (in the cache). + */ + switch (queue->mmio_base) { + case BCM43xx_MMIO_PIO1_BASE: + break; + case BCM43xx_MMIO_PIO2_BASE: + cookie = 0x1000; + break; + case BCM43xx_MMIO_PIO3_BASE: + cookie = 0x2000; + break; + case BCM43xx_MMIO_PIO4_BASE: + cookie = 0x3000; + break; + default: + assert(0); + } + assert(((u16)packetindex & 0xF000) == 0x0000); + cookie |= (u16)packetindex; + + return cookie; +} + +static +struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, + u16 cookie, + struct bcm43xx_pio_txpacket **packet) +{ + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); + struct bcm43xx_pioqueue *queue = NULL; + int packetindex; + + switch (cookie & 0xF000) { + case 0x0000: + queue = pio->queue0; + break; + case 0x1000: + queue = pio->queue1; + break; + case 0x2000: + queue = pio->queue2; + break; + case 0x3000: + queue = pio->queue3; + break; + default: + assert(0); + } + packetindex = (cookie & 0x0FFF); + assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS); + *packet = &(queue->tx_packets_cache[packetindex]); + + return queue; +} + +static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb, + struct bcm43xx_pio_txpacket *packet) +{ + struct bcm43xx_txhdr txhdr; + unsigned int octets; + + assert(skb_shinfo(skb)->nr_frags == 0); + bcm43xx_generate_txhdr(queue->bcm, + &txhdr, skb->data, skb->len, + (packet->xmitted_frags == 0), + generate_cookie(queue, pio_txpacket_getindex(packet))); + + tx_start(queue); + octets = skb->len + sizeof(txhdr); + if (queue->need_workarounds) + octets--; + tx_data(queue, &txhdr, (u8 *)skb->data, octets); + tx_complete(queue, skb); +} + +static void free_txpacket(struct bcm43xx_pio_txpacket *packet, + int irq_context) +{ + struct bcm43xx_pioqueue *queue = packet->queue; + + ieee80211_txb_free(packet->txb); + list_move(&packet->list, &queue->txfree); + queue->nr_txfree++; + + assert(queue->tx_devq_used >= packet->xmitted_octets); + assert(queue->tx_devq_packets >= packet->xmitted_frags); + queue->tx_devq_used -= packet->xmitted_octets; + queue->tx_devq_packets -= packet->xmitted_frags; +} + +static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) +{ + struct bcm43xx_pioqueue *queue = packet->queue; + struct ieee80211_txb *txb = packet->txb; + struct sk_buff *skb; + u16 octets; + int i; + + for (i = packet->xmitted_frags; i < txb->nr_frags; i++) { + skb = txb->fragments[i]; + + octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr); + assert(queue->tx_devq_size >= octets); + assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS); + assert(queue->tx_devq_used <= queue->tx_devq_size); + /* Check if there is sufficient free space on the device + * TX queue. If not, return and let the TX tasklet + * retry later. + */ + if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS) + return -EBUSY; + if (queue->tx_devq_used + octets > queue->tx_devq_size) + return -EBUSY; + /* Now poke the device. */ + pio_tx_write_fragment(queue, skb, packet); + + /* Account for the packet size. + * (We must not overflow the device TX queue) + */ + queue->tx_devq_packets++; + queue->tx_devq_used += octets; + + assert(packet->xmitted_frags <= packet->txb->nr_frags); + packet->xmitted_frags++; + packet->xmitted_octets += octets; + } + list_move_tail(&packet->list, &queue->txrunning); + + return 0; +} + +static void tx_tasklet(unsigned long d) +{ + struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d; + struct bcm43xx_private *bcm = queue->bcm; + unsigned long flags; + struct bcm43xx_pio_txpacket *packet, *tmp_packet; + int err; + + bcm43xx_lock_mmio(bcm, flags); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { + assert(packet->xmitted_frags < packet->txb->nr_frags); + if (packet->xmitted_frags == 0) { + int i; + struct sk_buff *skb; + + /* Check if the device queue is big + * enough for every fragment. If not, drop the + * whole packet. + */ + for (i = 0; i < packet->txb->nr_frags; i++) { + skb = packet->txb->fragments[i]; + if (unlikely(skb->len > queue->tx_devq_size)) { + dprintkl(KERN_ERR PFX "PIO TX device queue too small. " + "Dropping packet.\n"); + free_txpacket(packet, 1); + goto next_packet; + } + } + } + /* Try to transmit the packet. + * This may not completely succeed. + */ + err = pio_tx_packet(packet); + if (err) + break; + next_packet: + continue; + } + bcm43xx_unlock_mmio(bcm, flags); +} + +static void setup_txqueues(struct bcm43xx_pioqueue *queue) +{ + struct bcm43xx_pio_txpacket *packet; + int i; + + queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS; + for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) { + packet = &(queue->tx_packets_cache[i]); + + packet->queue = queue; + INIT_LIST_HEAD(&packet->list); + + list_add(&packet->list, &queue->txfree); + } +} + +static +struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, + u16 pio_mmio_base) +{ + struct bcm43xx_pioqueue *queue; + u32 value; + u16 qsize; + + queue = kzalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + goto out; + + queue->bcm = bcm; + queue->mmio_base = pio_mmio_base; + queue->need_workarounds = (bcm->current_core->rev < 3); + + INIT_LIST_HEAD(&queue->txfree); + INIT_LIST_HEAD(&queue->txqueue); + INIT_LIST_HEAD(&queue->txrunning); + tasklet_init(&queue->txtask, tx_tasklet, + (unsigned long)queue); + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value |= BCM43xx_SBF_XFER_REG_BYTESWAP; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); + + qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); + if (qsize <= BCM43xx_PIO_TXQADJUST) { + printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize); + goto err_freequeue; + } + qsize -= BCM43xx_PIO_TXQADJUST; + queue->tx_devq_size = qsize; + + setup_txqueues(queue); + +out: + return queue; + +err_freequeue: + kfree(queue); + queue = NULL; + goto out; +} + +static void cancel_transfers(struct bcm43xx_pioqueue *queue) +{ + struct bcm43xx_pio_txpacket *packet, *tmp_packet; + + netif_tx_disable(queue->bcm->net_dev); + assert(queue->bcm->shutting_down); + tasklet_disable(&queue->txtask); + + list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) + free_txpacket(packet, 0); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) + free_txpacket(packet, 0); +} + +static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) +{ + if (!queue) + return; + + cancel_transfers(queue); + kfree(queue); +} + +void bcm43xx_pio_free(struct bcm43xx_private *bcm) +{ + struct bcm43xx_pio *pio; + + if (!bcm43xx_using_pio(bcm)) + return; + pio = bcm43xx_current_pio(bcm); + + bcm43xx_destroy_pioqueue(pio->queue3); + pio->queue3 = NULL; + bcm43xx_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; + bcm43xx_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; + bcm43xx_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; +} + +int bcm43xx_pio_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); + struct bcm43xx_pioqueue *queue; + int err = -ENOMEM; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); + if (!queue) + goto out; + pio->queue0 = queue; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); + if (!queue) + goto err_destroy0; + pio->queue1 = queue; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); + if (!queue) + goto err_destroy1; + pio->queue2 = queue; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); + if (!queue) + goto err_destroy2; + pio->queue3 = queue; + + if (bcm->current_core->rev < 3) + bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; + + dprintk(KERN_INFO PFX "PIO initialized\n"); + err = 0; +out: + return err; + +err_destroy2: + bcm43xx_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; +err_destroy1: + bcm43xx_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; +err_destroy0: + bcm43xx_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; + goto out; +} + +int bcm43xx_pio_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1; + struct bcm43xx_pio_txpacket *packet; + u16 tmp; + + assert(!queue->tx_suspended); + assert(!list_empty(&queue->txfree)); + + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); + if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) + return -EBUSY; + + packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); + packet->txb = txb; + packet->xmitted_frags = 0; + packet->xmitted_octets = 0; + list_move_tail(&packet->list, &queue->txqueue); + queue->nr_txfree--; + assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS); + + /* Suspend TX, if we are out of packets in the "free" queue. */ + if (unlikely(list_empty(&queue->txfree))) { + netif_stop_queue(queue->bcm->net_dev); + queue->tx_suspended = 1; + } + + tasklet_schedule(&queue->txtask); + + return 0; +} + +void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ + struct bcm43xx_pioqueue *queue; + struct bcm43xx_pio_txpacket *packet; + + queue = parse_cookie(bcm, status->cookie, &packet); + assert(queue); +//TODO +if (!queue) +return; + free_txpacket(packet, 1); + if (unlikely(queue->tx_suspended)) { + queue->tx_suspended = 0; + netif_wake_queue(queue->bcm->net_dev); + } + /* If there are packets on the txqueue, poke the tasklet. */ + if (!list_empty(&queue->txqueue)) + tasklet_schedule(&queue->txtask); +} + +static void pio_rx_error(struct bcm43xx_pioqueue *queue, + int clear_buffers, + const char *error) +{ + int i; + + printkl("PIO RX error: %s\n", error); + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, + BCM43xx_PIO_RXCTL_READY); + if (clear_buffers) { + assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE); + for (i = 0; i < 15; i++) { + /* Dummy read. */ + bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); + } + } +} + +void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) +{ + u16 preamble[21] = { 0 }; + struct bcm43xx_rxhdr *rxhdr; + u16 tmp, len, rxflags2; + int i, preamble_readwords; + struct sk_buff *skb; + +return; + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); + if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) { + dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk. + return; + } + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, + BCM43xx_PIO_RXCTL_DATAAVAILABLE); + + for (i = 0; i < 10; i++) { + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); + if (tmp & BCM43xx_PIO_RXCTL_READY) + goto data_ready; + udelay(10); + } + dprintkl(KERN_ERR PFX "PIO RX timed out\n"); + return; +data_ready: + +//FIXME: endianess in this function. + len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + if (unlikely(len > 0x700)) { + pio_rx_error(queue, 0, "len > 0x700"); + return; + } + if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { + pio_rx_error(queue, 0, "len == 0"); + return; + } + preamble[0] = cpu_to_le16(len); + if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) + preamble_readwords = 14 / sizeof(u16); + else + preamble_readwords = 18 / sizeof(u16); + for (i = 0; i < preamble_readwords; i++) { + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); + preamble[i + 1] = cpu_to_be16(tmp);//FIXME? + } + rxhdr = (struct bcm43xx_rxhdr *)preamble; + rxflags2 = le16_to_cpu(rxhdr->flags2); + if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { + pio_rx_error(queue, + (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE), + "invalid frame"); + return; + } + if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { + /* We received an xmit status. */ + struct bcm43xx_hwxmitstatus *hw; + struct bcm43xx_xmitstatus stat; + + hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1); + stat.cookie = le16_to_cpu(hw->cookie); + stat.flags = hw->flags; + stat.cnt1 = hw->cnt1; + stat.cnt2 = hw->cnt2; + stat.seq = le16_to_cpu(hw->seq); + stat.unknown = le16_to_cpu(hw->unknown); + + bcm43xx_debugfs_log_txstat(queue->bcm, &stat); + bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat); + + return; + } + + skb = dev_alloc_skb(len); + if (unlikely(!skb)) { + pio_rx_error(queue, 1, "OOM"); + return; + } + skb_put(skb, len); + for (i = 0; i < len - 1; i += 2) { + tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + *((u16 *)(skb->data + i)) = tmp; + } + if (len % 2) { + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); + skb->data[len - 1] = (tmp & 0x00FF); + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) + skb->data[0x20] = (tmp & 0xFF00) >> 8; + else + skb->data[0x1E] = (tmp & 0xFF00) >> 8; + } + bcm43xx_rx(queue->bcm, skb, rxhdr); +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h new file mode 100644 index 000000000000..970627bc1769 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h @@ -0,0 +1,138 @@ +#ifndef BCM43xx_PIO_H_ +#define BCM43xx_PIO_H_ + +#include "bcm43xx.h" + +#include +#include +#include + + +#define BCM43xx_PIO_TXCTL 0x00 +#define BCM43xx_PIO_TXDATA 0x02 +#define BCM43xx_PIO_TXQBUFSIZE 0x04 +#define BCM43xx_PIO_RXCTL 0x08 +#define BCM43xx_PIO_RXDATA 0x0A + +#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 0) +#define BCM43xx_PIO_TXCTL_WRITELO (1 << 1) +#define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2) +#define BCM43xx_PIO_TXCTL_INIT (1 << 3) +#define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7) + +#define BCM43xx_PIO_RXCTL_DATAAVAILABLE (1 << 0) +#define BCM43xx_PIO_RXCTL_READY (1 << 1) + +/* PIO constants */ +#define BCM43xx_PIO_MAXTXDEVQPACKETS 31 +#define BCM43xx_PIO_TXQADJUST 80 + +/* PIO tuning knobs */ +#define BCM43xx_PIO_MAXTXPACKETS 256 + + + +#ifdef CONFIG_BCM43XX_PIO + + +struct bcm43xx_pioqueue; +struct bcm43xx_xmitstatus; + +struct bcm43xx_pio_txpacket { + struct bcm43xx_pioqueue *queue; + struct ieee80211_txb *txb; + struct list_head list; + + u8 xmitted_frags; + u16 xmitted_octets; +}; + +#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) + +struct bcm43xx_pioqueue { + struct bcm43xx_private *bcm; + u16 mmio_base; + + u8 tx_suspended:1, + need_workarounds:1; /* Workarounds needed for core.rev < 3 */ + + /* Adjusted size of the device internal TX buffer. */ + u16 tx_devq_size; + /* Used octets of the device internal TX buffer. */ + u16 tx_devq_used; + /* Used packet slots in the device internal TX buffer. */ + u8 tx_devq_packets; + /* Packets from the txfree list can + * be taken on incoming TX requests. + */ + struct list_head txfree; + unsigned int nr_txfree; + /* Packets on the txqueue are queued, + * but not completely written to the chip, yet. + */ + struct list_head txqueue; + /* Packets on the txrunning queue are completely + * posted to the device. We are waiting for the txstatus. + */ + struct list_head txrunning; + /* Total number or packets sent. + * (This counter can obviously wrap). + */ + unsigned int nr_tx_packets; + struct tasklet_struct txtask; + struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; +}; + +static inline +u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, + u16 offset) +{ + return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); +} + +static inline +void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, + u16 offset, u16 value) +{ + bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); +} + + +int bcm43xx_pio_init(struct bcm43xx_private *bcm); +void bcm43xx_pio_free(struct bcm43xx_private *bcm); + +int bcm43xx_pio_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb); +void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status); +void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); + +#else /* CONFIG_BCM43XX_PIO */ + +static inline +int bcm43xx_pio_init(struct bcm43xx_private *bcm) +{ + return 0; +} +static inline +void bcm43xx_pio_free(struct bcm43xx_private *bcm) +{ +} +static inline +int bcm43xx_pio_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return 0; +} +static inline +void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ +} +static inline +void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) +{ +} + +#endif /* CONFIG_BCM43XX_PIO */ +#endif /* BCM43xx_PIO_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c new file mode 100644 index 000000000000..3c92b62807c5 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.c @@ -0,0 +1,358 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "bcm43xx.h" +#include "bcm43xx_power.h" +#include "bcm43xx_main.h" + + +/* Get max/min slowclock frequency + * as described in http://bcm-specs.sipsolutions.net/PowerControl + */ +static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, + int get_max) +{ + int limit = 0; + int divisor; + int selection; + int err; + u32 tmp; + struct bcm43xx_coreinfo *old_core; + + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) + goto out; + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err) + goto out; + + if (bcm->current_core->rev < 6) { + if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) || + (bcm->bustype == BCM43xx_BUSTYPE_SB)) { + selection = 1; + divisor = 32; + } else { + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); + if (err) { + printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n"); + goto out_switchback; + } + if (tmp & 0x10) { + /* PCI */ + selection = 2; + divisor = 64; + } else { + /* XTAL */ + selection = 1; + divisor = 32; + } + } + } else if (bcm->current_core->rev < 10) { + selection = (tmp & 0x07); + if (selection) { + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); + } else + divisor = 1; + } else { + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); + divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); + selection = 1; + } + + switch (selection) { + case 0: + /* LPO */ + if (get_max) + limit = 43000; + else + limit = 25000; + break; + case 1: + /* XTAL */ + if (get_max) + limit = 20200000; + else + limit = 19800000; + break; + case 2: + /* PCI */ + if (get_max) + limit = 34000000; + else + limit = 25000000; + break; + default: + assert(0); + } + limit /= divisor; + +out_switchback: + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return limit; +} + +/* init power control + * as described in http://bcm-specs.sipsolutions.net/PowerControl + */ +int bcm43xx_pctl_init(struct bcm43xx_private *bcm) +{ + int err, maxfreq; + struct bcm43xx_coreinfo *old_core; + + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) + return 0; + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) + return 0; + if (err) + goto out; + + maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1); + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY, + (maxfreq * 150 + 999999) / 1000000); + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY, + (maxfreq * 15 + 999999) / 1000000); + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return err; +} + +u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm) +{ + u16 delay = 0; + int err; + u32 pll_on_delay; + struct bcm43xx_coreinfo *old_core; + int minfreq; + + if (bcm->bustype != BCM43xx_BUSTYPE_PCI) + goto out; + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) + goto out; + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) + goto out; + + minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0); + pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY); + delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return delay; +} + +/* set the powercontrol clock + * as described in http://bcm-specs.sipsolutions.net/PowerControl + */ +int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode) +{ + int err; + struct bcm43xx_coreinfo *old_core; + u32 tmp; + + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) + return 0; + if (err) + goto out; + + if (bcm->core_chipcommon.rev < 6) { + if (mode == BCM43xx_PCTL_CLK_FAST) { + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto out; + } + } else { + if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) && + (bcm->core_chipcommon.rev < 10)) { + switch (mode) { + case BCM43xx_PCTL_CLK_FAST: + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL; + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); + break; + case BCM43xx_PCTL_CLK_SLOW: + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp |= BCM43xx_PCTL_FORCE_SLOW; + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); + break; + case BCM43xx_PCTL_CLK_DYNAMIC: + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp &= ~BCM43xx_PCTL_FORCE_SLOW; + tmp |= BCM43xx_PCTL_FORCE_PLL; + tmp &= ~BCM43xx_PCTL_DYN_XTAL; + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); + } + } + } + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return err; +} + +int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on) +{ + int err; + u32 in, out, outenable; + + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in); + if (err) + goto err_pci; + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out); + if (err) + goto err_pci; + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable); + if (err) + goto err_pci; + + outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); + + if (on) { + if (in & 0x40) + return 0; + + out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); + + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); + if (err) + goto err_pci; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); + if (err) + goto err_pci; + udelay(1000); + + out &= ~BCM43xx_PCTL_PLL_POWERDOWN; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); + if (err) + goto err_pci; + udelay(5000); + } else { + if (bcm->current_core->rev < 5) + return 0; + if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW) + return 0; + +/* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time? + * err = bcm43xx_switch_core(bcm, bcm->active_80211_core); + * if (err) + * return err; + * if (((bcm->current_core->rev >= 3) && + * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) || + * ((bcm->current_core->rev < 3) && + * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4)))) + * return 0; + * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + * if (err) + * return err; + */ + + err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); + if (err) + goto out; + out &= ~BCM43xx_PCTL_XTAL_POWERUP; + out |= BCM43xx_PCTL_PLL_POWERDOWN; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); + if (err) + goto err_pci; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); + if (err) + goto err_pci; + } + +out: + return err; + +err_pci: + printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n"); + err = -EBUSY; + goto out; +} + +/* Set the PowerSavingControlBits. + * Bitvalues: + * 0 => unset the bit + * 1 => set the bit + * -1 => calculate the bit + */ +void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, + int bit25, int bit26) +{ + int i; + u32 status; + +//FIXME: Force 25 to off and 26 to on for now: +bit25 = 0; +bit26 = 1; + + if (bit25 == -1) { + //TODO: If powersave is not off and FIXME is not set and we are not in adhoc + // and thus is not an AP and we are associated, set bit 25 + } + if (bit26 == -1) { + //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME, + // or we are associated, or FIXME, or the latest PS-Poll packet sent was + // successful, set bit26 + } + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + if (bit25) + status |= BCM43xx_SBF_PS1; + else + status &= ~BCM43xx_SBF_PS1; + if (bit26) + status |= BCM43xx_SBF_PS2; + else + status &= ~BCM43xx_SBF_PS2; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + if (bit26 && bcm->current_core->rev >= 5) { + for (i = 0; i < 100; i++) { + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4) + break; + udelay(10); + } + } +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.h b/drivers/net/wireless/bcm43xx/bcm43xx_power.h new file mode 100644 index 000000000000..5f63640810bd --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.h @@ -0,0 +1,47 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_POWER_H_ +#define BCM43xx_POWER_H_ + +#include + + +struct bcm43xx_private; + +int bcm43xx_pctl_init(struct bcm43xx_private *bcm); +int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode); +int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on); +u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm); + +void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, + int bit25, int bit26); + +#endif /* BCM43xx_POWER_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c new file mode 100644 index 000000000000..af5c0bff1696 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -0,0 +1,2026 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_phy.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_ilt.h" + + +/* Table for bcm43xx_radio_calibrationvalue() */ +static const u16 rcc_table[16] = { + 0x0002, 0x0003, 0x0001, 0x000F, + 0x0006, 0x0007, 0x0005, 0x000F, + 0x000A, 0x000B, 0x0009, 0x000F, + 0x000E, 0x000F, 0x000D, 0x000F, +}; + +/* Reverse the bits of a 4bit value. + * Example: 1101 is flipped 1011 + */ +static u16 flip_4bit(u16 value) +{ + u16 flipped = 0x0000; + + assert((value & ~0x000F) == 0x0000); + + flipped |= (value & 0x0001) << 3; + flipped |= (value & 0x0002) << 1; + flipped |= (value & 0x0004) >> 1; + flipped |= (value & 0x0008) >> 3; + + return flipped; +} + +/* Get the freq, as it has to be written to the device. */ +static inline +u16 channel2freq_bg(u8 channel) +{ + /* Frequencies are given as frequencies_bg[index] + 2.4GHz + * Starting with channel 1 + */ + static const u16 frequencies_bg[14] = { + 12, 17, 22, 27, + 32, 37, 42, 47, + 52, 57, 62, 67, + 72, 84, + }; + + assert(channel >= 1 && channel <= 14); + + return frequencies_bg[channel - 1]; +} + +/* Get the freq, as it has to be written to the device. */ +static inline +u16 channel2freq_a(u8 channel) +{ + assert(channel <= 200); + + return (5000 + 5 * channel); +} + +void bcm43xx_radio_lock(struct bcm43xx_private *bcm) +{ + u32 status; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status |= BCM43xx_SBF_RADIOREG_LOCK; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + mmiowb(); + udelay(10); +} + +void bcm43xx_radio_unlock(struct bcm43xx_private *bcm) +{ + u32 status; + + bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */ + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status &= ~BCM43xx_SBF_RADIOREG_LOCK; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + mmiowb(); +} + +u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + offset |= 0x0040; + break; + case BCM43xx_PHYTYPE_B: + if (radio->version == 0x2053) { + if (offset < 0x70) + offset += 0x80; + else if (offset < 0x80) + offset += 0x70; + } else if (radio->version == 0x2050) { + offset |= 0x80; + } else + assert(0); + break; + case BCM43xx_PHYTYPE_G: + offset |= 0x80; + break; + } + + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); + return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); +} + +void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) +{ + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); + mmiowb(); + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val); +} + +static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, + s16 first, s16 second, s16 third) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 i; + u16 start = 0x08, end = 0x18; + u16 offset = 0x0400; + u16 tmp; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x10; + end = 0x20; + } + + for (i = 0; i < 4; i++) + bcm43xx_ilt_write(bcm, offset + i, first); + + for (i = start; i < end; i++) + bcm43xx_ilt_write(bcm, offset + i, second); + + if (third != -1) { + tmp = ((u16)third << 14) | ((u16)third << 6); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp); + } + bcm43xx_dummy_transmission(bcm); +} + +static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 i, tmp; + u16 offset = 0x0400; + u16 start = 0x0008, end = 0x0018; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x0010; + end = 0x0020; + } + + for (i = 0; i < 4; i++) { + tmp = (i & 0xFFFC); + tmp |= (i & 0x0001) << 1; + tmp |= (i & 0x0002) >> 1; + + bcm43xx_ilt_write(bcm, offset + i, tmp); + } + + for (i = start; i < end; i++) + bcm43xx_ilt_write(bcm, offset + i, i - start); + + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000); + bcm43xx_dummy_transmission(bcm); +} + +/* Synthetic PU workaround */ +static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + if (radio->version != 0x2050 || radio->revision >= 6) { + /* We do not need the workaround. */ + return; + } + + if (channel <= 10) { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(1)); + } + udelay(100); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(channel)); +} + +u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u8 ret = 0; + u16 saved, rssi, temp; + int i, j = 0; + + saved = bcm43xx_phy_read(bcm, 0x0403); + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5); + if (radio->aci_hw_rssi) + rssi = bcm43xx_phy_read(bcm, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0;i < 100; i++) { + temp = (bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + bcm43xx_phy_write(bcm, 0x0403, saved); + + return ret; +} + +u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u8 ret[13]; + unsigned int channel = radio->channel; + unsigned int i, j, start, end; + unsigned long phylock_flags; + + if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + bcm43xx_phy_lock(bcm, phylock_flags); + bcm43xx_radio_lock(bcm); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); + bcm43xx_set_all_gains(bcm, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i-1] = bcm43xx_radio_aci_detect(bcm, i); + } + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_phy_write(bcm, 0x0802, + (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003); + bcm43xx_phy_write(bcm, 0x0403, + bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); + bcm43xx_set_original_gains(bcm); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + bcm43xx_radio_unlock(bcm); + bcm43xx_phy_unlock(bcm, phylock_flags); + + return ret[channel - 1]; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val) +{ + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); + mmiowb(); + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset) +{ + u16 val; + + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); + val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA); + + return (s16)val; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val) +{ + u16 i; + s16 tmp; + + for (i = 0; i < 64; i++) { + tmp = bcm43xx_nrssi_hw_read(bcm, i); + tmp -= val; + tmp = limit_value(tmp, -32, 31); + bcm43xx_nrssi_hw_write(bcm, i, tmp); + } +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + s16 i, delta; + s32 tmp; + + delta = 0x1F - radio->nrssi[0]; + for (i = 0; i < 64; i++) { + tmp = (i - delta) * radio->nrssislope; + tmp /= 0x10000; + tmp += 0x3A; + tmp = limit_value(tmp, 0, 0x3F); + radio->nrssi_lt[i] = tmp; + } +} + +static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + u16 backup[20] = { 0 }; + s16 v47F; + u16 i; + u16 saved = 0xFFFF; + + backup[0] = bcm43xx_phy_read(bcm, 0x0001); + backup[1] = bcm43xx_phy_read(bcm, 0x0811); + backup[2] = bcm43xx_phy_read(bcm, 0x0812); + backup[3] = bcm43xx_phy_read(bcm, 0x0814); + backup[4] = bcm43xx_phy_read(bcm, 0x0815); + backup[5] = bcm43xx_phy_read(bcm, 0x005A); + backup[6] = bcm43xx_phy_read(bcm, 0x0059); + backup[7] = bcm43xx_phy_read(bcm, 0x0058); + backup[8] = bcm43xx_phy_read(bcm, 0x000A); + backup[9] = bcm43xx_phy_read(bcm, 0x0003); + backup[10] = bcm43xx_radio_read16(bcm, 0x007A); + backup[11] = bcm43xx_radio_read16(bcm, 0x0043); + + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0001, + (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2)); + if (phy->rev >= 6) { + backup[12] = bcm43xx_phy_read(bcm, 0x002E); + backup[13] = bcm43xx_phy_read(bcm, 0x002F); + backup[14] = bcm43xx_phy_read(bcm, 0x080F); + backup[15] = bcm43xx_phy_read(bcm, 0x0810); + backup[16] = bcm43xx_phy_read(bcm, 0x0801); + backup[17] = bcm43xx_phy_read(bcm, 0x0060); + backup[18] = bcm43xx_phy_read(bcm, 0x0014); + backup[19] = bcm43xx_phy_read(bcm, 0x0478); + + bcm43xx_phy_write(bcm, 0x002E, 0); + bcm43xx_phy_write(bcm, 0x002F, 0); + bcm43xx_phy_write(bcm, 0x080F, 0); + bcm43xx_phy_write(bcm, 0x0810, 0); + bcm43xx_phy_write(bcm, 0x0478, + bcm43xx_phy_read(bcm, 0x0478) | 0x0100); + bcm43xx_phy_write(bcm, 0x0801, + bcm43xx_phy_read(bcm, 0x0801) | 0x0040); + bcm43xx_phy_write(bcm, 0x0060, + bcm43xx_phy_read(bcm, 0x0060) | 0x0040); + bcm43xx_phy_write(bcm, 0x0014, + bcm43xx_phy_read(bcm, 0x0014) | 0x0200); + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); + udelay(30); + + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == 31) { + for (i = 7; i >= 4; i--) { + bcm43xx_radio_write16(bcm, 0x007B, i); + udelay(20); + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F < 31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 4; + } else { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0001); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) | 0x000C); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0030); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) | 0x0030); + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->rev == 0) { + bcm43xx_phy_write(bcm, 0x0003, 0x0122); + } else { + bcm43xx_phy_write(bcm, 0x000A, + bcm43xx_phy_read(bcm, 0x000A) + | 0x2000); + } + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0004); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F) + | 0x0040); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); + bcm43xx_set_all_gains(bcm, 3, 0, 1); + bcm43xx_radio_write16(bcm, 0x0043, + (bcm43xx_radio_read16(bcm, 0x0043) + & 0x00F0) | 0x000F); + udelay(30); + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == -32) { + for (i = 0; i < 4; i++) { + bcm43xx_radio_write16(bcm, 0x007B, i); + udelay(20); + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F > -31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 3; + } else + saved = 0; + } + bcm43xx_radio_write16(bcm, 0x007B, saved); + + if (phy->rev >= 6) { + bcm43xx_phy_write(bcm, 0x002E, backup[12]); + bcm43xx_phy_write(bcm, 0x002F, backup[13]); + bcm43xx_phy_write(bcm, 0x080F, backup[14]); + bcm43xx_phy_write(bcm, 0x0810, backup[15]); + } + bcm43xx_phy_write(bcm, 0x0814, backup[3]); + bcm43xx_phy_write(bcm, 0x0815, backup[4]); + bcm43xx_phy_write(bcm, 0x005A, backup[5]); + bcm43xx_phy_write(bcm, 0x0059, backup[6]); + bcm43xx_phy_write(bcm, 0x0058, backup[7]); + bcm43xx_phy_write(bcm, 0x000A, backup[8]); + bcm43xx_phy_write(bcm, 0x0003, backup[9]); + bcm43xx_radio_write16(bcm, 0x0043, backup[11]); + bcm43xx_radio_write16(bcm, 0x007A, backup[10]); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2); + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) | 0x8000); + bcm43xx_set_original_gains(bcm); + if (phy->rev >= 6) { + bcm43xx_phy_write(bcm, 0x0801, backup[16]); + bcm43xx_phy_write(bcm, 0x0060, backup[17]); + bcm43xx_phy_write(bcm, 0x0014, backup[18]); + bcm43xx_phy_write(bcm, 0x0478, backup[19]); + } + bcm43xx_phy_write(bcm, 0x0001, backup[0]); + bcm43xx_phy_write(bcm, 0x0812, backup[2]); + bcm43xx_phy_write(bcm, 0x0811, backup[1]); +} + +void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 backup[18] = { 0 }; + u16 tmp; + s16 nrssi0, nrssi1; + + switch (phy->type) { + case BCM43xx_PHYTYPE_B: + backup[0] = bcm43xx_radio_read16(bcm, 0x007A); + backup[1] = bcm43xx_radio_read16(bcm, 0x0052); + backup[2] = bcm43xx_radio_read16(bcm, 0x0043); + backup[3] = bcm43xx_phy_read(bcm, 0x0030); + backup[4] = bcm43xx_phy_read(bcm, 0x0026); + backup[5] = bcm43xx_phy_read(bcm, 0x0015); + backup[6] = bcm43xx_phy_read(bcm, 0x002A); + backup[7] = bcm43xx_phy_read(bcm, 0x0020); + backup[8] = bcm43xx_phy_read(bcm, 0x005A); + backup[9] = bcm43xx_phy_read(bcm, 0x0059); + backup[10] = bcm43xx_phy_read(bcm, 0x0058); + backup[11] = bcm43xx_read16(bcm, 0x03E2); + backup[12] = bcm43xx_read16(bcm, 0x03E6); + backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + + tmp = bcm43xx_radio_read16(bcm, 0x007A); + tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; + bcm43xx_radio_write16(bcm, 0x007A, tmp); + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); + bcm43xx_write16(bcm, 0x03EC, 0x7F7F); + bcm43xx_phy_write(bcm, 0x0026, 0x0000); + bcm43xx_phy_write(bcm, 0x0015, + bcm43xx_phy_read(bcm, 0x0015) | 0x0020); + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); + + nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); + if (phy->rev >= 2) { + bcm43xx_write16(bcm, 0x03E6, 0x0040); + } else if (phy->rev == 0) { + bcm43xx_write16(bcm, 0x03E6, 0x0122); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000); + } + bcm43xx_phy_write(bcm, 0x0020, 0x3F3F); + bcm43xx_phy_write(bcm, 0x0015, 0xF330); + bcm43xx_radio_write16(bcm, 0x005A, 0x0060); + bcm43xx_radio_write16(bcm, 0x0043, + bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0); + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + udelay(20); + + nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027); + bcm43xx_phy_write(bcm, 0x0030, backup[3]); + bcm43xx_radio_write16(bcm, 0x007A, backup[0]); + bcm43xx_write16(bcm, 0x03E2, backup[11]); + bcm43xx_phy_write(bcm, 0x0026, backup[4]); + bcm43xx_phy_write(bcm, 0x0015, backup[5]); + bcm43xx_phy_write(bcm, 0x002A, backup[6]); + bcm43xx_synth_pu_workaround(bcm, radio->channel); + if (phy->rev != 0) + bcm43xx_write16(bcm, 0x03F4, backup[13]); + + bcm43xx_phy_write(bcm, 0x0020, backup[7]); + bcm43xx_phy_write(bcm, 0x005A, backup[8]); + bcm43xx_phy_write(bcm, 0x0059, backup[9]); + bcm43xx_phy_write(bcm, 0x0058, backup[10]); + bcm43xx_radio_write16(bcm, 0x0052, backup[1]); + bcm43xx_radio_write16(bcm, 0x0043, backup[2]); + + if (nrssi0 == nrssi1) + radio->nrssislope = 0x00010000; + else + radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + + if (nrssi0 <= -4) { + radio->nrssi[0] = nrssi0; + radio->nrssi[1] = nrssi1; + } + break; + case BCM43xx_PHYTYPE_G: + if (radio->revision >= 9) + return; + if (radio->revision == 8) + bcm43xx_calc_nrssi_offset(bcm); + + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); + backup[7] = bcm43xx_read16(bcm, 0x03E2); + bcm43xx_write16(bcm, 0x03E2, + bcm43xx_read16(bcm, 0x03E2) | 0x8000); + backup[0] = bcm43xx_radio_read16(bcm, 0x007A); + backup[1] = bcm43xx_radio_read16(bcm, 0x0052); + backup[2] = bcm43xx_radio_read16(bcm, 0x0043); + backup[3] = bcm43xx_phy_read(bcm, 0x0015); + backup[4] = bcm43xx_phy_read(bcm, 0x005A); + backup[5] = bcm43xx_phy_read(bcm, 0x0059); + backup[6] = bcm43xx_phy_read(bcm, 0x0058); + backup[8] = bcm43xx_read16(bcm, 0x03E6); + backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = bcm43xx_phy_read(bcm, 0x002E); + backup[11] = bcm43xx_phy_read(bcm, 0x002F); + backup[12] = bcm43xx_phy_read(bcm, 0x080F); + backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL); + backup[14] = bcm43xx_phy_read(bcm, 0x0801); + backup[15] = bcm43xx_phy_read(bcm, 0x0060); + backup[16] = bcm43xx_phy_read(bcm, 0x0014); + backup[17] = bcm43xx_phy_read(bcm, 0x0478); + bcm43xx_phy_write(bcm, 0x002E, 0); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: case 6: case 7: + bcm43xx_phy_write(bcm, 0x0478, + bcm43xx_phy_read(bcm, 0x0478) + | 0x0100); + bcm43xx_phy_write(bcm, 0x0801, + bcm43xx_phy_read(bcm, 0x0801) + | 0x0040); + break; + case 3: case 5: + bcm43xx_phy_write(bcm, 0x0801, + bcm43xx_phy_read(bcm, 0x0801) + & 0xFFBF); + break; + } + bcm43xx_phy_write(bcm, 0x0060, + bcm43xx_phy_read(bcm, 0x0060) + | 0x0040); + bcm43xx_phy_write(bcm, 0x0014, + bcm43xx_phy_read(bcm, 0x0014) + | 0x0200); + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); + bcm43xx_set_all_gains(bcm, 0, 8, 0); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0811, + (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010); + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); + udelay(20); + + nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; + + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) + & 0xFF9F) | 0x0040); + } + + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) + | 0x2000); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); + bcm43xx_phy_write(bcm, 0x0015, 0xF330); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020); + bcm43xx_phy_write(bcm, 0x0811, + (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020); + } + + bcm43xx_set_all_gains(bcm, 3, 0, 1); + if (radio->revision == 8) { + bcm43xx_radio_write16(bcm, 0x0043, 0x001F); + } else { + tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F; + bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060); + tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0; + bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009); + } + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + radio->nrssislope = 0x00010000; + else + radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + radio->nrssi[0] = nrssi1; + radio->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + bcm43xx_phy_write(bcm, 0x002E, backup[10]); + bcm43xx_phy_write(bcm, 0x002F, backup[11]); + bcm43xx_phy_write(bcm, 0x080F, backup[12]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]); + } + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF); + } + + bcm43xx_radio_write16(bcm, 0x007A, backup[0]); + bcm43xx_radio_write16(bcm, 0x0052, backup[1]); + bcm43xx_radio_write16(bcm, 0x0043, backup[2]); + bcm43xx_write16(bcm, 0x03E2, backup[7]); + bcm43xx_write16(bcm, 0x03E6, backup[8]); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]); + bcm43xx_phy_write(bcm, 0x0015, backup[3]); + bcm43xx_phy_write(bcm, 0x005A, backup[4]); + bcm43xx_phy_write(bcm, 0x0059, backup[5]); + bcm43xx_phy_write(bcm, 0x0058, backup[6]); + bcm43xx_synth_pu_workaround(bcm, radio->channel); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002)); + bcm43xx_set_original_gains(bcm); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); + if (phy->rev >= 3) { + bcm43xx_phy_write(bcm, 0x0801, backup[14]); + bcm43xx_phy_write(bcm, 0x0060, backup[15]); + bcm43xx_phy_write(bcm, 0x0014, backup[16]); + bcm43xx_phy_write(bcm, 0x0478, backup[17]); + } + bcm43xx_nrssi_mem_update(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + break; + default: + assert(0); + } +} + +void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + s32 threshold; + s32 a, b; + s16 tmp16; + u16 tmp_u16; + + switch (phy->type) { + case BCM43xx_PHYTYPE_B: { + if (radio->version != 0x2050) + return; + if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) + return; + + if (radio->revision >= 6) { + threshold = (radio->nrssi[1] - radio->nrssi[0]) * 32; + threshold += 20 * (radio->nrssi[0] + 1); + threshold /= 40; + } else + threshold = radio->nrssi[1] - 5; + + threshold = limit_value(threshold, 0, 0x3E); + bcm43xx_phy_read(bcm, 0x0020); /* dummy read */ + bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C); + + if (radio->revision >= 6) { + bcm43xx_phy_write(bcm, 0x0087, 0x0E0D); + bcm43xx_phy_write(bcm, 0x0086, 0x0C0B); + bcm43xx_phy_write(bcm, 0x0085, 0x0A09); + bcm43xx_phy_write(bcm, 0x0084, 0x0808); + bcm43xx_phy_write(bcm, 0x0083, 0x0808); + bcm43xx_phy_write(bcm, 0x0082, 0x0604); + bcm43xx_phy_write(bcm, 0x0081, 0x0302); + bcm43xx_phy_write(bcm, 0x0080, 0x0100); + } + break; + } + case BCM43xx_PHYTYPE_G: + if (!phy->connected || + !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { + tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) { + bcm43xx_phy_write(bcm, 0x048A, + (bcm43xx_phy_read(bcm, 0x048A) + & 0xF000) | 0x09EB); + } else { + bcm43xx_phy_write(bcm, 0x048A, + (bcm43xx_phy_read(bcm, 0x048A) + & 0xF000) | 0x0AED); + } + } else { + if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!radio->aci_wlan_automatic && radio->aci_enable) { + a = 0x13; + b = 0x12; + } else { + a = 0xE; + b = 0x11; + } + + a = a * (radio->nrssi[1] - radio->nrssi[0]); + a += (radio->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; + a = limit_value(a, -31, 31); + + b = b * (radio->nrssi[1] - radio->nrssi[0]); + b += (radio->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; + b = limit_value(b, -31, 31); + + tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000; + tmp_u16 |= ((u32)b & 0x0000003F); + tmp_u16 |= (((u32)a & 0x0000003F) << 6); + bcm43xx_phy_write(bcm, 0x048A, tmp_u16); + } + break; + default: + assert(0); + } +} + +/* Stack implementation to save/restore values from the + * interference mitigation code. + * It is save to restore values in random order. + */ +static void _stack_save(u32 *_stackptr, size_t *stackidx, + u8 id, u16 offset, u16 value) +{ + u32 *stackptr = &(_stackptr[*stackidx]); + + assert((offset & 0xF000) == 0x0000); + assert((id & 0xF0) == 0x00); + *stackptr = offset; + *stackptr |= ((u32)id) << 12; + *stackptr |= ((u32)value) << 16; + (*stackidx)++; + assert(*stackidx < BCM43xx_INTERFSTACK_SIZE); +} + +static u16 _stack_restore(u32 *stackptr, + u8 id, u16 offset) +{ + size_t i; + + assert((offset & 0xF000) == 0x0000); + assert((id & 0xF0) == 0x00); + for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) { + if ((*stackptr & 0x00000FFF) != offset) + continue; + if (((*stackptr & 0x0000F000) >> 12) != id) + continue; + return ((*stackptr & 0xFFFF0000) >> 16); + } + assert(0); + + return 0; +} + +#define phy_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x1, (offset), \ + bcm43xx_phy_read(bcm, (offset))); \ + } while (0) +#define phy_stackrestore(offset) \ + do { \ + bcm43xx_phy_write(bcm, (offset), \ + _stack_restore(stack, 0x1, \ + (offset))); \ + } while (0) +#define radio_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x2, (offset), \ + bcm43xx_radio_read16(bcm, (offset))); \ + } while (0) +#define radio_stackrestore(offset) \ + do { \ + bcm43xx_radio_write16(bcm, (offset), \ + _stack_restore(stack, 0x2, \ + (offset))); \ + } while (0) +#define ilt_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x3, (offset), \ + bcm43xx_ilt_read(bcm, (offset))); \ + } while (0) +#define ilt_stackrestore(offset) \ + do { \ + bcm43xx_ilt_write(bcm, (offset), \ + _stack_restore(stack, 0x3, \ + (offset))); \ + } while (0) + +static void +bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, + int mode) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 tmp, flipped; + u32 tmp32; + size_t stackidx = 0; + u32 *stack = radio->interfstack; + + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) | 0x0800); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000); + break; + } + radio_stacksave(0x0078); + tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); + flipped = flip_4bit(tmp); + if (flipped < 10 && flipped >= 8) + flipped = 7; + else if (flipped >= 10) + flipped -= 3; + flipped = flip_4bit(flipped); + flipped = (flipped << 1) | 0x0020; + bcm43xx_radio_write16(bcm, 0x0078, flipped); + + bcm43xx_calc_nrssi_threshold(bcm); + + phy_stacksave(0x0406); + bcm43xx_phy_write(bcm, 0x0406, 0x7E28); + + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) | 0x0800); + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000); + + phy_stacksave(0x04A0); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008); + phy_stacksave(0x04A1); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605); + phy_stacksave(0x04A2); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204); + phy_stacksave(0x04A8); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0803); + phy_stacksave(0x04AB); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0605); + + phy_stacksave(0x04A7); + bcm43xx_phy_write(bcm, 0x04A7, 0x0002); + phy_stacksave(0x04A3); + bcm43xx_phy_write(bcm, 0x04A3, 0x287A); + phy_stacksave(0x04A9); + bcm43xx_phy_write(bcm, 0x04A9, 0x2027); + phy_stacksave(0x0493); + bcm43xx_phy_write(bcm, 0x0493, 0x32F5); + phy_stacksave(0x04AA); + bcm43xx_phy_write(bcm, 0x04AA, 0x2027); + phy_stacksave(0x04AC); + bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + if (bcm43xx_phy_read(bcm, 0x0033) & 0x0800) + break; + + radio->aci_enable = 1; + + phy_stacksave(BCM43xx_PHY_RADIO_BITFIELD); + phy_stacksave(BCM43xx_PHY_G_CRS); + if (phy->rev < 2) { + phy_stacksave(0x0406); + } else { + phy_stacksave(0x04C0); + phy_stacksave(0x04C1); + } + phy_stacksave(0x0033); + phy_stacksave(0x04A7); + phy_stacksave(0x04A3); + phy_stacksave(0x04A9); + phy_stacksave(0x04AA); + phy_stacksave(0x04AC); + phy_stacksave(0x0493); + phy_stacksave(0x04A1); + phy_stacksave(0x04A0); + phy_stacksave(0x04A2); + phy_stacksave(0x048A); + phy_stacksave(0x04A8); + phy_stacksave(0x04AB); + if (phy->rev == 2) { + phy_stacksave(0x04AD); + phy_stacksave(0x04AE); + } else if (phy->rev >= 3) { + phy_stacksave(0x04AD); + phy_stacksave(0x0415); + phy_stacksave(0x0416); + phy_stacksave(0x0417); + ilt_stacksave(0x1A00 + 0x2); + ilt_stacksave(0x1A00 + 0x3); + } + phy_stacksave(0x042B); + phy_stacksave(0x048C); + + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) + & ~0x1000); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) + & 0xFFFC) | 0x0002); + + bcm43xx_phy_write(bcm, 0x0033, 0x0800); + bcm43xx_phy_write(bcm, 0x04A3, 0x2027); + bcm43xx_phy_write(bcm, 0x04A9, 0x1CA8); + bcm43xx_phy_write(bcm, 0x0493, 0x287A); + bcm43xx_phy_write(bcm, 0x04AA, 0x1CA8); + bcm43xx_phy_write(bcm, 0x04AC, 0x287A); + + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) + & 0xFFC0) | 0x001A); + bcm43xx_phy_write(bcm, 0x04A7, 0x000D); + + if (phy->rev < 2) { + bcm43xx_phy_write(bcm, 0x0406, 0xFF0D); + } else if (phy->rev == 2) { + bcm43xx_phy_write(bcm, 0x04C0, 0xFFFF); + bcm43xx_phy_write(bcm, 0x04C1, 0x00A9); + } else { + bcm43xx_phy_write(bcm, 0x04C0, 0x00C1); + bcm43xx_phy_write(bcm, 0x04C1, 0x0059); + } + + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) + & 0xC0FF) | 0x1800); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) + & 0xFFC0) | 0x0015); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xCFFF) | 0x1000); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xF0FF) | 0x0A00); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xCFFF) | 0x1000); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xF0FF) | 0x0800); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xFFCF) | 0x0010); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xFFF0) | 0x0005); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xFFCF) | 0x0010); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xFFF0) | 0x0006); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) + & 0xF0FF) | 0x0800); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) + & 0xF0FF) | 0x0500); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) + & 0xFFF0) | 0x000B); + + if (phy->rev >= 3) { + bcm43xx_phy_write(bcm, 0x048A, + bcm43xx_phy_read(bcm, 0x048A) + & ~0x8000); + bcm43xx_phy_write(bcm, 0x0415, + (bcm43xx_phy_read(bcm, 0x0415) + & 0x8000) | 0x36D8); + bcm43xx_phy_write(bcm, 0x0416, + (bcm43xx_phy_read(bcm, 0x0416) + & 0x8000) | 0x36D8); + bcm43xx_phy_write(bcm, 0x0417, + (bcm43xx_phy_read(bcm, 0x0417) + & 0xFE00) | 0x016D); + } else { + bcm43xx_phy_write(bcm, 0x048A, + bcm43xx_phy_read(bcm, 0x048A) + | 0x1000); + bcm43xx_phy_write(bcm, 0x048A, + (bcm43xx_phy_read(bcm, 0x048A) + & 0x9FFF) | 0x2000); + tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + if (!(tmp32 & 0x800)) { + tmp32 |= 0x800; + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + tmp32); + } + } + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) + | 0x0800); + } + bcm43xx_phy_write(bcm, 0x048C, + (bcm43xx_phy_read(bcm, 0x048C) + & 0xF0FF) | 0x0200); + if (phy->rev == 2) { + bcm43xx_phy_write(bcm, 0x04AE, + (bcm43xx_phy_read(bcm, 0x04AE) + & 0xFF00) | 0x007F); + bcm43xx_phy_write(bcm, 0x04AD, + (bcm43xx_phy_read(bcm, 0x04AD) + & 0x00FF) | 0x1300); + } else if (phy->rev >= 6) { + bcm43xx_ilt_write(bcm, 0x1A00 + 0x3, 0x007F); + bcm43xx_ilt_write(bcm, 0x1A00 + 0x2, 0x007F); + bcm43xx_phy_write(bcm, 0x04AD, + bcm43xx_phy_read(bcm, 0x04AD) + & 0x00FF); + } + bcm43xx_calc_nrssi_slope(bcm); + break; + default: + assert(0); + } +} + +static void +bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, + int mode) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u32 tmp32; + u32 *stack = radio->interfstack; + + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); + break; + } + phy_stackrestore(0x0078); + bcm43xx_calc_nrssi_threshold(bcm); + phy_stackrestore(0x0406); + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); + if (!bcm->bad_frames_preempt) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) + & ~(1 << 11)); + } + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A7); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + if (!(bcm43xx_phy_read(bcm, 0x0033) & 0x0800)) + break; + + radio->aci_enable = 0; + + phy_stackrestore(BCM43xx_PHY_RADIO_BITFIELD); + phy_stackrestore(BCM43xx_PHY_G_CRS); + phy_stackrestore(0x0033); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A7); + if (phy->rev >= 2) { + phy_stackrestore(0x04C0); + phy_stackrestore(0x04C1); + } else + phy_stackrestore(0x0406); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A8); + if (phy->rev == 2) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x04AE); + } else if (phy->rev >= 3) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x0415); + phy_stackrestore(0x0416); + phy_stackrestore(0x0417); + ilt_stackrestore(0x1A00 + 0x2); + ilt_stackrestore(0x1A00 + 0x3); + } + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x042B); + phy_stackrestore(0x048C); + tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + if (tmp32 & 0x800) { + tmp32 &= ~0x800; + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + tmp32); + } + bcm43xx_calc_nrssi_slope(bcm); + break; + default: + assert(0); + } +} + +#undef phy_stacksave +#undef phy_stackrestore +#undef radio_stacksave +#undef radio_stackrestore +#undef ilt_stacksave +#undef ilt_stackrestore + +int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, + int mode) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + int currentmode; + + if ((phy->type != BCM43xx_PHYTYPE_G) || + (phy->rev == 0) || + (!phy->connected)) + return -ENODEV; + + radio->aci_wlan_automatic = 0; + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_AUTOWLAN: + radio->aci_wlan_automatic = 1; + if (radio->aci_enable) + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; + else + mode = BCM43xx_RADIO_INTERFMODE_NONE; + break; + case BCM43xx_RADIO_INTERFMODE_NONE: + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + break; + default: + return -EINVAL; + } + + currentmode = radio->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE) + bcm43xx_radio_interference_mitigation_disable(bcm, currentmode); + + if (mode == BCM43xx_RADIO_INTERFMODE_NONE) { + radio->aci_enable = 0; + radio->aci_hw_rssi = 0; + } else + bcm43xx_radio_interference_mitigation_enable(bcm, mode); + radio->interfmode = mode; + + return 0; +} + +u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) +{ + u16 reg, index, ret; + + reg = bcm43xx_radio_read16(bcm, 0x0060); + index = (reg & 0x001E) >> 1; + ret = rcc_table[index] << 1; + ret |= (reg & 0x0001); + ret |= 0x0020; + + return ret; +} + +u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 backup[19] = { 0 }; + u16 ret; + u16 i, j; + u32 tmp1 = 0, tmp2 = 0; + + backup[0] = bcm43xx_radio_read16(bcm, 0x0043); + backup[14] = bcm43xx_radio_read16(bcm, 0x0051); + backup[15] = bcm43xx_radio_read16(bcm, 0x0052); + backup[1] = bcm43xx_phy_read(bcm, 0x0015); + backup[16] = bcm43xx_phy_read(bcm, 0x005A); + backup[17] = bcm43xx_phy_read(bcm, 0x0059); + backup[18] = bcm43xx_phy_read(bcm, 0x0058); + if (phy->type == BCM43xx_PHYTYPE_B) { + backup[2] = bcm43xx_phy_read(bcm, 0x0030); + backup[3] = bcm43xx_read16(bcm, 0x03EC); + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); + bcm43xx_write16(bcm, 0x03EC, 0x3F3F); + } else { + if (phy->connected) { + backup[4] = bcm43xx_phy_read(bcm, 0x0811); + backup[5] = bcm43xx_phy_read(bcm, 0x0812); + backup[6] = bcm43xx_phy_read(bcm, 0x0814); + backup[7] = bcm43xx_phy_read(bcm, 0x0815); + backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); + backup[9] = bcm43xx_phy_read(bcm, 0x0802); + bcm43xx_phy_write(bcm, 0x0814, + (bcm43xx_phy_read(bcm, 0x0814) | 0x0003)); + bcm43xx_phy_write(bcm, 0x0815, + (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC)); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF)); + bcm43xx_phy_write(bcm, 0x0802, + (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC)); + bcm43xx_phy_write(bcm, 0x0811, 0x01B3); + bcm43xx_phy_write(bcm, 0x0812, 0x0FB2); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); + } + backup[10] = bcm43xx_phy_read(bcm, 0x0035); + bcm43xx_phy_write(bcm, 0x0035, + (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F)); + backup[11] = bcm43xx_read16(bcm, 0x03E6); + backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + + // Initialization + if (phy->version == 0) { + bcm43xx_write16(bcm, 0x03E6, 0x0122); + } else { + if (phy->version >= 2) + bcm43xx_write16(bcm, 0x03E6, 0x0040); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000)); + } + + ret = bcm43xx_radio_calibrationvalue(bcm); + + if (phy->type == BCM43xx_PHYTYPE_B) + bcm43xx_radio_write16(bcm, 0x0078, 0x0003); + + bcm43xx_phy_write(bcm, 0x0015, 0xBFAF); + bcm43xx_phy_write(bcm, 0x002B, 0x1403); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x00B2); + bcm43xx_phy_write(bcm, 0x0015, 0xBFA0); + bcm43xx_radio_write16(bcm, 0x0051, + (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004)); + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + bcm43xx_radio_write16(bcm, 0x0043, + bcm43xx_radio_read16(bcm, 0x0043) | 0x0009); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); + udelay(10); + tmp1 += bcm43xx_phy_read(bcm, 0x002D); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + } + + tmp1++; + tmp1 >>= 9; + udelay(10); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020); + backup[13] = bcm43xx_radio_read16(bcm, 0x0078); + udelay(10); + for (j = 0; j < 16; j++) { + bcm43xx_phy_write(bcm, 0x005A, 0x0D80); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */ + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); + udelay(10); + tmp2 += bcm43xx_phy_read(bcm, 0x002D); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + } + tmp2++; + tmp2 >>= 8; + if (tmp1 < tmp2) + break; + } + + /* Restore the registers */ + bcm43xx_phy_write(bcm, 0x0015, backup[1]); + bcm43xx_radio_write16(bcm, 0x0051, backup[14]); + bcm43xx_radio_write16(bcm, 0x0052, backup[15]); + bcm43xx_radio_write16(bcm, 0x0043, backup[0]); + bcm43xx_phy_write(bcm, 0x005A, backup[16]); + bcm43xx_phy_write(bcm, 0x0059, backup[17]); + bcm43xx_phy_write(bcm, 0x0058, backup[18]); + bcm43xx_write16(bcm, 0x03E6, backup[11]); + if (phy->version != 0) + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]); + bcm43xx_phy_write(bcm, 0x0035, backup[10]); + bcm43xx_radio_selectchannel(bcm, radio->channel, 1); + if (phy->type == BCM43xx_PHYTYPE_B) { + bcm43xx_phy_write(bcm, 0x0030, backup[2]); + bcm43xx_write16(bcm, 0x03EC, backup[3]); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0811, backup[4]); + bcm43xx_phy_write(bcm, 0x0812, backup[5]); + bcm43xx_phy_write(bcm, 0x0814, backup[6]); + bcm43xx_phy_write(bcm, 0x0815, backup[7]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]); + bcm43xx_phy_write(bcm, 0x0802, backup[9]); + } + } + if (i >= 15) + ret = backup[13]; + + return ret; +} + +void bcm43xx_radio_init2060(struct bcm43xx_private *bcm) +{ + int err; + + bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); + bcm43xx_radio_write16(bcm, 0x0005, 0x0008); + bcm43xx_radio_write16(bcm, 0x0009, 0x0040); + bcm43xx_radio_write16(bcm, 0x0005, 0x00AA); + bcm43xx_radio_write16(bcm, 0x0032, 0x008F); + bcm43xx_radio_write16(bcm, 0x0006, 0x008F); + bcm43xx_radio_write16(bcm, 0x0034, 0x008F); + bcm43xx_radio_write16(bcm, 0x002C, 0x0007); + bcm43xx_radio_write16(bcm, 0x0082, 0x0080); + bcm43xx_radio_write16(bcm, 0x0080, 0x0000); + bcm43xx_radio_write16(bcm, 0x003F, 0x00DA); + bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); + udelay(400); + + bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010); + udelay(400); + + bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008); + bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010); + bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040); + bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040); + bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008); + bcm43xx_phy_write(bcm, 0x0063, 0xDDC6); + bcm43xx_phy_write(bcm, 0x0069, 0x07BE); + bcm43xx_phy_write(bcm, 0x006A, 0x0000); + + err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0); + assert(err == 0); + udelay(1000); +} + +static inline +u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = bcm43xx_radio_read16(bcm, 0x001E); + int i, j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] << 4 | data_low[j])) { + bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0); + return; + } + } + } +} + +int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, + u8 channel, + int synthetic_pu_workaround) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 r8, tmp; + u16 freq; + + if ((radio->manufact == 0x17F) && + (radio->version == 0x2060) && + (radio->revision == 1)) { + if (channel > 200) + return -EINVAL; + freq = channel2freq_a(channel); + + r8 = bcm43xx_radio_read16(bcm, 0x0008); + bcm43xx_write16(bcm, 0x03F0, freq); + bcm43xx_radio_write16(bcm, 0x0008, r8); + + TODO();//TODO: write max channel TX power? to Radio 0x2D + tmp = bcm43xx_radio_read16(bcm, 0x002E); + tmp &= 0x0080; + TODO();//TODO: OR tmp with the Power out estimation for this channel? + bcm43xx_radio_write16(bcm, 0x002E, tmp); + + if (freq >= 4920 && freq <= 5500) { + /* + * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; + * = (freq * 0.025862069 + */ + r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ + } + bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8); + bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8); + bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8); + bcm43xx_radio_write16(bcm, 0x0022, + (bcm43xx_radio_read16(bcm, 0x0022) + & 0x000F) | (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x0008, + (bcm43xx_radio_read16(bcm, 0x0008) + & 0x00F0) | (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x0029, + (bcm43xx_radio_read16(bcm, 0x0029) + & 0xFF0F) | 0x00B0); + bcm43xx_radio_write16(bcm, 0x0035, 0x00AA); + bcm43xx_radio_write16(bcm, 0x0036, 0x0085); + bcm43xx_radio_write16(bcm, 0x003A, + (bcm43xx_radio_read16(bcm, 0x003A) + & 0xFF20) | freq_r3A_value(freq)); + bcm43xx_radio_write16(bcm, 0x003D, + bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF); + bcm43xx_radio_write16(bcm, 0x0081, + (bcm43xx_radio_read16(bcm, 0x0081) + & 0xFF7F) | 0x0080); + bcm43xx_radio_write16(bcm, 0x0035, + bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF); + bcm43xx_radio_write16(bcm, 0x0035, + (bcm43xx_radio_read16(bcm, 0x0035) + & 0xFFEF) | 0x0010); + bcm43xx_radio_set_tx_iq(bcm); + TODO(); //TODO: TSSI2dbm workaround + bcm43xx_phy_xmitpower(bcm);//FIXME correct? + } else { + if ((channel < 1) || (channel > 14)) + return -EINVAL; + + if (synthetic_pu_workaround) + bcm43xx_synth_pu_workaround(bcm, channel); + + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(channel)); + + if (channel == 14) { + if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) { + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET) + & ~(1 << 7)); + } else { + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET) + | (1 << 7)); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) + | (1 << 11)); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) + & 0xF7BF); + } + } + + radio->channel = channel; + //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states + // that 2000 usecs might suffice. + udelay(8000); + + return 0; +} + +void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val) +{ + u16 tmp; + + val <<= 8; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF; + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF; + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF; + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val); +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ +static u16 bcm43xx_get_txgain_base_band(u16 txpower) +{ + u16 ret; + + assert(txpower <= 63); + + if (txpower >= 54) + ret = 2; + else if (txpower >= 49) + ret = 4; + else if (txpower >= 44) + ret = 5; + else + ret = 6; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ +static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower) +{ + u16 ret; + + assert(txpower <= 63); + + if (txpower >= 32) + ret = 0; + else if (txpower >= 25) + ret = 1; + else if (txpower >= 20) + ret = 2; + else if (txpower >= 12) + ret = 3; + else + ret = 4; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ +static u16 bcm43xx_get_txgain_dac(u16 txpower) +{ + u16 ret; + + assert(txpower <= 63); + + if (txpower >= 54) + ret = txpower - 53; + else if (txpower >= 49) + ret = txpower - 42; + else if (txpower >= 44) + ret = txpower - 37; + else if (txpower >= 32) + ret = txpower - 32; + else if (txpower >= 25) + ret = txpower - 20; + else if (txpower >= 20) + ret = txpower - 13; + else if (txpower >= 12) + ret = txpower - 8; + else + ret = txpower; + + return ret; +} + +void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 pamp, base, dac, ilt; + + txpower = limit_value(txpower, 0, 63); + + pamp = bcm43xx_get_txgain_freq_power_amp(txpower); + pamp <<= 5; + pamp &= 0x00E0; + bcm43xx_phy_write(bcm, 0x0019, pamp); + + base = bcm43xx_get_txgain_base_band(txpower); + base &= 0x000F; + bcm43xx_phy_write(bcm, 0x0017, base | 0x0020); + + ilt = bcm43xx_ilt_read(bcm, 0x3001); + ilt &= 0x0007; + + dac = bcm43xx_get_txgain_dac(txpower); + dac <<= 3; + dac |= ilt; + + bcm43xx_ilt_write(bcm, 0x3001, dac); + + radio->txpwr_offset = txpower; + + TODO(); + //TODO: FuncPlaceholder (Adjust BB loft cancel) +} + +void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, + u16 baseband_attenuation, u16 radio_attenuation, + u16 txpower) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + if (baseband_attenuation == 0xFFFF) + baseband_attenuation = radio->baseband_atten; + if (radio_attenuation == 0xFFFF) + radio_attenuation = radio->radio_atten; + if (txpower == 0xFFFF) + txpower = radio->txctl1; + radio->baseband_atten = baseband_attenuation; + radio->radio_atten = radio_attenuation; + radio->txctl1 = txpower; + + assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11); + if (radio->revision < 6) + assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9); + else + assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31); + assert(/*txpower >= 0 &&*/ txpower <= 7); + + bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation); + bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation); + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070) + | ((txpower << 4) & 0x0070)); + } + //FIXME: The spec is very weird and unclear here. + if (phy->type == BCM43xx_PHYTYPE_G) + bcm43xx_phy_lo_adjust(bcm, 0); +} + +u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + if (radio->version == 0x2050 && radio->revision < 6) + return 0; + return 2; +} + +u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 att = 0xFFFF; + + if (phy->type == BCM43xx_PHYTYPE_A) + return 0x60; + + switch (radio->version) { + case 0x2053: + switch (radio->revision) { + case 1: + att = 6; + break; + } + break; + case 0x2050: + switch (radio->revision) { + case 0: + att = 5; + break; + case 1: + if (phy->type == BCM43xx_PHYTYPE_G) { + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421 && + bcm->board_revision >= 30) + att = 3; + else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x416) + att = 3; + else + att = 1; + } else { + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421 && + bcm->board_revision >= 30) + att = 7; + else + att = 6; + } + break; + case 2: + if (phy->type == BCM43xx_PHYTYPE_G) { + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421 && + bcm->board_revision >= 30) + att = 3; + else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x416) + att = 5; + else if (bcm->chip_id == 0x4320) + att = 4; + else + att = 3; + } else + att = 6; + break; + case 3: + att = 5; + break; + case 4: + case 5: + att = 1; + break; + case 6: + case 7: + att = 5; + break; + case 8: + att = 0x1A; + break; + case 9: + default: + att = 5; + } + } + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421) { + if (bcm->board_revision < 0x43) + att = 2; + else if (bcm->board_revision < 0x51) + att = 3; + } + if (att == 0xFFFF) + att = 5; + + return att; +} + +u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + if (radio->version != 0x2050) + return 0; + if (radio->revision == 1) + return 3; + if (radio->revision < 6) + return 2; + if (radio->revision == 8) + return 1; + return 0; +} + +void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + int err; + + if (radio->enabled) + return; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); + bcm43xx_radio_write16(bcm, 0x0005, 0x0008); + bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7); + bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7); + bcm43xx_radio_init2060(bcm); + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + bcm43xx_phy_write(bcm, 0x0015, 0x8000); + bcm43xx_phy_write(bcm, 0x0015, 0xCC00); + bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000)); + err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1); + assert(err == 0); + break; + default: + assert(0); + } + radio->enabled = 1; + dprintk(KERN_INFO PFX "Radio turned on\n"); +} + +void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + if (phy->type == BCM43xx_PHYTYPE_A) { + bcm43xx_radio_write16(bcm, 0x0004, 0x00FF); + bcm43xx_radio_write16(bcm, 0x0005, 0x00FB); + bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008); + bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008); + } + if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) { + bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C); + bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73); + } else + bcm43xx_phy_write(bcm, 0x0015, 0xAA00); + radio->enabled = 0; + dprintk(KERN_INFO PFX "Radio turned off\n"); +} + +void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F); + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F); + break; + } +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h new file mode 100644 index 000000000000..9ed18039fa3e --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h @@ -0,0 +1,99 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_RADIO_H_ +#define BCM43xx_RADIO_H_ + +#include "bcm43xx.h" + + +#define BCM43xx_RADIO_DEFAULT_CHANNEL_A 36 +#define BCM43xx_RADIO_DEFAULT_CHANNEL_BG 6 + +/* Force antenna 0. */ +#define BCM43xx_RADIO_TXANTENNA_0 0 +/* Force antenna 1. */ +#define BCM43xx_RADIO_TXANTENNA_1 1 +/* Use the RX antenna, that was selected for the most recently + * received good PLCP header. + */ +#define BCM43xx_RADIO_TXANTENNA_LASTPLCP 3 +#define BCM43xx_RADIO_TXANTENNA_DEFAULT BCM43xx_RADIO_TXANTENNA_LASTPLCP + +#define BCM43xx_RADIO_INTERFMODE_NONE 0 +#define BCM43xx_RADIO_INTERFMODE_NONWLAN 1 +#define BCM43xx_RADIO_INTERFMODE_MANUALWLAN 2 +#define BCM43xx_RADIO_INTERFMODE_AUTOWLAN 3 + + +void bcm43xx_radio_lock(struct bcm43xx_private *bcm); +void bcm43xx_radio_unlock(struct bcm43xx_private *bcm); + +u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val); + +u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm); +void bcm43xx_radio_init2060(struct bcm43xx_private *bcm); + +void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm); +void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm); + +int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, + int synthetic_pu_workaround); + +void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower); +void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, + u16 baseband_attenuation, u16 attenuation, + u16 txpower); + +u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm); +u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm); +u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm); + +void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val); + +void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm); + +u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel); +u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm); + +int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode); + +void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm); +void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm); +s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val); +void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val); +void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm); + +void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm); +u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm); + +#endif /* BCM43xx_RADIO_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c new file mode 100644 index 000000000000..c44d890b949b --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -0,0 +1,322 @@ +/* + + Broadcom BCM43xx wireless driver + + SYSFS support routines + + Copyright (c) 2006 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx_sysfs.h" +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_radio.h" + +#include + + +#define GENERIC_FILESIZE 64 + + +static int get_integer(const char *buf, size_t count) +{ + char tmp[10 + 1] = { 0 }; + int ret = -EINVAL; + + if (count == 0) + goto out; + count = min(count, (size_t)10); + memcpy(tmp, buf, count); + ret = simple_strtol(tmp, NULL, 10); +out: + return ret; +} + +static int get_boolean(const char *buf, size_t count) +{ + if (count != 0) { + if (buf[0] == '1') + return 1; + if (buf[0] == '0') + return 0; + if (count >= 4 && memcmp(buf, "true", 4) == 0) + return 1; + if (count >= 5 && memcmp(buf, "false", 5) == 0) + return 0; + if (count >= 3 && memcmp(buf, "yes", 3) == 0) + return 1; + if (count >= 2 && memcmp(buf, "no", 2) == 0) + return 0; + if (count >= 2 && memcmp(buf, "on", 2) == 0) + return 1; + if (count >= 3 && memcmp(buf, "off", 3) == 0) + return 0; + } + return -EINVAL; +} + +static ssize_t bcm43xx_attr_sprom_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + u16 *sprom; + unsigned long flags; + int i, err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + assert(BCM43xx_SPROM_SIZE * sizeof(u16) <= PAGE_SIZE); + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + return -ENOMEM; + bcm43xx_lock_mmio(bcm, flags); + assert(bcm->initialized); + err = bcm43xx_sprom_read(bcm, sprom); + if (!err) { + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + buf[i * 2] = sprom[i] & 0x00FF; + buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8; + } + } + bcm43xx_unlock_mmio(bcm, flags); + kfree(sprom); + + return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); +} + +static ssize_t bcm43xx_attr_sprom_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + u16 *sprom; + unsigned long flags; + int i, err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (count != BCM43xx_SPROM_SIZE * sizeof(u16)) + return -EINVAL; + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + return -ENOMEM; + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + sprom[i] = buf[i * 2] & 0xFF; + sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; + } + bcm43xx_lock_mmio(bcm, flags); + assert(bcm->initialized); + err = bcm43xx_sprom_write(bcm, sprom); + bcm43xx_unlock_mmio(bcm, flags); + kfree(sprom); + + return err ? err : count; + +} + +static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); + unsigned long flags; + int err; + ssize_t count = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + bcm43xx_lock(bcm, flags); + assert(bcm->initialized); + + switch (bcm43xx_current_radio(bcm)->interfmode) { + case BCM43xx_RADIO_INTERFMODE_NONE: + count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n"); + break; + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference Mitigation)\n"); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference Mitigation)\n"); + break; + default: + assert(0); + } + err = 0; + + bcm43xx_unlock(bcm, flags); + + return err ? err : count; + +} + +static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); + unsigned long flags; + int err; + int mode; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mode = get_integer(buf, count); + switch (mode) { + case 0: + mode = BCM43xx_RADIO_INTERFMODE_NONE; + break; + case 1: + mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; + break; + case 2: + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + break; + default: + return -EINVAL; + } + + bcm43xx_lock_mmio(bcm, flags); + assert(bcm->initialized); + + err = bcm43xx_radio_set_interference_mitigation(bcm, mode); + if (err) { + printk(KERN_ERR PFX "Interference Mitigation not " + "supported by device\n"); + } + + bcm43xx_unlock_mmio(bcm, flags); + + return err ? err : count; +} + +static ssize_t bcm43xx_attr_preamble_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); + unsigned long flags; + int err; + ssize_t count; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + bcm43xx_lock(bcm, flags); + assert(bcm->initialized); + + if (bcm->short_preamble) + count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); + else + count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); + + err = 0; + bcm43xx_unlock(bcm, flags); + + return err ? err : count; +} + +static ssize_t bcm43xx_attr_preamble_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); + unsigned long flags; + int err; + int value; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + value = get_boolean(buf, count); + if (value < 0) + return value; + bcm43xx_lock(bcm, flags); + assert(bcm->initialized); + + bcm->short_preamble = !!value; + + err = 0; + bcm43xx_unlock(bcm, flags); + + return err ? err : count; +} + +int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) +{ + struct device *dev = &bcm->pci_dev->dev; + struct bcm43xx_sysfs *sysfs = &bcm->sysfs; + int err; + + assert(bcm->initialized); + + sysfs->attr_sprom.attr.name = "sprom"; + sysfs->attr_sprom.attr.owner = THIS_MODULE; + sysfs->attr_sprom.attr.mode = 0600; + sysfs->attr_sprom.show = bcm43xx_attr_sprom_show; + sysfs->attr_sprom.store = bcm43xx_attr_sprom_store; + err = device_create_file(dev, &sysfs->attr_sprom); + if (err) + goto out; + + sysfs->attr_interfmode.attr.name = "interference"; + sysfs->attr_interfmode.attr.owner = THIS_MODULE; + sysfs->attr_interfmode.attr.mode = 0600; + sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show; + sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store; + err = device_create_file(dev, &sysfs->attr_interfmode); + if (err) + goto err_remove_sprom; + + sysfs->attr_preamble.attr.name = "shortpreamble"; + sysfs->attr_preamble.attr.owner = THIS_MODULE; + sysfs->attr_preamble.attr.mode = 0600; + sysfs->attr_preamble.show = bcm43xx_attr_preamble_show; + sysfs->attr_preamble.store = bcm43xx_attr_preamble_store; + err = device_create_file(dev, &sysfs->attr_preamble); + if (err) + goto err_remove_interfmode; + +out: + return err; +err_remove_interfmode: + device_remove_file(dev, &sysfs->attr_interfmode); +err_remove_sprom: + device_remove_file(dev, &sysfs->attr_sprom); + goto out; +} + +void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) +{ + struct device *dev = &bcm->pci_dev->dev; + struct bcm43xx_sysfs *sysfs = &bcm->sysfs; + + device_remove_file(dev, &sysfs->attr_preamble); + device_remove_file(dev, &sysfs->attr_interfmode); + device_remove_file(dev, &sysfs->attr_sprom); +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h new file mode 100644 index 000000000000..57f14514e3e0 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h @@ -0,0 +1,25 @@ +#ifndef BCM43xx_SYSFS_H_ +#define BCM43xx_SYSFS_H_ + +#include + + +struct bcm43xx_sysfs { + struct device_attribute attr_sprom; + struct device_attribute attr_interfmode; + struct device_attribute attr_preamble; +}; + +#define devattr_to_bcm(attr, attr_name) ({ \ + struct bcm43xx_sysfs *__s; struct bcm43xx_private *__p; \ + __s = container_of((attr), struct bcm43xx_sysfs, attr_name); \ + __p = container_of(__s, struct bcm43xx_private, sysfs); \ + __p; \ + }) + +struct bcm43xx_private; + +int bcm43xx_sysfs_register(struct bcm43xx_private *bcm); +void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm); + +#endif /* BCM43xx_SYSFS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c new file mode 100644 index 000000000000..3daee828ef4b --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -0,0 +1,1002 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include /* for capable() */ +#include + +#include "bcm43xx.h" +#include "bcm43xx_wx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_phy.h" + + +/* The WIRELESS_EXT version, which is implemented by this driver. */ +#define BCM43xx_WX_VERSION 18 + +#define MAX_WX_STRING 80 + + +static int bcm43xx_wx_get_name(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int i; + struct bcm43xx_phyinfo *phy; + char suffix[7] = { 0 }; + int have_a = 0, have_b = 0, have_g = 0; + + bcm43xx_lock(bcm, flags); + for (i = 0; i < bcm->nr_80211_available; i++) { + phy = &(bcm->core_80211_ext[i].phy); + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + have_a = 1; + break; + case BCM43xx_PHYTYPE_G: + have_g = 1; + case BCM43xx_PHYTYPE_B: + have_b = 1; + break; + default: + assert(0); + } + } + bcm43xx_unlock(bcm, flags); + + i = 0; + if (have_a) { + suffix[i++] = 'a'; + suffix[i++] = '/'; + } + if (have_b) { + suffix[i++] = 'b'; + suffix[i++] = '/'; + } + if (have_g) { + suffix[i++] = 'g'; + suffix[i++] = '/'; + } + if (i != 0) + suffix[i - 1] = '\0'; + + snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix); + + return 0; +} + +static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + u8 channel; + int freq; + int err = -EINVAL; + + bcm43xx_lock_mmio(bcm, flags); + if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { + channel = data->freq.m; + freq = bcm43xx_channel_to_freq(bcm, channel); + } else { + channel = bcm43xx_freq_to_channel(bcm, data->freq.m); + freq = data->freq.m; + } + if (!bcm43xx_is_valid_channel(bcm, channel)) + goto out_unlock; + if (bcm->initialized) { + //ieee80211softmac_disassoc(softmac, $REASON); + bcm43xx_mac_suspend(bcm); + err = bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_mac_enable(bcm); + } else { + bcm43xx_current_radio(bcm)->initial_channel = channel; + err = 0; + } +out_unlock: + bcm43xx_unlock_mmio(bcm, flags); + + return err; +} + +static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; + unsigned long flags; + int err = -ENODEV; + u16 channel; + + bcm43xx_lock(bcm, flags); + radio = bcm43xx_current_radio(bcm); + channel = radio->channel; + if (channel == 0xFF) { + assert(!bcm->initialized); + channel = radio->initial_channel; + if (channel == 0xFF) + goto out_unlock; + } + assert(channel > 0 && channel <= 1000); + data->freq.e = 1; + data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000; + data->freq.flags = 1; + + err = 0; +out_unlock: + bcm43xx_unlock(bcm, flags); + + return err; +} + +static int bcm43xx_wx_set_mode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int mode; + + mode = data->mode; + if (mode == IW_MODE_AUTO) + mode = BCM43xx_INITIAL_IWMODE; + + bcm43xx_lock_mmio(bcm, flags); + if (bcm->ieee->iw_mode != mode) + bcm43xx_set_iwmode(bcm, mode); + bcm43xx_unlock_mmio(bcm, flags); + + return 0; +} + +static int bcm43xx_wx_get_mode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + bcm43xx_lock(bcm, flags); + data->mode = bcm->ieee->iw_mode; + bcm43xx_unlock(bcm, flags); + + return 0; +} + +static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct iw_range *range = (struct iw_range *)extra; + const struct ieee80211_geo *geo; + unsigned long flags; + int i, j; + struct bcm43xx_phyinfo *phy; + + data->data.length = sizeof(*range); + memset(range, 0, sizeof(*range)); + + //TODO: What about 802.11b? + /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */ + range->throughput = 27 * 1000 * 1000; + + range->max_qual.qual = 100; + /* TODO: Real max RSSI */ + range->max_qual.level = 3; + range->max_qual.noise = 100; + range->max_qual.updated = 7; + + range->avg_qual.qual = 70; + range->avg_qual.level = 2; + range->avg_qual.noise = 40; + range->avg_qual.updated = 7; + + range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; + range->max_rts = BCM43xx_MAX_RTS_THRESHOLD; + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = WEP_KEYS; + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = BCM43xx_WX_VERSION; + + range->enc_capa = IW_ENC_CAPA_WPA | + IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | + IW_ENC_CAPA_CIPHER_CCMP; + + bcm43xx_lock(bcm, flags); + phy = bcm43xx_current_phy(bcm); + + range->num_bitrates = 0; + i = 0; + if (phy->type == BCM43xx_PHYTYPE_A || + phy->type == BCM43xx_PHYTYPE_G) { + range->num_bitrates = 8; + range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB; + } + if (phy->type == BCM43xx_PHYTYPE_B || + phy->type == BCM43xx_PHYTYPE_G) { + range->num_bitrates += 4; + range->bitrate[i++] = IEEE80211_CCK_RATE_1MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_2MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_5MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_11MB; + } + + geo = ieee80211_get_geo(bcm->ieee); + range->num_channels = geo->a_channels + geo->bg_channels; + j = 0; + for (i = 0; i < geo->a_channels; i++) { + if (j == IW_MAX_FREQUENCIES) + break; + range->freq[j].i = j + 1; + range->freq[j].m = geo->a[i].freq;//FIXME? + range->freq[j].e = 1; + j++; + } + for (i = 0; i < geo->bg_channels; i++) { + if (j == IW_MAX_FREQUENCIES) + break; + range->freq[j].i = j + 1; + range->freq[j].m = geo->bg[i].freq;//FIXME? + range->freq[j].e = 1; + j++; + } + range->num_frequency = j; + + bcm43xx_unlock(bcm, flags); + + return 0; +} + +static int bcm43xx_wx_set_nick(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + size_t len; + + bcm43xx_lock(bcm, flags); + len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); + memcpy(bcm->nick, extra, len); + bcm->nick[len] = '\0'; + bcm43xx_unlock(bcm, flags); + + return 0; +} + +static int bcm43xx_wx_get_nick(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + size_t len; + + bcm43xx_lock(bcm, flags); + len = strlen(bcm->nick) + 1; + memcpy(extra, bcm->nick, len); + data->data.length = (__u16)len; + data->data.flags = 1; + bcm43xx_unlock(bcm, flags); + + return 0; +} + +static int bcm43xx_wx_set_rts(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -EINVAL; + + bcm43xx_lock(bcm, flags); + if (data->rts.disabled) { + bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; + err = 0; + } else { + if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD && + data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) { + bcm->rts_threshold = data->rts.value; + err = 0; + } + } + bcm43xx_unlock(bcm, flags); + + return err; +} + +static int bcm43xx_wx_get_rts(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + bcm43xx_lock(bcm, flags); + data->rts.value = bcm->rts_threshold; + data->rts.fixed = 0; + data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); + bcm43xx_unlock(bcm, flags); + + return 0; +} + +static int bcm43xx_wx_set_frag(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -EINVAL; + + bcm43xx_lock(bcm, flags); + if (data->frag.disabled) { + bcm->ieee->fts = MAX_FRAG_THRESHOLD; + err = 0; + } else { + if (data->frag.value >= MIN_FRAG_THRESHOLD && + data->frag.value <= MAX_FRAG_THRESHOLD) { + bcm->ieee->fts = data->frag.value & ~0x1; + err = 0; + } + } + bcm43xx_unlock(bcm, flags); + + return err; +} + +static int bcm43xx_wx_get_frag(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + bcm43xx_lock(bcm, flags); + data->frag.value = bcm->ieee->fts; + data->frag.fixed = 0; + data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); + bcm43xx_unlock(bcm, flags); + + return 0; +} + +static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; + struct bcm43xx_phyinfo *phy; + unsigned long flags; + int err = -ENODEV; + u16 maxpower; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { + printk(PFX KERN_ERR "TX power not in dBm.\n"); + return -EOPNOTSUPP; + } + + bcm43xx_lock_mmio(bcm, flags); + if (!bcm->initialized) + goto out_unlock; + radio = bcm43xx_current_radio(bcm); + phy = bcm43xx_current_phy(bcm); + if (data->txpower.disabled != (!(radio->enabled))) { + if (data->txpower.disabled) + bcm43xx_radio_turn_off(bcm); + else + bcm43xx_radio_turn_on(bcm); + } + if (data->txpower.value > 0) { + /* desired and maxpower dBm values are in Q5.2 */ + if (phy->type == BCM43xx_PHYTYPE_A) + maxpower = bcm->sprom.maxpower_aphy; + else + maxpower = bcm->sprom.maxpower_bgphy; + radio->txpower_desired = limit_value(data->txpower.value << 2, + 0, maxpower); + bcm43xx_phy_xmitpower(bcm); + } + err = 0; + +out_unlock: + bcm43xx_unlock_mmio(bcm, flags); + + return err; +} + +static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; + unsigned long flags; + int err = -ENODEV; + + bcm43xx_lock(bcm, flags); + if (!bcm->initialized) + goto out_unlock; + radio = bcm43xx_current_radio(bcm); + /* desired dBm value is in Q5.2 */ + data->txpower.value = radio->txpower_desired >> 2; + data->txpower.fixed = 1; + data->txpower.flags = IW_TXPOW_DBM; + data->txpower.disabled = !(radio->enabled); + + err = 0; +out_unlock: + bcm43xx_unlock(bcm, flags); + + return err; +} + +static int bcm43xx_wx_set_encoding(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_set_encodingext(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_get_encoding(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int mode, err = 0; + + mode = *((int *)extra); + switch (mode) { + case 0: + mode = BCM43xx_RADIO_INTERFMODE_NONE; + break; + case 1: + mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; + break; + case 2: + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + break; + default: + printk(KERN_ERR PFX "set_interfmode allowed parameters are: " + "0 => None, 1 => Non-WLAN, 2 => WLAN, " + "3 => Auto-WLAN\n"); + return -EINVAL; + } + + bcm43xx_lock_mmio(bcm, flags); + if (bcm->initialized) { + err = bcm43xx_radio_set_interference_mitigation(bcm, mode); + if (err) { + printk(KERN_ERR PFX "Interference Mitigation not " + "supported by device\n"); + } + } else { + if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) { + printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN " + "not supported while the interface is down.\n"); + err = -ENODEV; + } else + bcm43xx_current_radio(bcm)->interfmode = mode; + } + bcm43xx_unlock_mmio(bcm, flags); + + return err; +} + +static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int mode; + + bcm43xx_lock(bcm, flags); + mode = bcm43xx_current_radio(bcm)->interfmode; + bcm43xx_unlock(bcm, flags); + + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_NONE: + strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING); + break; + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING); + break; + default: + assert(0); + } + data->data.length = strlen(extra) + 1; + + return 0; +} + +static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + on = *((int *)extra); + bcm43xx_lock(bcm, flags); + bcm->short_preamble = !!on; + bcm43xx_unlock(bcm, flags); + + return 0; +} + +static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + bcm43xx_lock(bcm, flags); + on = bcm->short_preamble; + bcm43xx_unlock(bcm, flags); + + if (on) + strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); + else + strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING); + data->data.length = strlen(extra) + 1; + + return 0; +} + +static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + on = *((int *)extra); + + bcm43xx_lock(bcm, flags); + bcm->ieee->host_encrypt = !!on; + bcm->ieee->host_decrypt = !!on; + bcm->ieee->host_build_iv = !on; + bcm43xx_unlock(bcm, flags); + + return 0; +} + +static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + bcm43xx_lock(bcm, flags); + on = bcm->ieee->host_encrypt; + bcm43xx_unlock(bcm, flags); + + if (on) + strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); + else + strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING); + data->data.length = strlen(extra + 1); + + return 0; +} + +/* Enough buffer to hold a hexdump of the sprom data. */ +#define SPROM_BUFFERSIZE 512 + +static int sprom2hex(const u16 *sprom, char *dump) +{ + int i, pos = 0; + + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1, + "%04X", swab16(sprom[i]) & 0xFFFF); + } + + return pos + 1; +} + +static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) +{ + char tmp[5] = { 0 }; + int cnt = 0; + unsigned long parsed; + + if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) + return -EINVAL; + while (cnt < BCM43xx_SPROM_SIZE) { + memcpy(tmp, dump, 4); + dump += 4; + parsed = simple_strtoul(tmp, NULL, 16); + sprom[cnt++] = swab16((u16)parsed); + } + + return 0; +} + +static int bcm43xx_wx_sprom_read(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = -EPERM; + u16 *sprom; + unsigned long flags; + + if (!capable(CAP_SYS_RAWIO)) + goto out; + + err = -ENOMEM; + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + goto out; + + bcm43xx_lock_mmio(bcm, flags); + err = -ENODEV; + if (bcm->initialized) + err = bcm43xx_sprom_read(bcm, sprom); + bcm43xx_unlock_mmio(bcm, flags); + if (!err) + data->data.length = sprom2hex(sprom, extra); + kfree(sprom); +out: + return err; +} + +static int bcm43xx_wx_sprom_write(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = -EPERM; + u16 *sprom; + unsigned long flags; + char *input; + unsigned int len; + + if (!capable(CAP_SYS_RAWIO)) + goto out; + + err = -ENOMEM; + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + goto out; + + len = data->data.length; + extra[len - 1] = '\0'; + input = strchr(extra, ':'); + if (input) { + input++; + len -= input - extra; + } else + input = extra; + err = hex2sprom(sprom, input, len); + if (err) + goto out_kfree; + + bcm43xx_lock_mmio(bcm, flags); + err = -ENODEV; + if (bcm->initialized) + err = bcm43xx_sprom_write(bcm, sprom); + bcm43xx_unlock_mmio(bcm, flags); +out_kfree: + kfree(sprom); +out: + return err; +} + +/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ + +static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); + struct iw_statistics *wstats; + + wstats = &bcm->stats.wstats; + if (!mac->associated) { + wstats->miss.beacon = 0; +// bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here? + wstats->discard.retries = 0; +// bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question + wstats->discard.nwid = 0; +// bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto + wstats->discard.code = 0; +// bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here + wstats->discard.fragment = 0; + wstats->discard.misc = 0; + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = 7; + wstats->qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + return wstats; + } + /* fill in the real statistics when iface associated */ + wstats->qual.qual = 100; // TODO: get the real signal quality + wstats->qual.level = 3 - bcm->stats.link_quality; + wstats->qual.noise = bcm->stats.noise; + wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | + IW_QUAL_NOISE_UPDATED; + wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; + wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; + wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; + wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments; + wstats->discard.misc = 0; // FIXME + wstats->miss.beacon = 0; // FIXME + return wstats; +} + + +#ifdef WX +# undef WX +#endif +#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT] +static const iw_handler bcm43xx_wx_handlers[] = { + /* Wireless Identification */ + WX(SIOCGIWNAME) = bcm43xx_wx_get_name, + /* Basic operations */ + WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq, + WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq, + WX(SIOCSIWMODE) = bcm43xx_wx_set_mode, + WX(SIOCGIWMODE) = bcm43xx_wx_get_mode, + /* Informative stuff */ + WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams, + /* Access Point manipulation */ + WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap, + WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap, + WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan, + WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results, + /* 802.11 specific support */ + WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid, + WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid, + WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick, + WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick, + /* Other parameters */ + WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate, + WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate, + WX(SIOCSIWRTS) = bcm43xx_wx_set_rts, + WX(SIOCGIWRTS) = bcm43xx_wx_get_rts, + WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag, + WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag, + WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower, + WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower, +//TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry, +//TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry, + /* Encoding */ + WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding, + WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding, + WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext, + WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext, + /* Power saving */ +//TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power, +//TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power, + WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie, + WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie, + WX(SIOCSIWAUTH) = ieee80211_wx_set_auth, + WX(SIOCGIWAUTH) = ieee80211_wx_get_auth, +}; +#undef WX + +static const iw_handler bcm43xx_priv_wx_handlers[] = { + /* Set Interference Mitigation Mode. */ + bcm43xx_wx_set_interfmode, + /* Get Interference Mitigation Mode. */ + bcm43xx_wx_get_interfmode, + /* Enable/Disable Short Preamble mode. */ + bcm43xx_wx_set_shortpreamble, + /* Get Short Preamble mode. */ + bcm43xx_wx_get_shortpreamble, + /* Enable/Disable Software Encryption mode */ + bcm43xx_wx_set_swencryption, + /* Get Software Encryption mode */ + bcm43xx_wx_get_swencryption, + /* Write SRPROM data. */ + bcm43xx_wx_sprom_write, + /* Read SPROM data. */ + bcm43xx_wx_sprom_read, +}; + +#define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0) +#define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1) +#define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2) +#define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3) +#define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4) +#define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5) +#define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6) +#define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7) + +#define PRIV_WX_DUMMY(ioctl) \ + { \ + .cmd = (ioctl), \ + .name = "__unused" \ + } + +static const struct iw_priv_args bcm43xx_priv_wx_args[] = { + { + .cmd = PRIV_WX_SET_INTERFMODE, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_interfmode", + }, + { + .cmd = PRIV_WX_GET_INTERFMODE, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_interfmode", + }, + { + .cmd = PRIV_WX_SET_SHORTPREAMBLE, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_shortpreambl", + }, + { + .cmd = PRIV_WX_GET_SHORTPREAMBLE, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_shortpreambl", + }, + { + .cmd = PRIV_WX_SET_SWENCRYPTION, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_swencryption", + }, + { + .cmd = PRIV_WX_GET_SWENCRYPTION, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_swencryption", + }, + { + .cmd = PRIV_WX_SPROM_WRITE, + .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE, + .name = "write_sprom", + }, + { + .cmd = PRIV_WX_SPROM_READ, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE, + .name = "read_sprom", + }, +}; + +const struct iw_handler_def bcm43xx_wx_handlers_def = { + .standard = bcm43xx_wx_handlers, + .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers), + .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers), + .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args), + .private = bcm43xx_priv_wx_handlers, + .private_args = bcm43xx_priv_wx_args, + .get_wireless_stats = bcm43xx_get_wireless_stats, +}; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.h b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h new file mode 100644 index 000000000000..1f29ff3aa4c3 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h @@ -0,0 +1,36 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_WX_H_ +#define BCM43xx_WX_H_ + +extern const struct iw_handler_def bcm43xx_wx_handlers_def; + +#endif /* BCM43xx_WX_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c new file mode 100644 index 000000000000..d8ece28c079f --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -0,0 +1,582 @@ +/* + + Broadcom BCM43xx wireless driver + + Transmission (TX/RX) related functions. + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx_xmit.h" + +#include + + +/* Extract the bitrate out of a CCK PLCP header. */ +static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp) +{ + switch (plcp->raw[0]) { + case 0x0A: + return IEEE80211_CCK_RATE_1MB; + case 0x14: + return IEEE80211_CCK_RATE_2MB; + case 0x37: + return IEEE80211_CCK_RATE_5MB; + case 0x6E: + return IEEE80211_CCK_RATE_11MB; + } + assert(0); + return 0; +} + +/* Extract the bitrate out of an OFDM PLCP header. */ +static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp) +{ + switch (plcp->raw[0] & 0xF) { + case 0xB: + return IEEE80211_OFDM_RATE_6MB; + case 0xF: + return IEEE80211_OFDM_RATE_9MB; + case 0xA: + return IEEE80211_OFDM_RATE_12MB; + case 0xE: + return IEEE80211_OFDM_RATE_18MB; + case 0x9: + return IEEE80211_OFDM_RATE_24MB; + case 0xD: + return IEEE80211_OFDM_RATE_36MB; + case 0x8: + return IEEE80211_OFDM_RATE_48MB; + case 0xC: + return IEEE80211_OFDM_RATE_54MB; + } + assert(0); + return 0; +} + +u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_CCK_RATE_1MB: + return 0x0A; + case IEEE80211_CCK_RATE_2MB: + return 0x14; + case IEEE80211_CCK_RATE_5MB: + return 0x37; + case IEEE80211_CCK_RATE_11MB: + return 0x6E; + } + assert(0); + return 0; +} + +u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_OFDM_RATE_6MB: + return 0xB; + case IEEE80211_OFDM_RATE_9MB: + return 0xF; + case IEEE80211_OFDM_RATE_12MB: + return 0xA; + case IEEE80211_OFDM_RATE_18MB: + return 0xE; + case IEEE80211_OFDM_RATE_24MB: + return 0x9; + case IEEE80211_OFDM_RATE_36MB: + return 0xD; + case IEEE80211_OFDM_RATE_48MB: + return 0x8; + case IEEE80211_OFDM_RATE_54MB: + return 0xC; + } + assert(0); + return 0; +} + +static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate, + const int ofdm_modulation) +{ + __le32 *data = &(plcp->data); + __u8 *raw = plcp->raw; + + if (ofdm_modulation) { + *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); + assert(!(octets & 0xF000)); + *data |= (octets << 5); + *data = cpu_to_le32(*data); + } else { + u32 plen; + + plen = octets * 16 / bitrate; + if ((octets * 16 % bitrate) > 0) { + plen++; + if ((bitrate == IEEE80211_CCK_RATE_11MB) + && ((octets * 8 % 11) < 4)) { + raw[1] = 0x84; + } else + raw[1] = 0x04; + } else + raw[1] = 0x04; + *data |= cpu_to_le32(plen << 16); + raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); + } +} + +static u8 bcm43xx_calc_fallback_rate(u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_CCK_RATE_1MB: + return IEEE80211_CCK_RATE_1MB; + case IEEE80211_CCK_RATE_2MB: + return IEEE80211_CCK_RATE_1MB; + case IEEE80211_CCK_RATE_5MB: + return IEEE80211_CCK_RATE_2MB; + case IEEE80211_CCK_RATE_11MB: + return IEEE80211_CCK_RATE_5MB; + case IEEE80211_OFDM_RATE_6MB: + return IEEE80211_CCK_RATE_5MB; + case IEEE80211_OFDM_RATE_9MB: + return IEEE80211_OFDM_RATE_6MB; + case IEEE80211_OFDM_RATE_12MB: + return IEEE80211_OFDM_RATE_9MB; + case IEEE80211_OFDM_RATE_18MB: + return IEEE80211_OFDM_RATE_12MB; + case IEEE80211_OFDM_RATE_24MB: + return IEEE80211_OFDM_RATE_18MB; + case IEEE80211_OFDM_RATE_36MB: + return IEEE80211_OFDM_RATE_24MB; + case IEEE80211_OFDM_RATE_48MB: + return IEEE80211_OFDM_RATE_36MB; + case IEEE80211_OFDM_RATE_54MB: + return IEEE80211_OFDM_RATE_48MB; + } + assert(0); + return 0; +} + +static +__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header, + u8 bitrate) +{ + const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl); + __le16 duration_id = wireless_header->duration_id; + + switch (WLAN_FC_GET_TYPE(frame_ctl)) { + case IEEE80211_FTYPE_DATA: + case IEEE80211_FTYPE_MGMT: + //TODO: Steal the code from ieee80211, once it is completed there. + break; + case IEEE80211_FTYPE_CTL: + /* Use the original duration/id. */ + break; + default: + assert(0); + } + + return duration_id; +} + +static inline +u16 ceiling_div(u16 dividend, u16 divisor) +{ + return ((dividend + divisor - 1) / divisor); +} + +static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy, + struct bcm43xx_txhdr *txhdr, + u16 *flags, + u8 bitrate, + const struct ieee80211_hdr_4addr *wlhdr) +{ + u16 fctl; + u16 dur; + u8 fallback_bitrate; + int ofdm_modulation; + int fallback_ofdm_modulation; +// u8 *sa, *da; + u16 flen; + +//FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr); +//FIXME da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr); + fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); + + flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN, + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp), + flen, bitrate, + !ieee80211_is_cck_rate(bitrate)); + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp), + flen, fallback_bitrate, + !ieee80211_is_cck_rate(fallback_bitrate)); + fctl = IEEE80211_FTYPE_CTL; + fctl |= IEEE80211_STYPE_RTS; + dur = le16_to_cpu(wlhdr->duration_id); +/*FIXME: should we test for dur==0 here and let it unmodified in this case? + * The following assert checks for this case... + */ +assert(dur); +/*FIXME: The duration calculation is not really correct. + * I am not 100% sure which bitrate to use. We use the RTS rate here, + * but this is likely to be wrong. + */ + if (phy->type == BCM43xx_PHYTYPE_A) { + /* Three times SIFS */ + dur += 16 * 3; + /* Add ACK duration. */ + dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, + bitrate * 4); + /* Add CTS duration. */ + dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, + bitrate * 4); + } else { + /* Three times SIFS */ + dur += 10 * 3; + /* Add ACK duration. */ + dur += ceiling_div(8 * (14 /*bytes*/) * 10, + bitrate); + /* Add CTS duration. */ + dur += ceiling_div(8 * (14 /*bytes*/) * 10, + bitrate); + } + + txhdr->rts_cts_frame_control = cpu_to_le16(fctl); + txhdr->rts_cts_dur = cpu_to_le16(dur); +//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3)); +//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da)); + memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME! +// memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); + + *flags |= BCM43xx_TXHDRFLAG_RTSCTS; + *flags |= BCM43xx_TXHDRFLAG_RTS; + if (ofdm_modulation) + *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM; + if (fallback_ofdm_modulation) + *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM; +} + +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie) +{ + const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data; + const struct ieee80211_security *secinfo = &bcm->ieee->sec; + u8 bitrate; + u8 fallback_bitrate; + int ofdm_modulation; + int fallback_ofdm_modulation; + u16 plcp_fragment_len = fragment_len; + u16 flags = 0; + u16 control = 0; + u16 wsec_rate = 0; + u16 encrypt_frame; + + /* Now construct the TX header. */ + memset(txhdr, 0, sizeof(*txhdr)); + + bitrate = bcm->softmac->txrates.default_rate; + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); + fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); + + /* Set Frame Control from 80211 header. */ + txhdr->frame_control = wireless_header->frame_ctl; + /* Copy address1 from 80211 header. */ + memcpy(txhdr->mac1, wireless_header->addr1, 6); + /* Set the fallback duration ID. */ + txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header, + fallback_bitrate); + /* Set the cookie (used as driver internal ID for the frame) */ + txhdr->cookie = cpu_to_le16(cookie); + + /* Hardware appends FCS. */ + plcp_fragment_len += IEEE80211_FCS_LEN; + + /* Hardware encryption. */ + encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; + if (encrypt_frame && !bcm->ieee->host_encrypt) { + const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; + memcpy(txhdr->wep_iv, hdr->payload, 4); + /* Hardware appends ICV. */ + plcp_fragment_len += 4; + + wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) + & BCM43xx_TXHDR_WSEC_ALGO_MASK; + wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) + & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; + } + + /* Generate the PLCP header and the fallback PLCP header. */ + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), + plcp_fragment_len, + bitrate, ofdm_modulation); + bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len, + fallback_bitrate, fallback_ofdm_modulation); + + /* Set the CONTROL field */ + if (ofdm_modulation) + control |= BCM43xx_TXHDRCTL_OFDM; + if (bcm->short_preamble) //FIXME: could be the other way around, please test + control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; + control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) + & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; + + /* Set the FLAGS field */ + if (!is_multicast_ether_addr(wireless_header->addr1) && + !is_broadcast_ether_addr(wireless_header->addr1)) + flags |= BCM43xx_TXHDRFLAG_EXPECTACK; + if (1 /* FIXME: PS poll?? */) + flags |= 0x10; // FIXME: unknown meaning. + if (fallback_ofdm_modulation) + flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; + if (is_first_fragment) + flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; + + /* Set WSEC/RATE field */ + wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT) + & BCM43xx_TXHDR_RATE_MASK; + + /* Generate the RTS/CTS packet, if required. */ + /* FIXME: We should first try with CTS-to-self, + * if we are on 80211g. If we get too many + * failures (hidden nodes), we should switch back to RTS/CTS. + */ + if (0/*FIXME txctl->use_rts_cts*/) { + bcm43xx_generate_rts(phy, txhdr, &flags, + 0/*FIXME txctl->rts_cts_rate*/, + wireless_header); + } + + txhdr->flags = cpu_to_le16(flags); + txhdr->control = cpu_to_le16(control); + txhdr->wsec_rate = cpu_to_le16(wsec_rate); +} + +static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi, int ofdm, + int adjust_2053, int adjust_2050) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + s32 tmp; + + switch (radio->version) { + case 0x2050: + if (ofdm) { + tmp = in_rssi; + if (tmp > 127) + tmp -= 256; + tmp *= 73; + tmp /= 64; + if (adjust_2050) + tmp += 25; + else + tmp -= 3; + } else { + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + if (in_rssi > 63) + in_rssi = 63; + tmp = radio->nrssi_lt[in_rssi]; + tmp = 31 - tmp; + tmp *= -131; + tmp /= 128; + tmp -= 57; + } else { + tmp = in_rssi; + tmp = 31 - tmp; + tmp *= -149; + tmp /= 128; + tmp -= 68; + } + if (phy->type == BCM43xx_PHYTYPE_G && + adjust_2050) + tmp += 25; + } + break; + case 0x2060: + if (in_rssi > 127) + tmp = in_rssi - 256; + else + tmp = in_rssi; + break; + default: + tmp = in_rssi; + tmp -= 11; + tmp *= 103; + tmp /= 64; + if (adjust_2053) + tmp -= 109; + else + tmp -= 83; + } + + return (s8)tmp; +} + +//TODO +#if 0 +static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + s8 ret; + + if (phy->type == BCM43xx_PHYTYPE_A) { + //TODO: Incomplete specs. + ret = 0; + } else + ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); + + return ret; +} +#endif + +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_plcp_hdr4 *plcp; + struct ieee80211_rx_stats stats; + struct ieee80211_hdr_4addr *wlhdr; + u16 frame_ctl; + int is_packet_for_us = 0; + int err = -EINVAL; + const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); + const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); + const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); + const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); + + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); + /* Skip two unknown bytes and the PLCP header. */ + skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); + } else { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); + /* Skip the PLCP header. */ + skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); + } + /* The SKB contains the PAYLOAD (wireless header + data) + * at this point. The FCS at the end is stripped. + */ + + memset(&stats, 0, sizeof(stats)); + stats.mac_time = le16_to_cpu(rxhdr->mactime); + stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, + !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), + !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); + stats.signal = rxhdr->signal_quality; //FIXME +//TODO stats.noise = + if (is_ofdm) + stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); + else + stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); +//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); + stats.received_channel = radio->channel; +//TODO stats.control = + stats.mask = IEEE80211_STATMASK_SIGNAL | +//TODO IEEE80211_STATMASK_NOISE | + IEEE80211_STATMASK_RATE | + IEEE80211_STATMASK_RSSI; + if (phy->type == BCM43xx_PHYTYPE_A) + stats.freq = IEEE80211_52GHZ_BAND; + else + stats.freq = IEEE80211_24GHZ_BAND; + stats.len = skb->len; + + bcm->stats.last_rx = jiffies; + if (bcm->ieee->iw_mode == IW_MODE_MONITOR) { + err = ieee80211_rx(bcm->ieee, skb, &stats); + return (err == 0) ? -EINVAL : 0; + } + + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); + + switch (bcm->ieee->iw_mode) { + case IW_MODE_ADHOC: + if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC) + is_packet_for_us = 1; + break; + case IW_MODE_INFRA: + default: + /* When receiving multicast or broadcast packets, filter out + the packets we send ourself; we shouldn't see those */ + if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && + (is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC))) + is_packet_for_us = 1; + break; + } + + frame_ctl = le16_to_cpu(wlhdr->frame_ctl); + if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { + frame_ctl &= ~IEEE80211_FCTL_PROTECTED; + wlhdr->frame_ctl = cpu_to_le16(frame_ctl); + /* trim IV and ICV */ + /* FIXME: this must be done only for WEP encrypted packets */ + if (skb->len < 32) { + dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag " + "set and length < 32)\n"); + return -EINVAL; + } else { + memmove(skb->data + 4, skb->data, 24); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + stats.len -= 8; + } + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); + } + + switch (WLAN_FC_GET_TYPE(frame_ctl)) { + case IEEE80211_FTYPE_MGMT: + ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); + break; + case IEEE80211_FTYPE_DATA: + if (is_packet_for_us) { + err = ieee80211_rx(bcm->ieee, skb, &stats); + err = (err == 0) ? -EINVAL : 0; + } + break; + case IEEE80211_FTYPE_CTL: + break; + default: + assert(0); + return -EINVAL; + } + + return err; +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h new file mode 100644 index 000000000000..2aed19e35c77 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h @@ -0,0 +1,156 @@ +#ifndef BCM43xx_XMIT_H_ +#define BCM43xx_XMIT_H_ + +#include "bcm43xx_main.h" + + +#define _bcm43xx_declare_plcp_hdr(size) \ + struct bcm43xx_plcp_hdr##size { \ + union { \ + __le32 data; \ + __u8 raw[size]; \ + } __attribute__((__packed__)); \ + } __attribute__((__packed__)) + +/* struct bcm43xx_plcp_hdr4 */ +_bcm43xx_declare_plcp_hdr(4); +/* struct bcm43xx_plcp_hdr6 */ +_bcm43xx_declare_plcp_hdr(6); + +#undef _bcm43xx_declare_plcp_hdr + +/* Device specific TX header. To be prepended to TX frames. */ +struct bcm43xx_txhdr { + union { + struct { + __le16 flags; + __le16 wsec_rate; + __le16 frame_control; + u16 unknown_zeroed_0; + __le16 control; + u8 wep_iv[10]; + u8 unknown_wsec_tkip_data[3]; //FIXME + PAD_BYTES(3); + u8 mac1[6]; + u16 unknown_zeroed_1; + struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp; + __le16 rts_cts_dur_fallback; + struct bcm43xx_plcp_hdr4 fallback_plcp; + __le16 fallback_dur_id; + PAD_BYTES(2); + __le16 cookie; + __le16 unknown_scb_stuff; //FIXME + struct bcm43xx_plcp_hdr6 rts_cts_plcp; + __le16 rts_cts_frame_control; + __le16 rts_cts_dur; + u8 rts_cts_mac1[6]; + u8 rts_cts_mac2[6]; + PAD_BYTES(2); + struct bcm43xx_plcp_hdr6 plcp; + } __attribute__((__packed__)); + u8 raw[82]; + } __attribute__((__packed__)); +} __attribute__((__packed__)); + +/* Values/Masks for the device TX header */ +#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001 +#define BCM43xx_TXHDRFLAG_RTSCTS 0x0002 +#define BCM43xx_TXHDRFLAG_RTS 0x0004 +#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008 +#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020 +#define BCM43xx_TXHDRFLAG_RTSCTS_OFDM 0x0080 +#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100 +#define BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM 0x0200 +#define BCM43xx_TXHDRFLAG_CTS 0x0400 +#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800 + +#define BCM43xx_TXHDRCTL_OFDM 0x0001 +#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010 +#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030 +#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8 + +#define BCM43xx_TXHDR_RATE_MASK 0x0F00 +#define BCM43xx_TXHDR_RATE_SHIFT 8 +#define BCM43xx_TXHDR_RTSRATE_MASK 0xF000 +#define BCM43xx_TXHDR_RTSRATE_SHIFT 12 +#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0 +#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4 +#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003 +#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0 + +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie); + +/* RX header as received from the hardware. */ +struct bcm43xx_rxhdr { + /* Frame Length. Must be generated explicitely in PIO mode. */ + __le16 frame_length; + PAD_BYTES(2); + /* Flags field 1 */ + __le16 flags1; + u8 rssi; + u8 signal_quality; + PAD_BYTES(2); + /* Flags field 3 */ + __le16 flags3; + /* Flags field 2 */ + __le16 flags2; + /* Lower 16bits of the TSF at the time the frame started. */ + __le16 mactime; + PAD_BYTES(14); +} __attribute__((__packed__)); + +#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0) +/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */ +#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7) +#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14) + +#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0) +#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2) +/*FIXME: WEP related flags */ + +#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10) + +/* Transmit Status as received from the hardware. */ +struct bcm43xx_hwxmitstatus { + PAD_BYTES(4); + __le16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + PAD_BYTES(2); + __le16 seq; + __le16 unknown; //FIXME +} __attribute__((__packed__)); + +/* Transmit Status in CPU byteorder. */ +struct bcm43xx_xmitstatus { + u16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + u16 seq; + u16 unknown; //FIXME +}; + +#define BCM43xx_TXSTAT_FLAG_ACK 0x01 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10 +#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 + +u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate); +u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate); + +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr); + +#endif /* BCM43xx_XMIT_H_ */ diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index 1fc72fe511e9..cc1ee7f4f5f8 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -92,8 +92,6 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); -struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct ieee80211_crypt_data *crypt); int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); #endif /* HOSTAP_80211_H */ diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 4a85e63906f1..06a5214145e3 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -299,8 +299,8 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Called only from software IRQ */ -struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) +static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, + struct ieee80211_crypt_data *crypt) { struct hostap_interface *iface; local_info_t *local; @@ -317,7 +317,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, } if (local->tkip_countermeasures && - crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { + strcmp(crypt->ops->name, "TKIP") == 0) { hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " @@ -469,7 +469,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) } if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && - !(fc & IEEE80211_FCTL_VERS)) { + !(fc & IEEE80211_FCTL_PROTECTED)) { no_encrypt = 1; PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " "unencrypted EAPOL frame\n", dev->name); @@ -535,5 +535,4 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) EXPORT_SYMBOL(hostap_dump_tx_80211); -EXPORT_SYMBOL(hostap_tx_encrypt); EXPORT_SYMBOL(hostap_master_start_xmit); diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index d335b250923a..55bed923fbe9 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -42,7 +42,7 @@ MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); /* struct local_info::hw_priv */ struct hostap_cs_priv { dev_node_t node; - dev_link_t *link; + struct pcmcia_device *link; int sandisk_connectplus; }; @@ -204,15 +204,13 @@ static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) static void prism2_detach(struct pcmcia_device *p_dev); static void prism2_release(u_long arg); -static int prism2_config(dev_link_t *link); +static int prism2_config(struct pcmcia_device *link); static int prism2_pccard_card_present(local_info_t *local) { struct hostap_cs_priv *hw_priv = local->hw_priv; - if (hw_priv != NULL && hw_priv->link != NULL && - ((hw_priv->link->state & (DEV_PRESENT | DEV_CONFIG)) == - (DEV_PRESENT | DEV_CONFIG))) + if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link)) return 1; return 0; } @@ -237,7 +235,7 @@ static void sandisk_set_iobase(local_info_t *local) reg.Action = CS_WRITE; reg.Offset = 0x10; /* 0x3f0 IO base 1 */ reg.Value = hw_priv->link->io.BasePort1 & 0x00ff; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" @@ -249,7 +247,7 @@ static void sandisk_set_iobase(local_info_t *local) reg.Action = CS_WRITE; reg.Offset = 0x12; /* 0x3f2 IO base 2 */ reg.Value = (hw_priv->link->io.BasePort1 & 0xff00) >> 8; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" @@ -301,9 +299,9 @@ static int sandisk_enable_wireless(struct net_device *dev) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) || - pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) || - pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) || + if (pcmcia_get_first_tuple(hw_priv->link, &tuple) || + pcmcia_get_tuple_data(hw_priv->link, &tuple) || + pcmcia_parse_tuple(hw_priv->link, &tuple, parse) || parse->manfid.manf != 0xd601 || parse->manfid.card != 0x0101) { /* No SanDisk manfid found */ ret = -ENODEV; @@ -311,9 +309,9 @@ static int sandisk_enable_wireless(struct net_device *dev) } tuple.DesiredTuple = CISTPL_LONGLINK_MFC; - if (pcmcia_get_first_tuple(hw_priv->link->handle, &tuple) || - pcmcia_get_tuple_data(hw_priv->link->handle, &tuple) || - pcmcia_parse_tuple(hw_priv->link->handle, &tuple, parse) || + if (pcmcia_get_first_tuple(hw_priv->link, &tuple) || + pcmcia_get_tuple_data(hw_priv->link, &tuple) || + pcmcia_parse_tuple(hw_priv->link, &tuple, parse) || parse->longlink_mfc.nfn < 2) { /* No multi-function links found */ ret = -ENODEV; @@ -328,7 +326,7 @@ static int sandisk_enable_wireless(struct net_device *dev) reg.Action = CS_WRITE; reg.Offset = CISREG_COR; reg.Value = COR_SOFT_RESET; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", @@ -345,7 +343,7 @@ static int sandisk_enable_wireless(struct net_device *dev) * will be enabled during the first cor_sreset call. */ reg.Value = COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | COR_FUNC_ENA; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", @@ -380,7 +378,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local) reg.Action = CS_READ; reg.Offset = CISREG_COR; reg.Value = 0; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", @@ -392,7 +390,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local) reg.Action = CS_WRITE; reg.Value |= COR_SOFT_RESET; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", @@ -405,7 +403,7 @@ static void prism2_pccard_cor_sreset(local_info_t *local) reg.Value &= ~COR_SOFT_RESET; if (hw_priv->sandisk_connectplus) reg.Value |= COR_IREQ_ENA; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", @@ -439,7 +437,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Action = CS_READ; reg.Offset = CISREG_COR; reg.Value = 0; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 1 " @@ -452,7 +450,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Action = CS_WRITE; reg.Value |= COR_SOFT_RESET; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 2 " @@ -466,7 +464,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Action = CS_WRITE; reg.Value = hcr; reg.Offset = CISREG_CCSR; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 3 " @@ -478,7 +476,7 @@ static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) reg.Action = CS_WRITE; reg.Offset = CISREG_COR; reg.Value = old_cor & ~COR_SOFT_RESET; - res = pcmcia_access_configuration_register(hw_priv->link->handle, + res = pcmcia_access_configuration_register(hw_priv->link, ®); if (res != CS_SUCCESS) { printk(KERN_DEBUG "prism2_pccard_genesis_sreset failed 4 " @@ -501,40 +499,27 @@ static struct prism2_helper_functions prism2_pccard_funcs = /* allocate local data and register with CardServices * initialize dev_link structure, but do not configure the card yet */ -static int prism2_attach(struct pcmcia_device *p_dev) +static int hostap_cs_probe(struct pcmcia_device *p_dev) { - dev_link_t *link; - - link = kmalloc(sizeof(dev_link_t), GFP_KERNEL); - if (link == NULL) - return -ENOMEM; - - memset(link, 0, sizeof(dev_link_t)); + int ret; PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); - link->conf.Vcc = 33; - link->conf.IntType = INT_MEMORY_AND_IO; + p_dev->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - if (prism2_config(link)) + ret = prism2_config(p_dev); + if (ret) { PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); + } - return 0; + return ret; } -static void prism2_detach(struct pcmcia_device *p_dev) +static void prism2_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - PDEBUG(DEBUG_FLOW, "prism2_detach\n"); - if (link->state & DEV_CONFIG) { - prism2_release((u_long)link); - } + prism2_release((u_long)link); /* release net devices */ if (link->priv) { @@ -547,7 +532,6 @@ static void prism2_detach(struct pcmcia_device *p_dev) prism2_free_local_data(dev); kfree(hw_priv); } - kfree(link); } @@ -558,7 +542,7 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) do { int ret = (retf); \ if (ret != 0) { \ PDEBUG(DEBUG_EXTRA, "CardServices(" #fn ") returned %d\n", ret); \ - cs_error(link->handle, fn, ret); \ + cs_error(link, fn, ret); \ goto next_entry; \ } \ } while (0) @@ -566,7 +550,7 @@ if (ret != 0) { \ /* run after a CARD_INSERTION event is received to configure the PCMCIA * socket and make the device available to the system */ -static int prism2_config(dev_link_t *link) +static int prism2_config(struct pcmcia_device *link) { struct net_device *dev; struct hostap_interface *iface; @@ -595,27 +579,24 @@ static int prism2_config(dev_link_t *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link->handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link->handle, &tuple, parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, parse)); link->conf.ConfigBase = parse->config.base; link->conf.Present = parse->config.rmask[0]; CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(link->handle, &conf)); - PDEBUG(DEBUG_HW, "%s: %s Vcc=%d (from config)\n", dev_info, - ignore_cis_vcc ? "ignoring" : "setting", conf.Vcc); - link->conf.Vcc = conf.Vcc; + pcmcia_get_configuration_info(link, &conf)); /* Look for an appropriate configuration table entry in the CIS */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link->handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); for (;;) { cistpl_cftable_entry_t *cfg = &(parse->cftable_entry); CFG_CHECK2(GetTupleData, - pcmcia_get_tuple_data(link->handle, &tuple)); + pcmcia_get_tuple_data(link, &tuple)); CFG_CHECK2(ParseTuple, - pcmcia_parse_tuple(link->handle, &tuple, parse)); + pcmcia_parse_tuple(link, &tuple, parse)); if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; @@ -650,10 +631,10 @@ static int prism2_config(dev_link_t *link) } if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; /* Do we need to allocate an interrupt? */ @@ -695,19 +676,19 @@ static int prism2_config(dev_link_t *link) /* This reserves IO space but doesn't actually enable it */ CFG_CHECK2(RequestIO, - pcmcia_request_io(link->handle, &link->io)); + pcmcia_request_io(link, &link->io)); /* This configuration table entry is OK */ break; next_entry: CS_CHECK(GetNextTuple, - pcmcia_get_next_tuple(link->handle, &tuple)); + pcmcia_get_next_tuple(link, &tuple)); } /* Need to allocate net_device before requesting IRQ handler */ dev = prism2_init_local_data(&prism2_pccard_funcs, 0, - &handle_to_dev(link->handle)); + &handle_to_dev(link)); if (dev == NULL) goto failed; link->priv = dev; @@ -717,7 +698,7 @@ static int prism2_config(dev_link_t *link) local->hw_priv = hw_priv; hw_priv->link = link; strcpy(hw_priv->node.dev_name, dev->name); - link->dev = &hw_priv->node; + link->dev_node = &hw_priv->node; /* * Allocate an interrupt line. Note that this does not assign a @@ -730,7 +711,7 @@ static int prism2_config(dev_link_t *link) link->irq.Handler = prism2_interrupt; link->irq.Instance = dev; CS_CHECK(RequestIRQ, - pcmcia_request_irq(link->handle, &link->irq)); + pcmcia_request_irq(link, &link->irq)); } /* @@ -739,18 +720,17 @@ static int prism2_config(dev_link_t *link) * card and host interface into "Memory and IO" mode. */ CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link->handle, &link->conf)); + pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; /* Finally, report what we've done */ - printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", - dev_info, link->conf.ConfigIndex, - link->conf.Vcc / 10, link->conf.Vcc % 10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1 / 10, - link->conf.Vpp1 % 10); + printk(KERN_INFO "%s: index 0x%02x: ", + dev_info, link->conf.ConfigIndex); + if (link->conf.Vpp) + printk(", Vpp %d.%d", link->conf.Vpp / 10, + link->conf.Vpp % 10); if (link->conf.Attributes & CONF_ENABLE_IRQ) printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) @@ -761,9 +741,6 @@ static int prism2_config(dev_link_t *link) link->io.BasePort2+link->io.NumPorts2-1); printk("\n"); - link->state |= DEV_CONFIG; - link->state &= ~DEV_CONFIG_PENDING; - local->shutdown = 0; sandisk_enable_wireless(dev); @@ -778,7 +755,7 @@ static int prism2_config(dev_link_t *link) return ret; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: kfree(parse); @@ -790,7 +767,7 @@ static int prism2_config(dev_link_t *link) static void prism2_release(u_long arg) { - dev_link_t *link = (dev_link_t *)arg; + struct pcmcia_device *link = (struct pcmcia_device *)arg; PDEBUG(DEBUG_FLOW, "prism2_release\n"); @@ -799,71 +776,54 @@ static void prism2_release(u_long arg) struct hostap_interface *iface; iface = netdev_priv(dev); - if (link->state & DEV_CONFIG) - prism2_hw_shutdown(dev, 0); + prism2_hw_shutdown(dev, 0); iface->local->shutdown = 1; } - if (link->win) - pcmcia_release_window(link->win); - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - if (link->irq.AssignedIRQ) - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; - + pcmcia_disable_device(link); PDEBUG(DEBUG_FLOW, "release - done\n"); } -static int hostap_cs_suspend(struct pcmcia_device *p_dev) +static int hostap_cs_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = (struct net_device *) link->priv; int dev_open = 0; + struct hostap_interface *iface = NULL; + + if (dev) + iface = netdev_priv(dev); PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); - - link->state |= DEV_SUSPEND; - - if (link->state & DEV_CONFIG) { - struct hostap_interface *iface = netdev_priv(dev); - if (iface && iface->local) - dev_open = iface->local->num_dev_open > 0; - if (dev_open) { - netif_stop_queue(dev); - netif_device_detach(dev); - } - prism2_suspend(dev); - pcmcia_release_configuration(link->handle); + if (iface && iface->local) + dev_open = iface->local->num_dev_open > 0; + if (dev_open) { + netif_stop_queue(dev); + netif_device_detach(dev); } + prism2_suspend(dev); return 0; } -static int hostap_cs_resume(struct pcmcia_device *p_dev) +static int hostap_cs_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = (struct net_device *) link->priv; int dev_open = 0; + struct hostap_interface *iface = NULL; + + if (dev) + iface = netdev_priv(dev); PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - struct hostap_interface *iface = netdev_priv(dev); - if (iface && iface->local) - dev_open = iface->local->num_dev_open > 0; + if (iface && iface->local) + dev_open = iface->local->num_dev_open > 0; - pcmcia_request_configuration(link->handle, &link->conf); - - prism2_hw_shutdown(dev, 1); - prism2_hw_config(dev, dev_open ? 0 : 1); - if (dev_open) { - netif_device_attach(dev); - netif_start_queue(dev); - } + prism2_hw_shutdown(dev, 1); + prism2_hw_config(dev, dev_open ? 0 : 1); + if (dev_open) { + netif_device_attach(dev); + netif_start_queue(dev); } return 0; @@ -930,7 +890,7 @@ static struct pcmcia_driver hostap_driver = { .drv = { .name = "hostap_cs", }, - .probe = prism2_attach, + .probe = hostap_cs_probe, .remove = prism2_detach, .owner = THIS_MODULE, .id_table = hostap_cs_ids, diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 9dce522526c5..bca89cff85a6 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -5573,8 +5573,7 @@ static void ipw_adhoc_create(struct ipw_priv *priv, case IEEE80211_52GHZ_BAND: network->mode = IEEE_A; i = ieee80211_channel_to_index(priv->ieee, priv->channel); - if (i == -1) - BUG(); + BUG_ON(i == -1); if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { IPW_WARNING("Overriding invalid channel\n"); priv->channel = geo->a[0].channel; @@ -5587,8 +5586,7 @@ static void ipw_adhoc_create(struct ipw_priv *priv, else network->mode = IEEE_B; i = ieee80211_channel_to_index(priv->ieee, priv->channel); - if (i == -1) - BUG(); + BUG_ON(i == -1); if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) { IPW_WARNING("Overriding invalid channel\n"); priv->channel = geo->bg[0].channel; @@ -6715,8 +6713,7 @@ static int ipw_qos_association(struct ipw_priv *priv, switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: - if (!(network->capability & WLAN_CAPABILITY_IBSS)) - BUG(); + BUG_ON(!(network->capability & WLAN_CAPABILITY_IBSS)); qos_data = &ibss_data; break; diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 75ce6ddb0cf5..9343d970537b 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -190,8 +190,8 @@ module_param(mem_speed, int, 0); /*====================================================================*/ /* PCMCIA (Card Services) related functions */ -static void netwave_release(dev_link_t *link); /* Card removal */ -static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card +static void netwave_release(struct pcmcia_device *link); /* Card removal */ +static int netwave_pcmcia_config(struct pcmcia_device *arg); /* Runs after card insertion */ static void netwave_detach(struct pcmcia_device *p_dev); /* Destroy instance */ @@ -221,10 +221,10 @@ static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); /* - A dev_link_t structure has fields for most things that are needed + A struct pcmcia_device structure has fields for most things that are needed to keep track of a socket, but there will usually be some device specific information that also needs to be kept track of. The - 'priv' pointer in a dev_link_t structure can be used to point to + 'priv' pointer in a struct pcmcia_device structure can be used to point to a device-specific private data structure, like this. A driver needs to provide a dev_node_t structure for each device @@ -232,7 +232,7 @@ static void set_multicast_list(struct net_device *dev); example, ethernet cards, modems). In other cases, there may be many actual or logical devices (SCSI adapters, memory cards with multiple partitions). The dev_node_t structures need to be kept - in a linked list starting at the 'dev' field of a dev_link_t + in a linked list starting at the 'dev' field of a struct pcmcia_device structure. We allocate them in the card's private data structure, because they generally can't be allocated dynamically. */ @@ -268,7 +268,7 @@ struct site_survey { }; typedef struct netwave_private { - dev_link_t link; + struct pcmcia_device *p_dev; spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ dev_node_t node; u_char __iomem *ramBase; @@ -376,20 +376,19 @@ static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev) * configure the card at this point -- we wait until we receive a * card insertion event. */ -static int netwave_attach(struct pcmcia_device *p_dev) +static int netwave_probe(struct pcmcia_device *link) { - dev_link_t *link; struct net_device *dev; netwave_private *priv; DEBUG(0, "netwave_attach()\n"); - /* Initialize the dev_link_t structure */ + /* Initialize the struct pcmcia_device structure */ dev = alloc_etherdev(sizeof(netwave_private)); if (!dev) return -ENOMEM; priv = netdev_priv(dev); - link = &priv->link; + priv->p_dev = link; link->priv = dev; /* The io structure describes IO port mapping */ @@ -406,7 +405,6 @@ static int netwave_attach(struct pcmcia_device *p_dev) /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; @@ -430,13 +428,7 @@ static int netwave_attach(struct pcmcia_device *p_dev) dev->stop = &netwave_close; link->irq.Instance = dev; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - netwave_pcmcia_config( link); - - return 0; + return netwave_pcmcia_config( link); } /* netwave_attach */ /* @@ -447,17 +439,15 @@ static int netwave_attach(struct pcmcia_device *p_dev) * structures are freed. Otherwise, the structures will be freed * when the device is released. */ -static void netwave_detach(struct pcmcia_device *p_dev) +static void netwave_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "netwave_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) - netwave_release(link); + netwave_release(link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); free_netdev(dev); @@ -743,8 +733,7 @@ static const struct iw_handler_def netwave_handler_def = #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void netwave_pcmcia_config(dev_link_t *link) { - client_handle_t handle = link->handle; +static int netwave_pcmcia_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; netwave_private *priv = netdev_priv(dev); tuple_t tuple; @@ -766,15 +755,12 @@ static void netwave_pcmcia_config(dev_link_t *link) { tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - /* * Try allocating IO ports. This tries a few fixed addresses. * If you want, you can also read the card's config table to @@ -782,11 +768,11 @@ static void netwave_pcmcia_config(dev_link_t *link) { */ for (i = j = 0x0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); goto failed; } @@ -794,16 +780,16 @@ static void netwave_pcmcia_config(dev_link_t *link) { * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); /* * This actually configures the PCMCIA socket -- setting up * the I/O windows and the interrupt mapping. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); /* - * Allocate a 32K memory window. Note that the dev_link_t + * Allocate a 32K memory window. Note that the struct pcmcia_device * structure provides space for one window handle -- if your * device needs several windows, you'll need to keep track of * the handles in your private data structure, dev->priv. @@ -813,7 +799,7 @@ static void netwave_pcmcia_config(dev_link_t *link) { req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE; req.Base = 0; req.Size = 0x8000; req.AccessSpeed = mem_speed; - CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); + CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); mem.CardOffset = 0x20000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); @@ -823,7 +809,7 @@ static void netwave_pcmcia_config(dev_link_t *link) { dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + SET_NETDEV_DEV(dev, &handle_to_dev(link)); if (register_netdev(dev) != 0) { printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n"); @@ -831,8 +817,7 @@ static void netwave_pcmcia_config(dev_link_t *link) { } strcpy(priv->node.dev_name, dev->name); - link->dev = &priv->node; - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &priv->node; /* Reset card before reading physical address */ netwave_doreset(dev->base_addr, ramBase); @@ -852,12 +837,13 @@ static void netwave_pcmcia_config(dev_link_t *link) { printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", get_uint16(ramBase + NETWAVE_EREG_ARW), get_uint16(ramBase + NETWAVE_EREG_ARW+2)); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: netwave_release(link); + return -ENODEV; } /* netwave_pcmcia_config */ /* @@ -867,52 +853,35 @@ failed: * device, and release the PCMCIA configuration. If the device is * still open, this will be postponed until it is closed. */ -static void netwave_release(dev_link_t *link) +static void netwave_release(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - netwave_private *priv = netdev_priv(dev); + struct net_device *dev = link->priv; + netwave_private *priv = netdev_priv(dev); - DEBUG(0, "netwave_release(0x%p)\n", link); + DEBUG(0, "netwave_release(0x%p)\n", link); - /* Don't bother checking to see if these succeed or not */ - if (link->win) { - iounmap(priv->ramBase); - pcmcia_release_window(link->win); - } - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); + if (link->win) + iounmap(priv->ramBase); } -static int netwave_suspend(struct pcmcia_device *p_dev) +static int netwave_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } + if (link->open) + netif_device_detach(dev); return 0; } -static int netwave_resume(struct pcmcia_device *p_dev) +static int netwave_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - netwave_reset(dev); - netif_device_attach(dev); - } + if (link->open) { + netwave_reset(dev); + netif_device_attach(dev); } return 0; @@ -1119,7 +1088,7 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs u_char __iomem *ramBase; struct net_device *dev = (struct net_device *)dev_id; struct netwave_private *priv = netdev_priv(dev); - dev_link_t *link = &priv->link; + struct pcmcia_device *link = priv->p_dev; int i; if (!netif_device_present(dev)) @@ -1138,7 +1107,7 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs status = inb(iobase + NETWAVE_REG_ASR); - if (!DEV_OK(link)) { + if (!pcmcia_dev_present(link)) { DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x " "from removed or suspended card!\n", status); break; @@ -1373,11 +1342,11 @@ static int netwave_rx(struct net_device *dev) static int netwave_open(struct net_device *dev) { netwave_private *priv = netdev_priv(dev); - dev_link_t *link = &priv->link; + struct pcmcia_device *link = priv->p_dev; DEBUG(1, "netwave_open: starting.\n"); - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; link->open++; @@ -1390,7 +1359,7 @@ static int netwave_open(struct net_device *dev) { static int netwave_close(struct net_device *dev) { netwave_private *priv = netdev_priv(dev); - dev_link_t *link = &priv->link; + struct pcmcia_device *link = priv->p_dev; DEBUG(1, "netwave_close: finishing.\n"); @@ -1411,7 +1380,7 @@ static struct pcmcia_driver netwave_driver = { .drv = { .name = "netwave_cs", }, - .probe = netwave_attach, + .probe = netwave_probe, .remove = netwave_detach, .id_table = netwave_ids, .suspend = netwave_suspend, diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index ec6f2a48895b..434f7d7ad841 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -49,7 +49,7 @@ MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket /* PCMCIA specific device information (goes in the card field of * struct orinoco_private */ struct orinoco_pccard { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; /* Used to handle hard reset */ @@ -63,8 +63,8 @@ struct orinoco_pccard { /* Function prototypes */ /********************************************************************/ -static void orinoco_cs_config(dev_link_t *link); -static void orinoco_cs_release(dev_link_t *link); +static int orinoco_cs_config(struct pcmcia_device *link); +static void orinoco_cs_release(struct pcmcia_device *link); static void orinoco_cs_detach(struct pcmcia_device *p_dev); /********************************************************************/ @@ -75,13 +75,13 @@ static int orinoco_cs_hard_reset(struct orinoco_private *priv) { struct orinoco_pccard *card = priv->card; - dev_link_t *link = &card->link; + struct pcmcia_device *link = card->p_dev; int err; /* We need atomic ops here, because we're not holding the lock */ set_bit(0, &card->hard_reset_in_progress); - err = pcmcia_reset_card(link->handle, NULL); + err = pcmcia_reset_card(link, NULL); if (err) return err; @@ -104,12 +104,11 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) * configure the card at this point -- we wait until we receive a card * insertion event. */ static int -orinoco_cs_attach(struct pcmcia_device *p_dev) +orinoco_cs_probe(struct pcmcia_device *link) { struct net_device *dev; struct orinoco_private *priv; struct orinoco_pccard *card; - dev_link_t *link; dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); if (! dev) @@ -118,7 +117,7 @@ orinoco_cs_attach(struct pcmcia_device *p_dev) card = priv->card; /* Link both structures together */ - link = &card->link; + card->p_dev = link; link->priv = dev; /* Interrupt setup */ @@ -135,16 +134,7 @@ orinoco_cs_attach(struct pcmcia_device *p_dev) link->conf.Attributes = 0; link->conf.IntType = INT_MEMORY_AND_IO; - /* Register with Card Services */ - link->next = NULL; - - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - orinoco_cs_config(link); - - return 0; + return orinoco_cs_config(link); } /* orinoco_cs_attach */ /* @@ -153,16 +143,14 @@ orinoco_cs_attach(struct pcmcia_device *p_dev) * are freed. Otherwise, the structures will be freed when the device * is released. */ -static void orinoco_cs_detach(struct pcmcia_device *p_dev) +static void orinoco_cs_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - if (link->state & DEV_CONFIG) - orinoco_cs_release(link); + orinoco_cs_release(link); - DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); - if (link->dev) { + DEBUG(0, PFX "detach: link=%p link->dev_node=%p\n", link, link->dev_node); + if (link->dev_node) { DEBUG(0, PFX "About to unregister net device %p\n", dev); unregister_netdev(dev); @@ -180,11 +168,10 @@ static void orinoco_cs_detach(struct pcmcia_device *p_dev) last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; \ } while (0) -static void -orinoco_cs_config(dev_link_t *link) +static int +orinoco_cs_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; - client_handle_t handle = link->handle; struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; @@ -196,7 +183,7 @@ orinoco_cs_config(dev_link_t *link) cisparse_t parse; void __iomem *mem; - CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info)); + CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info)); /* * This reads the card's CONFIG tuple to find its @@ -207,19 +194,15 @@ orinoco_cs_config(dev_link_t *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; + pcmcia_get_configuration_info(link, &conf)); /* * In this loop, we scan the CIS for configuration table @@ -236,13 +219,13 @@ orinoco_cs_config(dev_link_t *link) * implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_cftable_entry_t dflt = { .index = 0 }; - if ( (pcmcia_get_tuple_data(handle, &tuple) != 0) - || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0)) + if ( (pcmcia_get_tuple_data(link, &tuple) != 0) + || (pcmcia_parse_tuple(link, &tuple, &parse) != 0)) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) @@ -274,10 +257,10 @@ orinoco_cs_config(dev_link_t *link) } if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; /* Do we need to allocate an interrupt? */ @@ -307,7 +290,7 @@ orinoco_cs_config(dev_link_t *link) } /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; } @@ -317,9 +300,8 @@ orinoco_cs_config(dev_link_t *link) break; next_entry: - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - last_ret = pcmcia_get_next_tuple(handle, &tuple); + pcmcia_disable_device(link); + last_ret = pcmcia_get_next_tuple(link, &tuple); if (last_ret == CS_NO_MORE_ITEMS) { printk(KERN_ERR PFX "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " @@ -333,7 +315,7 @@ orinoco_cs_config(dev_link_t *link) * a handler to the interrupt, unless the 'Handler' member of * the irq structure is initialized. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); /* We initialize the hermes structure before completing PCMCIA * configuration just in case the interrupt handler gets @@ -350,7 +332,7 @@ orinoco_cs_config(dev_link_t *link) * card and host interface into "Memory and IO" mode. */ CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link->handle, &link->conf)); + pcmcia_request_configuration(link, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; @@ -358,7 +340,7 @@ orinoco_cs_config(dev_link_t *link) SET_MODULE_OWNER(dev); card->node.major = card->node.minor = 0; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + SET_NETDEV_DEV(dev, &handle_to_dev(link)); /* Tell the stack we exist */ if (register_netdev(dev) != 0) { printk(KERN_ERR PFX "register_netdev() failed\n"); @@ -366,20 +348,18 @@ orinoco_cs_config(dev_link_t *link) } /* At this point, the dev_node_t structure(s) needs to be - * initialized and arranged in a linked list at link->dev. */ + * initialized and arranged in a linked list at link->dev_node. */ strcpy(card->node.dev_name, dev->name); - link->dev = &card->node; /* link->dev being non-NULL is also + link->dev_node = &card->node; /* link->dev_node being non-NULL is also used to indicate that the net_device has been registered */ - link->state &= ~DEV_CONFIG_PENDING; /* Finally, report what we've done */ - printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d", - dev->name, link->conf.ConfigIndex, - link->conf.Vcc / 10, link->conf.Vcc % 10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1 / 10, - link->conf.Vpp1 % 10); + printk(KERN_DEBUG "%s: index 0x%02x: ", + dev->name, link->conf.ConfigIndex); + if (link->conf.Vpp) + printk(", Vpp %d.%d", link->conf.Vpp / 10, + link->conf.Vpp % 10); printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) printk(", io 0x%04x-0x%04x", link->io.BasePort1, @@ -389,13 +369,14 @@ orinoco_cs_config(dev_link_t *link) link->io.BasePort2 + link->io.NumPorts2 - 1); printk("\n"); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: orinoco_cs_release(link); + return -ENODEV; } /* orinoco_cs_config */ /* @@ -404,7 +385,7 @@ orinoco_cs_config(dev_link_t *link) * still open, this will be postponed until it is closed. */ static void -orinoco_cs_release(dev_link_t *link) +orinoco_cs_release(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); @@ -416,88 +397,68 @@ orinoco_cs_release(dev_link_t *link) priv->hw_unavailable++; spin_unlock_irqrestore(&priv->lock, flags); - /* Don't bother checking to see if these succeed or not */ - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - if (link->irq.AssignedIRQ) - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); if (priv->hw.iobase) ioport_unmap(priv->hw.iobase); } /* orinoco_cs_release */ -static int orinoco_cs_suspend(struct pcmcia_device *p_dev) +static int orinoco_cs_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; int err = 0; unsigned long flags; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - /* This is probably racy, but I can't think of - a better way, short of rewriting the PCMCIA - layer to not suck :-( */ - if (! test_bit(0, &card->hard_reset_in_progress)) { - spin_lock_irqsave(&priv->lock, flags); + /* This is probably racy, but I can't think of + a better way, short of rewriting the PCMCIA + layer to not suck :-( */ + if (! test_bit(0, &card->hard_reset_in_progress)) { + spin_lock_irqsave(&priv->lock, flags); - err = __orinoco_down(dev); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: Error %d downing interface\n", + dev->name, err); - netif_device_detach(dev); - priv->hw_unavailable++; + netif_device_detach(dev); + priv->hw_unavailable++; - spin_unlock_irqrestore(&priv->lock, flags); - } - - pcmcia_release_configuration(link->handle); + spin_unlock_irqrestore(&priv->lock, flags); } return 0; } -static int orinoco_cs_resume(struct pcmcia_device *p_dev) +static int orinoco_cs_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; int err = 0; unsigned long flags; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - /* FIXME: should we double check that this is - * the same card as we had before */ - pcmcia_request_configuration(link->handle, &link->conf); - - if (! test_bit(0, &card->hard_reset_in_progress)) { - err = orinoco_reinit_firmware(dev); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - return -EIO; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - priv->hw_unavailable--; - - if (priv->open && ! priv->hw_unavailable) { - err = __orinoco_up(dev); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", - dev->name, err); - } - - spin_unlock_irqrestore(&priv->lock, flags); + if (! test_bit(0, &card->hard_reset_in_progress)) { + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware\n", + dev->name, err); + return -EIO; } + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_attach(dev); + priv->hw_unavailable--; + + if (priv->open && ! priv->hw_unavailable) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); } return 0; @@ -604,7 +565,7 @@ static struct pcmcia_driver orinoco_driver = { .drv = { .name = DRIVER_NAME, }, - .probe = orinoco_cs_attach, + .probe = orinoco_cs_probe, .remove = orinoco_cs_detach, .id_table = orinoco_cs_ids, .suspend = orinoco_cs_suspend, diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 7880d8c31aad..879eb427607c 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -90,8 +90,8 @@ module_param(pc_debug, int, 0); #define DEBUG(n, args...) #endif /** Prototypes based on PCMCIA skeleton driver *******************************/ -static void ray_config(dev_link_t *link); -static void ray_release(dev_link_t *link); +static int ray_config(struct pcmcia_device *link); +static void ray_release(struct pcmcia_device *link); static void ray_detach(struct pcmcia_device *p_dev); /***** Prototypes indicated by device structure ******************************/ @@ -190,20 +190,17 @@ static int bc; static char *phy_addr = NULL; -/* A linked list of "instances" of the ray device. Each actual - PCMCIA card corresponds to one device instance, and is described - by one dev_link_t structure (defined in ds.h). -*/ -static dev_link_t *dev_list = NULL; - -/* A dev_link_t structure has fields for most things that are needed +/* A struct pcmcia_device structure has fields for most things that are needed to keep track of a socket, but there will usually be some device specific information that also needs to be kept track of. The - 'priv' pointer in a dev_link_t structure can be used to point to + 'priv' pointer in a struct pcmcia_device structure can be used to point to a device-specific private data structure, like this. */ static unsigned int ray_mem_speed = 500; +/* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */ +static struct pcmcia_device *this_device = NULL; + MODULE_AUTHOR("Corey Thomas "); MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver"); MODULE_LICENSE("GPL"); @@ -306,56 +303,46 @@ static char rcsid[] = "Raylink/WebGear wireless LAN - Corey priv; - - memset(link, 0, sizeof(struct dev_link_t)); + local->finder = p_dev; /* The io structure describes IO port mapping. None used here */ - link->io.NumPorts1 = 0; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = 5; + p_dev->io.NumPorts1 = 0; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = 5; /* Interrupt setup. For PCMCIA, driver takes what's given */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = &ray_interrupt; + p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.Handler = &ray_interrupt; /* General socket configuration */ - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; + p_dev->conf.Attributes = CONF_ENABLE_IRQ; + p_dev->conf.IntType = INT_MEMORY_AND_IO; + p_dev->conf.ConfigIndex = 1; + p_dev->conf.Present = PRESENT_OPTION; - link->priv = dev; - link->irq.Instance = dev; + p_dev->priv = dev; + p_dev->irq.Instance = dev; - local->finder = link; + local->finder = p_dev; local->card_status = CARD_INSERTED; local->authentication_state = UNAUTHENTICATED; local->num_multi = 0; - DEBUG(2,"ray_attach link = %p, dev = %p, local = %p, intr = %p\n", - link,dev,local,&ray_interrupt); + DEBUG(2,"ray_attach p_dev = %p, dev = %p, local = %p, intr = %p\n", + p_dev,dev,local,&ray_interrupt); /* Raylink entries in the device structure */ dev->hard_start_xmit = &ray_dev_start_xmit; @@ -379,16 +366,10 @@ static int ray_attach(struct pcmcia_device *p_dev) init_timer(&local->timer); - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - ray_config(link); - - return 0; + this_device = p_dev; + return ray_config(p_dev); fail_alloc_dev: - kfree(link); return -ENOMEM; } /* ray_attach */ /*============================================================================= @@ -397,37 +378,25 @@ fail_alloc_dev: structures are freed. Otherwise, the structures will be freed when the device is released. =============================================================================*/ -static void ray_detach(struct pcmcia_device *p_dev) +static void ray_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - dev_link_t **linkp; struct net_device *dev; ray_dev_t *local; DEBUG(1, "ray_detach(0x%p)\n", link); - - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) break; - if (*linkp == NULL) - return; + this_device = NULL; dev = link->priv; - if (link->state & DEV_CONFIG) { - ray_release(link); + ray_release(link); - local = (ray_dev_t *)dev->priv; - del_timer(&local->timer); - } + local = (ray_dev_t *)dev->priv; + del_timer(&local->timer); - /* Unlink device structure, free pieces */ - *linkp = link->next; if (link->priv) { - if (link->dev) unregister_netdev(dev); + if (link->dev_node) unregister_netdev(dev); free_netdev(dev); } - kfree(link); DEBUG(2,"ray_cs ray_detach ending\n"); } /* ray_detach */ /*============================================================================= @@ -438,9 +407,8 @@ static void ray_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) #define MAX_TUPLE_SIZE 128 -static void ray_config(dev_link_t *link) +static int ray_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; tuple_t tuple; cisparse_t parse; int last_fn = 0, last_ret = 0; @@ -455,48 +423,45 @@ static void ray_config(dev_link_t *link) /* This reads the card's CONFIG tuple to find its configuration regs */ tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = buf; tuple.TupleDataMax = MAX_TUPLE_SIZE; tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* Determine card type and firmware version */ buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0; tuple.DesiredTuple = CISTPL_VERS_1; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = buf; tuple.TupleDataMax = MAX_TUPLE_SIZE; tuple.TupleOffset = 2; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); for (i=0; istate |= DEV_CONFIG; - /* Now allocate an interrupt line. Note that this does not actually assign a handler to the interrupt. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); dev->irq = link->irq.AssignedIRQ; /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); /*** Set up 32k window for shared memory (transmit and control) ************/ req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; req.Base = 0; req.Size = 0x8000; req.AccessSpeed = ray_mem_speed; - CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &link->win)); + CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win)); mem.CardOffset = 0x0000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem)); local->sram = ioremap(req.Base,req.Size); @@ -506,7 +471,7 @@ static void ray_config(dev_link_t *link) req.Base = 0; req.Size = 0x4000; req.AccessSpeed = ray_mem_speed; - CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->rmem_handle)); + CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &local->rmem_handle)); mem.CardOffset = 0x8000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem)); local->rmem = ioremap(req.Base,req.Size); @@ -516,7 +481,7 @@ static void ray_config(dev_link_t *link) req.Base = 0; req.Size = 0x1000; req.AccessSpeed = ray_mem_speed; - CS_CHECK(RequestWindow, pcmcia_request_window(&link->handle, &req, &local->amem_handle)); + CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &local->amem_handle)); mem.CardOffset = 0x0000; mem.Page = 0; CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem)); local->amem = ioremap(req.Base,req.Size); @@ -526,32 +491,32 @@ static void ray_config(dev_link_t *link) DEBUG(3,"ray_config amem=%p\n",local->amem); if (ray_init(dev) < 0) { ray_release(link); - return; + return -ENODEV; } - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + SET_NETDEV_DEV(dev, &handle_to_dev(link)); i = register_netdev(dev); if (i != 0) { printk("ray_config register_netdev() failed\n"); ray_release(link); - return; + return i; } strcpy(local->node.dev_name, dev->name); - link->dev = &local->node; + link->dev_node = &local->node; - link->state &= ~DEV_CONFIG_PENDING; printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ", dev->name, dev->irq); for (i = 0; i < 6; i++) printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n")); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); ray_release(link); + return -ENODEV; } /* ray_config */ static inline struct ccs __iomem *ccs_base(ray_dev_t *dev) @@ -578,9 +543,9 @@ static int ray_init(struct net_device *dev) UCHAR *p; struct ccs __iomem *pccs; ray_dev_t *local = (ray_dev_t *)dev->priv; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; DEBUG(1, "ray_init(0x%p)\n", dev); - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(0,"ray_init - device not present\n"); return -1; } @@ -640,10 +605,10 @@ static int dl_startup_params(struct net_device *dev) int ccsindex; ray_dev_t *local = (ray_dev_t *)dev->priv; struct ccs __iomem *pccs; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; DEBUG(1,"dl_startup_params entered\n"); - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs dl_startup_params - device not present\n"); return -1; } @@ -747,9 +712,9 @@ static void verify_dl_startup(u_long data) ray_dev_t *local = (ray_dev_t *)data; struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs; UCHAR status; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs verify_dl_startup - device not present\n"); return; } @@ -787,8 +752,8 @@ static void start_net(u_long data) ray_dev_t *local = (ray_dev_t *)data; struct ccs __iomem *pccs; int ccsindex; - dev_link_t *link = local->finder; - if (!(link->state & DEV_PRESENT)) { + struct pcmcia_device *link = local->finder; + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs start_net - device not present\n"); return; } @@ -814,9 +779,9 @@ static void join_net(u_long data) struct ccs __iomem *pccs; int ccsindex; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs join_net - device not present\n"); return; } @@ -840,7 +805,7 @@ static void join_net(u_long data) device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed. =============================================================================*/ -static void ray_release(dev_link_t *link) +static void ray_release(struct pcmcia_device *link) { struct net_device *dev = link->priv; ray_dev_t *local = dev->priv; @@ -849,56 +814,38 @@ static void ray_release(dev_link_t *link) DEBUG(1, "ray_release(0x%p)\n", link); del_timer(&local->timer); - link->state &= ~DEV_CONFIG; iounmap(local->sram); iounmap(local->rmem); iounmap(local->amem); /* Do bother checking to see if these succeed or not */ - i = pcmcia_release_window(link->win); - if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(link->win) ret = %x\n",i); i = pcmcia_release_window(local->amem_handle); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i); i = pcmcia_release_window(local->rmem_handle); if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i); - i = pcmcia_release_configuration(link->handle); - if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseConfiguration ret = %x\n",i); - i = pcmcia_release_irq(link->handle, &link->irq); - if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i); + pcmcia_disable_device(link); DEBUG(2,"ray_release ending\n"); } -static int ray_suspend(struct pcmcia_device *p_dev) +static int ray_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - - pcmcia_release_configuration(link->handle); - } - + if (link->open) + netif_device_detach(dev); return 0; } -static int ray_resume(struct pcmcia_device *p_dev) +static int ray_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - ray_reset(dev); - netif_device_attach(dev); - } - } + if (link->open) { + ray_reset(dev); + netif_device_attach(dev); + } return 0; } @@ -910,10 +857,10 @@ int ray_dev_init(struct net_device *dev) int i; #endif /* RAY_IMMEDIATE_INIT */ ray_dev_t *local = dev->priv; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; DEBUG(1,"ray_dev_init(dev=%p)\n",dev); - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_dev_init - device not present\n"); return -1; } @@ -944,10 +891,10 @@ int ray_dev_init(struct net_device *dev) static int ray_dev_config(struct net_device *dev, struct ifmap *map) { ray_dev_t *local = dev->priv; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; /* Dummy routine to satisfy device structure */ DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map); - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_dev_config - device not present\n"); return -1; } @@ -958,10 +905,10 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map) static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev) { ray_dev_t *local = dev->priv; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; short length = skb->len; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_dev_start_xmit - device not present\n"); return -1; } @@ -1570,7 +1517,7 @@ static int ray_commit(struct net_device *dev, static iw_stats * ray_get_wireless_stats(struct net_device * dev) { ray_dev_t * local = (ray_dev_t *) dev->priv; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; struct status __iomem *p = local->sram + STATUS_BASE; if(local == (ray_dev_t *) NULL) @@ -1588,7 +1535,7 @@ static iw_stats * ray_get_wireless_stats(struct net_device * dev) } #endif /* WIRELESS_SPY */ - if((link->state & DEV_PRESENT)) { + if(pcmcia_dev_present(link)) { local->wstats.qual.noise = readb(&p->rxnoise); local->wstats.qual.updated |= 4; } @@ -1657,18 +1604,14 @@ static const struct iw_handler_def ray_handler_def = /*===========================================================================*/ static int ray_open(struct net_device *dev) { - dev_link_t *link; ray_dev_t *local = (ray_dev_t *)dev->priv; + struct pcmcia_device *link; + link = local->finder; DEBUG(1, "ray_open('%s')\n", dev->name); - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (!DEV_OK(link)) { - return -ENODEV; - } - - if (link->open == 0) local->num_multi = 0; + if (link->open == 0) + local->num_multi = 0; link->open++; /* If the card is not started, time to start it ! - Jean II */ @@ -1695,15 +1638,12 @@ static int ray_open(struct net_device *dev) /*===========================================================================*/ static int ray_dev_close(struct net_device *dev) { - dev_link_t *link; + ray_dev_t *local = (ray_dev_t *)dev->priv; + struct pcmcia_device *link; + link = local->finder; DEBUG(1, "ray_dev_close('%s')\n", dev->name); - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) - return -ENODEV; - link->open--; netif_stop_queue(dev); @@ -1725,9 +1665,9 @@ static void ray_reset(struct net_device *dev) { static int interrupt_ecf(ray_dev_t *local, int ccs) { int i = 50; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs interrupt_ecf - device not present\n"); return -1; } @@ -1752,9 +1692,9 @@ static int get_free_tx_ccs(ray_dev_t *local) { int i; struct ccs __iomem *pccs = ccs_base(local); - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs get_free_tx_ccs - device not present\n"); return ECARDGONE; } @@ -1783,9 +1723,9 @@ static int get_free_ccs(ray_dev_t *local) { int i; struct ccs __iomem *pccs = ccs_base(local); - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs get_free_ccs - device not present\n"); return ECARDGONE; } @@ -1858,9 +1798,9 @@ static int parse_addr(char *in_str, UCHAR *out) static struct net_device_stats *ray_get_stats(struct net_device *dev) { ray_dev_t *local = (ray_dev_t *)dev->priv; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; struct status __iomem *p = local->sram + STATUS_BASE; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs net_device_stats - device not present\n"); return &local->stats; } @@ -1888,12 +1828,12 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev) static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len) { ray_dev_t *local = (ray_dev_t *)dev->priv; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; int ccsindex; int i; struct ccs __iomem *pccs; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_update_parm - device not present\n"); return; } @@ -1925,10 +1865,10 @@ static void ray_update_multi_list(struct net_device *dev, int all) struct ccs __iomem *pccs; int i = 0; ray_dev_t *local = (ray_dev_t *)dev->priv; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; void __iomem *p = local->sram + HOST_TO_ECF_BASE; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_update_multi_list - device not present\n"); return; } @@ -2005,7 +1945,7 @@ static void set_multicast_list(struct net_device *dev) static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = (struct net_device *)dev_id; - dev_link_t *link; + struct pcmcia_device *link; ray_dev_t *local; struct ccs __iomem *pccs; struct rcs __iomem *prcs; @@ -2020,8 +1960,8 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs) DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev); local = (ray_dev_t *)dev->priv; - link = (dev_link_t *)local->finder; - if ( ! (link->state & DEV_PRESENT) || link->state & DEV_SUSPEND ) { + link = (struct pcmcia_device *)local->finder; + if (!pcmcia_dev_present(link)) { DEBUG(2,"ray_cs interrupt from device not present or suspended.\n"); return IRQ_NONE; } @@ -2540,9 +2480,9 @@ static void release_frag_chain(ray_dev_t *local, struct rcs __iomem * prcs) /*===========================================================================*/ static void authenticate(ray_dev_t *local) { - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; DEBUG(0,"ray_cs Starting authentication.\n"); - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs authenticate - device not present\n"); return; } @@ -2606,10 +2546,10 @@ static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs, static void associate(ray_dev_t *local) { struct ccs __iomem *pccs; - dev_link_t *link = local->finder; + struct pcmcia_device *link = local->finder; struct net_device *dev = link->priv; int ccsindex; - if (!(link->state & DEV_PRESENT)) { + if (!(pcmcia_dev_present(link))) { DEBUG(2,"ray_cs associate - device not present\n"); return; } @@ -2689,14 +2629,14 @@ static int ray_cs_proc_read(char *buf, char **start, off_t offset, int len) * eg ifconfig */ int i; - dev_link_t *link; + struct pcmcia_device *link; struct net_device *dev; ray_dev_t *local; UCHAR *p; struct freq_hop_element *pfh; UCHAR c[33]; - link = dev_list; + link = this_device; if (!link) return 0; dev = (struct net_device *)link->priv; @@ -2898,7 +2838,7 @@ static struct pcmcia_driver ray_driver = { .drv = { .name = "ray_cs", }, - .probe = ray_attach, + .probe = ray_probe, .remove = ray_detach, .id_table = ray_ids, .suspend = ray_suspend, @@ -2940,7 +2880,6 @@ static void __exit exit_ray_cs(void) #endif pcmcia_unregister_driver(&ray_driver); - BUG_ON(dev_list != NULL); } /* exit_ray_cs */ module_init(init_ray_cs); diff --git a/drivers/net/wireless/ray_cs.h b/drivers/net/wireless/ray_cs.h index 42660fe64bfd..bd73ebf03340 100644 --- a/drivers/net/wireless/ray_cs.h +++ b/drivers/net/wireless/ray_cs.h @@ -31,7 +31,7 @@ typedef struct ray_dev_t { void __iomem *sram; /* pointer to beginning of shared RAM */ void __iomem *amem; /* pointer to attribute mem window */ void __iomem *rmem; /* pointer to receive buffer window */ - dev_link_t *finder; /* pointer back to dev_link_t for card */ + struct pcmcia_device *finder; /* pointer back to struct pcmcia_device for card */ struct timer_list timer; long tx_ccs_lock; long ccs_lock; diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index 5fa6fbe35bb9..f7b77ce54d7b 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -63,7 +63,7 @@ MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket /* PCMCIA specific device information (goes in the card field of * struct orinoco_private */ struct orinoco_pccard { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; }; @@ -71,8 +71,8 @@ struct orinoco_pccard { /* Function prototypes */ /********************************************************************/ -static void spectrum_cs_config(dev_link_t *link); -static void spectrum_cs_release(dev_link_t *link); +static int spectrum_cs_config(struct pcmcia_device *link); +static void spectrum_cs_release(struct pcmcia_device *link); /********************************************************************/ /* Firmware downloader */ @@ -238,14 +238,14 @@ spectrum_aux_open(hermes_t *hw) * If IDLE is 1, stop the firmware, so that it can be safely rewritten. */ static int -spectrum_reset(dev_link_t *link, int idle) +spectrum_reset(struct pcmcia_device *link, int idle) { int last_ret, last_fn; conf_reg_t reg; u_int save_cor; /* Doing it if hardware is gone is guaranteed crash */ - if (!(link->state & DEV_CONFIG)) + if (pcmcia_dev_present(link)) return -ENODEV; /* Save original COR value */ @@ -253,7 +253,7 @@ spectrum_reset(dev_link_t *link, int idle) reg.Action = CS_READ; reg.Offset = CISREG_COR; CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link->handle, ®)); + pcmcia_access_configuration_register(link, ®)); save_cor = reg.Value; /* Soft-Reset card */ @@ -261,14 +261,14 @@ spectrum_reset(dev_link_t *link, int idle) reg.Offset = CISREG_COR; reg.Value = (save_cor | COR_SOFT_RESET); CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link->handle, ®)); + pcmcia_access_configuration_register(link, ®)); udelay(1000); /* Read CCSR */ reg.Action = CS_READ; reg.Offset = CISREG_CCSR; CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link->handle, ®)); + pcmcia_access_configuration_register(link, ®)); /* * Start or stop the firmware. Memory width bit should be @@ -278,7 +278,7 @@ spectrum_reset(dev_link_t *link, int idle) reg.Offset = CISREG_CCSR; reg.Value = (idle ? HCR_IDLE : HCR_RUN) | (reg.Value & HCR_MEM16); CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link->handle, ®)); + pcmcia_access_configuration_register(link, ®)); udelay(1000); /* Restore original COR configuration index */ @@ -286,12 +286,12 @@ spectrum_reset(dev_link_t *link, int idle) reg.Offset = CISREG_COR; reg.Value = (save_cor & ~COR_SOFT_RESET); CS_CHECK(AccessConfigurationRegister, - pcmcia_access_configuration_register(link->handle, ®)); + pcmcia_access_configuration_register(link, ®)); udelay(1000); return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); return -ENODEV; } @@ -441,7 +441,7 @@ spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block) * care of the PDA - read it and then write it on top of the firmware. */ static int -spectrum_dl_image(hermes_t *hw, dev_link_t *link, +spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link, const unsigned char *image) { int ret; @@ -505,14 +505,13 @@ spectrum_dl_image(hermes_t *hw, dev_link_t *link, * reset on the card, to make sure it's in a sane state. */ static int -spectrum_dl_firmware(hermes_t *hw, dev_link_t *link) +spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link) { int ret; - client_handle_t handle = link->handle; const struct firmware *fw_entry; if (request_firmware(&fw_entry, primary_fw_name, - &handle_to_dev(handle)) == 0) { + &handle_to_dev(link)) == 0) { primsym = fw_entry->data; } else { printk(KERN_ERR PFX "Cannot find firmware: %s\n", @@ -521,7 +520,7 @@ spectrum_dl_firmware(hermes_t *hw, dev_link_t *link) } if (request_firmware(&fw_entry, secondary_fw_name, - &handle_to_dev(handle)) == 0) { + &handle_to_dev(link)) == 0) { secsym = fw_entry->data; } else { printk(KERN_ERR PFX "Cannot find firmware: %s\n", @@ -554,12 +553,12 @@ static int spectrum_cs_hard_reset(struct orinoco_private *priv) { struct orinoco_pccard *card = priv->card; - dev_link_t *link = &card->link; + struct pcmcia_device *link = card->p_dev; int err; if (!hermes_present(&priv->hw)) { /* The firmware needs to be reloaded */ - if (spectrum_dl_firmware(&priv->hw, &card->link) != 0) { + if (spectrum_dl_firmware(&priv->hw, link) != 0) { printk(KERN_ERR PFX "Firmware download failed\n"); err = -ENODEV; } @@ -584,12 +583,11 @@ spectrum_cs_hard_reset(struct orinoco_private *priv) * configure the card at this point -- we wait until we receive a card * insertion event. */ static int -spectrum_cs_attach(struct pcmcia_device *p_dev) +spectrum_cs_probe(struct pcmcia_device *link) { struct net_device *dev; struct orinoco_private *priv; struct orinoco_pccard *card; - dev_link_t *link; dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset); if (! dev) @@ -598,7 +596,7 @@ spectrum_cs_attach(struct pcmcia_device *p_dev) card = priv->card; /* Link both structures together */ - link = &card->link; + card->p_dev = link; link->priv = dev; /* Interrupt setup */ @@ -615,13 +613,7 @@ spectrum_cs_attach(struct pcmcia_device *p_dev) link->conf.Attributes = 0; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - spectrum_cs_config(link); - - return 0; + return spectrum_cs_config(link); } /* spectrum_cs_attach */ /* @@ -630,16 +622,14 @@ spectrum_cs_attach(struct pcmcia_device *p_dev) * are freed. Otherwise, the structures will be freed when the device * is released. */ -static void spectrum_cs_detach(struct pcmcia_device *p_dev) +static void spectrum_cs_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - if (link->state & DEV_CONFIG) - spectrum_cs_release(link); + spectrum_cs_release(link); - DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); - if (link->dev) { + DEBUG(0, PFX "detach: link=%p link->dev_node=%p\n", link, link->dev_node); + if (link->dev_node) { DEBUG(0, PFX "About to unregister net device %p\n", dev); unregister_netdev(dev); @@ -653,11 +643,10 @@ static void spectrum_cs_detach(struct pcmcia_device *p_dev) * device available to the system. */ -static void -spectrum_cs_config(dev_link_t *link) +static int +spectrum_cs_config(struct pcmcia_device *link) { struct net_device *dev = link->priv; - client_handle_t handle = link->handle; struct orinoco_private *priv = netdev_priv(dev); struct orinoco_pccard *card = priv->card; hermes_t *hw = &priv->hw; @@ -669,7 +658,7 @@ spectrum_cs_config(dev_link_t *link) cisparse_t parse; void __iomem *mem; - CS_CHECK(ValidateCIS, pcmcia_validate_cis(handle, &info)); + CS_CHECK(ValidateCIS, pcmcia_validate_cis(link, &info)); /* * This reads the card's CONFIG tuple to find its @@ -680,19 +669,15 @@ spectrum_cs_config(dev_link_t *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; + pcmcia_get_configuration_info(link, &conf)); /* * In this loop, we scan the CIS for configuration table @@ -709,13 +694,13 @@ spectrum_cs_config(dev_link_t *link) * implementation-defined details. */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_cftable_entry_t dflt = { .index = 0 }; - if ( (pcmcia_get_tuple_data(handle, &tuple) != 0) - || (pcmcia_parse_tuple(handle, &tuple, &parse) != 0)) + if ( (pcmcia_get_tuple_data(link, &tuple) != 0) + || (pcmcia_parse_tuple(link, &tuple, &parse) != 0)) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) @@ -747,10 +732,10 @@ spectrum_cs_config(dev_link_t *link) } if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; /* Do we need to allocate an interrupt? */ @@ -780,7 +765,7 @@ spectrum_cs_config(dev_link_t *link) } /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; } @@ -790,9 +775,8 @@ spectrum_cs_config(dev_link_t *link) break; next_entry: - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - last_ret = pcmcia_get_next_tuple(handle, &tuple); + pcmcia_disable_device(link); + last_ret = pcmcia_get_next_tuple(link, &tuple); if (last_ret == CS_NO_MORE_ITEMS) { printk(KERN_ERR PFX "GetNextTuple(): No matching " "CIS configuration. Maybe you need the " @@ -806,7 +790,7 @@ spectrum_cs_config(dev_link_t *link) * a handler to the interrupt, unless the 'Handler' member of * the irq structure is initialized. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); /* We initialize the hermes structure before completing PCMCIA * configuration just in case the interrupt handler gets @@ -823,7 +807,7 @@ spectrum_cs_config(dev_link_t *link) * card and host interface into "Memory and IO" mode. */ CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link->handle, &link->conf)); + pcmcia_request_configuration(link, &link->conf)); /* Ok, we have the configuration, prepare to register the netdev */ dev->base_addr = link->io.BasePort1; @@ -836,7 +820,7 @@ spectrum_cs_config(dev_link_t *link) goto failed; } - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + SET_NETDEV_DEV(dev, &handle_to_dev(link)); /* Tell the stack we exist */ if (register_netdev(dev) != 0) { printk(KERN_ERR PFX "register_netdev() failed\n"); @@ -844,20 +828,18 @@ spectrum_cs_config(dev_link_t *link) } /* At this point, the dev_node_t structure(s) needs to be - * initialized and arranged in a linked list at link->dev. */ + * initialized and arranged in a linked list at link->dev_node. */ strcpy(card->node.dev_name, dev->name); - link->dev = &card->node; /* link->dev being non-NULL is also + link->dev_node = &card->node; /* link->dev_node being non-NULL is also used to indicate that the net_device has been registered */ - link->state &= ~DEV_CONFIG_PENDING; /* Finally, report what we've done */ - printk(KERN_DEBUG "%s: index 0x%02x: Vcc %d.%d", - dev->name, link->conf.ConfigIndex, - link->conf.Vcc / 10, link->conf.Vcc % 10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1 / 10, - link->conf.Vpp1 % 10); + printk(KERN_DEBUG "%s: index 0x%02x: ", + dev->name, link->conf.ConfigIndex); + if (link->conf.Vpp) + printk(", Vpp %d.%d", link->conf.Vpp / 10, + link->conf.Vpp % 10); printk(", irq %d", link->irq.AssignedIRQ); if (link->io.NumPorts1) printk(", io 0x%04x-0x%04x", link->io.BasePort1, @@ -867,13 +849,14 @@ spectrum_cs_config(dev_link_t *link) link->io.BasePort2 + link->io.NumPorts2 - 1); printk("\n"); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: spectrum_cs_release(link); + return -ENODEV; } /* spectrum_cs_config */ /* @@ -882,7 +865,7 @@ spectrum_cs_config(dev_link_t *link) * still open, this will be postponed until it is closed. */ static void -spectrum_cs_release(dev_link_t *link) +spectrum_cs_release(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); @@ -894,64 +877,46 @@ spectrum_cs_release(dev_link_t *link) priv->hw_unavailable++; spin_unlock_irqrestore(&priv->lock, flags); - /* Don't bother checking to see if these succeed or not */ - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - if (link->irq.AssignedIRQ) - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); if (priv->hw.iobase) ioport_unmap(priv->hw.iobase); } /* spectrum_cs_release */ static int -spectrum_cs_suspend(struct pcmcia_device *p_dev) +spectrum_cs_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err = 0; - link->state |= DEV_SUSPEND; /* Mark the device as stopped, to block IO until later */ - if (link->state & DEV_CONFIG) { - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->lock, flags); - err = __orinoco_down(dev); - if (err) - printk(KERN_WARNING "%s: Error %d downing interface\n", - dev->name, err); + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: Error %d downing interface\n", + dev->name, err); - netif_device_detach(dev); - priv->hw_unavailable++; + netif_device_detach(dev); + priv->hw_unavailable++; - spin_unlock_irqrestore(&priv->lock, flags); - - pcmcia_release_configuration(link->handle); - } + spin_unlock_irqrestore(&priv->lock, flags); return 0; } static int -spectrum_cs_resume(struct pcmcia_device *p_dev) +spectrum_cs_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - /* FIXME: should we double check that this is - * the same card as we had before */ - pcmcia_request_configuration(link->handle, &link->conf); - netif_device_attach(dev); - priv->hw_unavailable--; - schedule_work(&priv->reset_work); - } + netif_device_attach(dev); + priv->hw_unavailable--; + schedule_work(&priv->reset_work); + return 0; } @@ -979,7 +944,7 @@ static struct pcmcia_driver orinoco_driver = { .drv = { .name = DRIVER_NAME, }, - .probe = spectrum_cs_attach, + .probe = spectrum_cs_probe, .remove = spectrum_cs_detach, .suspend = spectrum_cs_suspend, .resume = spectrum_cs_resume, diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 98122f3a4bc2..f7724eb2fa7e 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -1005,7 +1005,7 @@ static inline void wv_82593_reconfig(struct net_device * dev) { net_local * lp = netdev_priv(dev); - dev_link_t * link = lp->link; + struct pcmcia_device * link = lp->link; unsigned long flags; /* Arm the flag, will be cleard in wv_82593_config() */ @@ -3744,16 +3744,16 @@ wv_pcmcia_reset(struct net_device * dev) { int i; conf_reg_t reg = { 0, CS_READ, CISREG_COR, 0 }; - dev_link_t * link = ((net_local *)netdev_priv(dev))->link; + struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name); #endif - i = pcmcia_access_configuration_register(link->handle, ®); + i = pcmcia_access_configuration_register(link, ®); if(i != CS_SUCCESS) { - cs_error(link->handle, AccessConfigurationRegister, i); + cs_error(link, AccessConfigurationRegister, i); return FALSE; } @@ -3764,19 +3764,19 @@ wv_pcmcia_reset(struct net_device * dev) reg.Action = CS_WRITE; reg.Value = reg.Value | COR_SW_RESET; - i = pcmcia_access_configuration_register(link->handle, ®); + i = pcmcia_access_configuration_register(link, ®); if(i != CS_SUCCESS) { - cs_error(link->handle, AccessConfigurationRegister, i); + cs_error(link, AccessConfigurationRegister, i); return FALSE; } reg.Action = CS_WRITE; reg.Value = COR_LEVEL_IRQ | COR_CONFIG; - i = pcmcia_access_configuration_register(link->handle, ®); + i = pcmcia_access_configuration_register(link, ®); if(i != CS_SUCCESS) { - cs_error(link->handle, AccessConfigurationRegister, i); + cs_error(link, AccessConfigurationRegister, i); return FALSE; } @@ -3940,9 +3940,8 @@ wv_hw_reset(struct net_device * dev) * (called by wavelan_event()) */ static inline int -wv_pcmcia_config(dev_link_t * link) +wv_pcmcia_config(struct pcmcia_device * link) { - client_handle_t handle = link->handle; tuple_t tuple; cisparse_t parse; struct net_device * dev = (struct net_device *) link->priv; @@ -3965,16 +3964,16 @@ wv_pcmcia_config(dev_link_t * link) { tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - i = pcmcia_get_first_tuple(handle, &tuple); + i = pcmcia_get_first_tuple(link, &tuple); if(i != CS_SUCCESS) break; tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - i = pcmcia_get_tuple_data(handle, &tuple); + i = pcmcia_get_tuple_data(link, &tuple); if(i != CS_SUCCESS) break; - i = pcmcia_parse_tuple(handle, &tuple, &parse); + i = pcmcia_parse_tuple(link, &tuple, &parse); if(i != CS_SUCCESS) break; link->conf.ConfigBase = parse.config.base; @@ -3983,19 +3982,16 @@ wv_pcmcia_config(dev_link_t * link) while(0); if(i != CS_SUCCESS) { - cs_error(link->handle, ParseTuple, i); - link->state &= ~DEV_CONFIG_PENDING; + cs_error(link, ParseTuple, i); return FALSE; } - - /* Configure card */ - link->state |= DEV_CONFIG; + do { - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if(i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); break; } @@ -4003,10 +3999,10 @@ wv_pcmcia_config(dev_link_t * link) * Now allocate an interrupt line. Note that this does not * actually assign a handler to the interrupt. */ - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if(i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); + cs_error(link, RequestIRQ, i); break; } @@ -4015,15 +4011,15 @@ wv_pcmcia_config(dev_link_t * link) * the I/O windows and the interrupt mapping. */ link->conf.ConfigIndex = 1; - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if(i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); + cs_error(link, RequestConfiguration, i); break; } /* - * Allocate a small memory window. Note that the dev_link_t + * Allocate a small memory window. Note that the struct pcmcia_device * structure provides space for one window handle -- if your * device needs several windows, you'll need to keep track of * the handles in your private data structure, link->priv. @@ -4031,10 +4027,10 @@ wv_pcmcia_config(dev_link_t * link) req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; req.Base = req.Size = 0; req.AccessSpeed = mem_speed; - i = pcmcia_request_window(&link->handle, &req, &link->win); + i = pcmcia_request_window(&link, &req, &link->win); if(i != CS_SUCCESS) { - cs_error(link->handle, RequestWindow, i); + cs_error(link, RequestWindow, i); break; } @@ -4046,7 +4042,7 @@ wv_pcmcia_config(dev_link_t * link) i = pcmcia_map_mem_page(link->win, &mem); if(i != CS_SUCCESS) { - cs_error(link->handle, MapMemPage, i); + cs_error(link, MapMemPage, i); break; } @@ -4060,7 +4056,7 @@ wv_pcmcia_config(dev_link_t * link) lp->mem, dev->irq, (u_int) dev->base_addr); #endif - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + SET_NETDEV_DEV(dev, &handle_to_dev(link)); i = register_netdev(dev); if(i != 0) { @@ -4072,7 +4068,6 @@ wv_pcmcia_config(dev_link_t * link) } while(0); /* Humm... Disguised goto !!! */ - link->state &= ~DEV_CONFIG_PENDING; /* If any step failed, release any partially configured state */ if(i != 0) { @@ -4081,7 +4076,7 @@ wv_pcmcia_config(dev_link_t * link) } strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name); - link->dev = &((net_local *) netdev_priv(dev))->node; + link->dev_node = &((net_local *) netdev_priv(dev))->node; #ifdef DEBUG_CONFIG_TRACE printk(KERN_DEBUG "<-wv_pcmcia_config()\n"); @@ -4096,26 +4091,20 @@ wv_pcmcia_config(dev_link_t * link) * still open, this will be postponed until it is closed. */ static void -wv_pcmcia_release(dev_link_t *link) +wv_pcmcia_release(struct pcmcia_device *link) { - struct net_device * dev = (struct net_device *) link->priv; - net_local * lp = netdev_priv(dev); + struct net_device * dev = (struct net_device *) link->priv; + net_local * lp = netdev_priv(dev); #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); + printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link); #endif - /* Don't bother checking to see if these succeed or not */ - iounmap(lp->mem); - pcmcia_release_window(link->win); - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + iounmap(lp->mem); + pcmcia_disable_device(link); #ifdef DEBUG_CONFIG_TRACE - printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); + printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name); #endif } @@ -4479,7 +4468,7 @@ static int wavelan_open(struct net_device * dev) { net_local * lp = netdev_priv(dev); - dev_link_t * link = lp->link; + struct pcmcia_device * link = lp->link; kio_addr_t base = dev->base_addr; #ifdef DEBUG_CALLBACK_TRACE @@ -4533,7 +4522,7 @@ wavelan_open(struct net_device * dev) static int wavelan_close(struct net_device * dev) { - dev_link_t * link = ((net_local *)netdev_priv(dev))->link; + struct pcmcia_device * link = ((net_local *)netdev_priv(dev))->link; kio_addr_t base = dev->base_addr; #ifdef DEBUG_CALLBACK_TRACE @@ -4587,45 +4576,36 @@ wavelan_close(struct net_device * dev) * card insertion event. */ static int -wavelan_attach(struct pcmcia_device *p_dev) +wavelan_probe(struct pcmcia_device *p_dev) { - dev_link_t * link; /* Info for cardmgr */ struct net_device * dev; /* Interface generic data */ net_local * lp; /* Interface specific data */ + int ret; #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "-> wavelan_attach()\n"); #endif - /* Initialize the dev_link_t structure */ - link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) return -ENOMEM; - /* The io structure describes IO port mapping */ - link->io.NumPorts1 = 8; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = 3; + p_dev->io.NumPorts1 = 8; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = 3; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = wavelan_interrupt; + p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.Handler = wavelan_interrupt; /* General socket configuration */ - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - - /* Chain drivers */ - link->next = NULL; + p_dev->conf.Attributes = CONF_ENABLE_IRQ; + p_dev->conf.IntType = INT_MEMORY_AND_IO; /* Allocate the generic data structure */ dev = alloc_etherdev(sizeof(net_local)); - if (!dev) { - kfree(link); + if (!dev) return -ENOMEM; - } - link->priv = link->irq.Instance = dev; + + p_dev->priv = p_dev->irq.Instance = dev; lp = netdev_priv(dev); @@ -4642,7 +4622,6 @@ wavelan_attach(struct pcmcia_device *p_dev) spin_lock_init(&lp->spinlock); /* back links */ - lp->link = link; lp->dev = dev; /* wavelan NET3 callbacks */ @@ -4668,15 +4647,18 @@ wavelan_attach(struct pcmcia_device *p_dev) /* Other specific data */ dev->mtu = WAVELAN_MTU; - link->handle = p_dev; - p_dev->instance = link; + ret = wv_pcmcia_config(p_dev); + if (ret) + return ret; - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - if(wv_pcmcia_config(link) && - wv_hw_config(dev)) - wv_init_info(dev); - else + ret = wv_hw_config(dev); + if (ret) { dev->irq = 0; + pcmcia_disable_device(p_dev); + return ret; + } + + wv_init_info(dev); #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "<- wavelan_attach()\n"); @@ -4693,25 +4675,14 @@ wavelan_attach(struct pcmcia_device *p_dev) * is released. */ static void -wavelan_detach(struct pcmcia_device *p_dev) +wavelan_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); #endif - /* - * If the device is currently configured and active, we won't - * actually delete it yet. Instead, it is marked so that when the - * release() function is called, that will trigger a proper - * detach(). - */ - if(link->state & DEV_CONFIG) - { - /* Some others haven't done their job : give them another chance */ - wv_pcmcia_release(link); - } + /* Some others haven't done their job : give them another chance */ + wv_pcmcia_release(link); /* Free pieces */ if(link->priv) @@ -4720,23 +4691,21 @@ wavelan_detach(struct pcmcia_device *p_dev) /* Remove ourselves from the kernel list of ethernet devices */ /* Warning : can't be called from interrupt, timer or wavelan_close() */ - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - link->dev = NULL; + link->dev_node = NULL; ((net_local *)netdev_priv(dev))->link = NULL; ((net_local *)netdev_priv(dev))->dev = NULL; free_netdev(dev); } - kfree(link); #ifdef DEBUG_CALLBACK_TRACE printk(KERN_DEBUG "<- wavelan_detach()\n"); #endif } -static int wavelan_suspend(struct pcmcia_device *p_dev) +static int wavelan_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device * dev = (struct net_device *) link->priv; /* NB: wavelan_close will be called, but too late, so we are @@ -4748,36 +4717,22 @@ static int wavelan_suspend(struct pcmcia_device *p_dev) /* Stop receiving new messages and wait end of transmission */ wv_ru_stop(dev); + if (link->open) + netif_device_detach(dev); + /* Power down the module */ hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT)); - /* The card is now suspended */ - link->state |= DEV_SUSPEND; - - if(link->state & DEV_CONFIG) - { - if(link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } - return 0; } -static int wavelan_resume(struct pcmcia_device *p_dev) +static int wavelan_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device * dev = (struct net_device *) link->priv; - link->state &= ~DEV_SUSPEND; - if(link->state & DEV_CONFIG) - { - pcmcia_request_configuration(link->handle, &link->conf); - if(link->open) /* If RESET -> True, If RESUME -> False ? */ - { - wv_hw_reset(dev); - netif_device_attach(dev); - } + if (link->open) { + wv_hw_reset(dev); + netif_device_attach(dev); } return 0; @@ -4798,7 +4753,7 @@ static struct pcmcia_driver wavelan_driver = { .drv = { .name = "wavelan_cs", }, - .probe = wavelan_attach, + .probe = wavelan_probe, .remove = wavelan_detach, .id_table = wavelan_ids, .suspend = wavelan_suspend, diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 451f6271dcbc..c65fe7a391ec 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -602,7 +602,7 @@ struct net_local dev_node_t node; /* ???? What is this stuff ???? */ struct net_device * dev; /* Reverse link... */ spinlock_t spinlock; /* Serialize access to the hardware (SMP) */ - dev_link_t * link; /* pcmcia structure */ + struct pcmcia_device * link; /* pcmcia structure */ en_stats stats; /* Ethernet interface statistics */ int nresets; /* Number of hw resets */ u_char configured; /* If it is configured */ @@ -733,9 +733,9 @@ static int static inline void wv_hw_reset(struct net_device *); /* Same, + start receiver unit */ static inline int - wv_pcmcia_config(dev_link_t *); /* Configure the pcmcia interface */ + wv_pcmcia_config(struct pcmcia_device *); /* Configure the pcmcia interface */ static void - wv_pcmcia_release(dev_link_t *);/* Remove a device */ + wv_pcmcia_release(struct pcmcia_device *);/* Remove a device */ /* ---------------------- INTERRUPT HANDLING ---------------------- */ static irqreturn_t wavelan_interrupt(int, /* Interrupt handler */ diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h index 4303c50c2ab6..65ceb088f700 100644 --- a/drivers/net/wireless/wl3501.h +++ b/drivers/net/wireless/wl3501.h @@ -611,5 +611,6 @@ struct wl3501_card { struct iw_spy_data spy_data; struct iw_public_data wireless_data; struct dev_node_t node; + struct pcmcia_device *p_dev; }; #endif diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 48e10b0c7e74..e52a650f6737 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -103,8 +103,8 @@ module_param(pc_debug, int, 0); * release a socket, in response to card insertion and ejection events. They * are invoked from the wl24 event handler. */ -static void wl3501_config(dev_link_t *link); -static void wl3501_release(dev_link_t *link); +static int wl3501_config(struct pcmcia_device *link); +static void wl3501_release(struct pcmcia_device *link); /* * The dev_info variable is the "key" that is used to match up this @@ -226,17 +226,6 @@ static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to, iw_set_mgmt_info_element(from->id, to, from->data, from->len); } -/* - * A linked list of "instances" of the wl24 device. Each actual PCMCIA card - * corresponds to one device instance, and is described by one dev_link_t - * structure (defined in ds.h). - * - * You may not want to use a linked list for this -- for example, the memory - * card driver uses an array of dev_link_t pointers, where minor device numbers - * are used to derive the corresponding array index. - */ -static dev_link_t *wl3501_dev_list; - static inline void wl3501_switch_page(struct wl3501_card *this, u8 page) { wl3501_outb(page, this->base_addr + WL3501_NIC_BSS); @@ -1281,15 +1270,10 @@ static int wl3501_close(struct net_device *dev) struct wl3501_card *this = dev->priv; int rc = -ENODEV; unsigned long flags; - dev_link_t *link; + struct pcmcia_device *link; + link = this->p_dev; spin_lock_irqsave(&this->lock, flags); - /* Check if the device is in wl3501_dev_list */ - for (link = wl3501_dev_list; link; link = link->next) - if (link->priv == dev) - break; - if (!link) - goto out; link->open--; /* Stop wl3501_hard_start_xmit() from now on */ @@ -1301,7 +1285,6 @@ static int wl3501_close(struct net_device *dev) rc = 0; printk(KERN_INFO "%s: WL3501 closed\n", dev->name); -out: spin_unlock_irqrestore(&this->lock, flags); return rc; } @@ -1400,14 +1383,11 @@ static int wl3501_open(struct net_device *dev) int rc = -ENODEV; struct wl3501_card *this = dev->priv; unsigned long flags; - dev_link_t *link; + struct pcmcia_device *link; + link = this->p_dev; spin_lock_irqsave(&this->lock, flags); - /* Check if the device is in wl3501_dev_list */ - for (link = wl3501_dev_list; link; link = link->next) - if (link->priv == dev) - break; - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) goto out; netif_device_attach(dev); link->open++; @@ -1497,38 +1477,23 @@ static struct ethtool_ops ops = { * Services. If it has been released, all local data structures are freed. * Otherwise, the structures will be freed when the device is released. */ -static void wl3501_detach(struct pcmcia_device *p_dev) +static void wl3501_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - dev_link_t **linkp; struct net_device *dev = link->priv; - /* Locate device structure */ - for (linkp = &wl3501_dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) - break; - if (!*linkp) - goto out; - /* If the device is currently configured and active, we won't actually * delete it yet. Instead, it is marked so that when the release() * function is called, that will trigger a proper detach(). */ - if (link->state & DEV_CONFIG) { - while (link->open > 0) - wl3501_close(dev); + while (link->open > 0) + wl3501_close(dev); - netif_device_detach(dev); - wl3501_release(link); - } - - /* Unlink device structure, free pieces */ - *linkp = link->next; + netif_device_detach(dev); + wl3501_release(link); if (link->priv) free_netdev(link->priv); - kfree(link); -out: + return; } @@ -1953,33 +1918,26 @@ static const struct iw_handler_def wl3501_handler_def = { * The dev_link structure is initialized, but we don't actually configure the * card at this point -- we wait until we receive a card insertion event. */ -static int wl3501_attach(struct pcmcia_device *p_dev) +static int wl3501_probe(struct pcmcia_device *p_dev) { - dev_link_t *link; struct net_device *dev; struct wl3501_card *this; - /* Initialize the dev_link_t structure */ - link = kzalloc(sizeof(*link), GFP_KERNEL); - if (!link) - return -ENOMEM; - /* The io structure describes IO port mapping */ - link->io.NumPorts1 = 16; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = 5; + p_dev->io.NumPorts1 = 16; + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = 5; /* Interrupt setup */ - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->irq.Handler = wl3501_interrupt; + p_dev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID; + p_dev->irq.Handler = wl3501_interrupt; /* General socket configuration */ - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.ConfigIndex = 1; - link->conf.Present = PRESENT_OPTION; + p_dev->conf.Attributes = CONF_ENABLE_IRQ; + p_dev->conf.IntType = INT_MEMORY_AND_IO; + p_dev->conf.ConfigIndex = 1; + p_dev->conf.Present = PRESENT_OPTION; dev = alloc_etherdev(sizeof(struct wl3501_card)); if (!dev) @@ -1992,22 +1950,15 @@ static int wl3501_attach(struct pcmcia_device *p_dev) dev->get_stats = wl3501_get_stats; this = dev->priv; this->wireless_data.spy_data = &this->spy_data; + this->p_dev = p_dev; dev->wireless_data = &this->wireless_data; dev->wireless_handlers = (struct iw_handler_def *)&wl3501_handler_def; SET_ETHTOOL_OPS(dev, &ops); netif_stop_queue(dev); - link->priv = link->irq.Instance = dev; + p_dev->priv = p_dev->irq.Instance = dev; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - wl3501_config(link); - - return 0; + return wl3501_config(p_dev); out_link: - kfree(link); - link = NULL; return -ENOMEM; } @@ -2022,11 +1973,10 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) * received, to configure the PCMCIA socket, and to make the ethernet device * available to the system. */ -static void wl3501_config(dev_link_t *link) +static int wl3501_config(struct pcmcia_device *link) { tuple_t tuple; cisparse_t parse; - client_handle_t handle = link->handle; struct net_device *dev = link->priv; int i = 0, j, last_fn, last_ret; unsigned char bf[64]; @@ -2035,18 +1985,15 @@ static void wl3501_config(dev_link_t *link) /* This reads the card's CONFIG tuple to find its config registers. */ tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); tuple.TupleData = bf; tuple.TupleDataMax = sizeof(bf); tuple.TupleOffset = 0; - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - /* Try allocating IO ports. This tries a few fixed addresses. If you * want, you can also read the card's config table to pick addresses -- * see the serial driver for an example. */ @@ -2056,28 +2003,28 @@ static void wl3501_config(dev_link_t *link) * 0x200-0x2ff, and so on, because this seems safer */ link->io.BasePort1 = j; link->io.BasePort2 = link->io.BasePort1 + 0x10; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); goto failed; } /* Now allocate an interrupt line. Note that this does not actually * assign a handler to the interrupt. */ - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); /* This actually configures the PCMCIA socket -- setting up the I/O * windows and the interrupt mapping. */ - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + SET_NETDEV_DEV(dev, &handle_to_dev(link)); if (register_netdev(dev)) { printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n"); goto failed; @@ -2088,10 +2035,9 @@ static void wl3501_config(dev_link_t *link) this = dev->priv; /* * At this point, the dev_node_t structure(s) should be initialized and - * arranged in a linked list at link->dev. + * arranged in a linked list at link->dev_node. */ - link->dev = &this->node; - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &this->node; this->base_addr = dev->base_addr; @@ -2127,13 +2073,13 @@ static void wl3501_config(dev_link_t *link) spin_lock_init(&this->lock); init_waitqueue_head(&this->wait); netif_start_queue(dev); - goto out; + return 0; + cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: wl3501_release(link); -out: - return; + return -ENODEV; } /** @@ -2144,52 +2090,36 @@ out: * and release the PCMCIA configuration. If the device is still open, this * will be postponed until it is closed. */ -static void wl3501_release(dev_link_t *link) +static void wl3501_release(struct pcmcia_device *link) { struct net_device *dev = link->priv; /* Unlink the device chain */ - if (link->dev) { + if (link->dev_node) unregister_netdev(dev); - link->dev = NULL; - } - /* Don't bother checking to see if these succeed or not */ - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } -static int wl3501_suspend(struct pcmcia_device *p_dev) +static int wl3501_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND); - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } + if (link->open) + netif_device_detach(dev); return 0; } -static int wl3501_resume(struct pcmcia_device *p_dev) +static int wl3501_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; wl3501_pwr_mgmt(dev->priv, WL3501_RESUME); - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - wl3501_reset(dev); - netif_device_attach(dev); - } + if (link->open) { + wl3501_reset(dev); + netif_device_attach(dev); } return 0; @@ -2207,7 +2137,7 @@ static struct pcmcia_driver wl3501_driver = { .drv = { .name = "wl3501_cs", }, - .probe = wl3501_attach, + .probe = wl3501_probe, .remove = wl3501_detach, .id_table = wl3501_ids, .suspend = wl3501_suspend, @@ -2221,9 +2151,7 @@ static int __init wl3501_init_module(void) static void __exit wl3501_exit_module(void) { - dprintk(0, ": unloading"); pcmcia_unregister_driver(&wl3501_driver); - BUG_ON(wl3501_dev_list != NULL); } module_init(wl3501_init_module); diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 75d56bfef0ee..fd0f43b7db5b 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1441,8 +1441,7 @@ static void __devexit yellowfin_remove_one (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct yellowfin_private *np; - if (!dev) - BUG(); + BUG_ON(!dev); np = netdev_priv(dev); pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status, diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 93f8a8fa8890..a5d826237b26 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1560,7 +1560,7 @@ static int ccio_probe(struct parisc_device *dev) *ioc_p = ioc; ioc->hw_path = dev->hw_path; - ioc->ioc_regs = ioremap(dev->hpa.start, 4096); + ioc->ioc_regs = ioremap_nocache(dev->hpa.start, 4096); ccio_ioc_init(ioc); ccio_init_resources(ioc); hppa_dma_ops = &ccio_ops; diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 3d1a7f98c676..6e8ed0c81a6c 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -5,6 +5,7 @@ ** (c) Copyright 1999 SuSE GmbH ** (c) Copyright 1999,2000 Hewlett-Packard Company ** (c) Copyright 2000 Grant Grundler +** (c) Copyright 2006 Helge Deller ** ** 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 @@ -785,7 +786,7 @@ dino_bridge_init(struct dino_device *dino_dev, const char *name) if((io_addr & (1 << i)) == 0) continue; - start = (unsigned long)(signed int)(0xf0000000 | (i << 23)); + start = F_EXTEND(0xf0000000UL) | (i << 23); end = start + 8 * 1024 * 1024 - 1; DBG("DINO RANGE %d is at 0x%lx-0x%lx\n", count, @@ -996,7 +997,7 @@ static int __init dino_probe(struct parisc_device *dev) } dino_dev->hba.dev = dev; - dino_dev->hba.base_addr = ioremap(hpa, 4096); + dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096); dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */ spin_lock_init(&dino_dev->dinosaur_pen); dino_dev->hba.iommu = ccio_get_iommu(dev); diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index 3d94d86c1c9f..9d3bd15bf53b 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -366,7 +366,7 @@ static int __devinit eisa_probe(struct parisc_device *dev) eisa_dev.eeprom_addr = MIRAGE_EEPROM_BASE_ADDR; } } - eisa_eeprom_addr = ioremap(eisa_dev.eeprom_addr, HPEE_MAX_LENGTH); + eisa_eeprom_addr = ioremap_nocache(eisa_dev.eeprom_addr, HPEE_MAX_LENGTH); result = eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space, &eisa_dev.hba.lmmio_space); init_eisa_pic(); diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 8d7a36392eb8..7a458d5bc751 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -879,7 +879,7 @@ void *iosapic_register(unsigned long hpa) return NULL; } - isi->addr = ioremap(hpa, 4096); + isi->addr = ioremap_nocache(hpa, 4096); isi->isi_hpa = hpa; isi->isi_version = iosapic_rd_version(isi); isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1; diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index e8a2a4a852f5..3fe4a77fa16a 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1213,7 +1213,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) ** Postable I/O port space is per PCI host adapter. ** base of 64MB PIOP region */ - lba_dev->iop_base = ioremap(p->start, 64 * 1024 * 1024); + lba_dev->iop_base = ioremap_nocache(p->start, 64 * 1024 * 1024); sprintf(lba_dev->hba.io_name, "PCI%02lx Ports", lba_dev->hba.bus_num.start); @@ -1525,7 +1525,7 @@ lba_driver_probe(struct parisc_device *dev) u32 func_class; void *tmp_obj; char *version; - void __iomem *addr = ioremap(dev->hpa.start, 4096); + void __iomem *addr = ioremap_nocache(dev->hpa.start, 4096); /* Read HW Rev First */ func_class = READ_REG32(addr + LBA_FCLASS); @@ -1619,7 +1619,7 @@ lba_driver_probe(struct parisc_device *dev) } else { if (!astro_iop_base) { /* Sprockets PDC uses NPIOP region */ - astro_iop_base = ioremap(LBA_PORT_BASE, 64 * 1024); + astro_iop_base = ioremap_nocache(LBA_PORT_BASE, 64 * 1024); pci_port = &lba_astro_port_ops; } @@ -1700,7 +1700,7 @@ void __init lba_init(void) */ void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask) { - void __iomem * base_addr = ioremap(lba->hpa.start, 4096); + void __iomem * base_addr = ioremap_nocache(lba->hpa.start, 4096); imask <<= 2; /* adjust for hints - 2 more bits */ diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index a28e17898fbd..4e53be9c03ab 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -4,9 +4,8 @@ * Copyright (C) 2005-2006 Thibaut VARENE * * 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. + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 0821747e44cf..42b32ff2fca6 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1642,9 +1642,9 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ** **************************************************************************/ -static void __iomem *ioc_remap(struct sba_device *sba_dev, int offset) +static void __iomem *ioc_remap(struct sba_device *sba_dev, unsigned int offset) { - return ioremap(sba_dev->dev->hpa.start + offset, SBA_FUNC_SIZE); + return ioremap_nocache(sba_dev->dev->hpa.start + offset, SBA_FUNC_SIZE); } static void sba_hw_init(struct sba_device *sba_dev) @@ -2040,7 +2040,7 @@ sba_driver_callback(struct parisc_device *dev) u32 func_class; int i; char *version; - void __iomem *sba_addr = ioremap(dev->hpa.start, SBA_FUNC_SIZE); + void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE); struct proc_dir_entry *info_entry, *bitmap_entry, *root; sba_dump_ranges(sba_addr); diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index ad6d3b28a3a6..719b863bc20e 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -12,6 +12,7 @@ * (C) Copyright 2001 John Marvin * (C) Copyright 2003 Grant Grundler * (C) Copyright 2005 Kyle McMartin + * (C) Copyright 2006 Helge Deller * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -388,43 +389,34 @@ int superio_fixup_irq(struct pci_dev *pcidev) return local_irq; } -static struct uart_port serial[] = { - { - .iotype = UPIO_PORT, - .line = 0, - .type = PORT_16550A, - .uartclk = 115200*16, - .fifosize = 16, - }, - { - .iotype = UPIO_PORT, - .line = 1, - .type = PORT_16550A, - .uartclk = 115200*16, - .fifosize = 16, - } -}; - static void __devinit superio_serial_init(void) { #ifdef CONFIG_SERIAL_8250 int retval; - - serial[0].iobase = sio_dev.sp1_base; - serial[0].irq = SP1_IRQ; - spin_lock_init(&serial[0].lock); + struct uart_port serial_port; - retval = early_serial_setup(&serial[0]); + memset(&serial_port, 0, sizeof(serial_port)); + serial_port.iotype = UPIO_PORT; + serial_port.type = PORT_16550A; + serial_port.uartclk = 115200*16; + serial_port.fifosize = 16; + spin_lock_init(&serial_port.lock); + + /* serial port #1 */ + serial_port.iobase = sio_dev.sp1_base; + serial_port.irq = SP1_IRQ; + serial_port.line = 0; + retval = early_serial_setup(&serial_port); if (retval < 0) { printk(KERN_WARNING PFX "Register Serial #0 failed.\n"); return; } - serial[1].iobase = sio_dev.sp2_base; - serial[1].irq = SP2_IRQ; - spin_lock_init(&serial[1].lock); - retval = early_serial_setup(&serial[1]); - + /* serial port #2 */ + serial_port.iobase = sio_dev.sp2_base; + serial_port.irq = SP2_IRQ; + serial_port.line = 1; + retval = early_serial_setup(&serial_port); if (retval < 0) printk(KERN_WARNING PFX "Register Serial #1 failed.\n"); #endif /* CONFIG_SERIAL_8250 */ diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index 158d92563259..b953d5907c05 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -81,15 +81,15 @@ static char *version = #define FORCE_EPP_MODE 0x08 typedef struct parport_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; int ndev; dev_node_t node; struct parport *port; } parport_info_t; static void parport_detach(struct pcmcia_device *p_dev); -static void parport_config(dev_link_t *link); -static void parport_cs_release(dev_link_t *); +static int parport_config(struct pcmcia_device *link); +static void parport_cs_release(struct pcmcia_device *); /*====================================================================== @@ -99,10 +99,9 @@ static void parport_cs_release(dev_link_t *); ======================================================================*/ -static int parport_attach(struct pcmcia_device *p_dev) +static int parport_probe(struct pcmcia_device *link) { parport_info_t *info; - dev_link_t *link; DEBUG(0, "parport_attach()\n"); @@ -110,23 +109,17 @@ static int parport_attach(struct pcmcia_device *p_dev) info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; memset(info, 0, sizeof(*info)); - link = &info->link; link->priv = info; + link->priv = info; + info->p_dev = link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - parport_config(link); - - return 0; + return parport_config(link); } /* parport_attach */ /*====================================================================== @@ -138,14 +131,11 @@ static int parport_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void parport_detach(struct pcmcia_device *p_dev) +static void parport_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - DEBUG(0, "parport_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) - parport_cs_release(link); + parport_cs_release(link); kfree(link->priv); } /* parport_detach */ @@ -161,14 +151,12 @@ static void parport_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -void parport_config(dev_link_t *link) +static int parport_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; parport_info_t *info = link->priv; tuple_t tuple; u_short buf[128]; cisparse_t parse; - config_info_t conf; cistpl_cftable_entry_t *cfg = &parse.cftable_entry; cistpl_cftable_entry_t dflt = { 0 }; struct parport *p; @@ -180,24 +168,18 @@ void parport_config(dev_link_t *link) tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - - /* Configure card */ - link->state |= DEV_CONFIG; - /* Not sure if this is right... look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { @@ -212,7 +194,7 @@ void parport_config(dev_link_t *link) link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; /* If we've got this far, we're done */ break; @@ -220,15 +202,12 @@ void parport_config(dev_link_t *link) next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); - release_region(link->io.BasePort1, link->io.NumPorts1); - if (link->io.NumPorts2) - release_region(link->io.BasePort2, link->io.NumPorts2); p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2, link->irq.AssignedIRQ, PARPORT_DMA_NONE, NULL); @@ -247,17 +226,15 @@ void parport_config(dev_link_t *link) info->node.minor = p->number; info->port = p; strcpy(info->node.dev_name, p->name); - link->dev = &info->node; + link->dev_node = &info->node; + + return 0; - link->state &= ~DEV_CONFIG_PENDING; - return; - cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: parport_cs_release(link); - link->state &= ~DEV_CONFIG_PENDING; - + return -ENODEV; } /* parport_config */ /*====================================================================== @@ -268,53 +245,21 @@ failed: ======================================================================*/ -void parport_cs_release(dev_link_t *link) +void parport_cs_release(struct pcmcia_device *link) { - parport_info_t *info = link->priv; - - DEBUG(0, "parport_release(0x%p)\n", link); + parport_info_t *info = link->priv; - if (info->ndev) { - struct parport *p = info->port; - parport_pc_unregister_port(p); - request_region(link->io.BasePort1, link->io.NumPorts1, - info->node.dev_name); - if (link->io.NumPorts2) - request_region(link->io.BasePort2, link->io.NumPorts2, - info->node.dev_name); - } - info->ndev = 0; - link->dev = NULL; - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + DEBUG(0, "parport_release(0x%p)\n", link); + if (info->ndev) { + struct parport *p = info->port; + parport_pc_unregister_port(p); + } + info->ndev = 0; + + pcmcia_disable_device(link); } /* parport_cs_release */ -static int parport_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int parport_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (DEV_OK(link)) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; -} static struct pcmcia_device_id parport_ids[] = { PCMCIA_DEVICE_FUNC_ID(3), @@ -328,11 +273,9 @@ static struct pcmcia_driver parport_cs_driver = { .drv = { .name = "parport_cs", }, - .probe = parport_attach, + .probe = parport_probe, .remove = parport_detach, .id_table = parport_ids, - .suspend = parport_suspend, - .resume = parport_resume, }; static int __init init_parport_cs(void) diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index d121644646b9..98b83a85c60e 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -100,8 +100,6 @@ static struct pci_device_id parport_serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, - { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845, PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9xx5_combo }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9855, diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index 6e79f5675b0d..638004546700 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -360,9 +360,6 @@ static int __init rpaphp_init(void) while ((dn = of_find_node_by_type(dn, "pci"))) rpaphp_add_slot(dn); - if (!num_slots) - return -ENODEV; - return 0; } diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index a77e79c8c82e..2087a397ef16 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -504,6 +504,201 @@ void pci_scan_msi_device(struct pci_dev *dev) nr_reserved_vectors++; } +#ifdef CONFIG_PM +int pci_save_msi_state(struct pci_dev *dev) +{ + int pos, i = 0; + u16 control; + struct pci_cap_saved_state *save_state; + u32 *cap; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (pos <= 0 || dev->no_msi) + return 0; + + pci_read_config_word(dev, msi_control_reg(pos), &control); + if (!(control & PCI_MSI_FLAGS_ENABLE)) + return 0; + + save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5, + GFP_KERNEL); + if (!save_state) { + printk(KERN_ERR "Out of memory in pci_save_msi_state\n"); + return -ENOMEM; + } + cap = &save_state->data[0]; + + pci_read_config_dword(dev, pos, &cap[i++]); + control = cap[0] >> 16; + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, &cap[i++]); + if (control & PCI_MSI_FLAGS_64BIT) { + pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, &cap[i++]); + pci_read_config_dword(dev, pos + PCI_MSI_DATA_64, &cap[i++]); + } else + pci_read_config_dword(dev, pos + PCI_MSI_DATA_32, &cap[i++]); + if (control & PCI_MSI_FLAGS_MASKBIT) + pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT, &cap[i++]); + disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + save_state->cap_nr = PCI_CAP_ID_MSI; + pci_add_saved_cap(dev, save_state); + return 0; +} + +void pci_restore_msi_state(struct pci_dev *dev) +{ + int i = 0, pos; + u16 control; + struct pci_cap_saved_state *save_state; + u32 *cap; + + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI); + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (!save_state || pos <= 0) + return; + cap = &save_state->data[0]; + + control = cap[i++] >> 16; + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]); + if (control & PCI_MSI_FLAGS_64BIT) { + pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]); + pci_write_config_dword(dev, pos + PCI_MSI_DATA_64, cap[i++]); + } else + pci_write_config_dword(dev, pos + PCI_MSI_DATA_32, cap[i++]); + if (control & PCI_MSI_FLAGS_MASKBIT) + pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]); + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); + enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + pci_remove_saved_cap(save_state); + kfree(save_state); +} + +int pci_save_msix_state(struct pci_dev *dev) +{ + int pos; + u16 control; + struct pci_cap_saved_state *save_state; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (pos <= 0 || dev->no_msi) + return 0; + + pci_read_config_word(dev, msi_control_reg(pos), &control); + if (!(control & PCI_MSIX_FLAGS_ENABLE)) + return 0; + save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16), + GFP_KERNEL); + if (!save_state) { + printk(KERN_ERR "Out of memory in pci_save_msix_state\n"); + return -ENOMEM; + } + *((u16 *)&save_state->data[0]) = control; + + disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); + save_state->cap_nr = PCI_CAP_ID_MSIX; + pci_add_saved_cap(dev, save_state); + return 0; +} + +void pci_restore_msix_state(struct pci_dev *dev) +{ + u16 save; + int pos; + int vector, head, tail = 0; + void __iomem *base; + int j; + struct msg_address address; + struct msg_data data; + struct msi_desc *entry; + int temp; + struct pci_cap_saved_state *save_state; + + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX); + if (!save_state) + return; + save = *((u16 *)&save_state->data[0]); + pci_remove_saved_cap(save_state); + kfree(save_state); + + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (pos <= 0) + return; + + /* route the table */ + temp = dev->irq; + if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) + return; + vector = head = dev->irq; + while (head != tail) { + entry = msi_desc[vector]; + base = entry->mask_base; + j = entry->msi_attrib.entry_nr; + + msi_address_init(&address); + msi_data_init(&data, vector); + + address.lo_address.value &= MSI_ADDRESS_DEST_ID_MASK; + address.lo_address.value |= entry->msi_attrib.current_cpu << + MSI_TARGET_CPU_SHIFT; + + writel(address.lo_address.value, + base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET); + writel(address.hi_address, + base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET); + writel(*(u32*)&data, + base + j * PCI_MSIX_ENTRY_SIZE + + PCI_MSIX_ENTRY_DATA_OFFSET); + + tail = msi_desc[vector]->link.tail; + vector = tail; + } + dev->irq = temp; + + pci_write_config_word(dev, msi_control_reg(pos), save); + enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); +} +#endif + +static void msi_register_init(struct pci_dev *dev, struct msi_desc *entry) +{ + struct msg_address address; + struct msg_data data; + int pos, vector = dev->irq; + u16 control; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + pci_read_config_word(dev, msi_control_reg(pos), &control); + /* Configure MSI capability structure */ + msi_address_init(&address); + msi_data_init(&data, vector); + entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> + MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); + pci_write_config_dword(dev, msi_lower_address_reg(pos), + address.lo_address.value); + if (is_64bit_address(control)) { + pci_write_config_dword(dev, + msi_upper_address_reg(pos), address.hi_address); + pci_write_config_word(dev, + msi_data_reg(pos, 1), *((u32*)&data)); + } else + pci_write_config_word(dev, + msi_data_reg(pos, 0), *((u32*)&data)); + if (entry->msi_attrib.maskbit) { + unsigned int maskbits, temp; + /* All MSIs are unmasked by default, Mask them all */ + pci_read_config_dword(dev, + msi_mask_bits_reg(pos, is_64bit_address(control)), + &maskbits); + temp = (1 << multi_msi_capable(control)); + temp = ((temp - 1) & ~temp); + maskbits |= temp; + pci_write_config_dword(dev, + msi_mask_bits_reg(pos, is_64bit_address(control)), + maskbits); + } +} + /** * msi_capability_init - configure device's MSI capability structure * @dev: pointer to the pci_dev data structure of MSI device function @@ -516,8 +711,6 @@ void pci_scan_msi_device(struct pci_dev *dev) static int msi_capability_init(struct pci_dev *dev) { struct msi_desc *entry; - struct msg_address address; - struct msg_data data; int pos, vector; u16 control; @@ -549,33 +742,8 @@ static int msi_capability_init(struct pci_dev *dev) /* Replace with MSI handler */ irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit); /* Configure MSI capability structure */ - msi_address_init(&address); - msi_data_init(&data, vector); - entry->msi_attrib.current_cpu = ((address.lo_address.u.dest_id >> - MSI_TARGET_CPU_SHIFT) & MSI_TARGET_CPU_MASK); - pci_write_config_dword(dev, msi_lower_address_reg(pos), - address.lo_address.value); - if (is_64bit_address(control)) { - pci_write_config_dword(dev, - msi_upper_address_reg(pos), address.hi_address); - pci_write_config_word(dev, - msi_data_reg(pos, 1), *((u32*)&data)); - } else - pci_write_config_word(dev, - msi_data_reg(pos, 0), *((u32*)&data)); - if (entry->msi_attrib.maskbit) { - unsigned int maskbits, temp; - /* All MSIs are unmasked by default, Mask them all */ - pci_read_config_dword(dev, - msi_mask_bits_reg(pos, is_64bit_address(control)), - &maskbits); - temp = (1 << multi_msi_capable(control)); - temp = ((temp - 1) & ~temp); - maskbits |= temp; - pci_write_config_dword(dev, - msi_mask_bits_reg(pos, is_64bit_address(control)), - maskbits); - } + msi_register_init(dev, entry); + attach_msi_entry(entry, vector); /* Set MSI enabled bits */ enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); @@ -731,6 +899,7 @@ int pci_enable_msi(struct pci_dev* dev) vector_irq[dev->irq] = -1; nr_released_vectors--; spin_unlock_irqrestore(&msi_lock, flags); + msi_register_init(dev, msi_desc[dev->irq]); enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); return 0; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index f22f69ac6445..1456759936c5 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -271,10 +271,12 @@ static int pci_device_suspend(struct device * dev, pm_message_t state) struct pci_driver * drv = pci_dev->driver; int i = 0; - if (drv && drv->suspend) + if (drv && drv->suspend) { i = drv->suspend(pci_dev, state); - else + suspend_report_result(drv->suspend, i); + } else { pci_save_state(pci_dev); + } return i; } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index bea1ad1ad5ba..2329f941a0dc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -307,9 +307,11 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) * Can enter D0 from any state, but if we can only go deeper * to sleep if we're already in a low power state */ - if (state != PCI_D0 && dev->current_state > state) + if (state != PCI_D0 && dev->current_state > state) { + printk(KERN_ERR "%s(): %s: state=%d, current state=%d\n", + __FUNCTION__, pci_name(dev), state, dev->current_state); return -EINVAL; - else if (dev->current_state == state) + } else if (dev->current_state == state) return 0; /* we're already there */ /* find PCI PM capability in list */ @@ -444,6 +446,10 @@ pci_save_state(struct pci_dev *dev) /* XXX: 100% dword access ok here? */ for (i = 0; i < 16; i++) pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]); + if ((i = pci_save_msi_state(dev)) != 0) + return i; + if ((i = pci_save_msix_state(dev)) != 0) + return i; return 0; } @@ -458,6 +464,8 @@ pci_restore_state(struct pci_dev *dev) for (i = 0; i < 16; i++) pci_write_config_dword(dev,i * 4, dev->saved_config_space[i]); + pci_restore_msi_state(dev); + pci_restore_msix_state(dev); return 0; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 8f3fb47ea671..30630cbe2fe3 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -55,6 +55,17 @@ void pci_no_msi(void); static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { } static inline void pci_no_msi(void) { } #endif +#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM) +int pci_save_msi_state(struct pci_dev *dev); +int pci_save_msix_state(struct pci_dev *dev); +void pci_restore_msi_state(struct pci_dev *dev); +void pci_restore_msix_state(struct pci_dev *dev); +#else +static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; } +static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; } +static inline void pci_restore_msi_state(struct pci_dev *dev) {} +static inline void pci_restore_msix_state(struct pci_dev *dev) {} +#endif extern int pcie_mch_quirk; extern struct device_attribute pci_dev_attrs[]; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4970f47be72c..827550d25c9e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -592,7 +592,7 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev) pci_write_config_byte( dev, AMD8131_MISC, tmp); } } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_APIC, quirk_amd_8131_ioapic ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); static void __init quirk_svw_msi(struct pci_dev *dev) { @@ -921,6 +921,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev) if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) { switch (dev->subsystem_device) { case 0x1882: /* M6V notebook */ + case 0x1977: /* A6VA notebook */ asus_hides_smbus = 1; } } @@ -999,6 +1000,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asu DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc ); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc ); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc ); static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev) { diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 1f4ad0e7836e..cba6c9eef28e 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -263,6 +263,13 @@ config OMAP_CF Say Y here to support the CompactFlash controller on OMAP. Note that this doesn't support "True IDE" mode. +config AT91_CF + tristate "AT91 CompactFlash Controller" + depends on PCMCIA && ARCH_AT91RM9200 + help + Say Y here to support the CompactFlash controller on AT91 chips. + Or choose M to compile the driver as a module named "at91_cf". + config PCCARD_NONSTATIC tristate diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index bcecf5133b7e..4276965517f2 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -10,7 +10,7 @@ pcmcia_core-y += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o obj-$(CONFIG_PCCARD) += pcmcia_core.o -pcmcia-y += ds.o pcmcia_compat.o pcmcia_resource.o +pcmcia-y += ds.o pcmcia_resource.o pcmcia-$(CONFIG_PCMCIA_IOCTL) += pcmcia_ioctl.o obj-$(CONFIG_PCMCIA) += pcmcia.o @@ -36,6 +36,7 @@ obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o obj-$(CONFIG_OMAP_CF) += omap_cf.o +obj-$(CONFIG_AT91_CF) += at91_cf.o sa11xx_core-y += soc_common.o sa11xx_base.o pxa2xx_core-y += soc_common.o pxa2xx_base.o diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c new file mode 100644 index 000000000000..a4d50940ebeb --- /dev/null +++ b/drivers/pcmcia/at91_cf.c @@ -0,0 +1,376 @@ +/* + * at91_cf.c -- AT91 CompactFlash controller driver + * + * Copyright (C) 2005 David Brownell + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + + +/* + * A0..A10 work in each range; A23 indicates I/O space; A25 is CFRNW; + * some other bit in {A24,A22..A11} is nREG to flag memory access + * (vs attributes). So more than 2KB/region would just be waste. + */ +#define CF_ATTR_PHYS (AT91_CF_BASE) +#define CF_IO_PHYS (AT91_CF_BASE + (1 << 23)) +#define CF_MEM_PHYS (AT91_CF_BASE + 0x017ff800) + +/*--------------------------------------------------------------------------*/ + +static const char driver_name[] = "at91_cf"; + +struct at91_cf_socket { + struct pcmcia_socket socket; + + unsigned present:1; + + struct platform_device *pdev; + struct at91_cf_data *board; +}; + +#define SZ_2K (2 * SZ_1K) + +static inline int at91_cf_present(struct at91_cf_socket *cf) +{ + return !at91_get_gpio_value(cf->board->det_pin); +} + +/*--------------------------------------------------------------------------*/ + +static int at91_cf_ss_init(struct pcmcia_socket *s) +{ + return 0; +} + +static irqreturn_t at91_cf_irq(int irq, void *_cf, struct pt_regs *r) +{ + struct at91_cf_socket *cf = (struct at91_cf_socket *) _cf; + + if (irq == cf->board->det_pin) { + unsigned present = at91_cf_present(cf); + + /* kick pccard as needed */ + if (present != cf->present) { + cf->present = present; + pr_debug("%s: card %s\n", driver_name, + present ? "present" : "gone"); + pcmcia_parse_events(&cf->socket, SS_DETECT); + } + } + + return IRQ_HANDLED; +} + +static int at91_cf_get_status(struct pcmcia_socket *s, u_int *sp) +{ + struct at91_cf_socket *cf; + + if (!sp) + return -EINVAL; + + cf = container_of(s, struct at91_cf_socket, socket); + + /* NOTE: CF is always 3VCARD */ + if (at91_cf_present(cf)) { + int rdy = cf->board->irq_pin; /* RDY/nIRQ */ + int vcc = cf->board->vcc_pin; + + *sp = SS_DETECT | SS_3VCARD; + if (!rdy || at91_get_gpio_value(rdy)) + *sp |= SS_READY; + if (!vcc || at91_get_gpio_value(vcc)) + *sp |= SS_POWERON; + } else + *sp = 0; + + return 0; +} + +static int +at91_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s) +{ + struct at91_cf_socket *cf; + + cf = container_of(sock, struct at91_cf_socket, socket); + + /* switch Vcc if needed and possible */ + if (cf->board->vcc_pin) { + switch (s->Vcc) { + case 0: + at91_set_gpio_value(cf->board->vcc_pin, 0); + break; + case 33: + at91_set_gpio_value(cf->board->vcc_pin, 1); + break; + default: + return -EINVAL; + } + } + + /* toggle reset if needed */ + at91_set_gpio_value(cf->board->rst_pin, s->flags & SS_RESET); + + pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n", + driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask); + + return 0; +} + +static int at91_cf_ss_suspend(struct pcmcia_socket *s) +{ + return at91_cf_set_socket(s, &dead_socket); +} + +/* we already mapped the I/O region */ +static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) +{ + struct at91_cf_socket *cf; + u32 csr; + + cf = container_of(s, struct at91_cf_socket, socket); + io->flags &= (MAP_ACTIVE | MAP_16BIT | MAP_AUTOSZ); + + /* + * Use 16 bit accesses unless/until we need 8-bit i/o space. + * Always set CSR4 ... PCMCIA won't always unmap things. + */ + csr = at91_sys_read(AT91_SMC_CSR(4)) & ~AT91_SMC_DBW; + + /* + * NOTE: this CF controller ignores IOIS16, so we can't really do + * MAP_AUTOSZ. The 16bit mode allows single byte access on either + * D0-D7 (even addr) or D8-D15 (odd), so it's close enough for many + * purposes (and handles ide-cs). + * + * The 8bit mode is needed for odd byte access on D0-D7. It seems + * some cards only like that way to get at the odd byte, despite + * CF 3.0 spec table 35 also giving the D8-D15 option. + */ + if (!(io->flags & (MAP_16BIT|MAP_AUTOSZ))) { + csr |= AT91_SMC_DBW_8; + pr_debug("%s: 8bit i/o bus\n", driver_name); + } else { + csr |= AT91_SMC_DBW_16; + pr_debug("%s: 16bit i/o bus\n", driver_name); + } + at91_sys_write(AT91_SMC_CSR(4), csr); + + io->start = cf->socket.io_offset; + io->stop = io->start + SZ_2K - 1; + + return 0; +} + +/* pcmcia layer maps/unmaps mem regions */ +static int +at91_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map) +{ + struct at91_cf_socket *cf; + + if (map->card_start) + return -EINVAL; + + cf = container_of(s, struct at91_cf_socket, socket); + + map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT; + if (map->flags & MAP_ATTRIB) + map->static_start = CF_ATTR_PHYS; + else + map->static_start = CF_MEM_PHYS; + + return 0; +} + +static struct pccard_operations at91_cf_ops = { + .init = at91_cf_ss_init, + .suspend = at91_cf_ss_suspend, + .get_status = at91_cf_get_status, + .set_socket = at91_cf_set_socket, + .set_io_map = at91_cf_set_io_map, + .set_mem_map = at91_cf_set_mem_map, +}; + +/*--------------------------------------------------------------------------*/ + +static int __init at91_cf_probe(struct device *dev) +{ + struct at91_cf_socket *cf; + struct at91_cf_data *board = dev->platform_data; + struct platform_device *pdev = to_platform_device(dev); + struct resource *io; + unsigned int csa; + int status; + + if (!board || !board->det_pin || !board->rst_pin) + return -ENODEV; + + io = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!io) + return -ENODEV; + + cf = kcalloc(1, sizeof *cf, GFP_KERNEL); + if (!cf) + return -ENOMEM; + + cf->board = board; + cf->pdev = pdev; + dev_set_drvdata(dev, cf); + + /* CF takes over CS4, CS5, CS6 */ + csa = at91_sys_read(AT91_EBI_CSA); + at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH); + + /* force poweron defaults for these pins ... */ + (void) at91_set_A_periph(AT91_PIN_PC9, 0); /* A25/CFRNW */ + (void) at91_set_A_periph(AT91_PIN_PC10, 0); /* NCS4/CFCS */ + (void) at91_set_A_periph(AT91_PIN_PC11, 0); /* NCS5/CFCE1 */ + (void) at91_set_A_periph(AT91_PIN_PC12, 0); /* NCS6/CFCE2 */ + + /* nWAIT is _not_ a default setting */ + (void) at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */ + + /* + * Static memory controller timing adjustments. + * REVISIT: these timings are in terms of MCK cycles, so + * when MCK changes (cpufreq etc) so must these values... + */ + at91_sys_write(AT91_SMC_CSR(4), + AT91_SMC_ACSS_STD + | AT91_SMC_DBW_16 + | AT91_SMC_BAT + | AT91_SMC_WSEN + | AT91_SMC_NWS_(32) /* wait states */ + | AT91_SMC_RWSETUP_(6) /* setup time */ + | AT91_SMC_RWHOLD_(4) /* hold time */ + ); + + /* must be a GPIO; ergo must trigger on both edges */ + status = request_irq(board->det_pin, at91_cf_irq, + SA_SAMPLE_RANDOM, driver_name, cf); + if (status < 0) + goto fail0; + + /* + * The card driver will request this irq later as needed. + * but it causes lots of "irqNN: nobody cared" messages + * unless we report that we handle everything (sigh). + * (Note: DK board doesn't wire the IRQ pin...) + */ + if (board->irq_pin) { + status = request_irq(board->irq_pin, at91_cf_irq, + SA_SHIRQ, driver_name, cf); + if (status < 0) + goto fail0a; + cf->socket.pci_irq = board->irq_pin; + } else + cf->socket.pci_irq = NR_IRQS + 1; + + /* pcmcia layer only remaps "real" memory not iospace */ + cf->socket.io_offset = (unsigned long) ioremap(CF_IO_PHYS, SZ_2K); + if (!cf->socket.io_offset) + goto fail1; + + /* reserve CS4, CS5, and CS6 regions; but use just CS4 */ + if (!request_mem_region(io->start, io->end + 1 - io->start, + driver_name)) + goto fail1; + + pr_info("%s: irqs det #%d, io #%d\n", driver_name, + board->det_pin, board->irq_pin); + + cf->socket.owner = THIS_MODULE; + cf->socket.dev.dev = dev; + cf->socket.ops = &at91_cf_ops; + cf->socket.resource_ops = &pccard_static_ops; + cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP + | SS_CAP_MEM_ALIGN; + cf->socket.map_size = SZ_2K; + cf->socket.io[0].res = io; + + status = pcmcia_register_socket(&cf->socket); + if (status < 0) + goto fail2; + + return 0; + +fail2: + iounmap((void __iomem *) cf->socket.io_offset); + release_mem_region(io->start, io->end + 1 - io->start); +fail1: + if (board->irq_pin) + free_irq(board->irq_pin, cf); +fail0a: + free_irq(board->det_pin, cf); +fail0: + at91_sys_write(AT91_EBI_CSA, csa); + kfree(cf); + return status; +} + +static int __exit at91_cf_remove(struct device *dev) +{ + struct at91_cf_socket *cf = dev_get_drvdata(dev); + struct resource *io = cf->socket.io[0].res; + unsigned int csa; + + pcmcia_unregister_socket(&cf->socket); + free_irq(cf->board->irq_pin, cf); + free_irq(cf->board->det_pin, cf); + iounmap((void __iomem *) cf->socket.io_offset); + release_mem_region(io->start, io->end + 1 - io->start); + + csa = at91_sys_read(AT91_EBI_CSA); + at91_sys_write(AT91_EBI_CSA, csa & ~AT91_EBI_CS4A); + + kfree(cf); + return 0; +} + +static struct device_driver at91_cf_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, + .probe = at91_cf_probe, + .remove = __exit_p(at91_cf_remove), + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, +}; + +/*--------------------------------------------------------------------------*/ + +static int __init at91_cf_init(void) +{ + return driver_register(&at91_cf_driver); +} +module_init(at91_cf_init); + +static void __exit at91_cf_exit(void) +{ + driver_unregister(&at91_cf_driver); +} +module_exit(at91_cf_exit); + +MODULE_DESCRIPTION("AT91 Compact Flash Driver"); +MODULE_AUTHOR("David Brownell"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 120fa8da6392..912c03e5eb0a 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -12,7 +12,6 @@ * (C) 1999 David A. Hinds */ -#include #include #include #include diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 613f2f1fbfdd..3162998579c1 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -111,9 +110,9 @@ int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state) list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { if (socket->dev.dev != dev) continue; - down(&socket->skt_sem); + mutex_lock(&socket->skt_mutex); socket_suspend(socket); - up(&socket->skt_sem); + mutex_unlock(&socket->skt_mutex); } up_read(&pcmcia_socket_list_rwsem); @@ -129,9 +128,9 @@ int pcmcia_socket_dev_resume(struct device *dev) list_for_each_entry(socket, &pcmcia_socket_list, socket_list) { if (socket->dev.dev != dev) continue; - down(&socket->skt_sem); + mutex_lock(&socket->skt_mutex); socket_resume(socket); - up(&socket->skt_sem); + mutex_unlock(&socket->skt_mutex); } up_read(&pcmcia_socket_list_rwsem); @@ -237,7 +236,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) init_completion(&socket->socket_released); init_completion(&socket->thread_done); init_waitqueue_head(&socket->thread_wait); - init_MUTEX(&socket->skt_sem); + mutex_init(&socket->skt_mutex); spin_lock_init(&socket->thread_lock); ret = kernel_thread(pccardd, socket, CLONE_KERNEL); @@ -406,8 +405,6 @@ static void socket_shutdown(struct pcmcia_socket *s) cb_free(s); #endif s->functions = 0; - kfree(s->config); - s->config = NULL; s->ops->get_status(s, &status); if (status & SS_POWERON) { @@ -664,7 +661,7 @@ static int pccardd(void *__skt) spin_unlock_irqrestore(&skt->thread_lock, flags); if (events) { - down(&skt->skt_sem); + mutex_lock(&skt->skt_mutex); if (events & SS_DETECT) socket_detect_change(skt); if (events & SS_BATDEAD) @@ -673,7 +670,7 @@ static int pccardd(void *__skt) send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW); if (events & SS_READY) send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW); - up(&skt->skt_sem); + mutex_unlock(&skt->skt_mutex); continue; } @@ -717,8 +714,8 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) { int ret = 0; - /* s->skt_sem also protects s->callback */ - down(&s->skt_sem); + /* s->skt_mutex also protects s->callback */ + mutex_lock(&s->skt_mutex); if (c) { /* registration */ @@ -734,7 +731,7 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) } else s->callback = NULL; err: - up(&s->skt_sem); + mutex_unlock(&s->skt_mutex); return ret; } @@ -752,7 +749,7 @@ int pccard_reset_card(struct pcmcia_socket *skt) cs_dbg(skt, 1, "resetting socket\n"); - down(&skt->skt_sem); + mutex_lock(&skt->skt_mutex); do { if (!(skt->state & SOCKET_PRESENT)) { ret = CS_NO_CARD; @@ -781,7 +778,7 @@ int pccard_reset_card(struct pcmcia_socket *skt) ret = CS_SUCCESS; } while (0); - up(&skt->skt_sem); + mutex_unlock(&skt->skt_mutex); return ret; } /* reset_card */ @@ -797,7 +794,7 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt) cs_dbg(skt, 1, "suspending socket\n"); - down(&skt->skt_sem); + mutex_lock(&skt->skt_mutex); do { if (!(skt->state & SOCKET_PRESENT)) { ret = CS_NO_CARD; @@ -814,7 +811,7 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt) } ret = socket_suspend(skt); } while (0); - up(&skt->skt_sem); + mutex_unlock(&skt->skt_mutex); return ret; } /* suspend_card */ @@ -827,7 +824,7 @@ int pcmcia_resume_card(struct pcmcia_socket *skt) cs_dbg(skt, 1, "waking up socket\n"); - down(&skt->skt_sem); + mutex_lock(&skt->skt_mutex); do { if (!(skt->state & SOCKET_PRESENT)) { ret = CS_NO_CARD; @@ -841,7 +838,7 @@ int pcmcia_resume_card(struct pcmcia_socket *skt) if (!ret && skt->callback) skt->callback->resume(skt); } while (0); - up(&skt->skt_sem); + mutex_unlock(&skt->skt_mutex); return ret; } /* resume_card */ @@ -855,7 +852,7 @@ int pcmcia_eject_card(struct pcmcia_socket *skt) cs_dbg(skt, 1, "user eject request\n"); - down(&skt->skt_sem); + mutex_lock(&skt->skt_mutex); do { if (!(skt->state & SOCKET_PRESENT)) { ret = -ENODEV; @@ -871,7 +868,7 @@ int pcmcia_eject_card(struct pcmcia_socket *skt) socket_remove(skt); ret = 0; } while (0); - up(&skt->skt_sem); + mutex_unlock(&skt->skt_mutex); return ret; } /* eject_card */ @@ -884,7 +881,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) cs_dbg(skt, 1, "user insert request\n"); - down(&skt->skt_sem); + mutex_lock(&skt->skt_mutex); do { if (skt->state & SOCKET_PRESENT) { ret = -EBUSY; @@ -896,7 +893,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt) } ret = 0; } while (0); - up(&skt->skt_sem); + mutex_unlock(&skt->skt_mutex); return ret; } /* insert_card */ diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 7b37eba35bf1..d6164cd583fd 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -15,7 +15,7 @@ #ifndef _LINUX_CS_INTERNAL_H #define _LINUX_CS_INTERNAL_H -#include +#include /* Flags in client state */ #define CLIENT_CONFIG_LOCKED 0x0001 @@ -23,7 +23,7 @@ #define CLIENT_IO_REQ 0x0004 #define CLIENT_UNBOUND 0x0008 #define CLIENT_STALE 0x0010 -#define CLIENT_WIN_REQ(i) (0x20<<(i)) +#define CLIENT_WIN_REQ(i) (0x1<<(i)) #define CLIENT_CARDBUS 0x8000 #define REGION_MAGIC 0xE3C9 @@ -31,7 +31,7 @@ typedef struct region_t { u_short region_magic; u_short state; dev_info_t dev_info; - client_handle_t mtd; + struct pcmcia_device *mtd; u_int MediaID; region_info_t info; } region_t; @@ -40,12 +40,12 @@ typedef struct region_t { /* Each card function gets one of these guys */ typedef struct config_t { + struct kref ref; u_int state; u_int Attributes; u_int IntType; u_int ConfigBase; u_char Status, Pin, Copy, Option, ExtStatus; - u_int Present; u_int CardValues; io_req_t io; struct { @@ -95,12 +95,6 @@ static inline void cs_socket_put(struct pcmcia_socket *skt) } } -#define CHECK_SOCKET(s) \ - (((s) >= sockets) || (socket_table[s]->ops == NULL)) - -#define SOCKET(h) (h->socket) -#define CONFIG(h) (&SOCKET(h)->config[(h)->func]) - /* In cardbus.c */ int cb_alloc(struct pcmcia_socket *s); void cb_free(struct pcmcia_socket *s); @@ -133,10 +127,9 @@ extern struct class_interface pccard_sysfs_interface; extern struct rw_semaphore pcmcia_socket_list_rwsem; extern struct list_head pcmcia_socket_list; int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req); -int pccard_get_configuration_info(struct pcmcia_socket *s, unsigned int function, config_info_t *config); +int pccard_get_configuration_info(struct pcmcia_socket *s, struct pcmcia_device *p_dev, config_info_t *config); int pccard_reset_card(struct pcmcia_socket *skt); -int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status); -int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int function, conf_reg_t *reg); +int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, cs_status_t *status); struct pcmcia_callback{ diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index bb96ce1db08c..ae10d1eed65e 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -10,10 +10,9 @@ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * (C) 1999 David A. Hinds - * (C) 2003 - 2005 Dominik Brodowski + * (C) 2003 - 2006 Dominik Brodowski */ -#include #include #include #include @@ -23,6 +22,7 @@ #include #include #include +#include #define IN_CARD_SERVICES #include @@ -343,12 +343,19 @@ void pcmcia_put_dev(struct pcmcia_device *p_dev) put_device(&p_dev->dev); } +static void pcmcia_release_function(struct kref *ref) +{ + struct config_t *c = container_of(ref, struct config_t, ref); + kfree(c); +} + static void pcmcia_release_dev(struct device *dev) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); ds_dbg(1, "releasing dev %p\n", p_dev); pcmcia_put_socket(p_dev->socket); kfree(p_dev->devname); + kref_put(&p_dev->function_config->ref, pcmcia_release_function); kfree(p_dev); } @@ -377,29 +384,12 @@ static int pcmcia_device_probe(struct device * dev) p_drv = to_pcmcia_drv(dev->driver); s = p_dev->socket; - if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) { + if ((!p_drv->probe) || (!p_dev->function_config) || + (!try_module_get(p_drv->owner))) { ret = -EINVAL; goto put_dev; } - p_dev->state &= ~CLIENT_UNBOUND; - - /* set up the device configuration, if it hasn't been done before */ - if (!s->functions) { - cistpl_longlink_mfc_t mfc; - if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, - &mfc) == CS_SUCCESS) - s->functions = mfc.nfn; - else - s->functions = 1; - s->config = kzalloc(sizeof(config_t) * s->functions, - GFP_KERNEL); - if (!s->config) { - ret = -ENOMEM; - goto put_module; - } - } - ret = p_drv->probe(p_dev); if (ret) goto put_module; @@ -425,15 +415,61 @@ static int pcmcia_device_probe(struct device * dev) } +/* + * Removes a PCMCIA card from the device tree and socket list. + */ +static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover) +{ + struct pcmcia_device *p_dev; + struct pcmcia_device *tmp; + unsigned long flags; + + ds_dbg(2, "unbind_request(%d)\n", s->sock); + + + if (!leftover) + s->device_count = 0; + else + s->device_count = 1; + + /* unregister all pcmcia_devices registered with this socket, except leftover */ + list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) { + if (p_dev == leftover) + continue; + + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + list_del(&p_dev->socket_device_list); + p_dev->_removed=1; + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + + device_unregister(&p_dev->dev); + } + + return; +} + + static int pcmcia_device_remove(struct device * dev) { struct pcmcia_device *p_dev; struct pcmcia_driver *p_drv; + struct pcmcia_device_id *did; int i; - /* detach the "instance" */ p_dev = to_pcmcia_dev(dev); p_drv = to_pcmcia_drv(dev->driver); + + /* If we're removing the primary module driving a + * pseudo multi-function card, we need to unbind + * all devices + */ + did = (struct pcmcia_device_id *) p_dev->dev.driver_data; + if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && + (p_dev->socket->device_count != 0) && + (p_dev->device_no == 0)) + pcmcia_card_remove(p_dev->socket, p_dev); + + /* detach the "instance" */ if (!p_drv) return 0; @@ -441,17 +477,16 @@ static int pcmcia_device_remove(struct device * dev) p_drv->remove(p_dev); /* check for proper unloading */ - if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) + if (p_dev->_irq || p_dev->_io || p_dev->_locked) printk(KERN_INFO "pcmcia: driver %s did not release config properly\n", p_drv->drv.name); for (i = 0; i < MAX_WIN; i++) - if (p_dev->state & CLIENT_WIN_REQ(i)) + if (p_dev->_win & CLIENT_WIN_REQ(i)) printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", p_drv->drv.name); /* references from pcmcia_probe_device */ - p_dev->state = CLIENT_UNBOUND; pcmcia_put_dev(p_dev); module_put(p_drv->owner); @@ -459,37 +494,6 @@ static int pcmcia_device_remove(struct device * dev) } -/* - * Removes a PCMCIA card from the device tree and socket list. - */ -static void pcmcia_card_remove(struct pcmcia_socket *s) -{ - struct pcmcia_device *p_dev; - unsigned long flags; - - ds_dbg(2, "unbind_request(%d)\n", s->sock); - - s->device_count = 0; - - for (;;) { - /* unregister all pcmcia_devices registered with this socket*/ - spin_lock_irqsave(&pcmcia_dev_list_lock, flags); - if (list_empty(&s->devices_list)) { - spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - return; - } - p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); - list_del(&p_dev->socket_device_list); - p_dev->state |= CLIENT_STALE; - spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - - device_unregister(&p_dev->dev); - } - - return; -} /* unbind_request */ - - /* * pcmcia_device_query -- determine information about a pcmcia device */ @@ -546,7 +550,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) tmp = vers1->str + vers1->ofs[i]; length = strlen(tmp) + 1; - if ((length < 3) || (length > 255)) + if ((length < 2) || (length > 255)) continue; p_dev->prod_id[i] = kmalloc(sizeof(char) * length, @@ -571,11 +575,11 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) * won't work, this doesn't matter much at the moment: the driver core doesn't * support it either. */ -static DECLARE_MUTEX(device_add_lock); +static DEFINE_MUTEX(device_add_lock); struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function) { - struct pcmcia_device *p_dev; + struct pcmcia_device *p_dev, *tmp_dev; unsigned long flags; int bus_id_len; @@ -583,7 +587,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f if (!s) return NULL; - down(&device_add_lock); + mutex_lock(&device_add_lock); /* max of 2 devices per card */ if (s->device_count == 2) @@ -596,6 +600,8 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f p_dev->socket = s; p_dev->device_no = (s->device_count++); p_dev->func = function; + if (s->functions <= function) + s->functions = function + 1; p_dev->dev.bus = &pcmcia_bus_type; p_dev->dev.parent = s->dev.dev; @@ -608,36 +614,55 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id); /* compat */ - p_dev->state = CLIENT_UNBOUND; + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + + /* + * p_dev->function_config must be the same for all card functions. + * Note that this is serialized by the device_add_lock, so that + * only one such struct will be created. + */ + list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) + if (p_dev->func == tmp_dev->func) { + p_dev->function_config = tmp_dev->function_config; + kref_get(&p_dev->function_config->ref); + } /* Add to the list in pcmcia_bus_socket */ - spin_lock_irqsave(&pcmcia_dev_list_lock, flags); list_add_tail(&p_dev->socket_device_list, &s->devices_list); + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + if (!p_dev->function_config) { + p_dev->function_config = kzalloc(sizeof(struct config_t), + GFP_KERNEL); + if (!p_dev->function_config) + goto err_unreg; + kref_init(&p_dev->function_config->ref); + } + printk(KERN_NOTICE "pcmcia: registering new device %s\n", p_dev->devname); pcmcia_device_query(p_dev); - if (device_register(&p_dev->dev)) { - spin_lock_irqsave(&pcmcia_dev_list_lock, flags); - list_del(&p_dev->socket_device_list); - spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + if (device_register(&p_dev->dev)) + goto err_unreg; - goto err_free; - } - - up(&device_add_lock); + mutex_unlock(&device_add_lock); return p_dev; + err_unreg: + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + list_del(&p_dev->socket_device_list); + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + err_free: kfree(p_dev->devname); kfree(p_dev); s->device_count--; err_put: - up(&device_add_lock); + mutex_unlock(&device_add_lock); pcmcia_put_socket(s); return NULL; @@ -696,7 +721,7 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt) int no_devices=0; unsigned long flags; - /* must be called with skt_sem held */ + /* must be called with skt_mutex held */ spin_lock_irqsave(&pcmcia_dev_list_lock, flags); if (list_empty(&skt->devices_list)) no_devices=1; @@ -819,9 +844,11 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); struct pcmcia_device_id *did = p_drv->id_table; +#ifdef CONFIG_PCMCIA_IOCTL /* matching by cardmgr */ if (p_dev->cardmgr == p_drv) return 1; +#endif while (did && did->match_flags) { if (pcmcia_devmatch(p_dev, did)) @@ -927,7 +954,7 @@ static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); - if (p_dev->dev.power.power_state.event != PM_EVENT_ON) + if (p_dev->suspended) return sprintf(buf, "off\n"); else return sprintf(buf, "on\n"); @@ -942,11 +969,9 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute if (!count) return -EINVAL; - if ((p_dev->dev.power.power_state.event == PM_EVENT_ON) && - (!strncmp(buf, "off", 3))) + if ((!p_dev->suspended) && !strncmp(buf, "off", 3)) ret = dpm_runtime_suspend(dev, PMSG_SUSPEND); - else if ((p_dev->dev.power.power_state.event != PM_EVENT_ON) && - (!strncmp(buf, "on", 2))) + else if (p_dev->suspended && !strncmp(buf, "on", 2)) dpm_runtime_resume(dev); return ret ? ret : count; @@ -982,9 +1007,9 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, if (!count) return -EINVAL; - down(&p_dev->socket->skt_sem); + mutex_lock(&p_dev->socket->skt_mutex); p_dev->allow_func_id_match = 1; - up(&p_dev->socket->skt_sem); + mutex_unlock(&p_dev->socket->skt_mutex); bus_rescan_devices(&pcmcia_bus_type); @@ -1012,14 +1037,27 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); struct pcmcia_driver *p_drv = NULL; + int ret = 0; if (dev->driver) p_drv = to_pcmcia_drv(dev->driver); - if (p_drv && p_drv->suspend) - return p_drv->suspend(p_dev); + if (!p_drv) + goto out; - return 0; + if (p_drv->suspend) { + ret = p_drv->suspend(p_dev); + if (ret) + goto out; + } + + if (p_dev->device_no == p_dev->func) + pcmcia_release_configuration(p_dev); + + out: + if (!ret) + p_dev->suspended = 1; + return ret; } @@ -1027,14 +1065,27 @@ static int pcmcia_dev_resume(struct device * dev) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); struct pcmcia_driver *p_drv = NULL; + int ret = 0; if (dev->driver) p_drv = to_pcmcia_drv(dev->driver); - if (p_drv && p_drv->resume) - return p_drv->resume(p_dev); + if (!p_drv) + goto out; - return 0; + if (p_dev->device_no == p_dev->func) { + ret = pcmcia_request_configuration(p_dev, &p_dev->conf); + if (ret) + goto out; + } + + if (p_drv->resume) + ret = p_drv->resume(p_dev); + + out: + if (!ret) + p_dev->suspended = 0; + return ret; } @@ -1100,7 +1151,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) switch (event) { case CS_EVENT_CARD_REMOVAL: s->pcmcia_state.present = 0; - pcmcia_card_remove(skt); + pcmcia_card_remove(skt, NULL); handle_event(skt, event); break; @@ -1128,6 +1179,32 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) } /* ds_event */ +struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *_p_dev) +{ + struct pcmcia_device *p_dev; + struct pcmcia_device *ret = NULL; + + p_dev = pcmcia_get_dev(_p_dev); + if (!p_dev) + return NULL; + + if (!p_dev->socket->pcmcia_state.present) + goto out; + + if (p_dev->_removed) + goto out; + + if (p_dev->suspended) + goto out; + + ret = p_dev; + out: + pcmcia_put_dev(p_dev); + return ret; +} +EXPORT_SYMBOL(pcmcia_dev_present); + + static struct pcmcia_callback pcmcia_bus_callback = { .owner = THIS_MODULE, .event = ds_event, diff --git a/drivers/pcmcia/ds_internal.h b/drivers/pcmcia/ds_internal.h index d359bd25a51c..3a2b25e6ed73 100644 --- a/drivers/pcmcia/ds_internal.h +++ b/drivers/pcmcia/ds_internal.h @@ -8,6 +8,8 @@ extern void pcmcia_put_dev(struct pcmcia_device *p_dev); struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function); +extern int pcmcia_release_configuration(struct pcmcia_device *p_dev); + #ifdef CONFIG_PCMCIA_IOCTL extern void __init pcmcia_setup_ioctl(void); extern void __exit pcmcia_cleanup_ioctl(void); @@ -15,7 +17,7 @@ extern void handle_event(struct pcmcia_socket *s, event_t event); extern int handle_request(struct pcmcia_socket *s, event_t event); #else static inline void __init pcmcia_setup_ioctl(void) { return; } -static inline void __init pcmcia_cleanup_ioctl(void) { return; } +static inline void __exit pcmcia_cleanup_ioctl(void) { return; } static inline void handle_event(struct pcmcia_socket *s, event_t event) { return; } static inline int handle_request(struct pcmcia_socket *s, event_t event) { return CS_SUCCESS; } #endif diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index 7979c85df3dc..d5f03a338c6c 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 35a92d1e4945..bd0308e89815 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c deleted file mode 100644 index ebb161c4f819..000000000000 --- a/drivers/pcmcia/pcmcia_compat.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * PCMCIA 16-bit compatibility functions - * - * The initial developer of the original code is David A. Hinds - * . Portions created by David A. Hinds - * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - * - * Copyright (C) 2004 Dominik Brodowski - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include -#include -#include - -#define IN_CARD_SERVICES -#include -#include -#include -#include -#include -#include - -#include "cs_internal.h" - -int pcmcia_get_first_tuple(struct pcmcia_device *p_dev, tuple_t *tuple) -{ - return pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple); -} -EXPORT_SYMBOL(pcmcia_get_first_tuple); - -int pcmcia_get_next_tuple(struct pcmcia_device *p_dev, tuple_t *tuple) -{ - return pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple); -} -EXPORT_SYMBOL(pcmcia_get_next_tuple); - -int pcmcia_get_tuple_data(struct pcmcia_device *p_dev, tuple_t *tuple) -{ - return pccard_get_tuple_data(p_dev->socket, tuple); -} -EXPORT_SYMBOL(pcmcia_get_tuple_data); - -int pcmcia_parse_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, cisparse_t *parse) -{ - return pccard_parse_tuple(tuple, parse); -} -EXPORT_SYMBOL(pcmcia_parse_tuple); - -int pcmcia_validate_cis(struct pcmcia_device *p_dev, cisinfo_t *info) -{ - return pccard_validate_cis(p_dev->socket, p_dev->func, info); -} -EXPORT_SYMBOL(pcmcia_validate_cis); - - -int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req) -{ - return pccard_reset_card(p_dev->socket); -} -EXPORT_SYMBOL(pcmcia_reset_card); diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 80969f7e7a0b..c53db7ceda5e 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -18,7 +18,6 @@ */ -#include #include #include #include @@ -70,10 +69,26 @@ extern int ds_pc_debug; #define ds_dbg(lvl, fmt, arg...) do { } while (0) #endif +static struct pcmcia_device *get_pcmcia_device(struct pcmcia_socket *s, + unsigned int function) +{ + struct pcmcia_device *p_dev = NULL; + unsigned long flags; + + spin_lock_irqsave(&pcmcia_dev_list_lock, flags); + list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { + if (p_dev->func == function) { + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + return pcmcia_get_dev(p_dev); + } + } + spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); + return NULL; +} /* backwards-compatible accessing of driver --- by name! */ -static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info) +static struct pcmcia_driver *get_pcmcia_driver(dev_info_t *dev_info) { struct device_driver *drv; struct pcmcia_driver *p_drv; @@ -214,7 +229,7 @@ static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info) * by userspace before, we need to * return the "instance". */ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - bind_info->instance = p_dev->instance; + bind_info->instance = p_dev; ret = -EBUSY; goto err_put_module; } else { @@ -253,9 +268,9 @@ rescan: /* * Prevent this racing with a card insertion. */ - down(&s->skt_sem); + mutex_lock(&s->skt_mutex); bus_rescan_devices(&pcmcia_bus_type); - up(&s->skt_sem); + mutex_unlock(&s->skt_mutex); /* check whether the driver indeed matched. I don't care if this * is racy or not, because it can only happen on cardmgr access @@ -289,6 +304,7 @@ static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int { dev_node_t *node; struct pcmcia_device *p_dev; + struct pcmcia_driver *p_drv; unsigned long flags; int ret = 0; @@ -343,16 +359,16 @@ static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int found: spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); - if ((!p_dev->instance) || - (p_dev->instance->state & DEV_CONFIG_PENDING)) { + p_drv = to_pcmcia_drv(p_dev->dev.driver); + if (p_drv && !p_dev->_locked) { ret = -EAGAIN; goto err_put; } if (first) - node = p_dev->instance->dev; + node = p_dev->dev_node; else - for (node = p_dev->instance->dev; node; node = node->next) + for (node = p_dev->dev_node; node; node = node->next) if (node == bind_info->next) break; if (!node) { @@ -583,14 +599,16 @@ static int ds_ioctl(struct inode * inode, struct file * file, if (buf->config.Function && (buf->config.Function >= s->functions)) ret = CS_BAD_ARGS; - else - ret = pccard_get_configuration_info(s, - buf->config.Function, &buf->config); + else { + struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function); + ret = pccard_get_configuration_info(s, p_dev, &buf->config); + pcmcia_put_dev(p_dev); + } break; case DS_GET_FIRST_TUPLE: - down(&s->skt_sem); + mutex_lock(&s->skt_mutex); pcmcia_validate_mem(s); - up(&s->skt_sem); + mutex_unlock(&s->skt_mutex); ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple); break; case DS_GET_NEXT_TUPLE: @@ -609,16 +627,19 @@ static int ds_ioctl(struct inode * inode, struct file * file, ret = pccard_reset_card(s); break; case DS_GET_STATUS: - if (buf->status.Function && - (buf->status.Function >= s->functions)) - ret = CS_BAD_ARGS; - else - ret = pccard_get_status(s, buf->status.Function, &buf->status); - break; + if (buf->status.Function && + (buf->status.Function >= s->functions)) + ret = CS_BAD_ARGS; + else { + struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function); + ret = pccard_get_status(s, p_dev, &buf->status); + pcmcia_put_dev(p_dev); + } + break; case DS_VALIDATE_CIS: - down(&s->skt_sem); + mutex_lock(&s->skt_mutex); pcmcia_validate_mem(s); - up(&s->skt_sem); + mutex_unlock(&s->skt_mutex); ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo); break; case DS_SUSPEND_CARD: @@ -638,12 +659,16 @@ static int ds_ioctl(struct inode * inode, struct file * file, err = -EPERM; goto free_out; } - if (buf->conf_reg.Function && - (buf->conf_reg.Function >= s->functions)) - ret = CS_BAD_ARGS; - else - ret = pccard_access_configuration_register(s, - buf->conf_reg.Function, &buf->conf_reg); + + ret = CS_BAD_ARGS; + + if (!(buf->conf_reg.Function && + (buf->conf_reg.Function >= s->functions))) { + struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->conf_reg.Function); + if (p_dev) + ret = pcmcia_access_configuration_register(p_dev, &buf->conf_reg); + pcmcia_put_dev(p_dev); + } break; case DS_GET_FIRST_REGION: case DS_GET_NEXT_REGION: diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 89022ad5b520..45063b4e5b78 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -14,7 +14,6 @@ * */ -#include #include #include #include @@ -89,7 +88,7 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base, } if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) { *base = s->io_offset | (*base & 0x0fff); - s->io[0].Attributes = attr; + s->io[0].res->flags = (s->io[0].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS); return 0; } /* Check for an already-allocated window that must conflict with @@ -97,38 +96,36 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base, * potential conflicts, just the most obvious ones. */ for (i = 0; i < MAX_IO_WIN; i++) - if ((s->io[i].NumPorts != 0) && - ((s->io[i].BasePort & (align-1)) == *base)) + if ((s->io[i].res) && + ((s->io[i].res->start & (align-1)) == *base)) return 1; for (i = 0; i < MAX_IO_WIN; i++) { - if (s->io[i].NumPorts == 0) { + if (!s->io[i].res) { s->io[i].res = pcmcia_find_io_region(*base, num, align, s); if (s->io[i].res) { - s->io[i].Attributes = attr; - s->io[i].BasePort = *base = s->io[i].res->start; - s->io[i].NumPorts = s->io[i].InUse = num; + *base = s->io[i].res->start; + s->io[i].res->flags = (s->io[i].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS); + s->io[i].InUse = num; break; } else return 1; - } else if (s->io[i].Attributes != attr) + } else if ((s->io[i].res->flags & IORESOURCE_BITS) != (attr & IORESOURCE_BITS)) continue; /* Try to extend top of window */ - try = s->io[i].BasePort + s->io[i].NumPorts; + try = s->io[i].res->end + 1; if ((*base == 0) || (*base == try)) if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start, s->io[i].res->end + num, s) == 0) { *base = try; - s->io[i].NumPorts += num; s->io[i].InUse += num; break; } /* Try to extend bottom of window */ - try = s->io[i].BasePort - num; + try = s->io[i].res->start - num; if ((*base == 0) || (*base == try)) if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num, s->io[i].res->end, s) == 0) { - s->io[i].BasePort = *base = try; - s->io[i].NumPorts += num; + *base = try; s->io[i].InUse += num; break; } @@ -143,12 +140,13 @@ static void release_io_space(struct pcmcia_socket *s, ioaddr_t base, int i; for (i = 0; i < MAX_IO_WIN; i++) { - if ((s->io[i].BasePort <= base) && - (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) { + if (!s->io[i].res) + continue; + if ((s->io[i].res->start <= base) && + (s->io[i].res->end >= base+num-1)) { s->io[i].InUse -= num; /* Free the window if no one else is using it */ if (s->io[i].InUse == 0) { - s->io[i].NumPorts = 0; release_resource(s->io[i].res); kfree(s->io[i].res); s->io[i].res = NULL; @@ -165,21 +163,19 @@ static void release_io_space(struct pcmcia_socket *s, ioaddr_t base, * this and the tuple reading services. */ -int pccard_access_configuration_register(struct pcmcia_socket *s, - unsigned int function, +int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg) { + struct pcmcia_socket *s; config_t *c; int addr; u_char val; - if (!s || !s->config) + if (!p_dev || !p_dev->function_config) return CS_NO_CARD; - c = &s->config[function]; - - if (c == NULL) - return CS_NO_CARD; + s = p_dev->socket; + c = p_dev->function_config; if (!(c->state & CONFIG_LOCKED)) return CS_CONFIGURATION_LOCKED; @@ -200,20 +196,12 @@ int pccard_access_configuration_register(struct pcmcia_socket *s, break; } return CS_SUCCESS; -} /* pccard_access_configuration_register */ - -int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, - conf_reg_t *reg) -{ - return pccard_access_configuration_register(p_dev->socket, - p_dev->func, reg); -} +} /* pcmcia_access_configuration_register */ EXPORT_SYMBOL(pcmcia_access_configuration_register); - int pccard_get_configuration_info(struct pcmcia_socket *s, - unsigned int function, + struct pcmcia_device *p_dev, config_info_t *config) { config_t *c; @@ -221,7 +209,7 @@ int pccard_get_configuration_info(struct pcmcia_socket *s, if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; - config->Function = function; + config->Function = p_dev->func; #ifdef CONFIG_CARDBUS if (s->state & SOCKET_CARDBUS) { @@ -235,14 +223,14 @@ int pccard_get_configuration_info(struct pcmcia_socket *s, config->AssignedIRQ = s->irq.AssignedIRQ; if (config->AssignedIRQ) config->Attributes |= CONF_ENABLE_IRQ; - config->BasePort1 = s->io[0].BasePort; - config->NumPorts1 = s->io[0].NumPorts; + config->BasePort1 = s->io[0].res->start; + config->NumPorts1 = s->io[0].res->end - config->BasePort1 + 1; } return CS_SUCCESS; } #endif - c = (s->config != NULL) ? &s->config[function] : NULL; + c = (p_dev) ? p_dev->function_config : NULL; if ((c == NULL) || !(c->state & CONFIG_LOCKED)) { config->Attributes = 0; @@ -271,7 +259,7 @@ int pccard_get_configuration_info(struct pcmcia_socket *s, int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config) { - return pccard_get_configuration_info(p_dev->socket, p_dev->func, + return pccard_get_configuration_info(p_dev->socket, p_dev, config); } EXPORT_SYMBOL(pcmcia_get_configuration_info); @@ -317,7 +305,7 @@ EXPORT_SYMBOL(pcmcia_get_window); * SocketState yet: I haven't seen any point for it. */ -int pccard_get_status(struct pcmcia_socket *s, unsigned int function, +int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, cs_status_t *status) { config_t *c; @@ -334,11 +322,12 @@ int pccard_get_status(struct pcmcia_socket *s, unsigned int function, if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; - c = (s->config != NULL) ? &s->config[function] : NULL; + c = (p_dev) ? p_dev->function_config : NULL; + if ((c != NULL) && (c->state & CONFIG_LOCKED) && (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) { u_char reg; - if (c->Present & PRESENT_PIN_REPLACE) { + if (c->CardValues & PRESENT_PIN_REPLACE) { pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); status->CardState |= (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; @@ -352,7 +341,7 @@ int pccard_get_status(struct pcmcia_socket *s, unsigned int function, /* No PRR? Then assume we're always ready */ status->CardState |= CS_EVENT_READY_CHANGE; } - if (c->Present & PRESENT_EXT_STATUS) { + if (c->CardValues & PRESENT_EXT_STATUS) { pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); status->CardState |= (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; @@ -370,11 +359,9 @@ int pccard_get_status(struct pcmcia_socket *s, unsigned int function, return CS_SUCCESS; } /* pccard_get_status */ -int pcmcia_get_status(client_handle_t handle, cs_status_t *status) +int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status) { - struct pcmcia_socket *s; - s = SOCKET(handle); - return pccard_get_status(s, handle->func, status); + return pccard_get_status(p_dev->socket, p_dev, status); } EXPORT_SYMBOL(pcmcia_get_status); @@ -422,7 +409,8 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, config_t *c; s = p_dev->socket; - c = CONFIG(p_dev); + c = p_dev->function_config; + if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; if (!(c->state & CONFIG_LOCKED)) @@ -454,6 +442,28 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, (mod->Attributes & CONF_VPP2_CHANGE_VALID)) return CS_BAD_VPP; + if (mod->Attributes & CONF_IO_CHANGE_WIDTH) { + pccard_io_map io_off = { 0, 0, 0, 0, 1 }; + pccard_io_map io_on; + int i; + + io_on.speed = io_speed; + for (i = 0; i < MAX_IO_WIN; i++) { + if (!s->io[i].res) + continue; + io_off.map = i; + io_on.map = i; + + io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8; + io_on.start = s->io[i].res->start; + io_on.stop = s->io[i].res->end; + + s->ops->set_io_map(s, &io_off); + mdelay(40); + s->ops->set_io_map(s, &io_on); + } + } + return CS_SUCCESS; } /* modify_configuration */ EXPORT_SYMBOL(pcmcia_modify_configuration); @@ -463,23 +473,23 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev) { pccard_io_map io = { 0, 0, 0, 0, 1 }; struct pcmcia_socket *s = p_dev->socket; + config_t *c = p_dev->function_config; int i; - if (!(p_dev->state & CLIENT_CONFIG_LOCKED)) - return CS_BAD_HANDLE; - p_dev->state &= ~CLIENT_CONFIG_LOCKED; - - if (!(p_dev->state & CLIENT_STALE)) { - config_t *c = CONFIG(p_dev); + if (p_dev->_locked) { + p_dev->_locked = 0; if (--(s->lock_count) == 0) { s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */ s->socket.Vpp = 0; s->socket.io_irq = 0; s->ops->set_socket(s, &s->socket); } + } + if (c->state & CONFIG_LOCKED) { + c->state &= ~CONFIG_LOCKED; if (c->state & CONFIG_IO_REQ) for (i = 0; i < MAX_IO_WIN; i++) { - if (s->io[i].NumPorts == 0) + if (!s->io[i].res) continue; s->io[i].Config--; if (s->io[i].Config != 0) @@ -487,12 +497,10 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev) io.map = i; s->ops->set_io_map(s, &io); } - c->state &= ~CONFIG_LOCKED; } return CS_SUCCESS; } /* pcmcia_release_configuration */ -EXPORT_SYMBOL(pcmcia_release_configuration); /** pcmcia_release_io @@ -503,25 +511,23 @@ EXPORT_SYMBOL(pcmcia_release_configuration); * don't bother checking the port ranges against the current socket * values. */ -int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req) +static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req) { struct pcmcia_socket *s = p_dev->socket; + config_t *c = p_dev->function_config; - if (!(p_dev->state & CLIENT_IO_REQ)) + if (!p_dev->_io ) return CS_BAD_HANDLE; - p_dev->state &= ~CLIENT_IO_REQ; - if (!(p_dev->state & CLIENT_STALE)) { - config_t *c = CONFIG(p_dev); - if (c->state & CONFIG_LOCKED) - return CS_CONFIGURATION_LOCKED; - if ((c->io.BasePort1 != req->BasePort1) || - (c->io.NumPorts1 != req->NumPorts1) || - (c->io.BasePort2 != req->BasePort2) || - (c->io.NumPorts2 != req->NumPorts2)) - return CS_BAD_ARGS; - c->state &= ~CONFIG_IO_REQ; - } + p_dev->_io = 0; + + if ((c->io.BasePort1 != req->BasePort1) || + (c->io.NumPorts1 != req->NumPorts1) || + (c->io.BasePort2 != req->BasePort2) || + (c->io.NumPorts2 != req->NumPorts2)) + return CS_BAD_ARGS; + + c->state &= ~CONFIG_IO_REQ; release_io_space(s, req->BasePort1, req->NumPorts1); if (req->NumPorts2) @@ -529,28 +535,26 @@ int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req) return CS_SUCCESS; } /* pcmcia_release_io */ -EXPORT_SYMBOL(pcmcia_release_io); -int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) +static int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) { struct pcmcia_socket *s = p_dev->socket; - if (!(p_dev->state & CLIENT_IRQ_REQ)) - return CS_BAD_HANDLE; - p_dev->state &= ~CLIENT_IRQ_REQ; + config_t *c= p_dev->function_config; - if (!(p_dev->state & CLIENT_STALE)) { - config_t *c = CONFIG(p_dev); - if (c->state & CONFIG_LOCKED) - return CS_CONFIGURATION_LOCKED; - if (c->irq.Attributes != req->Attributes) - return CS_BAD_ATTRIBUTE; - if (s->irq.AssignedIRQ != req->AssignedIRQ) - return CS_BAD_IRQ; - if (--s->irq.Config == 0) { - c->state &= ~CONFIG_IRQ_REQ; - s->irq.AssignedIRQ = 0; - } + if (!p_dev->_irq) + return CS_BAD_HANDLE; + p_dev->_irq = 0; + + if (c->state & CONFIG_LOCKED) + return CS_CONFIGURATION_LOCKED; + if (c->irq.Attributes != req->Attributes) + return CS_BAD_ATTRIBUTE; + if (s->irq.AssignedIRQ != req->AssignedIRQ) + return CS_BAD_IRQ; + if (--s->irq.Config == 0) { + c->state &= ~CONFIG_IRQ_REQ; + s->irq.AssignedIRQ = 0; } if (req->Attributes & IRQ_HANDLE_PRESENT) { @@ -563,7 +567,6 @@ int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req) return CS_SUCCESS; } /* pcmcia_release_irq */ -EXPORT_SYMBOL(pcmcia_release_irq); int pcmcia_release_window(window_handle_t win) @@ -573,7 +576,7 @@ int pcmcia_release_window(window_handle_t win) if ((win == NULL) || (win->magic != WINDOW_MAGIC)) return CS_BAD_HANDLE; s = win->sock; - if (!(win->handle->state & CLIENT_WIN_REQ(win->index))) + if (!(win->handle->_win & CLIENT_WIN_REQ(win->index))) return CS_BAD_HANDLE; /* Shut down memory window */ @@ -587,7 +590,7 @@ int pcmcia_release_window(window_handle_t win) kfree(win->ctl.res); win->ctl.res = NULL; } - win->handle->state &= ~CLIENT_WIN_REQ(win->index); + win->handle->_win &= ~CLIENT_WIN_REQ(win->index); win->magic = 0; @@ -610,16 +613,12 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, if (req->IntType & INT_CARDBUS) return CS_UNSUPPORTED_MODE; - c = CONFIG(p_dev); + c = p_dev->function_config; if (c->state & CONFIG_LOCKED) return CS_CONFIGURATION_LOCKED; /* Do power control. We don't allow changes in Vcc. */ - if (s->socket.Vcc != req->Vcc) - return CS_BAD_VCC; - if (req->Vpp1 != req->Vpp2) - return CS_BAD_VPP; - s->socket.Vpp = req->Vpp1; + s->socket.Vpp = req->Vpp; if (s->ops->set_socket(s, &s->socket)) return CS_BAD_VPP; @@ -643,7 +642,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, /* Set up CIS configuration registers */ base = c->ConfigBase = req->ConfigBase; - c->Present = c->CardValues = req->Present; + c->CardValues = req->Present; if (req->Present & PRESENT_COPY) { c->Copy = req->Copy; pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy); @@ -690,10 +689,10 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, if (c->state & CONFIG_IO_REQ) { iomap.speed = io_speed; for (i = 0; i < MAX_IO_WIN; i++) - if (s->io[i].NumPorts != 0) { + if (s->io[i].res) { iomap.map = i; iomap.flags = MAP_ACTIVE; - switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) { + switch (s->io[i].res->flags & IO_DATA_PATH_WIDTH) { case IO_DATA_PATH_WIDTH_16: iomap.flags |= MAP_16BIT; break; case IO_DATA_PATH_WIDTH_AUTO: @@ -701,15 +700,15 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, default: break; } - iomap.start = s->io[i].BasePort; - iomap.stop = iomap.start + s->io[i].NumPorts - 1; + iomap.start = s->io[i].res->start; + iomap.stop = s->io[i].res->end; s->ops->set_io_map(s, &iomap); s->io[i].Config++; } } c->state |= CONFIG_LOCKED; - p_dev->state |= CLIENT_CONFIG_LOCKED; + p_dev->_locked = 1; return CS_SUCCESS; } /* pcmcia_request_configuration */ EXPORT_SYMBOL(pcmcia_request_configuration); @@ -730,7 +729,7 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req) if (!req) return CS_UNSUPPORTED_MODE; - c = CONFIG(p_dev); + c = p_dev->function_config; if (c->state & CONFIG_LOCKED) return CS_CONFIGURATION_LOCKED; if (c->state & CONFIG_IO_REQ) @@ -755,7 +754,7 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req) c->io = *req; c->state |= CONFIG_IO_REQ; - p_dev->state |= CLIENT_IO_REQ; + p_dev->_io = 1; return CS_SUCCESS; } /* pcmcia_request_io */ EXPORT_SYMBOL(pcmcia_request_io); @@ -786,7 +785,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; - c = CONFIG(p_dev); + c = p_dev->function_config; if (c->state & CONFIG_LOCKED) return CS_CONFIGURATION_LOCKED; if (c->state & CONFIG_IRQ_REQ) @@ -851,7 +850,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) s->irq.Config++; c->state |= CONFIG_IRQ_REQ; - p_dev->state |= CLIENT_IRQ_REQ; + p_dev->_irq = 1; #ifdef CONFIG_PCMCIA_PROBE pcmcia_used_irq[irq]++; @@ -911,7 +910,7 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h if (!win->ctl.res) return CS_IN_USE; } - (*p_dev)->state |= CLIENT_WIN_REQ(w); + (*p_dev)->_win |= CLIENT_WIN_REQ(w); /* Configure the socket controller */ win->ctl.map = w+1; @@ -941,3 +940,14 @@ int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_h return CS_SUCCESS; } /* pcmcia_request_window */ EXPORT_SYMBOL(pcmcia_request_window); + +void pcmcia_disable_device(struct pcmcia_device *p_dev) { + pcmcia_release_configuration(p_dev); + pcmcia_release_io(p_dev, &p_dev->io); + pcmcia_release_irq(p_dev, &p_dev->irq); + if (&p_dev->win) + pcmcia_release_window(p_dev->win); + + p_dev->dev_node = NULL; +} +EXPORT_SYMBOL(pcmcia_disable_device); diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index f2789afb22b2..16d1ea7b0a18 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 514609369836..81dfc2cac2b4 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -12,7 +12,6 @@ * (C) 1999 David A. Hinds */ -#include #include #include @@ -22,6 +21,8 @@ #include "cs_internal.h" +#ifdef CONFIG_PCMCIA_IOCTL + #ifdef CONFIG_PCMCIA_PROBE static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) @@ -98,6 +99,8 @@ int pcmcia_adjust_resource_info(adjust_t *adj) } EXPORT_SYMBOL(pcmcia_adjust_resource_info); +#endif + int pcmcia_validate_mem(struct pcmcia_socket *s) { if (s->resource_ops->validate_mem) diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 5301ac60358f..0f8b157c9717 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -12,7 +12,6 @@ * (C) 1999 David A. Hinds */ -#include #include #include #include @@ -61,7 +60,7 @@ struct socket_data { unsigned int rsrc_mem_probe; }; -static DECLARE_MUTEX(rsrc_sem); +static DEFINE_MUTEX(rsrc_mutex); #define MEM_PROBE_LOW (1 << 0) #define MEM_PROBE_HIGH (1 << 1) @@ -484,7 +483,7 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) /* - * Locking note: Must be called with skt_sem held! + * Locking note: Must be called with skt_mutex held! */ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) { @@ -495,7 +494,7 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) if (!probe_mem) return 0; - down(&rsrc_sem); + mutex_lock(&rsrc_mutex); if (s->features & SS_CAP_PAGE_REGS) probe_mask = MEM_PROBE_HIGH; @@ -507,7 +506,7 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) s_data->rsrc_mem_probe |= probe_mask; } - up(&rsrc_sem); + mutex_unlock(&rsrc_mutex); return ret; } @@ -585,7 +584,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star struct socket_data *s_data = s->resource_data; int ret = -ENOMEM; - down(&rsrc_sem); + mutex_lock(&rsrc_mutex); for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) { unsigned long start = m->base; unsigned long end = m->base + m->num - 1; @@ -596,7 +595,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star ret = adjust_resource(res, r_start, r_end - r_start + 1); break; } - up(&rsrc_sem); + mutex_unlock(&rsrc_mutex); return ret; } @@ -630,7 +629,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, data.offset = base & data.mask; data.map = &s_data->io_db; - down(&rsrc_sem); + mutex_lock(&rsrc_mutex); #ifdef CONFIG_PCI if (s->cb_dev) { ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, @@ -639,7 +638,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, #endif ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, 1, pcmcia_align, &data); - up(&rsrc_sem); + mutex_unlock(&rsrc_mutex); if (ret != 0) { kfree(res); @@ -672,7 +671,7 @@ static struct resource * nonstatic_find_mem_region(u_long base, u_long num, min = 0x100000UL + base; } - down(&rsrc_sem); + mutex_lock(&rsrc_mutex); #ifdef CONFIG_PCI if (s->cb_dev) { ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, @@ -682,7 +681,7 @@ static struct resource * nonstatic_find_mem_region(u_long base, u_long num, #endif ret = allocate_resource(&iomem_resource, res, num, min, max, 1, pcmcia_align, &data); - up(&rsrc_sem); + mutex_unlock(&rsrc_mutex); if (ret == 0 || low) break; low = 1; @@ -705,7 +704,7 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned if (end < start) return -EINVAL; - down(&rsrc_sem); + mutex_lock(&rsrc_mutex); switch (action) { case ADD_MANAGED_RESOURCE: ret = add_interval(&data->mem_db, start, size); @@ -723,7 +722,7 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned default: ret = -EINVAL; } - up(&rsrc_sem); + mutex_unlock(&rsrc_mutex); return ret; } @@ -741,7 +740,7 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long if (end > IO_SPACE_LIMIT) return -EINVAL; - down(&rsrc_sem); + mutex_lock(&rsrc_mutex); switch (action) { case ADD_MANAGED_RESOURCE: if (add_interval(&data->io_db, start, size) != 0) { @@ -760,7 +759,7 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long ret = -EINVAL; break; } - up(&rsrc_sem); + mutex_unlock(&rsrc_mutex); return ret; } @@ -867,7 +866,7 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s) struct socket_data *data = s->resource_data; struct resource_map *p, *q; - down(&rsrc_sem); + mutex_lock(&rsrc_mutex); for (p = data->mem_db.next; p != &data->mem_db; p = q) { q = p->next; kfree(p); @@ -876,7 +875,7 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s) q = p->next; kfree(p); } - up(&rsrc_sem); + mutex_unlock(&rsrc_mutex); } @@ -901,7 +900,7 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf) struct resource_map *p; ssize_t ret = 0; - down(&rsrc_sem); + mutex_lock(&rsrc_mutex); data = s->resource_data; for (p = data->io_db.next; p != &data->io_db; p = p->next) { @@ -913,7 +912,7 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf) ((unsigned long) p->base + p->num - 1)); } - up(&rsrc_sem); + mutex_unlock(&rsrc_mutex); return (ret); } @@ -953,7 +952,7 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf) struct resource_map *p; ssize_t ret = 0; - down(&rsrc_sem); + mutex_lock(&rsrc_mutex); data = s->resource_data; for (p = data->mem_db.next; p != &data->mem_db; p = p->next) { @@ -965,7 +964,7 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf) ((unsigned long) p->base + p->num - 1)); } - up(&rsrc_sem); + mutex_unlock(&rsrc_mutex); return (ret); } diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c index 2b3c2895b43d..eb89928f2338 100644 --- a/drivers/pcmcia/sa1100_cerf.c +++ b/drivers/pcmcia/sa1100_cerf.c @@ -5,7 +5,6 @@ * Based off the Assabet. * */ -#include #include #include #include diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 5ab1cdef7c48..c5d7476da471 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -25,6 +24,7 @@ #include #include #include +#include #include #include @@ -183,7 +183,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, s->resource_setup_done = 1; spin_unlock_irqrestore(&s->lock, flags); - down(&s->skt_sem); + mutex_lock(&s->skt_mutex); if ((s->callback) && (s->state & SOCKET_PRESENT) && !(s->state & SOCKET_CARDBUS)) { @@ -192,7 +192,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, module_put(s->callback->owner); } } - up(&s->skt_sem); + mutex_unlock(&s->skt_mutex); return count; } @@ -322,7 +322,7 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz kfree(cis); if (!ret) { - down(&s->skt_sem); + mutex_lock(&s->skt_mutex); if ((s->callback) && (s->state & SOCKET_PRESENT) && !(s->state & SOCKET_CARDBUS)) { if (try_module_get(s->callback->owner)) { @@ -330,7 +330,7 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz module_put(s->callback->owner); } } - up(&s->skt_sem); + mutex_unlock(&s->skt_mutex); } diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index d5b4ff74462e..7a3d1b8e16b9 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h @@ -30,7 +30,6 @@ #ifndef _LINUX_TI113X_H #define _LINUX_TI113X_H -#include /* Register definitions for TI 113X PCI-to-CardBus bridges */ diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 0574efd7828a..459e6e1946fd 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -634,7 +634,7 @@ static void vrc4171_remove_sockets(void) static int __devinit vrc4171_card_setup(char *options) { if (options == NULL || *options == '\0') - return 0; + return 1; if (strncmp(options, "irq:", 4) == 0) { int irq; @@ -644,7 +644,7 @@ static int __devinit vrc4171_card_setup(char *options) vrc4171_irq = irq; if (*options != ',') - return 0; + return 1; options++; } @@ -663,10 +663,10 @@ static int __devinit vrc4171_card_setup(char *options) } if (*options != ',') - return 0; + return 1; options++; } else - return 0; + return 1; } @@ -688,7 +688,7 @@ static int __devinit vrc4171_card_setup(char *options) } if (*options != ',') - return 0; + return 1; options++; if (strncmp(options, "memnoprobe", 10) == 0) @@ -700,7 +700,7 @@ static int __devinit vrc4171_card_setup(char *options) } } - return 0; + return 1; } __setup("vrc4171_card=", vrc4171_card_setup); diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c index 57f38dba0a48..6004196f7cc1 100644 --- a/drivers/pcmcia/vrc4173_cardu.c +++ b/drivers/pcmcia/vrc4173_cardu.c @@ -516,7 +516,7 @@ static int __devinit vrc4173_cardu_probe(struct pci_dev *dev, static int __devinit vrc4173_cardu_setup(char *options) { if (options == NULL || *options == '\0') - return 0; + return 1; if (strncmp(options, "cardu1:", 7) == 0) { options += 7; @@ -527,9 +527,9 @@ static int __devinit vrc4173_cardu_setup(char *options) } if (*options != ',') - return 0; + return 1; } else - return 0; + return 1; } if (strncmp(options, "cardu2:", 7) == 0) { @@ -538,7 +538,7 @@ static int __devinit vrc4173_cardu_setup(char *options) cardu_sockets[CARDU2].noprobe = 1; } - return 0; + return 1; } __setup("vrc4173_cardu=", vrc4173_cardu_setup); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 929dd8090578..65d090dbef46 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -147,6 +147,16 @@ config RTC_DRV_SA1100 To compile this driver as a module, choose M here: the module will be called rtc-sa1100. +config RTC_DRV_VR41XX + tristate "NEC VR41XX" + depends on RTC_CLASS && CPU_VR41XX + help + If you say Y here you will get access to the real time clock + built into your NEC VR41XX CPU. + + To compile this driver as a module, choose M here: the + module will be called rtc-vr41xx. + config RTC_DRV_TEST tristate "Test driver/device" depends on RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 8d4c7fe88d58..a9ca0f171686 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o +obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 8533936d50d8..413c7d54ea10 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -96,6 +96,8 @@ exit_idr: idr_remove(&rtc_idr, id); exit: + dev_err(dev, "rtc core: unable to register %s, err = %d\n", + name, err); return ERR_PTR(err); } EXPORT_SYMBOL_GPL(rtc_device_register); diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 358695a416f3..9be81fd4737c 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -1,6 +1,8 @@ /* * An rtc/i2c driver for the Dallas DS1672 - * Copyright 2005 Alessandro Zummo + * Copyright 2005-06 Tower Technologies + * + * Author: Alessandro Zummo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,7 +13,7 @@ #include #include -#define DRV_VERSION "0.2" +#define DRV_VERSION "0.3" /* Addresses to scan: none. This chip cannot be detected. */ static unsigned short normal_i2c[] = { I2C_CLIENT_END }; @@ -25,6 +27,7 @@ I2C_CLIENT_INSMOD; #define DS1672_REG_CONTROL 4 #define DS1672_REG_TRICKLE 5 +#define DS1672_REG_CONTROL_EOSC 0x80 /* Prototypes */ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind); @@ -53,8 +56,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: raw read data - counters=%02x,%02x,%02x,%02x\n" - __FUNCTION__, - buf[0], buf[1], buf[2], buf[3]); + __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; @@ -62,8 +64,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, - tm->tm_sec, tm->tm_min, tm->tm_hour, + __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); return 0; @@ -72,16 +73,17 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs) { int xfer; - unsigned char buf[5]; + unsigned char buf[6]; buf[0] = DS1672_REG_CNT_BASE; buf[1] = secs & 0x000000FF; buf[2] = (secs & 0x0000FF00) >> 8; buf[3] = (secs & 0x00FF0000) >> 16; buf[4] = (secs & 0xFF000000) >> 24; + buf[5] = 0; /* set control reg to enable counting */ - xfer = i2c_master_send(client, buf, 5); - if (xfer != 5) { + xfer = i2c_master_send(client, buf, 6); + if (xfer != 6) { dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer); return -EIO; } @@ -120,6 +122,40 @@ static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs) return ds1672_set_mmss(to_i2c_client(dev), secs); } +static int ds1672_get_control(struct i2c_client *client, u8 *status) +{ + unsigned char addr = DS1672_REG_CONTROL; + + struct i2c_msg msgs[] = { + { client->addr, 0, 1, &addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 1, status }, /* read control */ + }; + + /* read control register */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + return 0; +} + +/* following are the sysfs callback functions */ +static ssize_t show_control(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 control; + int err; + + err = ds1672_get_control(client, &control); + if (err) + return err; + + return sprintf(buf, "%s\n", (control & DS1672_REG_CONTROL_EOSC) + ? "disabled" : "enabled"); +} +static DEVICE_ATTR(control, S_IRUGO, show_control, NULL); + static struct rtc_class_ops ds1672_rtc_ops = { .read_time = ds1672_rtc_read_time, .set_time = ds1672_rtc_set_time, @@ -128,7 +164,6 @@ static struct rtc_class_ops ds1672_rtc_ops = { static int ds1672_attach(struct i2c_adapter *adapter) { - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); return i2c_probe(adapter, &addr_data, ds1672_probe); } @@ -137,8 +172,6 @@ static int ds1672_detach(struct i2c_client *client) int err; struct rtc_device *rtc = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __FUNCTION__); - if (rtc) rtc_device_unregister(rtc); @@ -162,6 +195,7 @@ static struct i2c_driver ds1672_driver = { static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind) { int err = 0; + u8 control; struct i2c_client *client; struct rtc_device *rtc; @@ -195,13 +229,23 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind) if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&client->dev, - "unable to register the class device\n"); goto exit_detach; } i2c_set_clientdata(client, rtc); + /* read control register */ + err = ds1672_get_control(client, &control); + if (err) + goto exit_detach; + + if (control & DS1672_REG_CONTROL_EOSC) + dev_warn(&client->dev, "Oscillator not enabled. " + "Set time to enable.\n"); + + /* Register sysfs hooks */ + device_create_file(&client->dev, &dev_attr_control); + return 0; exit_detach: diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 0dd80ea686a9..e1a1169e4664 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -67,7 +67,6 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) ep93xx_get_swcomp(dev, &preload, &delete); - seq_printf(seq, "24hr\t\t: yes\n"); seq_printf(seq, "preload\t\t: %d\n", preload); seq_printf(seq, "delete\t\t: %d\n", delete); @@ -110,7 +109,6 @@ static int __devinit ep93xx_rtc_probe(struct platform_device *dev) &dev->dev, &ep93xx_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { - dev_err(&dev->dev, "unable to register\n"); return PTR_ERR(rtc); } diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index db445c872b1b..f6e7ee04f3dc 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -23,7 +23,7 @@ #define M48T86_REG_SECALRM 0x01 #define M48T86_REG_MIN 0x02 #define M48T86_REG_MINALRM 0x03 -#define M48T86_REG_HOUR 0x04 +#define M48T86_REG_HOUR 0x04 #define M48T86_REG_HOURALRM 0x05 #define M48T86_REG_DOW 0x06 /* 1 = sunday */ #define M48T86_REG_DOM 0x07 @@ -127,9 +127,6 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq) reg = ops->readb(M48T86_REG_B); - seq_printf(seq, "24hr\t\t: %s\n", - (reg & M48T86_REG_B_H24) ? "yes" : "no"); - seq_printf(seq, "mode\t\t: %s\n", (reg & M48T86_REG_B_DM) ? "binary" : "bcd"); @@ -154,10 +151,8 @@ static int __devinit m48t86_rtc_probe(struct platform_device *dev) struct rtc_device *rtc = rtc_device_register("m48t86", &dev->dev, &m48t86_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - dev_err(&dev->dev, "unable to register\n"); + if (IS_ERR(rtc)) return PTR_ERR(rtc); - } platform_set_drvdata(dev, rtc); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index d857d45bdbe8..ba9a583b7b68 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -227,14 +227,7 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) return pcf8563_set_datetime(to_i2c_client(dev), tm); } -static int pcf8563_rtc_proc(struct device *dev, struct seq_file *seq) -{ - seq_printf(seq, "24hr\t\t: yes\n"); - return 0; -} - static struct rtc_class_ops pcf8563_rtc_ops = { - .proc = pcf8563_rtc_proc, .read_time = pcf8563_rtc_read_time, .set_time = pcf8563_rtc_set_time, }; @@ -297,8 +290,6 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&client->dev, - "unable to register the class device\n"); goto exit_detach; } @@ -321,8 +312,6 @@ static int pcf8563_detach(struct i2c_client *client) int err; struct rtc_device *rtc = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __FUNCTION__); - if (rtc) rtc_device_unregister(rtc); diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index 90b8a97a0919..cef5f5a3bbf9 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -71,6 +71,8 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) alrm.pending ? "yes" : "no"); } + seq_printf(seq, "24hr\t\t: yes\n"); + if (ops->proc) ops->proc(class_dev->dev, seq); diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 396c8681f66c..7553d797603f 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -151,9 +151,8 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) { int err, osc, trim; - seq_printf(seq, "24hr\t\t: yes\n"); - - if ((err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim)) == 0) { + err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim); + if (err == 0) { seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000); seq_printf(seq, "trim\t: %d\n", trim); } @@ -170,30 +169,31 @@ static struct rtc_class_ops rs5c372_rtc_ops = { static ssize_t rs5c372_sysfs_show_trim(struct device *dev, struct device_attribute *attr, char *buf) { - int trim; + int err, trim; - if (rs5c372_get_trim(to_i2c_client(dev), NULL, &trim) == 0) - return sprintf(buf, "0x%2x\n", trim); + err = rs5c372_get_trim(to_i2c_client(dev), NULL, &trim); + if (err) + return err; - return 0; + return sprintf(buf, "0x%2x\n", trim); } static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL); static ssize_t rs5c372_sysfs_show_osc(struct device *dev, struct device_attribute *attr, char *buf) { - int osc; + int err, osc; - if (rs5c372_get_trim(to_i2c_client(dev), &osc, NULL) == 0) - return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000); + err = rs5c372_get_trim(to_i2c_client(dev), &osc, NULL); + if (err) + return err; - return 0; + return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000); } static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL); static int rs5c372_attach(struct i2c_adapter *adapter) { - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); return i2c_probe(adapter, &addr_data, rs5c372_probe); } @@ -233,8 +233,6 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&client->dev, - "unable to register the class device\n"); goto exit_detach; } @@ -260,8 +258,6 @@ static int rs5c372_detach(struct i2c_client *client) int err; struct rtc_device *rtc = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __FUNCTION__); - if (rtc) rtc_device_unregister(rtc); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 83b2bb480a16..a23ec54989f6 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -160,19 +160,19 @@ static int sa1100_rtc_open(struct device *dev) ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", dev); if (ret) { - printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz); + dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); goto fail_ui; } ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT, "rtc Alrm", dev); if (ret) { - printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm); + dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); goto fail_ai; } ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT, "rtc timer", dev); if (ret) { - printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1); + dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); goto fail_pi; } return 0; @@ -332,7 +332,7 @@ static int sa1100_rtc_probe(struct platform_device *pdev) */ if (RTTR == 0) { RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n"); + dev_warn(&pdev->dev, "warning: initializing default clock divider/trim value\n"); /* The current RTC value probably doesn't make sense either */ RCNR = 0; } @@ -340,15 +340,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev) rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - dev_err(&pdev->dev, "Unable to register the RTC device\n"); + if (IS_ERR(rtc)) return PTR_ERR(rtc); - } platform_set_drvdata(pdev, rtc); - dev_info(&pdev->dev, "SA11xx/PXA2xx RTC Registered\n"); - return 0; } diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 43d107487820..e1f7e8e86daf 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -49,7 +49,6 @@ static int test_rtc_proc(struct device *dev, struct seq_file *seq) { struct platform_device *plat_dev = to_platform_device(dev); - seq_printf(seq, "24hr\t\t: yes\n"); seq_printf(seq, "test\t\t: yes\n"); seq_printf(seq, "id\t\t: %d\n", plat_dev->id); @@ -120,8 +119,6 @@ static int test_probe(struct platform_device *plat_dev) &test_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&plat_dev->dev, - "unable to register the class device\n"); return err; } device_create_file(&plat_dev->dev, &dev_attr_irq); diff --git a/drivers/char/vr41xx_rtc.c b/drivers/rtc/rtc-vr41xx.c similarity index 57% rename from drivers/char/vr41xx_rtc.c rename to drivers/rtc/rtc-vr41xx.c index b109d9a502d6..4d49fd501198 100644 --- a/drivers/char/vr41xx_rtc.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -1,7 +1,7 @@ /* - * Driver for NEC VR4100 series Real Time Clock unit. + * Driver for NEC VR4100 series Real Time Clock unit. * - * Copyright (C) 2003-2005 Yoichi Yuasa + * Copyright (C) 2003-2006 Yoichi Yuasa * * 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 @@ -17,23 +17,18 @@ * 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 -#include #include #include @@ -99,27 +94,11 @@ static void __iomem *rtc2_base; static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */ -static spinlock_t rtc_task_lock; -static wait_queue_head_t rtc_wait; -static unsigned long rtc_irq_data; -static struct fasync_struct *rtc_async_queue; -static rtc_task_t *rtc_callback; +static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; static char rtc_name[] = "RTC"; static unsigned long periodic_frequency; static unsigned long periodic_count; -typedef enum { - RTC_RELEASE, - RTC_OPEN, -} rtc_status_t; - -static rtc_status_t rtc_status; - -typedef enum { - FUNCTION_RTC_IOCTL, - FUNCTION_RTC_CONTROL, -} rtc_callfrom_t; - struct resource rtc_resource[2] = { { .name = rtc_name, .flags = IORESOURCE_MEM, }, @@ -129,7 +108,9 @@ struct resource rtc_resource[2] = { static inline unsigned long read_elapsed_second(void) { + unsigned long first_low, first_mid, first_high; + unsigned long second_low, second_mid, second_high; do { @@ -156,9 +137,70 @@ static inline void write_elapsed_second(unsigned long sec) spin_unlock_irq(&rtc_lock); } -static void set_alarm(struct rtc_time *time) +static void vr41xx_rtc_release(struct device *dev) +{ + + spin_lock_irq(&rtc_lock); + + rtc1_write(ECMPLREG, 0); + rtc1_write(ECMPMREG, 0); + rtc1_write(ECMPHREG, 0); + rtc1_write(RTCL1LREG, 0); + rtc1_write(RTCL1HREG, 0); + + spin_unlock_irq(&rtc_lock); + + disable_irq(ELAPSEDTIME_IRQ); + disable_irq(RTCLONG1_IRQ); +} + +static int vr41xx_rtc_read_time(struct device *dev, struct rtc_time *time) +{ + unsigned long epoch_sec, elapsed_sec; + + epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); + elapsed_sec = read_elapsed_second(); + + rtc_time_to_tm(epoch_sec + elapsed_sec, time); + + return 0; +} + +static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time) +{ + unsigned long epoch_sec, current_sec; + + epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); + current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec); + + write_elapsed_second(current_sec - epoch_sec); + + return 0; +} + +static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + unsigned long low, mid, high; + struct rtc_time *time = &wkalrm->time; + + spin_lock_irq(&rtc_lock); + + low = rtc1_read(ECMPLREG); + mid = rtc1_read(ECMPMREG); + high = rtc1_read(ECMPHREG); + + spin_unlock_irq(&rtc_lock); + + rtc_time_to_tm((high << 17) | (mid << 1) | (low >> 15), time); + + return 0; +} + +static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) { unsigned long alarm_sec; + struct rtc_time *time = &wkalrm->time; alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); @@ -170,111 +212,12 @@ static void set_alarm(struct rtc_time *time) rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17)); spin_unlock_irq(&rtc_lock); -} - -static void read_alarm(struct rtc_time *time) -{ - unsigned long low, mid, high; - - spin_lock_irq(&rtc_lock); - - low = rtc1_read(ECMPLREG); - mid = rtc1_read(ECMPMREG); - high = rtc1_read(ECMPHREG); - - spin_unlock_irq(&rtc_lock); - - to_tm((high << 17) | (mid << 1) | (low >> 15), time); - time->tm_year -= 1900; -} - -static void read_time(struct rtc_time *time) -{ - unsigned long epoch_sec, elapsed_sec; - - epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); - elapsed_sec = read_elapsed_second(); - - to_tm(epoch_sec + elapsed_sec, time); - time->tm_year -= 1900; -} - -static void set_time(struct rtc_time *time) -{ - unsigned long epoch_sec, current_sec; - - epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); - current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, - time->tm_hour, time->tm_min, time->tm_sec); - - write_elapsed_second(current_sec - epoch_sec); -} - -static ssize_t rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long irq_data; - int retval = 0; - - if (count != sizeof(unsigned int) && count != sizeof(unsigned long)) - return -EINVAL; - - add_wait_queue(&rtc_wait, &wait); - - do { - __set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irq(&rtc_lock); - irq_data = rtc_irq_data; - rtc_irq_data = 0; - spin_unlock_irq(&rtc_lock); - - if (irq_data != 0) - break; - - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - } while (1); - - if (retval == 0) { - if (count == sizeof(unsigned int)) { - retval = put_user(irq_data, (unsigned int __user *)buf); - if (retval == 0) - retval = sizeof(unsigned int); - } else { - retval = put_user(irq_data, (unsigned long __user *)buf); - if (retval == 0) - retval = sizeof(unsigned long); - } - - } - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&rtc_wait, &wait); - - return retval; -} - -static unsigned int rtc_poll(struct file *file, struct poll_table_struct *table) -{ - poll_wait(file, &rtc_wait, table); - - if (rtc_irq_data != 0) - return POLLIN | POLLRDNORM; return 0; } -static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from) +static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - struct rtc_time time; unsigned long count; switch (cmd) { @@ -290,33 +233,6 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from case RTC_PIE_OFF: disable_irq(RTCLONG1_IRQ); break; - case RTC_ALM_SET: - if (copy_from_user(&time, (struct rtc_time __user *)arg, - sizeof(struct rtc_time))) - return -EFAULT; - - set_alarm(&time); - break; - case RTC_ALM_READ: - memset(&time, 0, sizeof(struct rtc_time)); - read_alarm(&time); - break; - case RTC_RD_TIME: - memset(&time, 0, sizeof(struct rtc_time)); - read_time(&time); - if (copy_to_user((void __user *)arg, &time, sizeof(struct rtc_time))) - return -EFAULT; - break; - case RTC_SET_TIME: - if (capable(CAP_SYS_TIME) == 0) - return -EACCES; - - if (copy_from_user(&time, (struct rtc_time __user *)arg, - sizeof(struct rtc_time))) - return -EFAULT; - - set_time(&time); - break; case RTC_IRQP_READ: return put_user(periodic_frequency, (unsigned long __user *)arg); break; @@ -324,8 +240,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from if (arg > MAX_PERIODIC_RATE) return -EINVAL; - if (from == FUNCTION_RTC_IOCTL && arg > MAX_USER_PERIODIC_RATE && - capable(CAP_SYS_RESOURCE) == 0) + if (arg > MAX_USER_PERIODIC_RATE && capable(CAP_SYS_RESOURCE) == 0) return -EACCES; periodic_frequency = arg; @@ -361,205 +276,46 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, rtc_callfrom_t from return 0; } -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - return rtc_do_ioctl(cmd, arg, FUNCTION_RTC_IOCTL); -} - -static int rtc_open(struct inode *inode, struct file *file) -{ - spin_lock_irq(&rtc_lock); - - if (rtc_status == RTC_OPEN) { - spin_unlock_irq(&rtc_lock); - return -EBUSY; - } - - rtc_status = RTC_OPEN; - rtc_irq_data = 0; - - spin_unlock_irq(&rtc_lock); - - return 0; -} - -static int rtc_release(struct inode *inode, struct file *file) -{ - if (file->f_flags & FASYNC) - (void)fasync_helper(-1, file, 0, &rtc_async_queue); - - spin_lock_irq(&rtc_lock); - - rtc1_write(ECMPLREG, 0); - rtc1_write(ECMPMREG, 0); - rtc1_write(ECMPHREG, 0); - rtc1_write(RTCL1LREG, 0); - rtc1_write(RTCL1HREG, 0); - - rtc_status = RTC_RELEASE; - - spin_unlock_irq(&rtc_lock); - - disable_irq(ELAPSEDTIME_IRQ); - disable_irq(RTCLONG1_IRQ); - - return 0; -} - -static int rtc_fasync(int fd, struct file *file, int on) -{ - return fasync_helper(fd, file, on, &rtc_async_queue); -} - -static struct file_operations rtc_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = rtc_read, - .poll = rtc_poll, - .ioctl = rtc_ioctl, - .open = rtc_open, - .release = rtc_release, - .fasync = rtc_fasync, -}; - static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - spin_lock(&rtc_lock); + struct platform_device *pdev = (struct platform_device *)dev_id; + struct rtc_device *rtc = platform_get_drvdata(pdev); + rtc2_write(RTCINTREG, ELAPSEDTIME_INT); - rtc_irq_data += 0x100; - rtc_irq_data &= ~0xff; - rtc_irq_data |= RTC_AF; - spin_unlock(&rtc_lock); - - spin_lock(&rtc_lock); - if (rtc_callback) - rtc_callback->func(rtc_callback->private_data); - spin_unlock(&rtc_lock); - - wake_up_interruptible(&rtc_wait); - - kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); + rtc_update_irq(&rtc->class_dev, 1, RTC_AF); return IRQ_HANDLED; } static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + struct platform_device *pdev = (struct platform_device *)dev_id; + struct rtc_device *rtc = platform_get_drvdata(pdev); unsigned long count = periodic_count; - spin_lock(&rtc_lock); rtc2_write(RTCINTREG, RTCLONG1_INT); rtc1_write(RTCL1LREG, count); rtc1_write(RTCL1HREG, count >> 16); - rtc_irq_data += 0x100; - rtc_irq_data &= ~0xff; - rtc_irq_data |= RTC_PF; - spin_unlock(&rtc_lock); - - spin_lock(&rtc_task_lock); - if (rtc_callback) - rtc_callback->func(rtc_callback->private_data); - spin_unlock(&rtc_task_lock); - - wake_up_interruptible(&rtc_wait); - - kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); + rtc_update_irq(&rtc->class_dev, 1, RTC_PF); return IRQ_HANDLED; } -int rtc_register(rtc_task_t *task) -{ - if (task == NULL || task->func == NULL) - return -EINVAL; - - spin_lock_irq(&rtc_lock); - if (rtc_status == RTC_OPEN) { - spin_unlock_irq(&rtc_lock); - return -EBUSY; - } - - spin_lock(&rtc_task_lock); - if (rtc_callback != NULL) { - spin_unlock(&rtc_task_lock); - spin_unlock_irq(&rtc_task_lock); - return -EBUSY; - } - - rtc_callback = task; - spin_unlock(&rtc_task_lock); - - rtc_status = RTC_OPEN; - - spin_unlock_irq(&rtc_lock); - - return 0; -} - -EXPORT_SYMBOL_GPL(rtc_register); - -int rtc_unregister(rtc_task_t *task) -{ - spin_lock_irq(&rtc_task_lock); - if (task == NULL || rtc_callback != task) { - spin_unlock_irq(&rtc_task_lock); - return -ENXIO; - } - - spin_lock(&rtc_lock); - - rtc1_write(ECMPLREG, 0); - rtc1_write(ECMPMREG, 0); - rtc1_write(ECMPHREG, 0); - rtc1_write(RTCL1LREG, 0); - rtc1_write(RTCL1HREG, 0); - - rtc_status = RTC_RELEASE; - - spin_unlock(&rtc_lock); - - rtc_callback = NULL; - - spin_unlock_irq(&rtc_task_lock); - - disable_irq(ELAPSEDTIME_IRQ); - disable_irq(RTCLONG1_IRQ); - - return 0; -} - -EXPORT_SYMBOL_GPL(rtc_unregister); - -int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) -{ - int retval = 0; - - spin_lock_irq(&rtc_task_lock); - - if (rtc_callback != task) - retval = -ENXIO; - else - rtc_do_ioctl(cmd, arg, FUNCTION_RTC_CONTROL); - - spin_unlock_irq(&rtc_task_lock); - - return retval; -} - -EXPORT_SYMBOL_GPL(rtc_control); - -static struct miscdevice rtc_miscdevice = { - .minor = RTC_MINOR, - .name = rtc_name, - .fops = &rtc_fops, +static struct rtc_class_ops vr41xx_rtc_ops = { + .release = vr41xx_rtc_release, + .ioctl = vr41xx_rtc_ioctl, + .read_time = vr41xx_rtc_read_time, + .set_time = vr41xx_rtc_set_time, + .read_alarm = vr41xx_rtc_read_alarm, + .set_alarm = vr41xx_rtc_set_alarm, }; static int __devinit rtc_probe(struct platform_device *pdev) { + struct rtc_device *rtc; unsigned int irq; int retval; @@ -577,13 +333,13 @@ static int __devinit rtc_probe(struct platform_device *pdev) return -EBUSY; } - retval = misc_register(&rtc_miscdevice); - if (retval < 0) { + rtc = rtc_device_register(rtc_name, &pdev->dev, &vr41xx_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { iounmap(rtc1_base); iounmap(rtc2_base); rtc1_base = NULL; rtc2_base = NULL; - return retval; + return PTR_ERR(rtc); } spin_lock_irq(&rtc_lock); @@ -594,24 +350,20 @@ static int __devinit rtc_probe(struct platform_device *pdev) rtc1_write(RTCL1LREG, 0); rtc1_write(RTCL1HREG, 0); - rtc_status = RTC_RELEASE; - rtc_irq_data = 0; - spin_unlock_irq(&rtc_lock); - init_waitqueue_head(&rtc_wait); - irq = ELAPSEDTIME_IRQ; retval = request_irq(irq, elapsedtime_interrupt, SA_INTERRUPT, - "elapsed_time", NULL); + "elapsed_time", pdev); if (retval == 0) { irq = RTCLONG1_IRQ; retval = request_irq(irq, rtclong1_interrupt, SA_INTERRUPT, - "rtclong1", NULL); + "rtclong1", pdev); } if (retval < 0) { printk(KERN_ERR "rtc: IRQ%d is busy\n", irq); + rtc_device_unregister(rtc); if (irq == RTCLONG1_IRQ) free_irq(ELAPSEDTIME_IRQ, NULL); iounmap(rtc1_base); @@ -621,23 +373,25 @@ static int __devinit rtc_probe(struct platform_device *pdev) return retval; } + platform_set_drvdata(pdev, rtc); + disable_irq(ELAPSEDTIME_IRQ); disable_irq(RTCLONG1_IRQ); - spin_lock_init(&rtc_task_lock); - printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n"); return 0; } -static int __devexit rtc_remove(struct platform_device *dev) +static int __devexit rtc_remove(struct platform_device *pdev) { - int retval; + struct rtc_device *rtc; - retval = misc_deregister(&rtc_miscdevice); - if (retval < 0) - return retval; + rtc = platform_get_drvdata(pdev); + if (rtc != NULL) + rtc_device_unregister(rtc); + + platform_set_drvdata(pdev, NULL); free_irq(ELAPSEDTIME_IRQ, NULL); free_irq(RTCLONG1_IRQ, NULL); @@ -651,7 +405,7 @@ static int __devexit rtc_remove(struct platform_device *dev) static struct platform_device *rtc_platform_device; -static struct platform_driver rtc_device_driver = { +static struct platform_driver rtc_platform_driver = { .probe = rtc_probe, .remove = __devexit_p(rtc_remove), .driver = { @@ -686,7 +440,7 @@ static int __init vr41xx_rtc_init(void) } rtc_platform_device = platform_device_alloc("RTC", -1); - if (!rtc_platform_device) + if (rtc_platform_device == NULL) return -ENOMEM; retval = platform_device_add_resources(rtc_platform_device, @@ -700,7 +454,7 @@ static int __init vr41xx_rtc_init(void) return retval; } - retval = platform_driver_register(&rtc_device_driver); + retval = platform_driver_register(&rtc_platform_driver); if (retval < 0) platform_device_unregister(rtc_platform_device); @@ -709,7 +463,7 @@ static int __init vr41xx_rtc_init(void) static void __exit vr41xx_rtc_exit(void) { - platform_driver_unregister(&rtc_device_driver); + platform_driver_unregister(&rtc_platform_driver); platform_device_unregister(rtc_platform_device); } diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 621d17afc0d9..788b6d1f8f2f 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -19,7 +19,7 @@ #include #include -#define DRV_VERSION "1.0.6" +#define DRV_VERSION "1.0.7" /* Addresses to scan: none. This chip is located at * 0x6f and uses a two bytes register addressing. @@ -451,8 +451,6 @@ static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) { int err, dtrim, atrim; - seq_printf(seq, "24hr\t\t: yes\n"); - if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0) seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim); @@ -473,30 +471,31 @@ static struct rtc_class_ops x1205_rtc_ops = { static ssize_t x1205_sysfs_show_atrim(struct device *dev, struct device_attribute *attr, char *buf) { - int atrim; + int err, atrim; - if (x1205_get_atrim(to_i2c_client(dev), &atrim) == 0) - return sprintf(buf, "%d.%02d pF\n", - atrim / 1000, atrim % 1000); - return 0; + err = x1205_get_atrim(to_i2c_client(dev), &atrim); + if (err) + return err; + + return sprintf(buf, "%d.%02d pF\n", atrim / 1000, atrim % 1000); } static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL); static ssize_t x1205_sysfs_show_dtrim(struct device *dev, struct device_attribute *attr, char *buf) { - int dtrim; + int err, dtrim; - if (x1205_get_dtrim(to_i2c_client(dev), &dtrim) == 0) - return sprintf(buf, "%d ppm\n", dtrim); + err = x1205_get_dtrim(to_i2c_client(dev), &dtrim); + if (err) + return err; - return 0; + return sprintf(buf, "%d ppm\n", dtrim); } static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL); static int x1205_attach(struct i2c_adapter *adapter) { - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); return i2c_probe(adapter, &addr_data, x1205_probe); } @@ -545,8 +544,6 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&client->dev, - "unable to register the class device\n"); goto exit_detach; } @@ -585,8 +582,6 @@ static int x1205_detach(struct i2c_client *client) int err; struct rtc_device *rtc = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __FUNCTION__); - if (rtc) rtc_device_unregister(rtc); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 0a9f12c4e911..a3bfebcf31ef 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1257,25 +1257,28 @@ __dasd_start_head(struct dasd_device * device) if (list_empty(&device->ccw_queue)) return; cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); - /* check FAILFAST */ + if (cqr->status != DASD_CQR_QUEUED) + return; + /* Non-temporary stop condition will trigger fail fast */ if (device->stopped & ~DASD_STOPPED_PENDING && test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && (!dasd_eer_enabled(device))) { cqr->status = DASD_CQR_FAILED; dasd_schedule_bh(device); + return; } - if ((cqr->status == DASD_CQR_QUEUED) && - (!device->stopped)) { - /* try to start the first I/O that can be started */ - rc = device->discipline->start_IO(cqr); - if (rc == 0) - dasd_set_timer(device, cqr->expires); - else if (rc == -EACCES) { - dasd_schedule_bh(device); - } else - /* Hmpf, try again in 1/2 sec */ - dasd_set_timer(device, 50); - } + /* Don't try to start requests if device is stopped */ + if (device->stopped) + return; + + rc = device->discipline->start_IO(cqr); + if (rc == 0) + dasd_set_timer(device, cqr->expires); + else if (rc == -EACCES) { + dasd_schedule_bh(device); + } else + /* Hmpf, try again in 1/2 sec */ + dasd_set_timer(device, 50); } /* @@ -1968,7 +1971,7 @@ int dasd_generic_set_offline (struct ccw_device *cdev) { struct dasd_device *device; - int max_count; + int max_count, open_count; device = dasd_device_from_cdev(cdev); if (IS_ERR(device)) @@ -1985,10 +1988,16 @@ dasd_generic_set_offline (struct ccw_device *cdev) * in the other openers. */ max_count = device->bdev ? 0 : -1; - if (atomic_read(&device->open_count) > max_count) { - printk (KERN_WARNING "Can't offline dasd device with open" - " count = %i.\n", - atomic_read(&device->open_count)); + open_count = (int) atomic_read(&device->open_count); + if (open_count > max_count) { + if (open_count > 0) + printk (KERN_WARNING "Can't offline dasd device with " + "open count = %i.\n", + open_count); + else + printk (KERN_WARNING "%s", + "Can't offline dasd device due to internal " + "use\n"); clear_bit(DASD_FLAG_OFFLINE, &device->flags); dasd_put_device(device); return -EBUSY; diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 8fd71ab02ef0..b842377cb0c6 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -32,9 +32,8 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize, int size; /* Sanity checks */ - if ( magic == NULL || datasize > PAGE_SIZE || - (cplength*sizeof(struct ccw1)) > PAGE_SIZE) - BUG(); + BUG_ON( magic == NULL || datasize > PAGE_SIZE || + (cplength*sizeof(struct ccw1)) > PAGE_SIZE); size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; if (cplength > 0) @@ -125,8 +124,7 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr) struct dasd_device *device; int success; - if (cqr->refers == NULL || cqr->function == NULL) - BUG(); + BUG_ON(cqr->refers == NULL || cqr->function == NULL); device = cqr->device; success = cqr->status == DASD_CQR_DONE; diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 1aa3c261718a..ad23aede356c 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -294,23 +294,40 @@ out_error: #endif /* CONFIG_DASD_PROFILE */ } +/* + * Create dasd proc-fs entries. + * In case creation failed, cleanup and return -ENOENT. + */ int dasd_proc_init(void) { dasd_proc_root_entry = proc_mkdir("dasd", &proc_root); + if (!dasd_proc_root_entry) + goto out_nodasd; dasd_proc_root_entry->owner = THIS_MODULE; dasd_devices_entry = create_proc_entry("devices", S_IFREG | S_IRUGO | S_IWUSR, dasd_proc_root_entry); + if (!dasd_devices_entry) + goto out_nodevices; dasd_devices_entry->proc_fops = &dasd_devices_file_ops; dasd_devices_entry->owner = THIS_MODULE; dasd_statistics_entry = create_proc_entry("statistics", S_IFREG | S_IRUGO | S_IWUSR, dasd_proc_root_entry); + if (!dasd_statistics_entry) + goto out_nostatistics; dasd_statistics_entry->read_proc = dasd_statistics_read; dasd_statistics_entry->write_proc = dasd_statistics_write; dasd_statistics_entry->owner = THIS_MODULE; return 0; + + out_nostatistics: + remove_proc_entry("devices", dasd_proc_root_entry); + out_nodevices: + remove_proc_entry("dasd", &proc_root); + out_nodasd: + return -ENOENT; } void diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index 6badd8403409..d4d2ff0a9da2 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -54,7 +54,7 @@ kbd_alloc(void) { if (!kbd) goto out; kbd->key_maps = kzalloc(sizeof(key_maps), GFP_KERNEL); - if (!key_maps) + if (!kbd->key_maps) goto out_kbd; for (i = 0; i < ARRAY_SIZE(key_maps); i++) { if (key_maps[i]) { diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index ac10dfb20a62..91e93c78f57a 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c @@ -24,7 +24,7 @@ /* * The room for the SCCB (only for writing) is not equal to a pages size - * (as it is specified as the maximum size in the the SCLP ducumentation) + * (as it is specified as the maximum size in the the SCLP documentation) * because of the additional data structure described above. */ #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer)) diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 5ced2725d6c7..b70d92690242 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -198,9 +198,7 @@ tapeblock_request_fn(request_queue_t *queue) device = (struct tape_device *) queue->queuedata; DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device); - if (device == NULL) - BUG(); - + BUG_ON(device == NULL); tapeblock_trigger_requeue(device); } @@ -307,8 +305,7 @@ tapeblock_revalidate_disk(struct gendisk *disk) int rc; device = (struct tape_device *) disk->private_data; - if (!device) - BUG(); + BUG_ON(!device); if (!device->blk_data.medium_changed) return 0; @@ -435,16 +432,14 @@ tapeblock_ioctl( ) { int rc; int minor; - struct gendisk *disk = inode->i_bdev->bd_disk; - struct tape_device *device = disk->private_data; + struct gendisk *disk; + struct tape_device *device; rc = 0; disk = inode->i_bdev->bd_disk; - if (!disk) - BUG(); + BUG_ON(!disk); device = disk->private_data; - if (!device) - BUG(); + BUG_ON(!device); minor = iminor(inode); DBF_LH(6, "tapeblock_ioctl(0x%0x)\n", command); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 389ee2c0f443..e6e4086d3224 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -210,18 +210,14 @@ tape_state_set(struct tape_device *device, enum tape_state newstate) return; } DBF_EVENT(4, "ts. dev: %x\n", device->first_minor); - if (device->tape_state < TO_SIZE && device->tape_state >= 0) - str = tape_state_verbose[device->tape_state]; - else - str = "UNKNOWN TS"; - DBF_EVENT(4, "old ts: %s\n", str); - if (device->tape_state < TO_SIZE && device->tape_state >=0 ) + DBF_EVENT(4, "old ts:\t\n"); + if (device->tape_state < TS_SIZE && device->tape_state >=0 ) str = tape_state_verbose[device->tape_state]; else str = "UNKNOWN TS"; DBF_EVENT(4, "%s\n", str); DBF_EVENT(4, "new ts:\t\n"); - if (newstate < TO_SIZE && newstate >= 0) + if (newstate < TS_SIZE && newstate >= 0) str = tape_state_verbose[newstate]; else str = "UNKNOWN TS"; diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index cb8e2e672b68..0960bef7b199 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -414,11 +414,11 @@ cio_ignore_proc_init (void) entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, &proc_root); if (!entry) - return 0; + return -ENOENT; entry->proc_fops = &cio_ignore_proc_fops; - return 1; + return 0; } __initcall (cio_ignore_proc_init); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index cbb86fa5f293..5b20d8c9c025 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -67,7 +67,7 @@ cio_debug_init (void) goto out_unregister; debug_register_view (cio_debug_msg_id, &debug_sprintf_view); debug_set_level (cio_debug_msg_id, 2); - cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 8); + cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 16); if (!cio_debug_trace_id) goto out_unregister; debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view); diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h index 6af8b27d366b..f88844adae1b 100644 --- a/drivers/s390/cio/cio_debug.h +++ b/drivers/s390/cio/cio_debug.h @@ -3,6 +3,11 @@ #include +/* for use of debug feature */ +extern debug_info_t *cio_debug_msg_id; +extern debug_info_t *cio_debug_trace_id; +extern debug_info_t *cio_debug_crw_id; + #define CIO_TRACE_EVENT(imp, txt) do { \ debug_text_event(cio_debug_trace_id, imp, txt); \ } while (0) @@ -15,18 +20,19 @@ debug_sprintf_event(cio_debug_crw_id, imp , ##args); \ } while (0) -#define CIO_HEX_EVENT(imp, args...) do { \ - debug_event(cio_debug_trace_id, imp, ##args); \ - } while (0) +static inline void +CIO_HEX_EVENT(int level, void *data, int length) +{ + while (length > 0) { + debug_event(cio_debug_trace_id, level, data, length); + length -= cio_debug_trace_id->buf_size; + data += cio_debug_trace_id->buf_size; + } +} #define CIO_DEBUG(printk_level,event_level,msg...) ({ \ if (cio_show_msg) printk(printk_level msg); \ CIO_MSG_EVENT (event_level, msg); \ }) -/* for use of debug feature */ -extern debug_info_t *cio_debug_msg_id; -extern debug_info_t *cio_debug_trace_id; -extern debug_info_t *cio_debug_crw_id; - #endif diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index edcf05d5d568..5d6b7a57b02f 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -675,9 +675,8 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) int index, rc; LCS_DBF_TEXT(5, trace, "rdybuff"); - if (buffer->state != BUF_STATE_LOCKED && - buffer->state != BUF_STATE_PROCESSED) - BUG(); + BUG_ON(buffer->state != BUF_STATE_LOCKED && + buffer->state != BUF_STATE_PROCESSED); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); buffer->state = BUF_STATE_READY; index = buffer - channel->iob; @@ -701,8 +700,7 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) int index, prev, next; LCS_DBF_TEXT(5, trace, "prcsbuff"); - if (buffer->state != BUF_STATE_READY) - BUG(); + BUG_ON(buffer->state != BUF_STATE_READY); buffer->state = BUF_STATE_PROCESSED; index = buffer - channel->iob; prev = (index - 1) & (LCS_NUM_BUFFS - 1); @@ -734,9 +732,8 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) unsigned long flags; LCS_DBF_TEXT(5, trace, "relbuff"); - if (buffer->state != BUF_STATE_LOCKED && - buffer->state != BUF_STATE_PROCESSED) - BUG(); + BUG_ON(buffer->state != BUF_STATE_LOCKED && + buffer->state != BUF_STATE_PROCESSED); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); buffer->state = BUF_STATE_EMPTY; spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 0d2b447c50ed..caeb6d246e57 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -65,6 +65,7 @@ 2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher. 2.26.02.006 - Fix 9550SX pchip reset timeout. Add big endian support. + 2.26.02.007 - Disable local interrupts during kmap/unmap_atomic(). */ #include @@ -88,7 +89,7 @@ #include "3w-9xxx.h" /* Globals */ -#define TW_DRIVER_VERSION "2.26.02.006" +#define TW_DRIVER_VERSION "2.26.02.007" static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; static unsigned int twa_device_extension_count; static int twa_major = -1; @@ -1942,9 +1943,13 @@ static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int re } if (tw_dev->srb[request_id]->use_sg == 1) { struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer; - char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; + char *buf; + unsigned long flags = 0; + local_irq_save(flags); + buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length); kunmap_atomic(buf - sg->offset, KM_IRQ0); + local_irq_restore(flags); } } } /* End twa_scsiop_execute_scsi_complete() */ diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 25f678d0780b..e8e41e6eb42a 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1508,10 +1508,12 @@ static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id, struct scsi_cmnd *cmd = tw_dev->srb[request_id]; void *buf; unsigned int transfer_len; + unsigned long flags = 0; if (cmd->use_sg) { struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer; + local_irq_save(flags); buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; transfer_len = min(sg->length, len); } else { @@ -1526,6 +1528,7 @@ static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id, sg = (struct scatterlist *)cmd->request_buffer; kunmap_atomic(buf - sg->offset, KM_IRQ0); + local_irq_restore(flags); } } diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 4035920ce3d8..3e7302692dbe 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1079,7 +1079,7 @@ config SCSI_SYM53C8XX_DMA_ADDRESSING_MODE memory using PCI DAC cycles. config SCSI_SYM53C8XX_DEFAULT_TAGS - int "default tagged command queue depth" + int "Default tagged command queue depth" depends on SCSI_SYM53C8XX_2 default "16" help @@ -1090,7 +1090,7 @@ config SCSI_SYM53C8XX_DEFAULT_TAGS exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS. config SCSI_SYM53C8XX_MAX_TAGS - int "maximum number of queued commands" + int "Maximum number of queued commands" depends on SCSI_SYM53C8XX_2 default "64" help @@ -1099,13 +1099,14 @@ config SCSI_SYM53C8XX_MAX_TAGS possible. The driver supports up to 256 queued commands per device. This value is used as a compiled-in hard limit. -config SCSI_SYM53C8XX_IOMAPPED - bool "use port IO" +config SCSI_SYM53C8XX_MMIO + bool "Use memory mapped IO" depends on SCSI_SYM53C8XX_2 + default y help - If you say Y here, the driver will use port IO to access - the card. This is significantly slower then using memory - mapped IO. Most people should answer N. + Memory mapped IO is faster than Port IO. Most people should + answer Y here, but some machines may have problems. If you have + to answer N here, please report the problem to the maintainer. config SCSI_IPR tristate "IBM Power Linux RAID adapter support" @@ -1309,15 +1310,6 @@ config SCSI_QLOGIC_FAS To compile this driver as a module, choose M here: the module will be called qlogicfas. -config SCSI_QLOGIC_FC - tristate "Qlogic ISP FC SCSI support" - depends on PCI && SCSI - help - This is a driver for the QLogic ISP2100 SCSI-FCP host adapter. - - To compile this driver as a module, choose M here: the - module will be called qlogicfc. - config SCSI_QLOGIC_FC_FIRMWARE bool "Include loadable firmware in driver" depends on SCSI_QLOGIC_FC diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index e513c3158ad9..81803a16f986 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -78,7 +78,6 @@ obj-$(CONFIG_SCSI_NCR_Q720) += NCR_Q720_mod.o obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o -obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/ obj-$(CONFIG_SCSI_LPFC) += lpfc/ diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 8df4a0ea3761..642a3b4e5937 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -149,20 +149,20 @@ static int dacmode = -1; static int commit = -1; -module_param(nondasd, int, 0); +module_param(nondasd, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); -module_param(dacmode, int, 0); +module_param(dacmode, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on"); -module_param(commit, int, 0); +module_param(commit, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on"); int numacb = -1; module_param(numacb, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control blocks (FIB) allocated. Valid\nvalues are 512 and down. Default is to use suggestion from Firmware."); +MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control blocks (FIB) allocated. Valid values are 512 and down. Default is to use suggestion from Firmware."); int acbsize = -1; module_param(acbsize, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512,\n2048, 4096 and 8192. Default is to use suggestion from Firmware."); +MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware."); /** * aac_get_config_status - check the adapter configuration * @common: adapter to query @@ -387,6 +387,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr) struct scsi_cmnd * scsicmd; scsicmd = (struct scsi_cmnd *) context; + scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); if (fibptr == NULL) @@ -453,8 +454,10 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) + if (status == -EINPROGRESS) { + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; return 0; + } printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status); aac_fib_complete(cmd_fibcontext); @@ -907,9 +910,10 @@ static void io_callback(void *context, struct fib * fibptr) u32 cid; scsicmd = (struct scsi_cmnd *) context; + scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; dev = (struct aac_dev *)scsicmd->device->host->hostdata; - cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); + cid = scmd_id(scsicmd); if (nblank(dprintk(x))) { u64 lba; @@ -1151,8 +1155,10 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) + if (status == -EINPROGRESS) { + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; return 0; + } printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status); /* @@ -1318,8 +1324,8 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) - { + if (status == -EINPROGRESS) { + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; return 0; } @@ -1341,6 +1347,7 @@ static void synchronize_callback(void *context, struct fib *fibptr) struct scsi_cmnd *cmd; cmd = context; + cmd->SCp.phase = AAC_OWNER_MIDLEVEL; dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); @@ -1354,7 +1361,7 @@ static void synchronize_callback(void *context, struct fib *fibptr) else { struct scsi_device *sdev = cmd->device; struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; - u32 cid = ID_LUN_TO_CONTAINER(sdev->id, sdev->lun); + u32 cid = sdev_id(sdev); printk(KERN_WARNING "synchronize_callback: synchronize failed, status = %d\n", le32_to_cpu(synchronizereply->status)); @@ -1386,12 +1393,12 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid) unsigned long flags; /* - * Wait for all commands to complete to this specific - * target (block). + * Wait for all outstanding queued commands to complete to this + * specific target (block). */ spin_lock_irqsave(&sdev->list_lock, flags); list_for_each_entry(cmd, &sdev->cmd_list, list) - if (cmd != scsicmd && cmd->serial_number != 0) { + if (cmd != scsicmd && cmd->SCp.phase == AAC_OWNER_FIRMWARE) { ++active; break; } @@ -1434,8 +1441,10 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS) + if (status == -EINPROGRESS) { + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; return 0; + } printk(KERN_WARNING "aac_synchronize: aac_fib_send failed with status: %d.\n", status); @@ -1458,7 +1467,6 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) struct Scsi_Host *host = scsicmd->device->host; struct aac_dev *dev = (struct aac_dev *)host->hostdata; struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev; - int ret; /* * If the bus, id or lun is out of range, return fail @@ -1466,13 +1474,14 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) * itself. */ if (scmd_id(scsicmd) != host->this_id) { - if ((scsicmd->device->channel == CONTAINER_CHANNEL)) { - if( (scsicmd->device->id >= dev->maximum_num_containers) || (scsicmd->device->lun != 0)){ + if ((scmd_channel(scsicmd) == CONTAINER_CHANNEL)) { + if((scmd_id(scsicmd) >= dev->maximum_num_containers) || + (scsicmd->device->lun != 0)) { scsicmd->result = DID_NO_CONNECT << 16; scsicmd->scsi_done(scsicmd); return 0; } - cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); + cid = scmd_id(scsicmd); /* * If the target container doesn't exist, it may have @@ -1548,7 +1557,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) { struct inquiry_data inq_data; - dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id)); + dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scmd_id(scsicmd))); memset(&inq_data, 0, sizeof (struct inquiry_data)); inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ @@ -1598,13 +1607,14 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) cp[11] = 0; cp[12] = 0; aac_internal_transfer(scsicmd, cp, 0, - min((unsigned int)scsicmd->cmnd[13], sizeof(cp))); + min_t(size_t, scsicmd->cmnd[13], sizeof(cp))); if (sizeof(cp) < scsicmd->cmnd[13]) { unsigned int len, offset = sizeof(cp); memset(cp, 0, offset); do { - len = min(scsicmd->cmnd[13]-offset, sizeof(cp)); + len = min_t(size_t, scsicmd->cmnd[13] - offset, + sizeof(cp)); aac_internal_transfer(scsicmd, cp, offset, len); } while ((offset += len) < scsicmd->cmnd[13]); } @@ -1728,24 +1738,19 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) * containers to /dev/sd device names */ - spin_unlock_irq(host->host_lock); if (scsicmd->request->rq_disk) strlcpy(fsa_dev_ptr[cid].devname, scsicmd->request->rq_disk->disk_name, min(sizeof(fsa_dev_ptr[cid].devname), sizeof(scsicmd->request->rq_disk->disk_name) + 1)); - ret = aac_read(scsicmd, cid); - spin_lock_irq(host->host_lock); - return ret; + + return aac_read(scsicmd, cid); case WRITE_6: case WRITE_10: case WRITE_12: case WRITE_16: - spin_unlock_irq(host->host_lock); - ret = aac_write(scsicmd, cid); - spin_lock_irq(host->host_lock); - return ret; + return aac_write(scsicmd, cid); case SYNCHRONIZE_CACHE: /* Issue FIB to tell Firmware to flush it's cache */ @@ -1778,7 +1783,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg) if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) return -EFAULT; if (qd.cnum == -1) - qd.cnum = ID_LUN_TO_CONTAINER(qd.id, qd.lun); + qd.cnum = qd.id; else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) { if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers) @@ -1890,6 +1895,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr) struct scsi_cmnd *scsicmd; scsicmd = (struct scsi_cmnd *) context; + scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; dev = (struct aac_dev *)scsicmd->device->host->hostdata; if (fibptr == NULL) @@ -2068,14 +2074,13 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) u32 timeout; dev = (struct aac_dev *)scsicmd->device->host->hostdata; - if (scsicmd->device->id >= dev->maximum_num_physicals || + if (scmd_id(scsicmd) >= dev->maximum_num_physicals || scsicmd->device->lun > 7) { scsicmd->result = DID_NO_CONNECT << 16; scsicmd->scsi_done(scsicmd); return 0; } - dev = (struct aac_dev *)scsicmd->device->host->hostdata; switch(scsicmd->sc_data_direction){ case DMA_TO_DEVICE: flag = SRB_DataOut; @@ -2103,8 +2108,8 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) srbcmd = (struct aac_srb*) fib_data(cmd_fibcontext); srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); - srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scsicmd->device->channel)); - srbcmd->id = cpu_to_le32(scsicmd->device->id); + srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(scsicmd))); + srbcmd->id = cpu_to_le32(scmd_id(scsicmd)); srbcmd->lun = cpu_to_le32(scsicmd->device->lun); srbcmd->flags = cpu_to_le32(flag); timeout = scsicmd->timeout_per_command/HZ; @@ -2161,7 +2166,8 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) /* * Check that the command queued to the controller */ - if (status == -EINPROGRESS){ + if (status == -EINPROGRESS) { + scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; return 0; } @@ -2192,8 +2198,6 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg) scsicmd->sc_data_direction); psg->count = cpu_to_le32(sg_count); - byte_count = 0; - for (i = 0; i < sg_count; i++) { psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg)); psg->sg[i].count = cpu_to_le32(sg_dma_len(sg)); @@ -2249,18 +2253,17 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, scsicmd->sc_data_direction); - psg->count = cpu_to_le32(sg_count); - - byte_count = 0; for (i = 0; i < sg_count; i++) { + int count = sg_dma_len(sg); addr = sg_dma_address(sg); psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); psg->sg[i].addr[1] = cpu_to_le32(addr>>32); - psg->sg[i].count = cpu_to_le32(sg_dma_len(sg)); - byte_count += sg_dma_len(sg); + psg->sg[i].count = cpu_to_le32(count); + byte_count += count; sg++; } + psg->count = cpu_to_le32(sg_count); /* hba wants the size to be exact */ if(byte_count > scsicmd->request_bufflen){ u32 temp = le32_to_cpu(psg->sg[i-1].count) - @@ -2275,16 +2278,15 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p } } else if(scsicmd->request_bufflen) { - u64 addr; - addr = pci_map_single(dev->pdev, + scsicmd->SCp.dma_handle = pci_map_single(dev->pdev, scsicmd->request_buffer, scsicmd->request_bufflen, scsicmd->sc_data_direction); + addr = scsicmd->SCp.dma_handle; psg->count = cpu_to_le32(1); psg->sg[0].addr[0] = cpu_to_le32(addr & 0xffffffff); psg->sg[0].addr[1] = cpu_to_le32(addr >> 32); psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen); - scsicmd->SCp.dma_handle = addr; byte_count = scsicmd->request_bufflen; } return byte_count; diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 9ce7002bd070..f773b0dcfc95 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -10,6 +10,10 @@ * D E F I N E S *----------------------------------------------------------------------------*/ +#ifndef AAC_DRIVER_BUILD +# define AAC_DRIVER_BUILD 2409 +# define AAC_DRIVER_BRANCH "-mh1" +#endif #define MAXIMUM_NUM_CONTAINERS 32 #define AAC_NUM_MGT_FIB 8 @@ -25,7 +29,6 @@ * These macros convert from physical channels to virtual channels */ #define CONTAINER_CHANNEL (0) -#define ID_LUN_TO_CONTAINER(id, lun) (id) #define CONTAINER_TO_CHANNEL(cont) (CONTAINER_CHANNEL) #define CONTAINER_TO_ID(cont) (cont) #define CONTAINER_TO_LUN(cont) (0) @@ -789,6 +792,7 @@ struct fsa_dev_info { u64 size; u32 type; u32 config_waiting_on; + unsigned long config_waiting_stamp; u16 queue_depth; u8 config_needed; u8 valid; @@ -1771,6 +1775,11 @@ static inline u32 cap_to_cyls(sector_t capacity, u32 divisor) } struct scsi_cmnd; +/* SCp.phase values */ +#define AAC_OWNER_MIDLEVEL 0x101 +#define AAC_OWNER_LOWLEVEL 0x102 +#define AAC_OWNER_ERROR_HANDLER 0x103 +#define AAC_OWNER_FIRMWARE 0x106 const char *aac_driverinfo(struct Scsi_Host *); struct fib *aac_fib_alloc(struct aac_dev *dev); diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 47fefca72695..9f75144e5247 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include @@ -293,6 +295,16 @@ return_fib: status = 0; } else { spin_unlock_irqrestore(&dev->fib_lock, flags); + /* If someone killed the AIF aacraid thread, restart it */ + status = !dev->aif_thread; + if (status && dev->queues && dev->fsa_dev) { + /* Be paranoid, be very paranoid! */ + kthread_stop(dev->thread); + ssleep(1); + dev->aif_thread = 0; + dev->thread = kthread_run(aac_command_thread, dev, dev->name); + ssleep(1); + } if (f.wait) { if(down_interruptible(&fibctx->wait_sem) < 0) { status = -EINTR; diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index c7f80ec7abde..9f9f4aae23c0 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -767,9 +767,9 @@ void aac_printf(struct aac_dev *dev, u32 val) if (cp[length] != 0) cp[length] = 0; if (level == LOG_AAC_HIGH_ERROR) - printk(KERN_WARNING "aacraid:%s", cp); + printk(KERN_WARNING "%s:%s", dev->name, cp); else - printk(KERN_INFO "aacraid:%s", cp); + printk(KERN_INFO "%s:%s", dev->name, cp); } memset(cp, 0, 256); } @@ -784,6 +784,7 @@ void aac_printf(struct aac_dev *dev, u32 val) * dispatches it to the appropriate routine for handling. */ +#define AIF_SNIFF_TIMEOUT (30*HZ) static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) { struct hw_fib * hw_fib = fibptr->hw_fib; @@ -837,6 +838,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) if (device) { dev->fsa_dev[container].config_needed = CHANGE; dev->fsa_dev[container].config_waiting_on = AifEnConfigChange; + dev->fsa_dev[container].config_waiting_stamp = jiffies; scsi_device_put(device); } } @@ -849,13 +851,15 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) if (container != (u32)-1) { if (container >= dev->maximum_num_containers) break; - if (dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(u32 *)aifcmd->data)) + if ((dev->fsa_dev[container].config_waiting_on == + le32_to_cpu(*(u32 *)aifcmd->data)) && + time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } else for (container = 0; container < dev->maximum_num_containers; ++container) { - if (dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(u32 *)aifcmd->data)) + if ((dev->fsa_dev[container].config_waiting_on == + le32_to_cpu(*(u32 *)aifcmd->data)) && + time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } break; @@ -872,6 +876,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) dev->fsa_dev[container].config_needed = ADD; dev->fsa_dev[container].config_waiting_on = AifEnConfigChange; + dev->fsa_dev[container].config_waiting_stamp = jiffies; break; /* @@ -884,6 +889,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) dev->fsa_dev[container].config_needed = DELETE; dev->fsa_dev[container].config_waiting_on = AifEnConfigChange; + dev->fsa_dev[container].config_waiting_stamp = jiffies; break; /* @@ -894,11 +900,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) container = le32_to_cpu(((u32 *)aifcmd->data)[1]); if (container >= dev->maximum_num_containers) break; - if (dev->fsa_dev[container].config_waiting_on) + if (dev->fsa_dev[container].config_waiting_on && + time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) break; dev->fsa_dev[container].config_needed = CHANGE; dev->fsa_dev[container].config_waiting_on = AifEnConfigChange; + dev->fsa_dev[container].config_waiting_stamp = jiffies; break; case AifEnConfigChange: @@ -913,13 +921,15 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) if (container != (u32)-1) { if (container >= dev->maximum_num_containers) break; - if (dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(u32 *)aifcmd->data)) + if ((dev->fsa_dev[container].config_waiting_on == + le32_to_cpu(*(u32 *)aifcmd->data)) && + time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } else for (container = 0; container < dev->maximum_num_containers; ++container) { - if (dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(u32 *)aifcmd->data)) + if ((dev->fsa_dev[container].config_waiting_on == + le32_to_cpu(*(u32 *)aifcmd->data)) && + time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } break; @@ -946,6 +956,8 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) dev->fsa_dev[container].config_waiting_on = AifEnContainerChange; dev->fsa_dev[container].config_needed = ADD; + dev->fsa_dev[container].config_waiting_stamp = + jiffies; } } if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero)) @@ -961,6 +973,8 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) dev->fsa_dev[container].config_waiting_on = AifEnContainerChange; dev->fsa_dev[container].config_needed = DELETE; + dev->fsa_dev[container].config_waiting_stamp = + jiffies; } } break; @@ -969,8 +983,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) device_config_needed = NOTHING; for (container = 0; container < dev->maximum_num_containers; ++container) { - if ((dev->fsa_dev[container].config_waiting_on == 0) - && (dev->fsa_dev[container].config_needed != NOTHING)) { + if ((dev->fsa_dev[container].config_waiting_on == 0) && + (dev->fsa_dev[container].config_needed != NOTHING) && + time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) { device_config_needed = dev->fsa_dev[container].config_needed; dev->fsa_dev[container].config_needed = NOTHING; diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 720330778648..6ef89c99dd12 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -27,12 +27,6 @@ * Abstract: Linux Driver entry module for Adaptec RAID Array Controller */ -#define AAC_DRIVER_VERSION "1.1-4" -#ifndef AAC_DRIVER_BRANCH -#define AAC_DRIVER_BRANCH "" -#endif -#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__ -#define AAC_DRIVERNAME "aacraid" #include #include @@ -62,6 +56,13 @@ #include "aacraid.h" +#define AAC_DRIVER_VERSION "1.1-5" +#ifndef AAC_DRIVER_BRANCH +#define AAC_DRIVER_BRANCH "" +#endif +#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__ +#define AAC_DRIVERNAME "aacraid" + #ifdef AAC_DRIVER_BUILD #define _str(x) #x #define str(x) _str(x) @@ -73,7 +74,7 @@ MODULE_AUTHOR("Red Hat Inc and Adaptec"); MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, " "Adaptec Advanced Raid Products, " - "and HP NetRAID-4M SCSI driver"); + "HP NetRAID-4M, IBM ServeRAID & ICP SCSI driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(AAC_DRIVER_FULL_VERSION); @@ -243,6 +244,7 @@ static struct aac_driver_ident aac_drivers[] = { static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { cmd->scsi_done = done; + cmd->SCp.phase = AAC_OWNER_LOWLEVEL; return (aac_scsi_cmd(cmd) ? FAILED : 0); } @@ -471,7 +473,8 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) __shost_for_each_device(dev, host) { spin_lock_irqsave(&dev->list_lock, flags); list_for_each_entry(command, &dev->cmd_list, list) { - if (command->serial_number) { + if ((command != cmd) && + (command->SCp.phase == AAC_OWNER_FIRMWARE)) { active++; break; } @@ -569,12 +572,12 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long f = compat_alloc_user_space(sizeof(*f)); ret = 0; - if (clear_user(f, sizeof(*f) != sizeof(*f))) + if (clear_user(f, sizeof(*f)) != sizeof(*f)) ret = -EFAULT; if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32))) ret = -EFAULT; if (!ret) - ret = aac_do_ioctl(dev, cmd, (void __user *)arg); + ret = aac_do_ioctl(dev, cmd, f); break; } @@ -687,6 +690,18 @@ static ssize_t aac_show_serial_number(struct class_device *class_dev, return len; } +static ssize_t aac_show_max_channel(struct class_device *class_dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + class_to_shost(class_dev)->max_channel); +} + +static ssize_t aac_show_max_id(struct class_device *class_dev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + class_to_shost(class_dev)->max_id); +} + static struct class_device_attribute aac_model = { .attr = { @@ -730,6 +745,20 @@ static struct class_device_attribute aac_serial_number = { }, .show = aac_show_serial_number, }; +static struct class_device_attribute aac_max_channel = { + .attr = { + .name = "max_channel", + .mode = S_IRUGO, + }, + .show = aac_show_max_channel, +}; +static struct class_device_attribute aac_max_id = { + .attr = { + .name = "max_id", + .mode = S_IRUGO, + }, + .show = aac_show_max_id, +}; static struct class_device_attribute *aac_attrs[] = { &aac_model, @@ -738,6 +767,8 @@ static struct class_device_attribute *aac_attrs[] = { &aac_monitor_version, &aac_bios_version, &aac_serial_number, + &aac_max_channel, + &aac_max_id, NULL }; @@ -775,6 +806,7 @@ static struct scsi_host_template aac_driver_template = { .cmd_per_lun = AAC_NUM_IO_FIB, #endif .use_clustering = ENABLE_CLUSTERING, + .emulated = 1, }; @@ -798,10 +830,11 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, error = pci_enable_device(pdev); if (error) goto out; + error = -ENODEV; if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) - goto out; + goto out_disable_pdev; /* * If the quirk31 bit is set, the adapter needs adapter * to driver communication memory to be allocated below 2gig @@ -809,7 +842,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) || pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK)) - goto out; + goto out_disable_pdev; pci_set_master(pdev); @@ -904,9 +937,9 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, * physical channels are address by their actual physical number+1 */ if (aac->nondasd_support == 1) - shost->max_channel = aac->maximum_num_channels + 1; + shost->max_channel = aac->maximum_num_channels; else - shost->max_channel = 1; + shost->max_channel = 0; aac_get_config_status(aac); aac_get_containers(aac); @@ -1020,7 +1053,8 @@ static int __init aac_init(void) static void __exit aac_exit(void) { - unregister_chrdev(aac_cfg_major, "aac"); + if (aac_cfg_major > -1) + unregister_chrdev(aac_cfg_major, "aac"); pci_unregister_driver(&aac_pci_driver); } diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index e9b775d6bec9..7a23e027eb78 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c @@ -183,7 +183,7 @@ static int rkt_sync_cmd(struct aac_dev *dev, u32 command, /* * Yield the processor in case we are slow */ - schedule_timeout_uninterruptible(1); + msleep(1); } if (ok != 1) { /* @@ -343,7 +343,7 @@ static int aac_rkt_check_health(struct aac_dev *dev) NULL, NULL, NULL, NULL, NULL); pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), post, paddr); - if ((buffer[0] == '0') && (buffer[1] == 'x')) { + if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) { ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10); ret <<= 4; ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10); diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 6998bc877dd6..729b9eb268c2 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -183,7 +183,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command, /* * Yield the processor in case we are slow */ - schedule_timeout_uninterruptible(1); + msleep(1); } if (ok != 1) { /* @@ -342,7 +342,7 @@ static int aac_rx_check_health(struct aac_dev *dev) NULL, NULL, NULL, NULL, NULL); pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), post, paddr); - if ((buffer[0] == '0') && (buffer[1] == 'x')) { + if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) { ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10); ret <<= 4; ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10); diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 466f05cfbf0c..a53454908205 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -189,7 +189,7 @@ static int sa_sync_cmd(struct aac_dev *dev, u32 command, ok = 1; break; } - schedule_timeout_uninterruptible(1); + msleep(1); } if (ok != 1) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index ffba65656a83..b4f8fb1d628b 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -207,7 +207,6 @@ static struct scsi_host_template ahci_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = AHCI_MAX_SG, @@ -293,6 +292,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { board_ahci }, /* JMicron JMB360 */ { 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_ahci }, /* JMicron JMB363 */ + { PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* ATI SB600 non-raid */ + { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* ATI SB600 raid */ { } /* terminate list */ }; diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx index 6c2c395554ff..5517da5855f0 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx @@ -86,7 +86,7 @@ config AIC7XXX_DEBUG_MASK default "0" help Bit mask of debug options that is only valid if the - CONFIG_AIC7XXX_DEBUG_ENBLE option is enabled. The bits in this mask + CONFIG_AIC7XXX_DEBUG_ENABLE option is enabled. The bits in this mask are defined in the drivers/scsi/aic7xxx/aic7xxx.h - search for the variable ahc_debug in that file to find them. diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index 1d11f7e77564..bb5166da4358 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -372,7 +372,7 @@ typedef enum { AHD_CURRENT_SENSING = 0x40000, AHD_SCB_CONFIG_USED = 0x80000,/* No SEEPROM but SCB had info. */ AHD_HP_BOARD = 0x100000, - AHD_RESET_POLL_ACTIVE = 0x200000, + AHD_BUS_RESET_ACTIVE = 0x200000, AHD_UPDATE_PEND_CMDS = 0x400000, AHD_RUNNING_QOUTFIFO = 0x800000, AHD_HAD_FIRST_SEL = 0x1000000 @@ -589,7 +589,7 @@ typedef enum { SCB_PACKETIZED = 0x00800, SCB_EXPECT_PPR_BUSFREE = 0x01000, SCB_PKT_SENSE = 0x02000, - SCB_CMDPHASE_ABORT = 0x04000, + SCB_EXTERNAL_RESET = 0x04000,/* Device was reset externally */ SCB_ON_COL_LIST = 0x08000, SCB_SILENT = 0x10000 /* * Be quiet about transmission type diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 326a62226235..08771f6f6859 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -207,7 +207,6 @@ static void ahd_add_scb_to_free_list(struct ahd_softc *ahd, static u_int ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid, u_int prev, u_int next, u_int tid); static void ahd_reset_current_bus(struct ahd_softc *ahd); -static ahd_callback_t ahd_reset_poll; static ahd_callback_t ahd_stat_timer; #ifdef AHD_DUMP_SEQ static void ahd_dumpseq(struct ahd_softc *ahd); @@ -1054,12 +1053,10 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) * If a target takes us into the command phase * assume that it has been externally reset and * has thus lost our previous packetized negotiation - * agreement. Since we have not sent an identify - * message and may not have fully qualified the - * connection, we change our command to TUR, assert - * ATN and ABORT the task when we go to message in - * phase. The OSM will see the REQUEUE_REQUEST - * status and retry the command. + * agreement. + * Revert to async/narrow transfers until we + * can renegotiate with the device and notify + * the OSM about the reset. */ scbid = ahd_get_scbptr(ahd); scb = ahd_lookup_scb(ahd, scbid); @@ -1086,31 +1083,15 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, /*ppr_options*/0, AHD_TRANS_ACTIVE, /*paused*/TRUE); - ahd_outb(ahd, SCB_CDB_STORE, 0); - ahd_outb(ahd, SCB_CDB_STORE+1, 0); - ahd_outb(ahd, SCB_CDB_STORE+2, 0); - ahd_outb(ahd, SCB_CDB_STORE+3, 0); - ahd_outb(ahd, SCB_CDB_STORE+4, 0); - ahd_outb(ahd, SCB_CDB_STORE+5, 0); - ahd_outb(ahd, SCB_CDB_LEN, 6); - scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE); - scb->hscb->control |= MK_MESSAGE; - ahd_outb(ahd, SCB_CONTROL, scb->hscb->control); - ahd_outb(ahd, MSG_OUT, HOST_MSG); - ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid); - /* - * The lun is 0, regardless of the SCB's lun - * as we have not sent an identify message. - */ - ahd_outb(ahd, SAVED_LUN, 0); - ahd_outb(ahd, SEQ_FLAGS, 0); - ahd_assert_atn(ahd); - scb->flags &= ~SCB_PACKETIZED; - scb->flags |= SCB_ABORT|SCB_CMDPHASE_ABORT; + scb->flags |= SCB_EXTERNAL_RESET; ahd_freeze_devq(ahd, scb); ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); ahd_freeze_scb(scb); + /* Notify XPT */ + ahd_send_async(ahd, devinfo.channel, devinfo.target, + CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + /* * Allow the sequencer to continue with * non-pack processing. @@ -1534,6 +1515,18 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) lqistat1 = ahd_inb(ahd, LQISTAT1); lqostat0 = ahd_inb(ahd, LQOSTAT0); busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; + + /* + * Ignore external resets after a bus reset. + */ + if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE)) + return; + + /* + * Clear bus reset flag + */ + ahd->flags &= ~AHD_BUS_RESET_ACTIVE; + if ((status0 & (SELDI|SELDO)) != 0) { u_int simode0; @@ -2207,22 +2200,6 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) if (sent_msg == MSG_ABORT_TAG) tag = SCB_GET_TAG(scb); - if ((scb->flags & SCB_CMDPHASE_ABORT) != 0) { - /* - * This abort is in response to an - * unexpected switch to command phase - * for a packetized connection. Since - * the identify message was never sent, - * "saved lun" is 0. We really want to - * abort only the SCB that encountered - * this error, which could have a different - * lun. The SCB will be retried so the OS - * will see the UA after renegotiating to - * packetized. - */ - tag = SCB_GET_TAG(scb); - saved_lun = scb->hscb->lun; - } found = ahd_abort_scbs(ahd, target, 'A', saved_lun, tag, ROLE_INITIATOR, CAM_REQ_ABORTED); @@ -7847,6 +7824,17 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) int found; u_int fifo; u_int next_fifo; + uint8_t scsiseq; + + /* + * Check if the last bus reset is cleared + */ + if (ahd->flags & AHD_BUS_RESET_ACTIVE) { + printf("%s: bus reset still active\n", + ahd_name(ahd)); + return 0; + } + ahd->flags |= AHD_BUS_RESET_ACTIVE; ahd->pending_device = NULL; @@ -7860,6 +7848,12 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) /* Make sure the sequencer is in a safe location. */ ahd_clear_critical_section(ahd); + /* + * Run our command complete fifos to ensure that we perform + * completion processing on any commands that 'completed' + * before the reset occurred. + */ + ahd_run_qoutfifo(ahd); #ifdef AHD_TARGET_MODE if ((ahd->flags & AHD_TARGETROLE) != 0) { ahd_run_tqinfifo(ahd, /*paused*/TRUE); @@ -7924,30 +7918,14 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) ahd_clear_fifo(ahd, 1); /* - * Revert to async/narrow transfers until we renegotiate. + * Reenable selections */ + ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST); + scsiseq = ahd_inb(ahd, SCSISEQ_TEMPLATE); + ahd_outb(ahd, SCSISEQ1, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); + max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7; - for (target = 0; target <= max_scsiid; target++) { - - if (ahd->enabled_targets[target] == NULL) - continue; - for (initiator = 0; initiator <= max_scsiid; initiator++) { - struct ahd_devinfo devinfo; - - ahd_compile_devinfo(&devinfo, target, initiator, - CAM_LUN_WILDCARD, - 'A', ROLE_UNKNOWN); - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_CUR, /*paused*/TRUE); - ahd_set_syncrate(ahd, &devinfo, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHD_TRANS_CUR, /*paused*/TRUE); - } - } - #ifdef AHD_TARGET_MODE - max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7; - /* * Send an immediate notify ccb to all target more peripheral * drivers affected by this action. @@ -7975,53 +7953,33 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) /* Notify the XPT that a bus reset occurred */ ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); - ahd_restart(ahd); + /* - * Freeze the SIMQ until our poller can determine that - * the bus reset has really gone away. We set the initial - * timer to 0 to have the check performed as soon as possible - * from the timer context. + * Revert to async/narrow transfers until we renegotiate. */ - if ((ahd->flags & AHD_RESET_POLL_ACTIVE) == 0) { - ahd->flags |= AHD_RESET_POLL_ACTIVE; - ahd_freeze_simq(ahd); - ahd_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd); + for (target = 0; target <= max_scsiid; target++) { + + if (ahd->enabled_targets[target] == NULL) + continue; + for (initiator = 0; initiator <= max_scsiid; initiator++) { + struct ahd_devinfo devinfo; + + ahd_compile_devinfo(&devinfo, target, initiator, + CAM_LUN_WILDCARD, + 'A', ROLE_UNKNOWN); + ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHD_TRANS_CUR, /*paused*/TRUE); + ahd_set_syncrate(ahd, &devinfo, /*period*/0, + /*offset*/0, /*ppr_options*/0, + AHD_TRANS_CUR, /*paused*/TRUE); + } } + + ahd_restart(ahd); + return (found); } - -#define AHD_RESET_POLL_US 1000 -static void -ahd_reset_poll(void *arg) -{ - struct ahd_softc *ahd = arg; - u_int scsiseq1; - u_long s; - - ahd_lock(ahd, &s); - ahd_pause(ahd); - ahd_update_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); - if ((ahd_inb(ahd, SSTAT1) & SCSIRSTI) != 0) { - ahd_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_US, - ahd_reset_poll, ahd); - ahd_unpause(ahd); - ahd_unlock(ahd, &s); - return; - } - - /* Reset is now low. Complete chip reinitialization. */ - ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST); - scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE); - ahd_outb(ahd, SCSISEQ1, scsiseq1 & (ENSELI|ENRSELI|ENAUTOATNP)); - ahd_unpause(ahd); - ahd->flags &= ~AHD_RESET_POLL_ACTIVE; - ahd_unlock(ahd, &s); - ahd_release_simq(ahd); -} - /**************************** Statistics Processing ***************************/ static void ahd_stat_timer(void *arg) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index bcced0a417e6..66e4a47bb9ee 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -782,6 +782,7 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd) { struct ahd_softc *ahd; int found; + unsigned long flags; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; #ifdef AHD_DEBUG @@ -789,8 +790,11 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd) printf("%s: Bus reset called for cmd %p\n", ahd_name(ahd), cmd); #endif + ahd_lock(ahd, &flags); + found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', /*initiate reset*/TRUE); + ahd_unlock(ahd, &flags); if (bootverbose) printf("%s: SCSI bus reset delivered. " diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 2d5be84d8bd4..6dc88149f9f1 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -209,7 +209,6 @@ static struct scsi_host_template piix_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, @@ -301,7 +300,7 @@ static struct piix_map_db ich6_map_db = { .mask = 0x3, .map = { /* PM PS SM SS MAP */ - { P0, P1, P2, P3 }, /* 00b */ + { P0, P2, P1, P3 }, /* 00b */ { IDE, IDE, P1, P3 }, /* 01b */ { P0, P2, IDE, IDE }, /* 10b */ { RV, RV, RV, RV }, @@ -312,7 +311,7 @@ static struct piix_map_db ich6m_map_db = { .mask = 0x3, .map = { /* PM PS SM SS MAP */ - { P0, P1, P2, P3 }, /* 00b */ + { P0, P2, RV, RV }, /* 00b */ { RV, RV, RV, RV }, { P0, P2, IDE, IDE }, /* 10b */ { RV, RV, RV, RV }, diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index ef57f253031c..dfcb96f3e60c 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -294,18 +294,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) if (sht->unchecked_isa_dma && privsize) gfp_mask |= __GFP_DMA; - /* Check to see if this host has any error handling facilities */ - if (!sht->eh_strategy_handler && !sht->eh_abort_handler && - !sht->eh_device_reset_handler && !sht->eh_bus_reset_handler && - !sht->eh_host_reset_handler) { - printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\n" - "ERROR: This is not a safe way to run your " - "SCSI host\n" - "ERROR: The error handling must be added to " - "this driver\n", sht->proc_name); - dump_stack(); - } - shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask); if (!shost) return NULL; diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 3a8462e8d063..24eb59e143a9 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -2488,7 +2488,7 @@ static int option_setup(char *str) } ints[0] = i - 1; internal_ibmmca_scsi_setup(cur, ints); - return 0; + return 1; } __setup("ibmmcascsi=", option_setup); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index eaefeddb2b4a..0a8ad37ae899 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -168,7 +168,7 @@ static void release_event_pool(struct event_pool *pool, ++in_use; if (pool->events[i].ext_list) { dma_free_coherent(hostdata->dev, - SG_ALL * sizeof(struct memory_descriptor), + SG_ALL * sizeof(struct srp_direct_buf), pool->events[i].ext_list, pool->events[i].ext_list_token); } @@ -284,40 +284,37 @@ static void set_srp_direction(struct scsi_cmnd *cmd, struct srp_cmd *srp_cmd, int numbuf) { + u8 fmt; + if (numbuf == 0) return; - if (numbuf == 1) { + if (numbuf == 1) + fmt = SRP_DATA_DESC_DIRECT; + else { + fmt = SRP_DATA_DESC_INDIRECT; + numbuf = min(numbuf, MAX_INDIRECT_BUFS); + if (cmd->sc_data_direction == DMA_TO_DEVICE) - srp_cmd->data_out_format = SRP_DIRECT_BUFFER; - else - srp_cmd->data_in_format = SRP_DIRECT_BUFFER; - } else { - if (cmd->sc_data_direction == DMA_TO_DEVICE) { - srp_cmd->data_out_format = SRP_INDIRECT_BUFFER; - srp_cmd->data_out_count = - numbuf < MAX_INDIRECT_BUFS ? - numbuf: MAX_INDIRECT_BUFS; - } else { - srp_cmd->data_in_format = SRP_INDIRECT_BUFFER; - srp_cmd->data_in_count = - numbuf < MAX_INDIRECT_BUFS ? - numbuf: MAX_INDIRECT_BUFS; - } + srp_cmd->data_out_desc_cnt = numbuf; + else + srp_cmd->data_in_desc_cnt = numbuf; } + + if (cmd->sc_data_direction == DMA_TO_DEVICE) + srp_cmd->buf_fmt = fmt << 4; + else + srp_cmd->buf_fmt = fmt; } -static void unmap_sg_list(int num_entries, +static void unmap_sg_list(int num_entries, struct device *dev, - struct memory_descriptor *md) -{ + struct srp_direct_buf *md) +{ int i; - for (i = 0; i < num_entries; ++i) { - dma_unmap_single(dev, - md[i].virtual_address, - md[i].length, DMA_BIDIRECTIONAL); - } + for (i = 0; i < num_entries; ++i) + dma_unmap_single(dev, md[i].va, md[i].len, DMA_BIDIRECTIONAL); } /** @@ -330,23 +327,26 @@ static void unmap_cmd_data(struct srp_cmd *cmd, struct srp_event_struct *evt_struct, struct device *dev) { - if ((cmd->data_out_format == SRP_NO_BUFFER) && - (cmd->data_in_format == SRP_NO_BUFFER)) + u8 out_fmt, in_fmt; + + out_fmt = cmd->buf_fmt >> 4; + in_fmt = cmd->buf_fmt & ((1U << 4) - 1); + + if (out_fmt == SRP_NO_DATA_DESC && in_fmt == SRP_NO_DATA_DESC) return; - else if ((cmd->data_out_format == SRP_DIRECT_BUFFER) || - (cmd->data_in_format == SRP_DIRECT_BUFFER)) { - struct memory_descriptor *data = - (struct memory_descriptor *)cmd->additional_data; - dma_unmap_single(dev, data->virtual_address, data->length, - DMA_BIDIRECTIONAL); + else if (out_fmt == SRP_DATA_DESC_DIRECT || + in_fmt == SRP_DATA_DESC_DIRECT) { + struct srp_direct_buf *data = + (struct srp_direct_buf *) cmd->add_data; + dma_unmap_single(dev, data->va, data->len, DMA_BIDIRECTIONAL); } else { - struct indirect_descriptor *indirect = - (struct indirect_descriptor *)cmd->additional_data; - int num_mapped = indirect->head.length / - sizeof(indirect->list[0]); + struct srp_indirect_buf *indirect = + (struct srp_indirect_buf *) cmd->add_data; + int num_mapped = indirect->table_desc.len / + sizeof(struct srp_direct_buf); if (num_mapped <= MAX_INDIRECT_BUFS) { - unmap_sg_list(num_mapped, dev, &indirect->list[0]); + unmap_sg_list(num_mapped, dev, &indirect->desc_list[0]); return; } @@ -356,17 +356,17 @@ static void unmap_cmd_data(struct srp_cmd *cmd, static int map_sg_list(int num_entries, struct scatterlist *sg, - struct memory_descriptor *md) + struct srp_direct_buf *md) { int i; u64 total_length = 0; for (i = 0; i < num_entries; ++i) { - struct memory_descriptor *descr = md + i; + struct srp_direct_buf *descr = md + i; struct scatterlist *sg_entry = &sg[i]; - descr->virtual_address = sg_dma_address(sg_entry); - descr->length = sg_dma_len(sg_entry); - descr->memory_handle = 0; + descr->va = sg_dma_address(sg_entry); + descr->len = sg_dma_len(sg_entry); + descr->key = 0; total_length += sg_dma_len(sg_entry); } return total_length; @@ -389,10 +389,10 @@ static int map_sg_data(struct scsi_cmnd *cmd, int sg_mapped; u64 total_length = 0; struct scatterlist *sg = cmd->request_buffer; - struct memory_descriptor *data = - (struct memory_descriptor *)srp_cmd->additional_data; - struct indirect_descriptor *indirect = - (struct indirect_descriptor *)data; + struct srp_direct_buf *data = + (struct srp_direct_buf *) srp_cmd->add_data; + struct srp_indirect_buf *indirect = + (struct srp_indirect_buf *) data; sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL); @@ -403,9 +403,9 @@ static int map_sg_data(struct scsi_cmnd *cmd, /* special case; we can use a single direct descriptor */ if (sg_mapped == 1) { - data->virtual_address = sg_dma_address(&sg[0]); - data->length = sg_dma_len(&sg[0]); - data->memory_handle = 0; + data->va = sg_dma_address(&sg[0]); + data->len = sg_dma_len(&sg[0]); + data->key = 0; return 1; } @@ -416,25 +416,26 @@ static int map_sg_data(struct scsi_cmnd *cmd, return 0; } - indirect->head.virtual_address = 0; - indirect->head.length = sg_mapped * sizeof(indirect->list[0]); - indirect->head.memory_handle = 0; + indirect->table_desc.va = 0; + indirect->table_desc.len = sg_mapped * sizeof(struct srp_direct_buf); + indirect->table_desc.key = 0; if (sg_mapped <= MAX_INDIRECT_BUFS) { - total_length = map_sg_list(sg_mapped, sg, &indirect->list[0]); - indirect->total_length = total_length; + total_length = map_sg_list(sg_mapped, sg, + &indirect->desc_list[0]); + indirect->len = total_length; return 1; } /* get indirect table */ if (!evt_struct->ext_list) { - evt_struct->ext_list =(struct memory_descriptor*) + evt_struct->ext_list = (struct srp_direct_buf *) dma_alloc_coherent(dev, - SG_ALL * sizeof(struct memory_descriptor), - &evt_struct->ext_list_token, 0); + SG_ALL * sizeof(struct srp_direct_buf), + &evt_struct->ext_list_token, 0); if (!evt_struct->ext_list) { - printk(KERN_ERR - "ibmvscsi: Can't allocate memory for indirect table\n"); + printk(KERN_ERR + "ibmvscsi: Can't allocate memory for indirect table\n"); return 0; } @@ -442,11 +443,11 @@ static int map_sg_data(struct scsi_cmnd *cmd, total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list); - indirect->total_length = total_length; - indirect->head.virtual_address = evt_struct->ext_list_token; - indirect->head.length = sg_mapped * sizeof(indirect->list[0]); - memcpy(indirect->list, evt_struct->ext_list, - MAX_INDIRECT_BUFS * sizeof(struct memory_descriptor)); + indirect->len = total_length; + indirect->table_desc.va = evt_struct->ext_list_token; + indirect->table_desc.len = sg_mapped * sizeof(indirect->desc_list[0]); + memcpy(indirect->desc_list, evt_struct->ext_list, + MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf)); return 1; } @@ -463,20 +464,20 @@ static int map_sg_data(struct scsi_cmnd *cmd, static int map_single_data(struct scsi_cmnd *cmd, struct srp_cmd *srp_cmd, struct device *dev) { - struct memory_descriptor *data = - (struct memory_descriptor *)srp_cmd->additional_data; + struct srp_direct_buf *data = + (struct srp_direct_buf *) srp_cmd->add_data; - data->virtual_address = + data->va = dma_map_single(dev, cmd->request_buffer, cmd->request_bufflen, DMA_BIDIRECTIONAL); - if (dma_mapping_error(data->virtual_address)) { + if (dma_mapping_error(data->va)) { printk(KERN_ERR "ibmvscsi: Unable to map request_buffer for command!\n"); return 0; } - data->length = cmd->request_bufflen; - data->memory_handle = 0; + data->len = cmd->request_bufflen; + data->key = 0; set_srp_direction(cmd, srp_cmd, 1); @@ -548,7 +549,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, /* Copy the IU into the transfer area */ *evt_struct->xfer_iu = evt_struct->iu; - evt_struct->xfer_iu->srp.generic.tag = (u64)evt_struct; + evt_struct->xfer_iu->srp.rsp.tag = (u64)evt_struct; /* Add this to the sent list. We need to do this * before we actually send @@ -586,27 +587,27 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct) struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp; struct scsi_cmnd *cmnd = evt_struct->cmnd; - if (unlikely(rsp->type != SRP_RSP_TYPE)) { + if (unlikely(rsp->opcode != SRP_RSP)) { if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: bad SRP RSP type %d\n", - rsp->type); + rsp->opcode); } if (cmnd) { cmnd->result = rsp->status; if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION) memcpy(cmnd->sense_buffer, - rsp->sense_and_response_data, - rsp->sense_data_list_length); + rsp->data, + rsp->sense_data_len); unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, evt_struct->hostdata->dev); - if (rsp->doover) - cmnd->resid = rsp->data_out_residual_count; - else if (rsp->diover) - cmnd->resid = rsp->data_in_residual_count; + if (rsp->flags & SRP_RSP_FLAG_DOOVER) + cmnd->resid = rsp->data_out_res_cnt; + else if (rsp->flags & SRP_RSP_FLAG_DIOVER) + cmnd->resid = rsp->data_in_res_cnt; } if (evt_struct->cmnd_done) @@ -633,10 +634,11 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, { struct srp_cmd *srp_cmd; struct srp_event_struct *evt_struct; - struct indirect_descriptor *indirect; + struct srp_indirect_buf *indirect; struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata; u16 lun = lun_from_dev(cmnd->device); + u8 out_fmt, in_fmt; evt_struct = get_event_struct(&hostdata->pool); if (!evt_struct) @@ -644,8 +646,8 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, /* Set up the actual SRP IU */ srp_cmd = &evt_struct->iu.srp.cmd; - memset(srp_cmd, 0x00, sizeof(*srp_cmd)); - srp_cmd->type = SRP_CMD_TYPE; + memset(srp_cmd, 0x00, SRP_MAX_IU_LEN); + srp_cmd->opcode = SRP_CMD; memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd)); srp_cmd->lun = ((u64) lun) << 48; @@ -664,13 +666,15 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, evt_struct->cmnd_done = done; /* Fix up dma address of the buffer itself */ - indirect = (struct indirect_descriptor *)srp_cmd->additional_data; - if (((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) || - (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) && - (indirect->head.virtual_address == 0)) { - indirect->head.virtual_address = evt_struct->crq.IU_data_ptr + - offsetof(struct srp_cmd, additional_data) + - offsetof(struct indirect_descriptor, list); + indirect = (struct srp_indirect_buf *) srp_cmd->add_data; + out_fmt = srp_cmd->buf_fmt >> 4; + in_fmt = srp_cmd->buf_fmt & ((1U << 4) - 1); + if ((in_fmt == SRP_DATA_DESC_INDIRECT || + out_fmt == SRP_DATA_DESC_INDIRECT) && + indirect->table_desc.va == 0) { + indirect->table_desc.va = evt_struct->crq.IU_data_ptr + + offsetof(struct srp_cmd, add_data) + + offsetof(struct srp_indirect_buf, desc_list); } return ibmvscsi_send_srp_event(evt_struct, hostdata); @@ -780,10 +784,10 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) static void login_rsp(struct srp_event_struct *evt_struct) { struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; - switch (evt_struct->xfer_iu->srp.generic.type) { - case SRP_LOGIN_RSP_TYPE: /* it worked! */ + switch (evt_struct->xfer_iu->srp.login_rsp.opcode) { + case SRP_LOGIN_RSP: /* it worked! */ break; - case SRP_LOGIN_REJ_TYPE: /* refused! */ + case SRP_LOGIN_REJ: /* refused! */ printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REJ reason %u\n", evt_struct->xfer_iu->srp.login_rej.reason); /* Login failed. */ @@ -792,7 +796,7 @@ static void login_rsp(struct srp_event_struct *evt_struct) default: printk(KERN_ERR "ibmvscsi: Invalid login response typecode 0x%02x!\n", - evt_struct->xfer_iu->srp.generic.type); + evt_struct->xfer_iu->srp.login_rsp.opcode); /* Login failed. */ atomic_set(&hostdata->request_limit, -1); return; @@ -800,17 +804,17 @@ static void login_rsp(struct srp_event_struct *evt_struct) printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n"); - if (evt_struct->xfer_iu->srp.login_rsp.request_limit_delta > + if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta > (max_requests - 2)) - evt_struct->xfer_iu->srp.login_rsp.request_limit_delta = + evt_struct->xfer_iu->srp.login_rsp.req_lim_delta = max_requests - 2; /* Now we know what the real request-limit is */ atomic_set(&hostdata->request_limit, - evt_struct->xfer_iu->srp.login_rsp.request_limit_delta); + evt_struct->xfer_iu->srp.login_rsp.req_lim_delta); hostdata->host->can_queue = - evt_struct->xfer_iu->srp.login_rsp.request_limit_delta - 2; + evt_struct->xfer_iu->srp.login_rsp.req_lim_delta - 2; if (hostdata->host->can_queue < 1) { printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n"); @@ -849,18 +853,19 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata) login = &evt_struct->iu.srp.login_req; memset(login, 0x00, sizeof(struct srp_login_req)); - login->type = SRP_LOGIN_REQ_TYPE; - login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu); - login->required_buffer_formats = 0x0006; + login->opcode = SRP_LOGIN_REQ; + login->req_it_iu_len = sizeof(union srp_iu); + login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT; + spin_lock_irqsave(hostdata->host->host_lock, flags); /* Start out with a request limit of 1, since this is negotiated in * the login request we are just sending */ atomic_set(&hostdata->request_limit, 1); - spin_lock_irqsave(hostdata->host->host_lock, flags); rc = ibmvscsi_send_srp_event(evt_struct, hostdata); spin_unlock_irqrestore(hostdata->host->host_lock, flags); + printk("ibmvscsic: sent SRP login\n"); return rc; }; @@ -928,13 +933,13 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) /* Set up an abort SRP command */ memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->type = SRP_TSK_MGMT_TYPE; + tsk_mgmt->opcode = SRP_TSK_MGMT; tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->task_mgmt_flags = 0x01; /* ABORT TASK */ - tsk_mgmt->managed_task_tag = (u64) found_evt; + tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK; + tsk_mgmt->task_tag = (u64) found_evt; printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n", - tsk_mgmt->lun, tsk_mgmt->managed_task_tag); + tsk_mgmt->lun, tsk_mgmt->task_tag); evt->sync_srp = &srp_rsp; init_completion(&evt->comp); @@ -948,25 +953,25 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) wait_for_completion(&evt->comp); /* make sure we got a good response */ - if (unlikely(srp_rsp.srp.generic.type != SRP_RSP_TYPE)) { + if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) { if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: abort bad SRP RSP type %d\n", - srp_rsp.srp.generic.type); + srp_rsp.srp.rsp.opcode); return FAILED; } - if (srp_rsp.srp.rsp.rspvalid) - rsp_rc = *((int *)srp_rsp.srp.rsp.sense_and_response_data); + if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID) + rsp_rc = *((int *)srp_rsp.srp.rsp.data); else rsp_rc = srp_rsp.srp.rsp.status; if (rsp_rc) { if (printk_ratelimit()) printk(KERN_WARNING - "ibmvscsi: abort code %d for task tag 0x%lx\n", + "ibmvscsi: abort code %d for task tag 0x%lx\n", rsp_rc, - tsk_mgmt->managed_task_tag); + tsk_mgmt->task_tag); return FAILED; } @@ -987,13 +992,13 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) spin_unlock_irqrestore(hostdata->host->host_lock, flags); printk(KERN_INFO "ibmvscsi: aborted task tag 0x%lx completed\n", - tsk_mgmt->managed_task_tag); + tsk_mgmt->task_tag); return SUCCESS; } printk(KERN_INFO "ibmvscsi: successfully aborted task tag 0x%lx\n", - tsk_mgmt->managed_task_tag); + tsk_mgmt->task_tag); cmd->result = (DID_ABORT << 16); list_del(&found_evt->list); @@ -1040,9 +1045,9 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) /* Set up a lun reset SRP command */ memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->type = SRP_TSK_MGMT_TYPE; + tsk_mgmt->opcode = SRP_TSK_MGMT; tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->task_mgmt_flags = 0x08; /* LUN RESET */ + tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET; printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n", tsk_mgmt->lun); @@ -1059,16 +1064,16 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) wait_for_completion(&evt->comp); /* make sure we got a good response */ - if (unlikely(srp_rsp.srp.generic.type != SRP_RSP_TYPE)) { + if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) { if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: reset bad SRP RSP type %d\n", - srp_rsp.srp.generic.type); + srp_rsp.srp.rsp.opcode); return FAILED; } - if (srp_rsp.srp.rsp.rspvalid) - rsp_rc = *((int *)srp_rsp.srp.rsp.sense_and_response_data); + if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID) + rsp_rc = *((int *)srp_rsp.srp.rsp.data); else rsp_rc = srp_rsp.srp.rsp.status; @@ -1076,8 +1081,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) if (printk_ratelimit()) printk(KERN_WARNING "ibmvscsi: reset code %d for task tag 0x%lx\n", - rsp_rc, - tsk_mgmt->managed_task_tag); + rsp_rc, tsk_mgmt->task_tag); return FAILED; } @@ -1179,6 +1183,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, /* We need to re-setup the interpartition connection */ printk(KERN_INFO "ibmvscsi: Re-enabling adapter!\n"); + atomic_set(&hostdata->request_limit, -1); purge_requests(hostdata, DID_REQUEUE); if (ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata) == 0) @@ -1226,7 +1231,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, } if (crq->format == VIOSRP_SRP_FORMAT) - atomic_add(evt_struct->xfer_iu->srp.rsp.request_limit_delta, + atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta, &hostdata->request_limit); if (evt_struct->done) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 4550d71e4744..5c6d93582929 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -68,7 +68,7 @@ struct srp_event_struct { void (*cmnd_done) (struct scsi_cmnd *); struct completion comp; union viosrp_iu *sync_srp; - struct memory_descriptor *ext_list; + struct srp_direct_buf *ext_list; dma_addr_t ext_list_token; }; diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index f47dd87c05e7..1a9992bdfef8 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -34,7 +34,6 @@ #include #include #include "ibmvscsi.h" -#include "srp.h" static char partition_name[97] = "UNKNOWN"; static unsigned int partition_number = -1; @@ -80,7 +79,7 @@ void ibmvscsi_release_crq_queue(struct crq_queue *queue, tasklet_kill(&hostdata->srp_task); do { rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while ((rc == H_Busy) || (H_isLongBusy(rc))); + } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); dma_unmap_single(hostdata->dev, queue->msg_token, queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); @@ -230,7 +229,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, queue->msg_token, PAGE_SIZE); - if (rc == H_Resource) + if (rc == H_RESOURCE) /* maybe kexecing and resource is busy. try a reset */ rc = ibmvscsi_reset_crq_queue(queue, hostdata); @@ -269,7 +268,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, req_irq_failed: do { rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while ((rc == H_Busy) || (H_isLongBusy(rc))); + } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); reg_crq_failed: dma_unmap_single(hostdata->dev, queue->msg_token, @@ -295,7 +294,7 @@ int ibmvscsi_reenable_crq_queue(struct crq_queue *queue, /* Re-enable the CRQ */ do { rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); - } while ((rc == H_InProgress) || (rc == H_Busy) || (H_isLongBusy(rc))); + } while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); if (rc) printk(KERN_ERR "ibmvscsi: Error %d enabling adapter\n", rc); @@ -317,7 +316,7 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue, /* Close the CRQ */ do { rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while ((rc == H_Busy) || (H_isLongBusy(rc))); + } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); /* Clean out the queue */ memset(queue->msgs, 0x00, PAGE_SIZE); diff --git a/drivers/scsi/ibmvscsi/srp.h b/drivers/scsi/ibmvscsi/srp.h deleted file mode 100644 index 7d8e4c4accb9..000000000000 --- a/drivers/scsi/ibmvscsi/srp.h +++ /dev/null @@ -1,227 +0,0 @@ -/*****************************************************************************/ -/* srp.h -- SCSI RDMA Protocol definitions */ -/* */ -/* Written By: Colin Devilbis, IBM Corporation */ -/* */ -/* Copyright (C) 2003 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 structures and definitions for the SCSI RDMA Protocol */ -/* (SRP) as defined in the T10 standard available at www.t10.org. This */ -/* file was based on the 16a version of the standard */ -/* */ -/*****************************************************************************/ -#ifndef SRP_H -#define SRP_H - -#define SRP_VERSION "16.a" - -#define PACKED __attribute__((packed)) - -enum srp_types { - SRP_LOGIN_REQ_TYPE = 0x00, - SRP_LOGIN_RSP_TYPE = 0xC0, - SRP_LOGIN_REJ_TYPE = 0xC2, - SRP_I_LOGOUT_TYPE = 0x03, - SRP_T_LOGOUT_TYPE = 0x80, - SRP_TSK_MGMT_TYPE = 0x01, - SRP_CMD_TYPE = 0x02, - SRP_RSP_TYPE = 0xC1, - SRP_CRED_REQ_TYPE = 0x81, - SRP_CRED_RSP_TYPE = 0x41, - SRP_AER_REQ_TYPE = 0x82, - SRP_AER_RSP_TYPE = 0x42 -}; - -enum srp_descriptor_formats { - SRP_NO_BUFFER = 0x00, - SRP_DIRECT_BUFFER = 0x01, - SRP_INDIRECT_BUFFER = 0x02 -}; - -struct memory_descriptor { - u64 virtual_address; - u32 memory_handle; - u32 length; -}; - -struct indirect_descriptor { - struct memory_descriptor head; - u32 total_length; - struct memory_descriptor list[1] PACKED; -}; - -struct srp_generic { - u8 type; - u8 reserved1[7]; - u64 tag; -}; - -struct srp_login_req { - u8 type; - u8 reserved1[7]; - u64 tag; - u32 max_requested_initiator_to_target_iulen; - u32 reserved2; - u16 required_buffer_formats; - u8 reserved3:6; - u8 multi_channel_action:2; - u8 reserved4; - u32 reserved5; - u8 initiator_port_identifier[16]; - u8 target_port_identifier[16]; -}; - -struct srp_login_rsp { - u8 type; - u8 reserved1[3]; - u32 request_limit_delta; - u64 tag; - u32 max_initiator_to_target_iulen; - u32 max_target_to_initiator_iulen; - u16 supported_buffer_formats; - u8 reserved2:6; - u8 multi_channel_result:2; - u8 reserved3; - u8 reserved4[24]; -}; - -struct srp_login_rej { - u8 type; - u8 reserved1[3]; - u32 reason; - u64 tag; - u64 reserved2; - u16 supported_buffer_formats; - u8 reserved3[6]; -}; - -struct srp_i_logout { - u8 type; - u8 reserved1[7]; - u64 tag; -}; - -struct srp_t_logout { - u8 type; - u8 reserved1[3]; - u32 reason; - u64 tag; -}; - -struct srp_tsk_mgmt { - u8 type; - u8 reserved1[7]; - u64 tag; - u32 reserved2; - u64 lun PACKED; - u8 reserved3; - u8 reserved4; - u8 task_mgmt_flags; - u8 reserved5; - u64 managed_task_tag; - u64 reserved6; -}; - -struct srp_cmd { - u8 type; - u32 reserved1 PACKED; - u8 data_out_format:4; - u8 data_in_format:4; - u8 data_out_count; - u8 data_in_count; - u64 tag; - u32 reserved2; - u64 lun PACKED; - u8 reserved3; - u8 reserved4:5; - u8 task_attribute:3; - u8 reserved5; - u8 additional_cdb_len; - u8 cdb[16]; - u8 additional_data[0x100 - 0x30]; -}; - -struct srp_rsp { - u8 type; - u8 reserved1[3]; - u32 request_limit_delta; - u64 tag; - u16 reserved2; - u8 reserved3:2; - u8 diunder:1; - u8 diover:1; - u8 dounder:1; - u8 doover:1; - u8 snsvalid:1; - u8 rspvalid:1; - u8 status; - u32 data_in_residual_count; - u32 data_out_residual_count; - u32 sense_data_list_length; - u32 response_data_list_length; - u8 sense_and_response_data[18]; -}; - -struct srp_cred_req { - u8 type; - u8 reserved1[3]; - u32 request_limit_delta; - u64 tag; -}; - -struct srp_cred_rsp { - u8 type; - u8 reserved1[7]; - u64 tag; -}; - -struct srp_aer_req { - u8 type; - u8 reserved1[3]; - u32 request_limit_delta; - u64 tag; - u32 reserved2; - u64 lun; - u32 sense_data_list_length; - u32 reserved3; - u8 sense_data[20]; -}; - -struct srp_aer_rsp { - u8 type; - u8 reserved1[7]; - u64 tag; -}; - -union srp_iu { - struct srp_generic generic; - struct srp_login_req login_req; - struct srp_login_rsp login_rsp; - struct srp_login_rej login_rej; - struct srp_i_logout i_logout; - struct srp_t_logout t_logout; - struct srp_tsk_mgmt tsk_mgmt; - struct srp_cmd cmd; - struct srp_rsp rsp; - struct srp_cred_req cred_req; - struct srp_cred_rsp cred_rsp; - struct srp_aer_req aer_req; - struct srp_aer_rsp aer_rsp; -}; - -#endif diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h index 6a6bba8a2f34..90f1a61283ad 100644 --- a/drivers/scsi/ibmvscsi/viosrp.h +++ b/drivers/scsi/ibmvscsi/viosrp.h @@ -33,7 +33,22 @@ /*****************************************************************************/ #ifndef VIOSRP_H #define VIOSRP_H -#include "srp.h" +#include + +#define SRP_VERSION "16.a" +#define SRP_MAX_IU_LEN 256 + +union srp_iu { + struct srp_login_req login_req; + struct srp_login_rsp login_rsp; + struct srp_login_rej login_rej; + struct srp_i_logout i_logout; + struct srp_t_logout t_logout; + struct srp_tsk_mgmt tsk_mgmt; + struct srp_cmd cmd; + struct srp_rsp rsp; + u8 reserved[SRP_MAX_IU_LEN]; +}; enum viosrp_crq_formats { VIOSRP_SRP_FORMAT = 0x01, diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 5890e5f92d82..8b80e59c8c52 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -164,29 +164,6 @@ MODULE_PARM_DESC(auto_create, "Auto-create single device RAID 0 arrays when init MODULE_LICENSE("GPL"); MODULE_VERSION(IPR_DRIVER_VERSION); -static const char *ipr_gpdd_dev_end_states[] = { - "Command complete", - "Terminated by host", - "Terminated by device reset", - "Terminated by bus reset", - "Unknown", - "Command not started" -}; - -static const char *ipr_gpdd_dev_bus_phases[] = { - "Bus free", - "Arbitration", - "Selection", - "Message out", - "Command", - "Message in", - "Data out", - "Data in", - "Status", - "Reselection", - "Unknown" -}; - /* A constant array of IOASCs/URCs/Error Messages */ static const struct ipr_error_table_t ipr_error_table[] = { @@ -869,8 +846,8 @@ static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg, if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) { if (res->sdev) { - res->sdev->hostdata = NULL; res->del_from_ml = 1; + res->cfgte.res_handle = IPR_INVALID_RES_HANDLE; if (ioa_cfg->allow_ml_add_del) schedule_work(&ioa_cfg->work_q); } else @@ -1356,8 +1333,8 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, return; if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) { - ipr_res_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr, - "%s\n", ipr_error_table[error_index].error); + ipr_ra_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr, + "%s\n", ipr_error_table[error_index].error); } else { dev_err(&ioa_cfg->pdev->dev, "%s\n", ipr_error_table[error_index].error); @@ -2107,7 +2084,6 @@ restart: did_work = 1; sdev = res->sdev; if (!scsi_device_get(sdev)) { - res->sdev = NULL; list_move_tail(&res->queue, &ioa_cfg->free_res_q); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); scsi_remove_device(sdev); @@ -2124,6 +2100,7 @@ restart: bus = res->cfgte.res_addr.bus; target = res->cfgte.res_addr.target; lun = res->cfgte.res_addr.lun; + res->add_to_ml = 0; spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); scsi_add_device(ioa_cfg->host, bus, target, lun); spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); @@ -3214,7 +3191,7 @@ static int ipr_slave_configure(struct scsi_device *sdev) sdev->timeout = IPR_VSET_RW_TIMEOUT; blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS); } - if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)) + if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)) sdev->allow_restart = 1; scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); } @@ -3303,6 +3280,44 @@ static int ipr_eh_host_reset(struct scsi_cmnd * cmd) return rc; } +/** + * ipr_device_reset - Reset the device + * @ioa_cfg: ioa config struct + * @res: resource entry struct + * + * This function issues a device reset to the affected device. + * If the device is a SCSI device, a LUN reset will be sent + * to the device first. If that does not work, a target reset + * will be sent. + * + * Return value: + * 0 on success / non-zero on failure + **/ +static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, + struct ipr_resource_entry *res) +{ + struct ipr_cmnd *ipr_cmd; + struct ipr_ioarcb *ioarcb; + struct ipr_cmd_pkt *cmd_pkt; + u32 ioasc; + + ENTER; + ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); + ioarcb = &ipr_cmd->ioarcb; + cmd_pkt = &ioarcb->cmd_pkt; + + ioarcb->res_handle = res->cfgte.res_handle; + cmd_pkt->request_type = IPR_RQTYPE_IOACMD; + cmd_pkt->cdb[0] = IPR_RESET_DEVICE; + + ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); + ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); + + LEAVE; + return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0); +} + /** * ipr_eh_dev_reset - Reset the device * @scsi_cmd: scsi command struct @@ -3319,8 +3334,7 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) struct ipr_cmnd *ipr_cmd; struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; - struct ipr_cmd_pkt *cmd_pkt; - u32 ioasc; + int rc; ENTER; ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; @@ -3347,25 +3361,12 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) } res->resetting_device = 1; - - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - - ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle; - cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; - cmd_pkt->request_type = IPR_RQTYPE_IOACMD; - cmd_pkt->cdb[0] = IPR_RESET_DEVICE; - - ipr_sdev_err(scsi_cmd->device, "Resetting device\n"); - ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); - - ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); - + scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n"); + rc = ipr_device_reset(ioa_cfg, res); res->resetting_device = 0; - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - LEAVE; - return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS); + return (rc ? FAILED : SUCCESS); } static int ipr_eh_dev_reset(struct scsi_cmnd * cmd) @@ -3440,7 +3441,7 @@ static void ipr_abort_timeout(struct ipr_cmnd *ipr_cmd) return; } - ipr_sdev_err(ipr_cmd->u.sdev, "Abort timed out. Resetting bus\n"); + sdev_printk(KERN_ERR, ipr_cmd->u.sdev, "Abort timed out. Resetting bus.\n"); reset_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); ipr_cmd->sibling = reset_cmd; reset_cmd->sibling = ipr_cmd; @@ -3504,7 +3505,8 @@ static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; ipr_cmd->u.sdev = scsi_cmd->device; - ipr_sdev_err(scsi_cmd->device, "Aborting command: %02X\n", scsi_cmd->cmnd[0]); + scmd_printk(KERN_ERR, scsi_cmd, "Aborting command: %02X\n", + scsi_cmd->cmnd[0]); ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT); ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); @@ -3815,8 +3817,8 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { scsi_cmd->result |= (DID_ERROR << 16); - ipr_sdev_err(scsi_cmd->device, - "Request Sense failed with IOASC: 0x%08X\n", ioasc); + scmd_printk(KERN_ERR, scsi_cmd, + "Request Sense failed with IOASC: 0x%08X\n", ioasc); } else { memcpy(scsi_cmd->sense_buffer, ipr_cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); @@ -3938,6 +3940,7 @@ static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd) * ipr_dump_ioasa - Dump contents of IOASA * @ioa_cfg: ioa config struct * @ipr_cmd: ipr command struct + * @res: resource entry struct * * This function is invoked by the interrupt handler when ops * fail. It will log the IOASA if appropriate. Only called @@ -3947,7 +3950,7 @@ static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd) * none **/ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_cmnd *ipr_cmd) + struct ipr_cmnd *ipr_cmd, struct ipr_resource_entry *res) { int i; u16 data_len; @@ -3975,16 +3978,7 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, return; } - ipr_sdev_err(ipr_cmd->scsi_cmd->device, "%s\n", - ipr_error_table[error_index].error); - - if ((ioasa->u.gpdd.end_state <= ARRAY_SIZE(ipr_gpdd_dev_end_states)) && - (ioasa->u.gpdd.bus_phase <= ARRAY_SIZE(ipr_gpdd_dev_bus_phases))) { - ipr_sdev_err(ipr_cmd->scsi_cmd->device, - "Device End state: %s Phase: %s\n", - ipr_gpdd_dev_end_states[ioasa->u.gpdd.end_state], - ipr_gpdd_dev_bus_phases[ioasa->u.gpdd.bus_phase]); - } + ipr_res_err(ioa_cfg, res, "%s\n", ipr_error_table[error_index].error); if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len)) data_len = sizeof(struct ipr_ioasa); @@ -4141,7 +4135,7 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, } if (ipr_is_gscsi(res)) - ipr_dump_ioasa(ioa_cfg, ipr_cmd); + ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); else ipr_gen_sense(ipr_cmd); @@ -4540,7 +4534,7 @@ static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd) ipr_cmd->job_step = ipr_ioa_reset_done; list_for_each_entry_continue(res, &ioa_cfg->used_res_q, queue) { - if (!IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data)) + if (!ipr_is_scsi_disk(res)) continue; ipr_cmd->u.res = res; @@ -4980,7 +4974,7 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd) list_for_each_entry_safe(res, temp, &old_res, queue) { if (res->sdev) { res->del_from_ml = 1; - res->sdev->hostdata = NULL; + res->cfgte.res_handle = IPR_INVALID_RES_HANDLE; list_move_tail(&res->queue, &ioa_cfg->used_res_q); } else { list_move_tail(&res->queue, &ioa_cfg->free_res_q); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index fd360bfe56dd..1ad24df69d70 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -36,8 +36,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.1.2" -#define IPR_DRIVER_DATE "(February 8, 2006)" +#define IPR_DRIVER_VERSION "2.1.3" +#define IPR_DRIVER_DATE "(March 29, 2006)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -133,6 +133,7 @@ #define IPR_MAX_SCSI_RATE(width) ((320 * 10) / ((width) / 8)) #define IPR_IOA_RES_HANDLE 0xffffffff +#define IPR_INVALID_RES_HANDLE 0 #define IPR_IOA_RES_ADDR 0x00ffffff /* @@ -1191,30 +1192,17 @@ struct ipr_ucode_image_header { */ #define ipr_err(...) printk(KERN_ERR IPR_NAME ": "__VA_ARGS__) #define ipr_info(...) printk(KERN_INFO IPR_NAME ": "__VA_ARGS__) -#define ipr_crit(...) printk(KERN_CRIT IPR_NAME ": "__VA_ARGS__) -#define ipr_warn(...) printk(KERN_WARNING IPR_NAME": "__VA_ARGS__) #define ipr_dbg(...) IPR_DBG_CMD(printk(KERN_INFO IPR_NAME ": "__VA_ARGS__)) -#define ipr_sdev_printk(level, sdev, fmt, args...) \ - sdev_printk(level, sdev, fmt, ## args) +#define ipr_ra_printk(level, ioa_cfg, ra, fmt, ...) \ + printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, (ioa_cfg)->host->host_no, \ + (ra).bus, (ra).target, (ra).lun, ##__VA_ARGS__) -#define ipr_sdev_err(sdev, fmt, ...) \ - ipr_sdev_printk(KERN_ERR, sdev, fmt, ##__VA_ARGS__) - -#define ipr_sdev_info(sdev, fmt, ...) \ - ipr_sdev_printk(KERN_INFO, sdev, fmt, ##__VA_ARGS__) - -#define ipr_sdev_dbg(sdev, fmt, ...) \ - IPR_DBG_CMD(ipr_sdev_printk(KERN_INFO, sdev, fmt, ##__VA_ARGS__)) - -#define ipr_res_printk(level, ioa_cfg, res, fmt, ...) \ - printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, ioa_cfg->host->host_no, \ - res.bus, res.target, res.lun, ##__VA_ARGS__) +#define ipr_ra_err(ioa_cfg, ra, fmt, ...) \ + ipr_ra_printk(KERN_ERR, ioa_cfg, ra, fmt, ##__VA_ARGS__) #define ipr_res_err(ioa_cfg, res, fmt, ...) \ - ipr_res_printk(KERN_ERR, ioa_cfg, res, fmt, ##__VA_ARGS__) -#define ipr_res_dbg(ioa_cfg, res, fmt, ...) \ - IPR_DBG_CMD(ipr_res_printk(KERN_INFO, ioa_cfg, res, fmt, ##__VA_ARGS__)) + ipr_ra_err(ioa_cfg, (res)->cfgte.res_addr, fmt, ##__VA_ARGS__) #define ipr_phys_res_err(ioa_cfg, res, fmt, ...) \ { \ @@ -1303,6 +1291,22 @@ static inline int ipr_is_gscsi(struct ipr_resource_entry *res) return 0; } +/** + * ipr_is_scsi_disk - Determine if a resource is a SCSI disk + * @res: resource entry struct + * + * Return value: + * 1 if SCSI disk / 0 if not SCSI disk + **/ +static inline int ipr_is_scsi_disk(struct ipr_resource_entry *res) +{ + if (ipr_is_af_dasd_device(res) || + (ipr_is_gscsi(res) && IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data))) + return 1; + else + return 0; +} + /** * ipr_is_naca_model - Determine if a resource is using NACA queueing model * @res: resource entry struct diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 459a4daebece..eb7bd310cc82 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -112,7 +112,7 @@ lasi700_probe(struct parisc_device *dev) hostdata->dev = &dev->dev; dma_set_mask(&dev->dev, DMA_32BIT_MASK); - hostdata->base = ioremap(base, 0x100); + hostdata->base = ioremap_nocache(base, 0x100); hostdata->differential = 0; if (dev->id.sversion == LASI_700_SVERSION) { diff --git a/drivers/scsi/libata-bmdma.c b/drivers/scsi/libata-bmdma.c index 95d81d86d8b7..835dff0bafdc 100644 --- a/drivers/scsi/libata-bmdma.c +++ b/drivers/scsi/libata-bmdma.c @@ -703,6 +703,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); int p = 0; + unsigned long bmdma; if (!probe_ent) return NULL; @@ -716,7 +717,12 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int probe_ent->port[p].altstatus_addr = probe_ent->port[p].ctl_addr = pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4); + bmdma = pci_resource_start(pdev, 4); + if (bmdma) { + if (inb(bmdma + 2) & 0x80) + probe_ent->host_set_flags |= ATA_HOST_SIMPLEX; + probe_ent->port[p].bmdma_addr = bmdma; + } ata_std_ports(&probe_ent->port[p]); p++; } @@ -726,7 +732,13 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int probe_ent->port[p].altstatus_addr = probe_ent->port[p].ctl_addr = pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8; + bmdma = pci_resource_start(pdev, 4); + if (bmdma) { + bmdma += 8; + if(inb(bmdma + 2) & 0x80) + probe_ent->host_set_flags |= ATA_HOST_SIMPLEX; + probe_ent->port[p].bmdma_addr = bmdma; + } ata_std_ports(&probe_ent->port[p]); p++; } @@ -740,6 +752,7 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info *port, int port_num) { struct ata_probe_ent *probe_ent; + unsigned long bmdma; probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port); if (!probe_ent) @@ -766,8 +779,13 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, break; } - probe_ent->port[0].bmdma_addr = - pci_resource_start(pdev, 4) + 8 * port_num; + bmdma = pci_resource_start(pdev, 4); + if (bmdma != 0) { + bmdma += 8 * port_num; + probe_ent->port[0].bmdma_addr = bmdma; + if (inb(bmdma + 2) & 0x80) + probe_ent->host_set_flags |= ATA_HOST_SIMPLEX; + } ata_std_ports(&probe_ent->port[0]); return probe_ent; diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index d279666dcb38..bd147207f25d 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -62,7 +62,9 @@ #include "libata.h" static unsigned int ata_dev_init_params(struct ata_port *ap, - struct ata_device *dev); + struct ata_device *dev, + u16 heads, + u16 sectors); static void ata_set_mode(struct ata_port *ap); static unsigned int ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); @@ -276,7 +278,7 @@ static void ata_unpack_xfermask(unsigned int xfer_mask, } static const struct ata_xfer_ent { - unsigned int shift, bits; + int shift, bits; u8 base; } ata_xfer_tbl[] = { { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 }, @@ -987,9 +989,7 @@ ata_exec_internal(struct ata_port *ap, struct ata_device *dev, qc->private_data = &wait; qc->complete_fn = ata_qc_complete_internal; - qc->err_mask = ata_qc_issue(qc); - if (qc->err_mask) - ata_qc_complete(qc); + ata_qc_issue(qc); spin_unlock_irqrestore(&ap->host_set->lock, flags); @@ -1081,9 +1081,8 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) * * Read ID data from the specified device. ATA_CMD_ID_ATA is * performed on ATA devices and ATA_CMD_ID_ATAPI on ATAPI - * devices. This function also takes care of EDD signature - * misreporting (to be removed once EDD support is gone) and - * issues ATA_CMD_INIT_DEV_PARAMS for pre-ATA4 drives. + * devices. This function also issues ATA_CMD_INIT_DEV_PARAMS + * for pre-ATA4 drives. * * LOCKING: * Kernel thread context (may sleep) @@ -1095,7 +1094,6 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, unsigned int *p_class, int post_reset, u16 **p_id) { unsigned int class = *p_class; - unsigned int using_edd; struct ata_taskfile tf; unsigned int err_mask = 0; u16 *id; @@ -1104,12 +1102,6 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno); - if (ap->ops->probe_reset || - ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET)) - using_edd = 0; - else - using_edd = 1; - ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ id = kmalloc(sizeof(id[0]) * ATA_ID_WORDS, GFP_KERNEL); @@ -1139,39 +1131,16 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, err_mask = ata_exec_internal(ap, dev, &tf, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); - if (err_mask) { rc = -EIO; reason = "I/O error"; - - if (err_mask & ~AC_ERR_DEV) - goto err_out; - - /* - * arg! EDD works for all test cases, but seems to return - * the ATA signature for some ATAPI devices. Until the - * reason for this is found and fixed, we fix up the mess - * here. If IDENTIFY DEVICE returns command aborted - * (as ATAPI devices do), then we issue an - * IDENTIFY PACKET DEVICE. - * - * ATA software reset (SRST, the default) does not appear - * to have this problem. - */ - if ((using_edd) && (class == ATA_DEV_ATA)) { - u8 err = tf.feature; - if (err & ATA_ABORTED) { - class = ATA_DEV_ATAPI; - goto retry; - } - } goto err_out; } swap_buf_le16(id, ATA_ID_WORDS); /* sanity check */ - if ((class == ATA_DEV_ATA) != ata_id_is_ata(id)) { + if ((class == ATA_DEV_ATA) != (ata_id_is_ata(id) | ata_id_is_cfa(id))) { rc = -EINVAL; reason = "device reports illegal type"; goto err_out; @@ -1187,7 +1156,7 @@ static int ata_dev_read_id(struct ata_port *ap, struct ata_device *dev, * Some drives were very specific about that exact sequence. */ if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { - err_mask = ata_dev_init_params(ap, dev); + err_mask = ata_dev_init_params(ap, dev, id[3], id[6]); if (err_mask) { rc = -EIO; reason = "INIT_DEV_PARAMS failed"; @@ -1440,7 +1409,11 @@ static int ata_bus_probe(struct ata_port *ap) if (!found) goto err_out_disable; - ata_set_mode(ap); + if (ap->ops->set_mode) + ap->ops->set_mode(ap); + else + ata_set_mode(ap); + if (ap->flags & ATA_FLAG_PORT_DISABLED) goto err_out_disable; @@ -1845,7 +1818,7 @@ static void ata_host_set_dma(struct ata_port *ap) */ static void ata_set_mode(struct ata_port *ap) { - int i, rc; + int i, rc, used_dma = 0; /* step 1: calculate xfer_mask */ for (i = 0; i < ATA_MAX_DEVICES; i++) { @@ -1863,6 +1836,9 @@ static void ata_set_mode(struct ata_port *ap) dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask); dev->pio_mode = ata_xfer_mask2mode(pio_mask); dev->dma_mode = ata_xfer_mask2mode(dma_mask); + + if (dev->dma_mode) + used_dma = 1; } /* step 2: always set host PIO timings */ @@ -1884,6 +1860,17 @@ static void ata_set_mode(struct ata_port *ap) goto err_out; } + /* + * Record simplex status. If we selected DMA then the other + * host channels are not permitted to do so. + */ + + if (used_dma && (ap->host_set->flags & ATA_HOST_SIMPLEX)) + ap->host_set->simplex_claimed = 1; + + /* + * Chip specific finalisation + */ if (ap->ops->post_set_mode) ap->ops->post_set_mode(ap); @@ -2005,45 +1992,6 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask) ap->ops->dev_select(ap, 0); } -/** - * ata_bus_edd - Issue EXECUTE DEVICE DIAGNOSTIC command. - * @ap: Port to reset and probe - * - * Use the EXECUTE DEVICE DIAGNOSTIC command to reset and - * probe the bus. Not often used these days. - * - * LOCKING: - * PCI/etc. bus probe sem. - * Obtains host_set lock. - * - */ - -static unsigned int ata_bus_edd(struct ata_port *ap) -{ - struct ata_taskfile tf; - unsigned long flags; - - /* set up execute-device-diag (bus reset) taskfile */ - /* also, take interrupts to a known state (disabled) */ - DPRINTK("execute-device-diag\n"); - ata_tf_init(ap, &tf, 0); - tf.ctl |= ATA_NIEN; - tf.command = ATA_CMD_EDD; - tf.protocol = ATA_PROT_NODATA; - - /* do bus reset */ - spin_lock_irqsave(&ap->host_set->lock, flags); - ata_tf_to_host(ap, &tf); - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - /* spec says at least 2ms. but who knows with those - * crazy ATAPI devices... - */ - msleep(150); - - return ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); -} - static unsigned int ata_bus_softreset(struct ata_port *ap, unsigned int devmask) { @@ -2078,13 +2026,12 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, */ msleep(150); - /* Before we perform post reset processing we want to see if - the bus shows 0xFF because the odd clown forgets the D7 pulldown - resistor */ - + * the bus shows 0xFF because the odd clown forgets the D7 + * pulldown resistor. + */ if (ata_check_status(ap) == 0xFF) - return 1; /* Positive is failure for some reason */ + return AC_ERR_OTHER; ata_bus_post_reset(ap, devmask); @@ -2116,7 +2063,7 @@ void ata_bus_reset(struct ata_port *ap) struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; u8 err; - unsigned int dev0, dev1 = 0, rc = 0, devmask = 0; + unsigned int dev0, dev1 = 0, devmask = 0; DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no); @@ -2139,18 +2086,8 @@ void ata_bus_reset(struct ata_port *ap) /* issue bus reset */ if (ap->flags & ATA_FLAG_SRST) - rc = ata_bus_softreset(ap, devmask); - else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) { - /* set up device control */ - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); - rc = ata_bus_edd(ap); - } - - if (rc) - goto err_out; + if (ata_bus_softreset(ap, devmask)) + goto err_out; /* * determine by signature whether we have ATA or ATAPI devices @@ -2223,9 +2160,9 @@ static int sata_phy_resume(struct ata_port *ap) * so makes reset sequence different from the original * ->phy_reset implementation and Jeff nervous. :-P */ -extern void ata_std_probeinit(struct ata_port *ap) +void ata_std_probeinit(struct ata_port *ap) { - if (ap->flags & ATA_FLAG_SATA && ap->ops->scr_read) { + if ((ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read) { sata_phy_resume(ap); if (sata_dev_present(ap)) ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); @@ -2714,18 +2651,23 @@ static int ata_dma_blacklisted(const struct ata_device *dev) * known limits including host controller limits, device * blacklist, etc... * + * FIXME: The current implementation limits all transfer modes to + * the fastest of the lowested device on the port. This is not + * required on most controllers. + * * LOCKING: * None. */ static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) { + struct ata_host_set *hs = ap->host_set; unsigned long xfer_mask; int i; xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, ap->udma_mask); - /* use port-wide xfermask for now */ + /* FIXME: Use port-wide xfermask for now */ for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *d = &ap->device[i]; if (!ata_dev_present(d)) @@ -2735,12 +2677,23 @@ static void ata_dev_xfermask(struct ata_port *ap, struct ata_device *dev) xfer_mask &= ata_id_xfermask(d->id); if (ata_dma_blacklisted(d)) xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); + /* Apply cable rule here. Don't apply it early because when + we handle hot plug the cable type can itself change */ + if (ap->cbl == ATA_CBL_PATA40) + xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA); } if (ata_dma_blacklisted(dev)) printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, " "disabling DMA\n", ap->id, dev->devno); + if (hs->flags & ATA_HOST_SIMPLEX) { + if (hs->simplex_claimed) + xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); + } + if (ap->ops->mode_filter) + xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask); + ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask, &dev->udma_mask); } @@ -2795,16 +2748,16 @@ static unsigned int ata_dev_set_xfermode(struct ata_port *ap, */ static unsigned int ata_dev_init_params(struct ata_port *ap, - struct ata_device *dev) + struct ata_device *dev, + u16 heads, + u16 sectors) { struct ata_taskfile tf; unsigned int err_mask; - u16 sectors = dev->id[6]; - u16 heads = dev->id[3]; /* Number of sectors per track 1-255. Number of heads 1-16 */ if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) - return 0; + return AC_ERR_INVALID; /* set up init dev params taskfile */ DPRINTK("init dev params \n"); @@ -4042,15 +3995,14 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc) * * LOCKING: * spin_lock_irqsave(host_set lock) - * - * RETURNS: - * Zero on success, AC_ERR_* mask on failure */ - -unsigned int ata_qc_issue(struct ata_queued_cmd *qc) +void ata_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + qc->ap->active_tag = qc->tag; + qc->flags |= ATA_QCFLAG_ACTIVE; + if (ata_should_dma_map(qc)) { if (qc->flags & ATA_QCFLAG_SG) { if (ata_sg_setup(qc)) @@ -4065,17 +4017,18 @@ unsigned int ata_qc_issue(struct ata_queued_cmd *qc) ap->ops->qc_prep(qc); - qc->ap->active_tag = qc->tag; - qc->flags |= ATA_QCFLAG_ACTIVE; - - return ap->ops->qc_issue(qc); + qc->err_mask |= ap->ops->qc_issue(qc); + if (unlikely(qc->err_mask)) + goto err; + return; sg_err: qc->flags &= ~ATA_QCFLAG_DMAMAP; - return AC_ERR_SYSTEM; + qc->err_mask |= AC_ERR_SYSTEM; +err: + ata_qc_complete(qc); } - /** * ata_qc_issue_prot - issue taskfile to device in proto-dependent manner * @qc: command to issue to device @@ -4536,6 +4489,14 @@ static struct ata_port * ata_host_add(const struct ata_probe_ent *ent, int rc; DPRINTK("ENTER\n"); + + if (!ent->port_ops->probe_reset && + !(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) { + printk(KERN_ERR "ata%u: no reset mechanism available\n", + port_no); + return NULL; + } + host = scsi_host_alloc(ent->sht, sizeof(struct ata_port)); if (!host) return NULL; @@ -4596,6 +4557,7 @@ int ata_device_add(const struct ata_probe_ent *ent) host_set->mmio_base = ent->mmio_base; host_set->private_data = ent->private_data; host_set->ops = ent->port_ops; + host_set->flags = ent->host_set_flags; /* register each port bound to this device */ for (i = 0; i < ent->n_ports; i++) { @@ -4976,7 +4938,6 @@ EXPORT_SYMBOL_GPL(ata_busy_sleep); EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); -EXPORT_SYMBOL_GPL(ata_scsi_error); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_release); EXPORT_SYMBOL_GPL(ata_host_intr); diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 628191bfd990..a0289ec3e283 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -53,6 +53,7 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd); static struct ata_device * ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); +static void ata_scsi_error(struct Scsi_Host *host); enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd); #define RW_RECOVERY_MPAGE 0x1 @@ -99,6 +100,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { * It just needs the eh_timed_out hook. */ struct scsi_transport_template ata_scsi_transport_template = { + .eh_strategy_handler = ata_scsi_error, .eh_timed_out = ata_scsi_timed_out, }; @@ -772,12 +774,9 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) * * LOCKING: * Inherited from SCSI layer (none, can sleep) - * - * RETURNS: - * Zero. */ -int ata_scsi_error(struct Scsi_Host *host) +static void ata_scsi_error(struct Scsi_Host *host) { struct ata_port *ap; unsigned long flags; @@ -805,7 +804,6 @@ int ata_scsi_error(struct Scsi_Host *host) spin_unlock_irqrestore(&ap->host_set->lock, flags); DPRINTK("EXIT\n"); - return 0; } static void ata_eh_scsidone(struct scsi_cmnd *scmd) @@ -1431,9 +1429,7 @@ static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev, goto early_finish; /* select device, send command to hardware */ - qc->err_mask = ata_qc_issue(qc); - if (qc->err_mask) - ata_qc_complete(qc); + ata_qc_issue(qc); VPRINTK("EXIT\n"); return; @@ -2199,9 +2195,7 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) qc->complete_fn = atapi_sense_complete; - qc->err_mask = ata_qc_issue(qc); - if (qc->err_mask) - ata_qc_complete(qc); + ata_qc_issue(qc); DPRINTK("EXIT\n"); } diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 65f52beea884..bac8cbae06fe 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -47,7 +47,7 @@ extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, extern int ata_rwcmd_protocol(struct ata_queued_cmd *qc); extern void ata_port_flush_task(struct ata_port *ap); extern void ata_qc_free(struct ata_queued_cmd *qc); -extern unsigned int ata_qc_issue(struct ata_queued_cmd *qc); +extern void ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); @@ -60,7 +60,6 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); extern struct scsi_transport_template ata_scsi_transport_template; extern void ata_scsi_scan_host(struct ata_port *ap); -extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index d6d2125f9044..f852421002ef 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1748,7 +1748,7 @@ static int mesh_host_reset(struct scsi_cmnd *cmd) static void set_mesh_power(struct mesh_state *ms, int state) { - if (_machine != _MACH_Pmac) + if (!machine_is(powermac)) return; if (state) { pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1); diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 5609847e254a..ee449b29fc82 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -89,29 +89,29 @@ MODULE_LICENSE("Dual MPL/GPL"); /*====================================================================*/ typedef struct scsi_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct Scsi_Host *host; } scsi_info_t; -static void aha152x_release_cs(dev_link_t *link); +static void aha152x_release_cs(struct pcmcia_device *link); static void aha152x_detach(struct pcmcia_device *p_dev); -static void aha152x_config_cs(dev_link_t *link); +static int aha152x_config_cs(struct pcmcia_device *link); -static dev_link_t *dev_list; +static struct pcmcia_device *dev_list; -static int aha152x_attach(struct pcmcia_device *p_dev) +static int aha152x_probe(struct pcmcia_device *link) { scsi_info_t *info; - dev_link_t *link; - + DEBUG(0, "aha152x_attach()\n"); /* Create new SCSI device */ info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; memset(info, 0, sizeof(*info)); - link = &info->link; link->priv = info; + info->p_dev = link; + link->priv = info; link->io.NumPorts1 = 0x20; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; @@ -119,41 +119,22 @@ static int aha152x_attach(struct pcmcia_device *p_dev) link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - aha152x_config_cs(link); - - return 0; + return aha152x_config_cs(link); } /* aha152x_attach */ /*====================================================================*/ -static void aha152x_detach(struct pcmcia_device *p_dev) +static void aha152x_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - dev_link_t **linkp; - DEBUG(0, "aha152x_detach(0x%p)\n", link); - - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) break; - if (*linkp == NULL) - return; - if (link->state & DEV_CONFIG) - aha152x_release_cs(link); + aha152x_release_cs(link); /* Unlink device structure, free bits */ - *linkp = link->next; kfree(link->priv); - } /* aha152x_detach */ /*====================================================================*/ @@ -161,9 +142,8 @@ static void aha152x_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void aha152x_config_cs(dev_link_t *link) +static int aha152x_config_cs(struct pcmcia_device *link) { - client_handle_t handle = link->handle; scsi_info_t *info = link->priv; struct aha152x_setup s; tuple_t tuple; @@ -178,19 +158,16 @@ static void aha152x_config_cs(dev_link_t *link) tuple.TupleData = tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; - /* Configure card */ - link->state |= DEV_CONFIG; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; /* For New Media T&J, look for a SCSI window */ if (parse.cftable_entry.io.win[0].len >= 0x20) @@ -201,15 +178,15 @@ static void aha152x_config_cs(dev_link_t *link) if ((parse.cftable_entry.io.nwin > 0) && (link->io.BasePort1 < 0xffff)) { link->conf.ConfigIndex = parse.cftable_entry.index; - i = pcmcia_request_io(handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); /* Set configuration options for the aha152x driver */ memset(&s, 0, sizeof(s)); @@ -231,53 +208,30 @@ static void aha152x_config_cs(dev_link_t *link) } sprintf(info->node.dev_name, "scsi%d", host->host_no); - link->dev = &info->node; + link->dev_node = &info->node; info->host = host; - link->state &= ~DEV_CONFIG_PENDING; - return; - + return 0; + cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); aha152x_release_cs(link); - return; + return -ENODEV; } -static void aha152x_release_cs(dev_link_t *link) +static void aha152x_release_cs(struct pcmcia_device *link) { scsi_info_t *info = link->priv; aha152x_release(info->host); - link->dev = NULL; - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } -static int aha152x_suspend(struct pcmcia_device *dev) +static int aha152x_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int aha152x_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); scsi_info_t *info = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - aha152x_host_reset_host(info->host); - } + aha152x_host_reset_host(info->host); return 0; } @@ -297,10 +251,9 @@ static struct pcmcia_driver aha152x_cs_driver = { .drv = { .name = "aha152x_cs", }, - .probe = aha152x_attach, + .probe = aha152x_probe, .remove = aha152x_detach, .id_table = aha152x_ids, - .suspend = aha152x_suspend, .resume = aha152x_resume, }; @@ -317,4 +270,3 @@ static void __exit exit_aha152x_cs(void) module_init(init_aha152x_cs); module_exit(exit_aha152x_cs); - diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index 788c58d805f3..85f7ffac19a0 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c @@ -73,57 +73,48 @@ static char *version = /*====================================================================*/ typedef struct scsi_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct Scsi_Host *host; } scsi_info_t; -static void fdomain_release(dev_link_t *link); +static void fdomain_release(struct pcmcia_device *link); static void fdomain_detach(struct pcmcia_device *p_dev); -static void fdomain_config(dev_link_t *link); +static int fdomain_config(struct pcmcia_device *link); -static int fdomain_attach(struct pcmcia_device *p_dev) +static int fdomain_probe(struct pcmcia_device *link) { - scsi_info_t *info; - dev_link_t *link; + scsi_info_t *info; - DEBUG(0, "fdomain_attach()\n"); + DEBUG(0, "fdomain_attach()\n"); - /* Create new SCSI device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return -ENOMEM; - memset(info, 0, sizeof(*info)); - link = &info->link; link->priv = info; - link->io.NumPorts1 = 0x10; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - link->io.IOAddrLines = 10; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.Present = PRESENT_OPTION; + /* Create new SCSI device */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; - link->handle = p_dev; - p_dev->instance = link; + info->p_dev = link; + link->priv = info; + link->io.NumPorts1 = 0x10; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_LEVEL_ID; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - fdomain_config(link); - - return 0; + return fdomain_config(link); } /* fdomain_attach */ /*====================================================================*/ -static void fdomain_detach(struct pcmcia_device *p_dev) +static void fdomain_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - DEBUG(0, "fdomain_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) - fdomain_release(link); + fdomain_release(link); kfree(link->priv); } /* fdomain_detach */ @@ -133,9 +124,8 @@ static void fdomain_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void fdomain_config(dev_link_t *link) +static int fdomain_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; scsi_info_t *info = link->priv; tuple_t tuple; cisparse_t parse; @@ -150,103 +140,75 @@ static void fdomain_config(dev_link_t *link) tuple.TupleData = tuple_data; tuple.TupleDataMax = 64; tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; - /* Configure card */ - link->state |= DEV_CONFIG; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; link->conf.ConfigIndex = parse.cftable_entry.index; link->io.BasePort1 = parse.cftable_entry.io.win[0].base; - i = pcmcia_request_io(handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); - + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + /* A bad hack... */ release_region(link->io.BasePort1, link->io.NumPorts1); /* Set configuration options for the fdomain driver */ sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ); fdomain_setup(str); - + host = __fdomain_16x0_detect(&fdomain_driver_template); if (!host) { printk(KERN_INFO "fdomain_cs: no SCSI devices found\n"); goto cs_failed; } - - scsi_add_host(host, NULL); /* XXX handle failure */ + + if (scsi_add_host(host, NULL)) + goto cs_failed; scsi_scan_host(host); sprintf(info->node.dev_name, "scsi%d", host->host_no); - link->dev = &info->node; + link->dev_node = &info->node; info->host = host; - - link->state &= ~DEV_CONFIG_PENDING; - return; - + + return 0; + cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); fdomain_release(link); - return; - + return -ENODEV; } /* fdomain_config */ /*====================================================================*/ -static void fdomain_release(dev_link_t *link) +static void fdomain_release(struct pcmcia_device *link) { - scsi_info_t *info = link->priv; + scsi_info_t *info = link->priv; - DEBUG(0, "fdomain_release(0x%p)\n", link); + DEBUG(0, "fdomain_release(0x%p)\n", link); - scsi_remove_host(info->host); - link->dev = NULL; - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - scsi_unregister(info->host); - - link->state &= ~DEV_CONFIG; + scsi_remove_host(info->host); + pcmcia_disable_device(link); + scsi_unregister(info->host); } /*====================================================================*/ -static int fdomain_suspend(struct pcmcia_device *dev) +static int fdomain_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int fdomain_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - fdomain_16x0_bus_reset(NULL); - } + fdomain_16x0_bus_reset(NULL); return 0; } @@ -264,10 +226,9 @@ static struct pcmcia_driver fdomain_cs_driver = { .drv = { .name = "fdomain_cs", }, - .probe = fdomain_attach, + .probe = fdomain_probe, .remove = fdomain_detach, .id_table = fdomain_ids, - .suspend = fdomain_suspend, .resume = fdomain_resume, }; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 9e3ab3fd5355..231f9c311c69 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1593,11 +1593,11 @@ static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt) configure the card at this point -- we wait until we receive a card insertion event. ======================================================================*/ -static int nsp_cs_attach(struct pcmcia_device *p_dev) +static int nsp_cs_probe(struct pcmcia_device *link) { scsi_info_t *info; - dev_link_t *link; nsp_hw_data *data = &nsp_data_base; + int ret; nsp_dbg(NSP_DEBUG_INIT, "in"); @@ -1605,7 +1605,7 @@ static int nsp_cs_attach(struct pcmcia_device *p_dev) info = kmalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { return -ENOMEM; } memset(info, 0, sizeof(*info)); - link = &info->link; + info->p_dev = link; link->priv = info; data->ScsiInfo = info; @@ -1627,18 +1627,13 @@ static int nsp_cs_attach(struct pcmcia_device *p_dev) /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - nsp_cs_config(link); + ret = nsp_cs_config(link); nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); - return 0; + return ret; } /* nsp_cs_attach */ @@ -1648,16 +1643,12 @@ static int nsp_cs_attach(struct pcmcia_device *p_dev) structures are freed. Otherwise, the structures will be freed when the device is released. ======================================================================*/ -static void nsp_cs_detach(struct pcmcia_device *p_dev) +static void nsp_cs_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link); - if (link->state & DEV_CONFIG) { - ((scsi_info_t *)link->priv)->stop = 1; - nsp_cs_release(link); - } + ((scsi_info_t *)link->priv)->stop = 1; + nsp_cs_release(link); kfree(link->priv); link->priv = NULL; @@ -1672,9 +1663,9 @@ static void nsp_cs_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) /*====================================================================*/ -static void nsp_cs_config(dev_link_t *link) +static int nsp_cs_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; + int ret; scsi_info_t *info = link->priv; tuple_t tuple; cisparse_t parse; @@ -1698,26 +1689,22 @@ static void nsp_cs_config(dev_link_t *link) tuple.TupleData = tuple_data; tuple.TupleDataMax = sizeof(tuple_data); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; } @@ -1743,10 +1730,10 @@ static void nsp_cs_config(dev_link_t *link) } if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) { - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000; } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) { - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000; } @@ -1773,7 +1760,7 @@ static void nsp_cs_config(dev_link_t *link) link->io.NumPorts2 = io->win[1].len; } /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; } @@ -1788,7 +1775,7 @@ static void nsp_cs_config(dev_link_t *link) req.Size = 0x1000; } req.AccessSpeed = 0; - if (pcmcia_request_window(&link->handle, &req, &link->win) != 0) + if (pcmcia_request_window(&link, &req, &link->win) != 0) goto next_entry; map.Page = 0; map.CardOffset = mem->win[0].card_addr; if (pcmcia_map_mem_page(link->win, &map) != 0) @@ -1802,17 +1789,14 @@ static void nsp_cs_config(dev_link_t *link) next_entry: nsp_dbg(NSP_DEBUG_INIT, "next"); - - if (link->io.NumPorts1) { - pcmcia_release_io(link->handle, &link->io); - } - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + pcmcia_disable_device(link); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } if (link->conf.Attributes & CONF_ENABLE_IRQ) { - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); } - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); if (free_ports) { if (link->io.BasePort1) { @@ -1854,16 +1838,19 @@ static void nsp_cs_config(dev_link_t *link) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) - scsi_add_host (host, NULL); + ret = scsi_add_host (host, NULL); + if (ret) + goto cs_failed; + scsi_scan_host(host); snprintf(info->node.dev_name, sizeof(info->node.dev_name), "scsi%d", host->host_no); - link->dev = &info->node; + link->dev_node = &info->node; info->host = host; #else nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO"); - tail = &link->dev; + tail = &link->dev_node; info->ndev = 0; nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host); @@ -1908,11 +1895,10 @@ static void nsp_cs_config(dev_link_t *link) #endif /* Finally, report what we've done */ - printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d", - link->conf.ConfigIndex, - link->conf.Vcc/10, link->conf.Vcc%10); - if (link->conf.Vpp1) { - printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + printk(KERN_INFO "nsp_cs: index 0x%02x: ", + link->conf.ConfigIndex); + if (link->conf.Vpp) { + printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); } if (link->conf.Attributes & CONF_ENABLE_IRQ) { printk(", irq %d", link->irq.AssignedIRQ); @@ -1929,15 +1915,14 @@ static void nsp_cs_config(dev_link_t *link) req.Base+req.Size-1); printk("\n"); - link->state &= ~DEV_CONFIG_PENDING; - return; + return 0; cs_failed: nsp_dbg(NSP_DEBUG_INIT, "config fail"); - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); nsp_cs_release(link); - return; + return -ENODEV; } /* nsp_cs_config */ #undef CS_CHECK @@ -1947,7 +1932,7 @@ static void nsp_cs_config(dev_link_t *link) device, and release the PCMCIA configuration. If the device is still open, this will be postponed until it is closed. ======================================================================*/ -static void nsp_cs_release(dev_link_t *link) +static void nsp_cs_release(struct pcmcia_device *link) { scsi_info_t *info = link->priv; nsp_hw_data *data = NULL; @@ -1968,22 +1953,15 @@ static void nsp_cs_release(dev_link_t *link) #else scsi_unregister_host(&nsp_driver_template); #endif - link->dev = NULL; + link->dev_node = NULL; if (link->win) { if (data != NULL) { iounmap((void *)(data->MmioAddress)); } - pcmcia_release_window(link->win); } - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) { - pcmcia_release_io(link->handle, &link->io); - } - if (link->irq.AssignedIRQ) { - pcmcia_release_irq(link->handle, &link->irq); - } - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)) if (info->host != NULL) { scsi_host_put(info->host); @@ -1991,14 +1969,11 @@ static void nsp_cs_release(dev_link_t *link) #endif } /* nsp_cs_release */ -static int nsp_cs_suspend(struct pcmcia_device *dev) +static int nsp_cs_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); scsi_info_t *info = link->priv; nsp_hw_data *data; - link->state |= DEV_SUSPEND; - nsp_dbg(NSP_DEBUG_INIT, "event: suspend"); if (info->host != NULL) { @@ -2011,25 +1986,16 @@ static int nsp_cs_suspend(struct pcmcia_device *dev) info->stop = 1; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - return 0; } -static int nsp_cs_resume(struct pcmcia_device *dev) +static int nsp_cs_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); scsi_info_t *info = link->priv; nsp_hw_data *data; nsp_dbg(NSP_DEBUG_INIT, "event: resume"); - link->state &= ~DEV_SUSPEND; - - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); - info->stop = 0; if (info->host != NULL) { @@ -2065,7 +2031,7 @@ static struct pcmcia_driver nsp_driver = { .drv = { .name = "nsp_cs", }, - .probe = nsp_cs_attach, + .probe = nsp_cs_probe, .remove = nsp_cs_detach, .id_table = nsp_cs_ids, .suspend = nsp_cs_suspend, @@ -2098,19 +2064,7 @@ static int __init nsp_cs_init(void) static void __exit nsp_cs_exit(void) { nsp_msg(KERN_INFO, "unloading..."); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) pcmcia_unregister_driver(&nsp_driver); -#else - unregister_pcmcia_driver(&dev_info); - /* XXX: this really needs to move into generic code.. */ - while (dev_list != NULL) { - if (dev_list->state & DEV_CONFIG) { - nsp_cs_release(dev_list); - } - nsp_cs_detach(dev_list); - } -#endif } diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index b66b140a745e..8908b8e5b78a 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -225,7 +225,7 @@ /*====================================================================*/ typedef struct scsi_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; struct Scsi_Host *host; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74)) dev_node_t node; @@ -297,8 +297,8 @@ typedef struct _nsp_hw_data { /* Card service functions */ static void nsp_cs_detach (struct pcmcia_device *p_dev); -static void nsp_cs_release(dev_link_t *link); -static void nsp_cs_config (dev_link_t *link); +static void nsp_cs_release(struct pcmcia_device *link); +static int nsp_cs_config (struct pcmcia_device *link); /* Linux SCSI subsystem specific functions */ static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht); @@ -450,7 +450,7 @@ static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno) return host; } -static void cs_error(client_handle_t handle, int func, int ret) +static void cs_error(struct pcmcia_device *handle, int func, int ret) { error_info_t err = { func, ret }; pcmcia_report_error(handle, &err); diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index dce7e687fd4a..86c2ac6ae623 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c @@ -91,18 +91,18 @@ static struct scsi_host_template qlogicfas_driver_template = { /*====================================================================*/ typedef struct scsi_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct Scsi_Host *host; unsigned short manf_id; } scsi_info_t; -static void qlogic_release(dev_link_t *link); +static void qlogic_release(struct pcmcia_device *link); static void qlogic_detach(struct pcmcia_device *p_dev); -static void qlogic_config(dev_link_t * link); +static int qlogic_config(struct pcmcia_device * link); static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host, - dev_link_t *link, int qbase, int qlirq) + struct pcmcia_device *link, int qbase, int qlirq) { int qltyp; /* type of chip */ int qinitid; @@ -156,10 +156,9 @@ free_scsi_host: err: return NULL; } -static int qlogic_attach(struct pcmcia_device *p_dev) +static int qlogic_probe(struct pcmcia_device *link) { scsi_info_t *info; - dev_link_t *link; DEBUG(0, "qlogic_attach()\n"); @@ -168,7 +167,7 @@ static int qlogic_attach(struct pcmcia_device *p_dev) if (!info) return -ENOMEM; memset(info, 0, sizeof(*info)); - link = &info->link; + info->p_dev = link; link->priv = info; link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; @@ -176,30 +175,19 @@ static int qlogic_attach(struct pcmcia_device *p_dev) link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - qlogic_config(link); - - return 0; + return qlogic_config(link); } /* qlogic_attach */ /*====================================================================*/ -static void qlogic_detach(struct pcmcia_device *p_dev) +static void qlogic_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - DEBUG(0, "qlogic_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) - qlogic_release(link); - + qlogic_release(link); kfree(link->priv); } /* qlogic_detach */ @@ -209,9 +197,8 @@ static void qlogic_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void qlogic_config(dev_link_t * link) +static int qlogic_config(struct pcmcia_device * link) { - client_handle_t handle = link->handle; scsi_info_t *info = link->priv; tuple_t tuple; cisparse_t parse; @@ -225,38 +212,35 @@ static void qlogic_config(dev_link_t * link) tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; tuple.DesiredTuple = CISTPL_MANFID; - if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) + if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) info->manf_id = le16_to_cpu(tuple.TupleData[0]); - /* Configure card */ - link->state |= DEV_CONFIG; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; link->conf.ConfigIndex = parse.cftable_entry.index; link->io.BasePort1 = parse.cftable_entry.io.win[0].base; link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; if (link->io.BasePort1 != 0) { - i = pcmcia_request_io(handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { /* set ATAcmd */ @@ -275,82 +259,54 @@ static void qlogic_config(dev_link_t * link) if (!host) { printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name); - goto out; + goto cs_failed; } sprintf(info->node.dev_name, "scsi%d", host->host_no); - link->dev = &info->node; + link->dev_node = &info->node; info->host = host; -out: - link->state &= ~DEV_CONFIG_PENDING; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); - link->dev = NULL; - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; - return; + cs_error(link, last_fn, last_ret); + pcmcia_disable_device(link); + return -ENODEV; } /* qlogic_config */ /*====================================================================*/ -static void qlogic_release(dev_link_t *link) +static void qlogic_release(struct pcmcia_device *link) { scsi_info_t *info = link->priv; DEBUG(0, "qlogic_release(0x%p)\n", link); scsi_remove_host(info->host); - link->dev = NULL; free_irq(link->irq.AssignedIRQ, info->host); - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); + pcmcia_disable_device(link); scsi_host_put(info->host); - - link->state &= ~DEV_CONFIG; } /*====================================================================*/ -static int qlogic_suspend(struct pcmcia_device *dev) +static int qlogic_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); + scsi_info_t *info = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int qlogic_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - scsi_info_t *info = link->priv; - - pcmcia_request_configuration(link->handle, &link->conf); - if ((info->manf_id == MANFID_MACNICA) || - (info->manf_id == MANFID_PIONEER) || - (info->manf_id == 0x0098)) { - outb(0x80, link->io.BasePort1 + 0xd); - outb(0x24, link->io.BasePort1 + 0x9); - outb(0x04, link->io.BasePort1 + 0xd); - } - /* Ugggglllyyyy!!! */ - qlogicfas408_bus_reset(NULL); + pcmcia_request_configuration(link, &link->conf); + if ((info->manf_id == MANFID_MACNICA) || + (info->manf_id == MANFID_PIONEER) || + (info->manf_id == 0x0098)) { + outb(0x80, link->io.BasePort1 + 0xd); + outb(0x24, link->io.BasePort1 + 0x9); + outb(0x04, link->io.BasePort1 + 0xd); } + /* Ugggglllyyyy!!! */ + qlogicfas408_bus_reset(NULL); return 0; } @@ -382,10 +338,9 @@ static struct pcmcia_driver qlogic_cs_driver = { .drv = { .name = "qlogic_cs", }, - .probe = qlogic_attach, + .probe = qlogic_probe, .remove = qlogic_detach, .id_table = qlogic_ids, - .suspend = qlogic_suspend, .resume = qlogic_resume, }; diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 3a4dd6f5b81f..9f59827707f0 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -202,7 +202,7 @@ static char *version = /* ================================================================== */ struct scsi_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; struct Scsi_Host *host; unsigned short manf_id; @@ -527,7 +527,7 @@ idle_out: } static void -SYM53C500_release(dev_link_t *link) +SYM53C500_release(struct pcmcia_device *link) { struct scsi_info_t *info = link->priv; struct Scsi_Host *shost = info->host; @@ -550,13 +550,7 @@ SYM53C500_release(dev_link_t *link) if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); - link->dev = NULL; - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); scsi_host_put(shost); } /* SYM53C500_release */ @@ -713,10 +707,9 @@ static struct scsi_host_template sym53c500_driver_template = { #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void -SYM53C500_config(dev_link_t *link) +static int +SYM53C500_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct scsi_info_t *info = link->priv; tuple_t tuple; cisparse_t parse; @@ -733,40 +726,37 @@ SYM53C500_config(dev_link_t *link) tuple.TupleDataMax = 64; tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; tuple.DesiredTuple = CISTPL_MANFID; - if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && - (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS)) + if ((pcmcia_get_first_tuple(link, &tuple) == CS_SUCCESS) && + (pcmcia_get_tuple_data(link, &tuple) == CS_SUCCESS)) info->manf_id = le16_to_cpu(tuple.TupleData[0]); - /* Configure card */ - link->state |= DEV_CONFIG; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; link->conf.ConfigIndex = parse.cftable_entry.index; link->io.BasePort1 = parse.cftable_entry.io.win[0].base; link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; if (link->io.BasePort1 != 0) { - i = pcmcia_request_io(handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) break; } next_entry: - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); /* * That's the trouble with copying liberally from another driver. @@ -835,7 +825,7 @@ next_entry: data->fast_pio = USE_FAST_PIO; sprintf(info->node.dev_name, "scsi%d", host->host_no); - link->dev = &info->node; + link->dev_node = &info->node; info->host = host; if (scsi_add_host(host, NULL)) @@ -843,7 +833,7 @@ next_entry: scsi_scan_host(host); - goto out; /* SUCCESS */ + return 0; err_free_irq: free_irq(irq_level, host); @@ -852,74 +842,50 @@ err_free_scsi: err_release: release_region(port_base, 0x10); printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n"); - -out: - link->state &= ~DEV_CONFIG_PENDING; - return; + return -ENODEV; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); SYM53C500_release(link); - return; + return -ENODEV; } /* SYM53C500_config */ -static int sym53c500_suspend(struct pcmcia_device *dev) +static int sym53c500_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int sym53c500_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); struct scsi_info_t *info = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - - /* See earlier comment about manufacturer IDs. */ - if ((info->manf_id == MANFID_MACNICA) || - (info->manf_id == MANFID_PIONEER) || - (info->manf_id == 0x0098)) { - outb(0x80, link->io.BasePort1 + 0xd); - outb(0x24, link->io.BasePort1 + 0x9); - outb(0x04, link->io.BasePort1 + 0xd); - } - /* - * If things don't work after a "resume", - * this is a good place to start looking. - */ - SYM53C500_int_host_reset(link->io.BasePort1); + /* See earlier comment about manufacturer IDs. */ + if ((info->manf_id == MANFID_MACNICA) || + (info->manf_id == MANFID_PIONEER) || + (info->manf_id == 0x0098)) { + outb(0x80, link->io.BasePort1 + 0xd); + outb(0x24, link->io.BasePort1 + 0x9); + outb(0x04, link->io.BasePort1 + 0xd); } + /* + * If things don't work after a "resume", + * this is a good place to start looking. + */ + SYM53C500_int_host_reset(link->io.BasePort1); return 0; } static void -SYM53C500_detach(struct pcmcia_device *p_dev) +SYM53C500_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - DEBUG(0, "SYM53C500_detach(0x%p)\n", link); - if (link->state & DEV_CONFIG) - SYM53C500_release(link); + SYM53C500_release(link); kfree(link->priv); link->priv = NULL; } /* SYM53C500_detach */ static int -SYM53C500_attach(struct pcmcia_device *p_dev) +SYM53C500_probe(struct pcmcia_device *link) { struct scsi_info_t *info; - dev_link_t *link; DEBUG(0, "SYM53C500_attach()\n"); @@ -928,7 +894,7 @@ SYM53C500_attach(struct pcmcia_device *p_dev) if (!info) return -ENOMEM; memset(info, 0, sizeof(*info)); - link = &info->link; + info->p_dev = link; link->priv = info; link->io.NumPorts1 = 16; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; @@ -936,17 +902,10 @@ SYM53C500_attach(struct pcmcia_device *p_dev) link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - SYM53C500_config(link); - - return 0; + return SYM53C500_config(link); } /* SYM53C500_attach */ MODULE_AUTHOR("Bob Tracy "); @@ -966,10 +925,9 @@ static struct pcmcia_driver sym53c500_cs_driver = { .drv = { .name = "sym53c500_cs", }, - .probe = SYM53C500_attach, + .probe = SYM53C500_probe, .remove = SYM53C500_detach, .id_table = sym53c500_ids, - .suspend = sym53c500_suspend, .resume = sym53c500_resume, }; diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index 3c85c4b66e19..5cda16cfacb0 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -143,7 +143,6 @@ static struct scsi_host_template adma_ata_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c deleted file mode 100644 index 52b224a5d6fd..000000000000 --- a/drivers/scsi/qlogicfc.c +++ /dev/null @@ -1,2228 +0,0 @@ -/* - * QLogic ISP2x00 SCSI-FCP - * Written by Erik H. Moe, ehm@cris.com - * Copyright 1995, Erik H. Moe - * - * 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. - */ - -/* Renamed and updated to 1.3.x by Michael Griffith */ - -/* This is a version of the isp1020 driver which was modified by - * Chris Loveland to support the isp2100 and isp2200 - * - * Big endian support and dynamic DMA mapping added - * by Jakub Jelinek . - * - * Conversion to final pci64 DMA interfaces - * by David S. Miller . - */ - -/* - * $Date: 1995/09/22 02:23:15 $ - * $Revision: 0.5 $ - * - * $Log: isp1020.c,v $ - * Revision 0.5 1995/09/22 02:23:15 root - * do auto request sense - * - * Revision 0.4 1995/08/07 04:44:33 root - * supply firmware with driver. - * numerous bug fixes/general cleanup of code. - * - * Revision 0.3 1995/07/16 16:15:39 root - * added reset/abort code. - * - * Revision 0.2 1995/06/29 03:14:19 root - * fixed biosparam. - * added queue protocol. - * - * Revision 0.1 1995/06/25 01:55:45 root - * Initial release. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "scsi.h" -#include - -#define pci64_dma_hi32(a) ((u32) (0xffffffff & (((u64)(a))>>32))) -#define pci64_dma_lo32(a) ((u32) (0xffffffff & (((u64)(a))))) -#define pci64_dma_build(hi,lo) \ - ((dma_addr_t)(((u64)(lo))|(((u64)(hi))<<32))) - -/* - * With the qlogic interface, every queue slot can hold a SCSI - * command with up to 2 scatter/gather entries. If we need more - * than 2 entries, continuation entries can be used that hold - * another 5 entries each. Unlike for other drivers, this means - * that the maximum number of scatter/gather entries we can - * support at any given time is a function of the number of queue - * slots available. That is, host->can_queue and host->sg_tablesize - * are dynamic and _not_ independent. This all works fine because - * requests are queued serially and the scatter/gather limit is - * determined for each queue request anew. - */ - -#define DATASEGS_PER_COMMAND 2 -#define DATASEGS_PER_CONT 5 - -#define QLOGICFC_REQ_QUEUE_LEN 255 /* must be power of two - 1 */ -#define QLOGICFC_MAX_SG(ql) (DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0)) -#define QLOGICFC_CMD_PER_LUN 8 - -/* Configuration section **************************************************** */ - -/* Set the following macro to 1 to reload the ISP2x00's firmware. This is - version 1.17.30 of the isp2100's firmware and version 2.00.40 of the - isp2200's firmware. -*/ - -#define USE_NVRAM_DEFAULTS 1 - -#define ISP2x00_PORTDB 1 - -/* Set the following to 1 to include fabric support, fabric support is - * currently not as well tested as the other aspects of the driver */ - -#define ISP2x00_FABRIC 1 - -/* Macros used for debugging */ -#define DEBUG_ISP2x00 0 -#define DEBUG_ISP2x00_INT 0 -#define DEBUG_ISP2x00_INTR 0 -#define DEBUG_ISP2x00_SETUP 0 -#define DEBUG_ISP2x00_FABRIC 0 -#define TRACE_ISP 0 - - -#define DEFAULT_LOOP_COUNT 1000000000 - -#define ISP_TIMEOUT (2*HZ) -/* End Configuration section ************************************************ */ - -#include - -#if TRACE_ISP - -#define TRACE_BUF_LEN (32*1024) - -struct { - u_long next; - struct { - u_long time; - u_int index; - u_int addr; - u_char *name; - } buf[TRACE_BUF_LEN]; -} trace; - -#define TRACE(w, i, a) \ -{ \ - unsigned long flags; \ - \ - save_flags(flags); \ - cli(); \ - trace.buf[trace.next].name = (w); \ - trace.buf[trace.next].time = jiffies; \ - trace.buf[trace.next].index = (i); \ - trace.buf[trace.next].addr = (long) (a); \ - trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1); \ - restore_flags(flags); \ -} - -#else -#define TRACE(w, i, a) -#endif - -#if DEBUG_ISP2x00_FABRIC -#define DEBUG_FABRIC(x) x -#else -#define DEBUG_FABRIC(x) -#endif /* DEBUG_ISP2x00_FABRIC */ - - -#if DEBUG_ISP2x00 -#define ENTER(x) printk("isp2x00 : entering %s()\n", x); -#define LEAVE(x) printk("isp2x00 : leaving %s()\n", x); -#define DEBUG(x) x -#else -#define ENTER(x) -#define LEAVE(x) -#define DEBUG(x) -#endif /* DEBUG_ISP2x00 */ - -#if DEBUG_ISP2x00_INTR -#define ENTER_INTR(x) printk("isp2x00 : entering %s()\n", x); -#define LEAVE_INTR(x) printk("isp2x00 : leaving %s()\n", x); -#define DEBUG_INTR(x) x -#else -#define ENTER_INTR(x) -#define LEAVE_INTR(x) -#define DEBUG_INTR(x) -#endif /* DEBUG ISP2x00_INTR */ - - -#define ISP2100_REV_ID1 1 -#define ISP2100_REV_ID3 3 -#define ISP2200_REV_ID5 5 - -/* host configuration and control registers */ -#define HOST_HCCR 0xc0 /* host command and control */ - -/* pci bus interface registers */ -#define FLASH_BIOS_ADDR 0x00 -#define FLASH_BIOS_DATA 0x02 -#define ISP_CTRL_STATUS 0x06 /* configuration register #1 */ -#define PCI_INTER_CTL 0x08 /* pci interrupt control */ -#define PCI_INTER_STS 0x0a /* pci interrupt status */ -#define PCI_SEMAPHORE 0x0c /* pci semaphore */ -#define PCI_NVRAM 0x0e /* pci nvram interface */ - -/* mailbox registers */ -#define MBOX0 0x10 /* mailbox 0 */ -#define MBOX1 0x12 /* mailbox 1 */ -#define MBOX2 0x14 /* mailbox 2 */ -#define MBOX3 0x16 /* mailbox 3 */ -#define MBOX4 0x18 /* mailbox 4 */ -#define MBOX5 0x1a /* mailbox 5 */ -#define MBOX6 0x1c /* mailbox 6 */ -#define MBOX7 0x1e /* mailbox 7 */ - -/* mailbox command complete status codes */ -#define MBOX_COMMAND_COMPLETE 0x4000 -#define INVALID_COMMAND 0x4001 -#define HOST_INTERFACE_ERROR 0x4002 -#define TEST_FAILED 0x4003 -#define COMMAND_ERROR 0x4005 -#define COMMAND_PARAM_ERROR 0x4006 -#define PORT_ID_USED 0x4007 -#define LOOP_ID_USED 0x4008 -#define ALL_IDS_USED 0x4009 - -/* async event status codes */ -#define RESET_DETECTED 0x8001 -#define SYSTEM_ERROR 0x8002 -#define REQUEST_TRANSFER_ERROR 0x8003 -#define RESPONSE_TRANSFER_ERROR 0x8004 -#define REQUEST_QUEUE_WAKEUP 0x8005 -#define LIP_OCCURRED 0x8010 -#define LOOP_UP 0x8011 -#define LOOP_DOWN 0x8012 -#define LIP_RECEIVED 0x8013 -#define PORT_DB_CHANGED 0x8014 -#define CHANGE_NOTIFICATION 0x8015 -#define SCSI_COMMAND_COMPLETE 0x8020 -#define POINT_TO_POINT_UP 0x8030 -#define CONNECTION_MODE 0x8036 - -struct Entry_header { - u_char entry_type; - u_char entry_cnt; - u_char sys_def_1; - u_char flags; -}; - -/* entry header type commands */ -#define ENTRY_COMMAND 0x19 -#define ENTRY_CONTINUATION 0x0a - -#define ENTRY_STATUS 0x03 -#define ENTRY_MARKER 0x04 - - -/* entry header flag definitions */ -#define EFLAG_BUSY 2 -#define EFLAG_BAD_HEADER 4 -#define EFLAG_BAD_PAYLOAD 8 - -struct dataseg { - u_int d_base; - u_int d_base_hi; - u_int d_count; -}; - -struct Command_Entry { - struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short expanded_lun; - u_short control_flags; - u_short rsvd2; - u_short time_out; - u_short segment_cnt; - u_char cdb[16]; - u_int total_byte_cnt; - struct dataseg dataseg[DATASEGS_PER_COMMAND]; -}; - -/* command entry control flag definitions */ -#define CFLAG_NODISC 0x01 -#define CFLAG_HEAD_TAG 0x02 -#define CFLAG_ORDERED_TAG 0x04 -#define CFLAG_SIMPLE_TAG 0x08 -#define CFLAG_TAR_RTN 0x10 -#define CFLAG_READ 0x20 -#define CFLAG_WRITE 0x40 - -struct Continuation_Entry { - struct Entry_header hdr; - struct dataseg dataseg[DATASEGS_PER_CONT]; -}; - -struct Marker_Entry { - struct Entry_header hdr; - u_int reserved; - u_char target_lun; - u_char target_id; - u_char modifier; - u_char expanded_lun; - u_char rsvds[52]; -}; - -/* marker entry modifier definitions */ -#define SYNC_DEVICE 0 -#define SYNC_TARGET 1 -#define SYNC_ALL 2 - -struct Status_Entry { - struct Entry_header hdr; - u_int handle; - u_short scsi_status; - u_short completion_status; - u_short state_flags; - u_short status_flags; - u_short res_info_len; - u_short req_sense_len; - u_int residual; - u_char res_info[8]; - u_char req_sense_data[32]; -}; - -/* status entry completion status definitions */ -#define CS_COMPLETE 0x0000 -#define CS_DMA_ERROR 0x0002 -#define CS_RESET_OCCURRED 0x0004 -#define CS_ABORTED 0x0005 -#define CS_TIMEOUT 0x0006 -#define CS_DATA_OVERRUN 0x0007 -#define CS_DATA_UNDERRUN 0x0015 -#define CS_QUEUE_FULL 0x001c -#define CS_PORT_UNAVAILABLE 0x0028 -#define CS_PORT_LOGGED_OUT 0x0029 -#define CS_PORT_CONFIG_CHANGED 0x002a - -/* status entry state flag definitions */ -#define SF_SENT_CDB 0x0400 -#define SF_TRANSFERRED_DATA 0x0800 -#define SF_GOT_STATUS 0x1000 - -/* status entry status flag definitions */ -#define STF_BUS_RESET 0x0008 -#define STF_DEVICE_RESET 0x0010 -#define STF_ABORTED 0x0020 -#define STF_TIMEOUT 0x0040 - -/* interrupt control commands */ -#define ISP_EN_INT 0x8000 -#define ISP_EN_RISC 0x0008 - -/* host control commands */ -#define HCCR_NOP 0x0000 -#define HCCR_RESET 0x1000 -#define HCCR_PAUSE 0x2000 -#define HCCR_RELEASE 0x3000 -#define HCCR_SINGLE_STEP 0x4000 -#define HCCR_SET_HOST_INTR 0x5000 -#define HCCR_CLEAR_HOST_INTR 0x6000 -#define HCCR_CLEAR_RISC_INTR 0x7000 -#define HCCR_BP_ENABLE 0x8000 -#define HCCR_BIOS_DISABLE 0x9000 -#define HCCR_TEST_MODE 0xf000 - -#define RISC_BUSY 0x0004 - -/* mailbox commands */ -#define MBOX_NO_OP 0x0000 -#define MBOX_LOAD_RAM 0x0001 -#define MBOX_EXEC_FIRMWARE 0x0002 -#define MBOX_DUMP_RAM 0x0003 -#define MBOX_WRITE_RAM_WORD 0x0004 -#define MBOX_READ_RAM_WORD 0x0005 -#define MBOX_MAILBOX_REG_TEST 0x0006 -#define MBOX_VERIFY_CHECKSUM 0x0007 -#define MBOX_ABOUT_FIRMWARE 0x0008 -#define MBOX_LOAD_RISC_RAM 0x0009 -#define MBOX_DUMP_RISC_RAM 0x000a -#define MBOX_CHECK_FIRMWARE 0x000e -#define MBOX_INIT_REQ_QUEUE 0x0010 -#define MBOX_INIT_RES_QUEUE 0x0011 -#define MBOX_EXECUTE_IOCB 0x0012 -#define MBOX_WAKE_UP 0x0013 -#define MBOX_STOP_FIRMWARE 0x0014 -#define MBOX_ABORT_IOCB 0x0015 -#define MBOX_ABORT_DEVICE 0x0016 -#define MBOX_ABORT_TARGET 0x0017 -#define MBOX_BUS_RESET 0x0018 -#define MBOX_STOP_QUEUE 0x0019 -#define MBOX_START_QUEUE 0x001a -#define MBOX_SINGLE_STEP_QUEUE 0x001b -#define MBOX_ABORT_QUEUE 0x001c -#define MBOX_GET_DEV_QUEUE_STATUS 0x001d -#define MBOX_GET_FIRMWARE_STATUS 0x001f -#define MBOX_GET_INIT_SCSI_ID 0x0020 -#define MBOX_GET_RETRY_COUNT 0x0022 -#define MBOX_GET_TARGET_PARAMS 0x0028 -#define MBOX_GET_DEV_QUEUE_PARAMS 0x0029 -#define MBOX_SET_RETRY_COUNT 0x0032 -#define MBOX_SET_TARGET_PARAMS 0x0038 -#define MBOX_SET_DEV_QUEUE_PARAMS 0x0039 -#define MBOX_EXECUTE_IOCB64 0x0054 -#define MBOX_INIT_FIRMWARE 0x0060 -#define MBOX_GET_INIT_CB 0x0061 -#define MBOX_INIT_LIP 0x0062 -#define MBOX_GET_POS_MAP 0x0063 -#define MBOX_GET_PORT_DB 0x0064 -#define MBOX_CLEAR_ACA 0x0065 -#define MBOX_TARGET_RESET 0x0066 -#define MBOX_CLEAR_TASK_SET 0x0067 -#define MBOX_ABORT_TASK_SET 0x0068 -#define MBOX_GET_FIRMWARE_STATE 0x0069 -#define MBOX_GET_PORT_NAME 0x006a -#define MBOX_SEND_SNS 0x006e -#define MBOX_PORT_LOGIN 0x006f -#define MBOX_SEND_CHANGE_REQUEST 0x0070 -#define MBOX_PORT_LOGOUT 0x0071 - -/* - * Firmware if needed (note this is a hack, it belongs in a separate - * module. - */ - -#ifdef CONFIG_SCSI_QLOGIC_FC_FIRMWARE -#include "qlogicfc_asm.c" -#else -static unsigned short risc_code_addr01 = 0x1000 ; -#endif - -/* Each element in mbox_param is an 8 bit bitmap where each bit indicates - if that mbox should be copied as input. For example 0x2 would mean - only copy mbox1. */ - -static const u_char mbox_param[] = -{ - 0x01, /* MBOX_NO_OP */ - 0x1f, /* MBOX_LOAD_RAM */ - 0x03, /* MBOX_EXEC_FIRMWARE */ - 0x1f, /* MBOX_DUMP_RAM */ - 0x07, /* MBOX_WRITE_RAM_WORD */ - 0x03, /* MBOX_READ_RAM_WORD */ - 0xff, /* MBOX_MAILBOX_REG_TEST */ - 0x03, /* MBOX_VERIFY_CHECKSUM */ - 0x01, /* MBOX_ABOUT_FIRMWARE */ - 0xff, /* MBOX_LOAD_RISC_RAM */ - 0xff, /* MBOX_DUMP_RISC_RAM */ - 0x00, /* 0x000b */ - 0x00, /* 0x000c */ - 0x00, /* 0x000d */ - 0x01, /* MBOX_CHECK_FIRMWARE */ - 0x00, /* 0x000f */ - 0x1f, /* MBOX_INIT_REQ_QUEUE */ - 0x2f, /* MBOX_INIT_RES_QUEUE */ - 0x0f, /* MBOX_EXECUTE_IOCB */ - 0x03, /* MBOX_WAKE_UP */ - 0x01, /* MBOX_STOP_FIRMWARE */ - 0x0f, /* MBOX_ABORT_IOCB */ - 0x03, /* MBOX_ABORT_DEVICE */ - 0x07, /* MBOX_ABORT_TARGET */ - 0x03, /* MBOX_BUS_RESET */ - 0x03, /* MBOX_STOP_QUEUE */ - 0x03, /* MBOX_START_QUEUE */ - 0x03, /* MBOX_SINGLE_STEP_QUEUE */ - 0x03, /* MBOX_ABORT_QUEUE */ - 0x03, /* MBOX_GET_DEV_QUEUE_STATUS */ - 0x00, /* 0x001e */ - 0x01, /* MBOX_GET_FIRMWARE_STATUS */ - 0x01, /* MBOX_GET_INIT_SCSI_ID */ - 0x00, /* 0x0021 */ - 0x01, /* MBOX_GET_RETRY_COUNT */ - 0x00, /* 0x0023 */ - 0x00, /* 0x0024 */ - 0x00, /* 0x0025 */ - 0x00, /* 0x0026 */ - 0x00, /* 0x0027 */ - 0x03, /* MBOX_GET_TARGET_PARAMS */ - 0x03, /* MBOX_GET_DEV_QUEUE_PARAMS */ - 0x00, /* 0x002a */ - 0x00, /* 0x002b */ - 0x00, /* 0x002c */ - 0x00, /* 0x002d */ - 0x00, /* 0x002e */ - 0x00, /* 0x002f */ - 0x00, /* 0x0030 */ - 0x00, /* 0x0031 */ - 0x07, /* MBOX_SET_RETRY_COUNT */ - 0x00, /* 0x0033 */ - 0x00, /* 0x0034 */ - 0x00, /* 0x0035 */ - 0x00, /* 0x0036 */ - 0x00, /* 0x0037 */ - 0x0f, /* MBOX_SET_TARGET_PARAMS */ - 0x0f, /* MBOX_SET_DEV_QUEUE_PARAMS */ - 0x00, /* 0x003a */ - 0x00, /* 0x003b */ - 0x00, /* 0x003c */ - 0x00, /* 0x003d */ - 0x00, /* 0x003e */ - 0x00, /* 0x003f */ - 0x00, /* 0x0040 */ - 0x00, /* 0x0041 */ - 0x00, /* 0x0042 */ - 0x00, /* 0x0043 */ - 0x00, /* 0x0044 */ - 0x00, /* 0x0045 */ - 0x00, /* 0x0046 */ - 0x00, /* 0x0047 */ - 0x00, /* 0x0048 */ - 0x00, /* 0x0049 */ - 0x00, /* 0x004a */ - 0x00, /* 0x004b */ - 0x00, /* 0x004c */ - 0x00, /* 0x004d */ - 0x00, /* 0x004e */ - 0x00, /* 0x004f */ - 0x00, /* 0x0050 */ - 0x00, /* 0x0051 */ - 0x00, /* 0x0052 */ - 0x00, /* 0x0053 */ - 0xcf, /* MBOX_EXECUTE_IOCB64 */ - 0x00, /* 0x0055 */ - 0x00, /* 0x0056 */ - 0x00, /* 0x0057 */ - 0x00, /* 0x0058 */ - 0x00, /* 0x0059 */ - 0x00, /* 0x005a */ - 0x00, /* 0x005b */ - 0x00, /* 0x005c */ - 0x00, /* 0x005d */ - 0x00, /* 0x005e */ - 0x00, /* 0x005f */ - 0xff, /* MBOX_INIT_FIRMWARE */ - 0xcd, /* MBOX_GET_INIT_CB */ - 0x01, /* MBOX_INIT_LIP */ - 0xcd, /* MBOX_GET_POS_MAP */ - 0xcf, /* MBOX_GET_PORT_DB */ - 0x03, /* MBOX_CLEAR_ACA */ - 0x03, /* MBOX_TARGET_RESET */ - 0x03, /* MBOX_CLEAR_TASK_SET */ - 0x03, /* MBOX_ABORT_TASK_SET */ - 0x01, /* MBOX_GET_FIRMWARE_STATE */ - 0x03, /* MBOX_GET_PORT_NAME */ - 0x00, /* 0x006b */ - 0x00, /* 0x006c */ - 0x00, /* 0x006d */ - 0xcf, /* MBOX_SEND_SNS */ - 0x0f, /* MBOX_PORT_LOGIN */ - 0x03, /* MBOX_SEND_CHANGE_REQUEST */ - 0x03, /* MBOX_PORT_LOGOUT */ -}; - -#define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short)) - - -struct id_name_map { - u64 wwn; - u_char loop_id; -}; - -struct sns_cb { - u_short len; - u_short res1; - u_int response_low; - u_int response_high; - u_short sub_len; - u_short res2; - u_char data[44]; -}; - -/* address of instance of this struct is passed to adapter to initialize things - */ -struct init_cb { - u_char version; - u_char reseverd1[1]; - u_short firm_opts; - u_short max_frame_len; - u_short max_iocb; - u_short exec_throttle; - u_char retry_cnt; - u_char retry_delay; - u_short node_name[4]; - u_short hard_addr; - u_char reserved2[10]; - u_short req_queue_out; - u_short res_queue_in; - u_short req_queue_len; - u_short res_queue_len; - u_int req_queue_addr_lo; - u_int req_queue_addr_high; - u_int res_queue_addr_lo; - u_int res_queue_addr_high; - /* the rest of this structure only applies to the isp2200 */ - u_short lun_enables; - u_char cmd_resource_cnt; - u_char notify_resource_cnt; - u_short timeout; - u_short reserved3; - u_short add_firm_opts; - u_char res_accum_timer; - u_char irq_delay_timer; - u_short special_options; - u_short reserved4[13]; -}; - -/* - * The result queue can be quite a bit smaller since continuation entries - * do not show up there: - */ -#define RES_QUEUE_LEN ((QLOGICFC_REQ_QUEUE_LEN + 1) / 8 - 1) -#define QUEUE_ENTRY_LEN 64 - -#if ISP2x00_FABRIC -#define QLOGICFC_MAX_ID 0xff -#else -#define QLOGICFC_MAX_ID 0x7d -#endif - -#define QLOGICFC_MAX_LUN 128 -#define QLOGICFC_MAX_LOOP_ID 0x7d - -/* the following connection options only apply to the 2200. i have only - * had success with LOOP_ONLY and P2P_ONLY. - */ - -#define LOOP_ONLY 0 -#define P2P_ONLY 1 -#define LOOP_PREFERED 2 -#define P2P_PREFERED 3 - -#define CONNECTION_PREFERENCE LOOP_ONLY - -/* adapter_state values */ -#define AS_FIRMWARE_DEAD -1 -#define AS_LOOP_DOWN 0 -#define AS_LOOP_GOOD 1 -#define AS_REDO_FABRIC_PORTDB 2 -#define AS_REDO_LOOP_PORTDB 4 - -#define RES_SIZE ((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) -#define REQ_SIZE ((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN) - -struct isp2x00_hostdata { - u_char revision; - struct pci_dev *pci_dev; - /* result and request queues (shared with isp2x00): */ - u_int req_in_ptr; /* index of next request slot */ - u_int res_out_ptr; /* index of next result slot */ - - /* this is here so the queues are nicely aligned */ - long send_marker; /* do we need to send a marker? */ - - char * res; - char * req; - struct init_cb control_block; - int adapter_state; - unsigned long int tag_ages[QLOGICFC_MAX_ID + 1]; - Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1]; - unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1]; - struct id_name_map port_db[QLOGICFC_MAX_ID + 1]; - u_char mbox_done; - u64 wwn; - u_int port_id; - u_char queued; - u_char host_id; - struct timer_list explore_timer; - struct id_name_map tempmap[QLOGICFC_MAX_ID + 1]; -}; - - -/* queue length's _must_ be power of two: */ -#define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql)) -#define REQ_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, \ - QLOGICFC_REQ_QUEUE_LEN) -#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN) - -static void isp2x00_enable_irqs(struct Scsi_Host *); -static void isp2x00_disable_irqs(struct Scsi_Host *); -static int isp2x00_init(struct Scsi_Host *); -static int isp2x00_reset_hardware(struct Scsi_Host *); -static int isp2x00_mbox_command(struct Scsi_Host *, u_short[]); -static int isp2x00_return_status(Scsi_Cmnd *, struct Status_Entry *); -static void isp2x00_intr_handler(int, void *, struct pt_regs *); -static irqreturn_t do_isp2x00_intr_handler(int, void *, struct pt_regs *); -static int isp2x00_make_portdb(struct Scsi_Host *); - -#if ISP2x00_FABRIC -static int isp2x00_init_fabric(struct Scsi_Host *, struct id_name_map *, int); -#endif - -#if USE_NVRAM_DEFAULTS -static int isp2x00_get_nvram_defaults(struct Scsi_Host *, struct init_cb *); -static u_short isp2x00_read_nvram_word(struct Scsi_Host *, u_short); -#endif - -#if DEBUG_ISP2x00 -static void isp2x00_print_scsi_cmd(Scsi_Cmnd *); -#endif - -#if DEBUG_ISP2x00_INTR -static void isp2x00_print_status_entry(struct Status_Entry *); -#endif - -static inline void isp2x00_enable_irqs(struct Scsi_Host *host) -{ - outw(ISP_EN_INT | ISP_EN_RISC, host->io_port + PCI_INTER_CTL); -} - - -static inline void isp2x00_disable_irqs(struct Scsi_Host *host) -{ - outw(0x0, host->io_port + PCI_INTER_CTL); -} - - -static int isp2x00_detect(struct scsi_host_template * tmpt) -{ - int hosts = 0; - unsigned long wait_time; - struct Scsi_Host *host = NULL; - struct isp2x00_hostdata *hostdata; - struct pci_dev *pdev; - unsigned short device_ids[2]; - dma_addr_t busaddr; - int i; - - - ENTER("isp2x00_detect"); - - device_ids[0] = PCI_DEVICE_ID_QLOGIC_ISP2100; - device_ids[1] = PCI_DEVICE_ID_QLOGIC_ISP2200; - - tmpt->proc_name = "isp2x00"; - - for (i=0; i<2; i++){ - pdev = NULL; - while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, device_ids[i], pdev))) { - if (pci_enable_device(pdev)) - continue; - - /* Try to configure DMA attributes. */ - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) && - pci_set_dma_mask(pdev, DMA_32BIT_MASK)) - continue; - - host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata)); - if (!host) { - printk("qlogicfc%d : could not register host.\n", hosts); - continue; - } - host->max_id = QLOGICFC_MAX_ID + 1; - host->max_lun = QLOGICFC_MAX_LUN; - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - memset(hostdata, 0, sizeof(struct isp2x00_hostdata)); - hostdata->pci_dev = pdev; - hostdata->res = pci_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr); - - if (!hostdata->res){ - printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hosts); - scsi_unregister(host); - continue; - } - hostdata->req = hostdata->res + (RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN; - hostdata->queued = 0; - /* set up the control block */ - hostdata->control_block.version = 0x1; - hostdata->control_block.firm_opts = cpu_to_le16(0x800e); - hostdata->control_block.max_frame_len = cpu_to_le16(2048); - hostdata->control_block.max_iocb = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN); - hostdata->control_block.exec_throttle = cpu_to_le16(QLOGICFC_CMD_PER_LUN); - hostdata->control_block.retry_delay = 5; - hostdata->control_block.retry_cnt = 1; - hostdata->control_block.node_name[0] = cpu_to_le16(0x0020); - hostdata->control_block.node_name[1] = cpu_to_le16(0xE000); - hostdata->control_block.node_name[2] = cpu_to_le16(0x008B); - hostdata->control_block.node_name[3] = cpu_to_le16(0x0000); - hostdata->control_block.hard_addr = cpu_to_le16(0x0003); - hostdata->control_block.req_queue_len = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN + 1); - hostdata->control_block.res_queue_len = cpu_to_le16(RES_QUEUE_LEN + 1); - hostdata->control_block.res_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr)); - hostdata->control_block.res_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr)); - hostdata->control_block.req_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr + RES_SIZE)); - hostdata->control_block.req_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr + RES_SIZE)); - - - hostdata->control_block.add_firm_opts |= cpu_to_le16(CONNECTION_PREFERENCE<<4); - hostdata->adapter_state = AS_LOOP_DOWN; - hostdata->explore_timer.data = 1; - hostdata->host_id = hosts; - - if (isp2x00_init(host) || isp2x00_reset_hardware(host)) { - pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); - scsi_unregister(host); - continue; - } - host->this_id = 0; - - if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) { - printk("qlogicfc%d : interrupt %d already in use\n", - hostdata->host_id, host->irq); - pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); - scsi_unregister(host); - continue; - } - if (!request_region(host->io_port, 0xff, "qlogicfc")) { - printk("qlogicfc%d : i/o region 0x%lx-0x%lx already " - "in use\n", - hostdata->host_id, host->io_port, host->io_port + 0xff); - free_irq(host->irq, host); - pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); - scsi_unregister(host); - continue; - } - - outw(0x0, host->io_port + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); - isp2x00_enable_irqs(host); - /* wait for the loop to come up */ - for (wait_time = jiffies + 10 * HZ; time_before(jiffies, wait_time) && hostdata->adapter_state == AS_LOOP_DOWN;) { - barrier(); - cpu_relax(); - } - if (hostdata->adapter_state == AS_LOOP_DOWN) { - printk("qlogicfc%d : link is not up\n", hostdata->host_id); - } - hosts++; - hostdata->explore_timer.data = 0; - } - } - - - /* this busy loop should not be needed but the isp2x00 seems to need - some time before recognizing it is attached to a fabric */ - -#if ISP2x00_FABRIC - if (hosts) { - for (wait_time = jiffies + 5 * HZ; time_before(jiffies, wait_time);) { - barrier(); - cpu_relax(); - } - } -#endif - - LEAVE("isp2x00_detect"); - - return hosts; -} - - -static int isp2x00_make_portdb(struct Scsi_Host *host) -{ - - short param[8]; - int i, j; - struct isp2x00_hostdata *hostdata; - - isp2x00_disable_irqs(host); - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - memset(hostdata->tempmap, 0, sizeof(hostdata->tempmap)); - -#if ISP2x00_FABRIC - for (i = 0x81; i < QLOGICFC_MAX_ID; i++) { - param[0] = MBOX_PORT_LOGOUT; - param[1] = i << 8; - param[2] = 0; - param[3] = 0; - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - - DEBUG_FABRIC(printk("qlogicfc%d : logout failed %x %x\n", hostdata->host_id, i, param[0])); - } - } -#endif - - - param[0] = MBOX_GET_INIT_SCSI_ID; - - isp2x00_mbox_command(host, param); - - if (param[0] == MBOX_COMMAND_COMPLETE) { - hostdata->port_id = ((u_int) param[3]) << 16; - hostdata->port_id |= param[2]; - hostdata->tempmap[0].loop_id = param[1]; - hostdata->tempmap[0].wwn = hostdata->wwn; - } - else { - printk("qlogicfc%d : error getting scsi id.\n", hostdata->host_id); - } - - for (i = 0; i <=QLOGICFC_MAX_ID; i++) - hostdata->tempmap[i].loop_id = hostdata->tempmap[0].loop_id; - - for (i = 0, j = 1; i <= QLOGICFC_MAX_LOOP_ID; i++) { - param[0] = MBOX_GET_PORT_NAME; - param[1] = (i << 8) & 0xff00; - - isp2x00_mbox_command(host, param); - - if (param[0] == MBOX_COMMAND_COMPLETE) { - hostdata->tempmap[j].loop_id = i; - hostdata->tempmap[j].wwn = ((u64) (param[2] & 0xff)) << 56; - hostdata->tempmap[j].wwn |= ((u64) ((param[2] >> 8) & 0xff)) << 48; - hostdata->tempmap[j].wwn |= ((u64) (param[3] & 0xff)) << 40; - hostdata->tempmap[j].wwn |= ((u64) ((param[3] >> 8) & 0xff)) << 32; - hostdata->tempmap[j].wwn |= ((u64) (param[6] & 0xff)) << 24; - hostdata->tempmap[j].wwn |= ((u64) ((param[6] >> 8) & 0xff)) << 16; - hostdata->tempmap[j].wwn |= ((u64) (param[7] & 0xff)) << 8; - hostdata->tempmap[j].wwn |= ((u64) ((param[7] >> 8) & 0xff)); - - j++; - - } - } - - -#if ISP2x00_FABRIC - isp2x00_init_fabric(host, hostdata->tempmap, j); -#endif - - for (i = 0; i <= QLOGICFC_MAX_ID; i++) { - if (hostdata->tempmap[i].wwn != hostdata->port_db[i].wwn) { - for (j = 0; j <= QLOGICFC_MAX_ID; j++) { - if (hostdata->tempmap[j].wwn == hostdata->port_db[i].wwn) { - hostdata->port_db[i].loop_id = hostdata->tempmap[j].loop_id; - break; - } - } - if (j == QLOGICFC_MAX_ID + 1) - hostdata->port_db[i].loop_id = hostdata->tempmap[0].loop_id; - - for (j = 0; j <= QLOGICFC_MAX_ID; j++) { - if (hostdata->port_db[j].wwn == hostdata->tempmap[i].wwn || !hostdata->port_db[j].wwn) { - break; - } - } - if (j == QLOGICFC_MAX_ID + 1) - printk("qlogicfc%d : Too many scsi devices, no more room in port map.\n", hostdata->host_id); - if (!hostdata->port_db[j].wwn) { - hostdata->port_db[j].loop_id = hostdata->tempmap[i].loop_id; - hostdata->port_db[j].wwn = hostdata->tempmap[i].wwn; - } - } else - hostdata->port_db[i].loop_id = hostdata->tempmap[i].loop_id; - - } - - isp2x00_enable_irqs(host); - - return 0; -} - - -#if ISP2x00_FABRIC - -#define FABRIC_PORT 0x7e -#define FABRIC_CONTROLLER 0x7f -#define FABRIC_SNS 0x80 - -int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int cur_scsi_id) -{ - - u_short param[8]; - u64 wwn; - int done = 0; - u_short loop_id = 0x81; - u_short scsi_id = cur_scsi_id; - u_int port_id; - struct sns_cb *req; - u_char *sns_response; - dma_addr_t busaddr; - struct isp2x00_hostdata *hostdata; - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id)); - param[0] = MBOX_GET_PORT_NAME; - param[1] = (u16)FABRIC_PORT << 8; - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - DEBUG_FABRIC(printk("qlogicfc%d : fabric check result %x\n", hostdata->host_id, param[0])); - return 0; - } - printk("qlogicfc%d : Fabric found.\n", hostdata->host_id); - - req = (struct sns_cb *)pci_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr); - - if (!req){ - printk("qlogicfc%d : Could not allocate DMA resources for fabric initialization\n", hostdata->host_id); - return 0; - } - sns_response = (u_char *)(req + 1); - - if (hostdata->adapter_state & AS_REDO_LOOP_PORTDB){ - memset(req, 0, sizeof(*req)); - - req->len = cpu_to_le16(8); - req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); - req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); - req->sub_len = cpu_to_le16(22); - req->data[0] = 0x17; - req->data[1] = 0x02; - req->data[8] = (u_char) (hostdata->port_id & 0xff); - req->data[9] = (u_char) (hostdata->port_id >> 8 & 0xff); - req->data[10] = (u_char) (hostdata->port_id >> 16 & 0xff); - req->data[13] = 0x01; - param[0] = MBOX_SEND_SNS; - param[1] = 30; - param[2] = pci64_dma_lo32(busaddr) >> 16; - param[3] = pci64_dma_lo32(busaddr); - param[6] = pci64_dma_hi32(busaddr) >> 16; - param[7] = pci64_dma_hi32(busaddr); - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) - printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id); - } - - port_id = hostdata->port_id; - while (!done) { - memset(req, 0, sizeof(*req)); - - req->len = cpu_to_le16(304); - req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req))); - req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req))); - req->sub_len = cpu_to_le16(6); - req->data[0] = 0x00; - req->data[1] = 0x01; - req->data[8] = (u_char) (port_id & 0xff); - req->data[9] = (u_char) (port_id >> 8 & 0xff); - req->data[10] = (u_char) (port_id >> 16 & 0xff); - - param[0] = MBOX_SEND_SNS; - param[1] = 14; - param[2] = pci64_dma_lo32(busaddr) >> 16; - param[3] = pci64_dma_lo32(busaddr); - param[6] = pci64_dma_hi32(busaddr) >> 16; - param[7] = pci64_dma_hi32(busaddr); - - isp2x00_mbox_command(host, param); - - if (param[0] == MBOX_COMMAND_COMPLETE) { - DEBUG_FABRIC(printk("qlogicfc%d : found node %02x%02x%02x%02x%02x%02x%02x%02x ", hostdata->host_id, sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27])); - DEBUG_FABRIC(printk(" port id: %02x%02x%02x\n", sns_response[17], sns_response[18], sns_response[19])); - port_id = ((u_int) sns_response[17]) << 16; - port_id |= ((u_int) sns_response[18]) << 8; - port_id |= ((u_int) sns_response[19]); - wwn = ((u64) sns_response[20]) << 56; - wwn |= ((u64) sns_response[21]) << 48; - wwn |= ((u64) sns_response[22]) << 40; - wwn |= ((u64) sns_response[23]) << 32; - wwn |= ((u64) sns_response[24]) << 24; - wwn |= ((u64) sns_response[25]) << 16; - wwn |= ((u64) sns_response[26]) << 8; - wwn |= ((u64) sns_response[27]); - if (hostdata->port_id >> 8 != port_id >> 8) { - DEBUG_FABRIC(printk("qlogicfc%d : adding a fabric port: %x\n", hostdata->host_id, port_id)); - param[0] = MBOX_PORT_LOGIN; - param[1] = loop_id << 8; - param[2] = (u_short) (port_id >> 16); - param[3] = (u_short) (port_id); - - isp2x00_mbox_command(host, param); - - if (param[0] == MBOX_COMMAND_COMPLETE) { - port_db[scsi_id].wwn = wwn; - port_db[scsi_id].loop_id = loop_id; - loop_id++; - scsi_id++; - } else { - printk("qlogicfc%d : Error performing port login %x\n", hostdata->host_id, param[0]); - DEBUG_FABRIC(printk("qlogicfc%d : loop_id: %x\n", hostdata->host_id, loop_id)); - param[0] = MBOX_PORT_LOGOUT; - param[1] = loop_id << 8; - param[2] = 0; - param[3] = 0; - - isp2x00_mbox_command(host, param); - - } - - } - if (hostdata->port_id == port_id) - done = 1; - } else { - printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]); - pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); - return 0; - } - } - - pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr); - return 1; -} - -#endif /* ISP2x00_FABRIC */ - - -static int isp2x00_release(struct Scsi_Host *host) -{ - struct isp2x00_hostdata *hostdata; - dma_addr_t busaddr; - - ENTER("isp2x00_release"); - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - outw(0x0, host->io_port + PCI_INTER_CTL); - free_irq(host->irq, host); - - release_region(host->io_port, 0xff); - - busaddr = pci64_dma_build(le32_to_cpu(hostdata->control_block.res_queue_addr_high), - le32_to_cpu(hostdata->control_block.res_queue_addr_lo)); - pci_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr); - - LEAVE("isp2x00_release"); - - return 0; -} - - -static const char *isp2x00_info(struct Scsi_Host *host) -{ - static char buf[80]; - struct isp2x00_hostdata *hostdata; - ENTER("isp2x00_info"); - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - sprintf(buf, - "QLogic ISP%04x SCSI on PCI bus %02x device %02x irq %d base 0x%lx", - hostdata->pci_dev->device, hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq, - host->io_port); - - - LEAVE("isp2x00_info"); - - return buf; -} - - -/* - * The middle SCSI layer ensures that queuecommand never gets invoked - * concurrently with itself or the interrupt handler (though the - * interrupt handler may call this routine as part of - * request-completion handling). - */ -static int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *)) -{ - int i, sg_count, n, num_free; - u_int in_ptr, out_ptr; - struct dataseg *ds; - struct scatterlist *sg; - struct Command_Entry *cmd; - struct Continuation_Entry *cont; - struct Scsi_Host *host; - struct isp2x00_hostdata *hostdata; - - ENTER("isp2x00_queuecommand"); - - host = Cmnd->device->host; - hostdata = (struct isp2x00_hostdata *) host->hostdata; - Cmnd->scsi_done = done; - - DEBUG(isp2x00_print_scsi_cmd(Cmnd)); - - if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) { - isp2x00_make_portdb(host); - hostdata->adapter_state = AS_LOOP_GOOD; - printk("qlogicfc%d : Port Database\n", hostdata->host_id); - for (i = 0; hostdata->port_db[i].wwn != 0; i++) { - printk("wwn: %08x%08x scsi_id: %x loop_id: ", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i); - if (hostdata->port_db[i].loop_id != hostdata->port_db[0].loop_id || i == 0) - printk("%x", hostdata->port_db[i].loop_id); - else - printk("Not Available"); - printk("\n"); - } - } - if (hostdata->adapter_state == AS_FIRMWARE_DEAD) { - printk("qlogicfc%d : The firmware is dead, just return.\n", hostdata->host_id); - host->max_id = 0; - return 0; - } - - out_ptr = inw(host->io_port + MBOX4); - in_ptr = hostdata->req_in_ptr; - - DEBUG(printk("qlogicfc%d : request queue depth %d\n", hostdata->host_id, - REQ_QUEUE_DEPTH(in_ptr, out_ptr))); - - cmd = (struct Command_Entry *) &hostdata->req[in_ptr*QUEUE_ENTRY_LEN]; - in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; - if (in_ptr == out_ptr) { - DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id)); - return 1; - } - if (hostdata->send_marker) { - struct Marker_Entry *marker; - - TRACE("queue marker", in_ptr, 0); - - DEBUG(printk("qlogicfc%d : adding marker entry\n", hostdata->host_id)); - marker = (struct Marker_Entry *) cmd; - memset(marker, 0, sizeof(struct Marker_Entry)); - - marker->hdr.entry_type = ENTRY_MARKER; - marker->hdr.entry_cnt = 1; - marker->modifier = SYNC_ALL; - - hostdata->send_marker = 0; - - if (((in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN) == out_ptr) { - outw(in_ptr, host->io_port + MBOX4); - hostdata->req_in_ptr = in_ptr; - DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id)); - return 1; - } - cmd = (struct Command_Entry *) &hostdata->req[in_ptr*QUEUE_ENTRY_LEN]; - in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; - } - TRACE("queue command", in_ptr, Cmnd); - - memset(cmd, 0, sizeof(struct Command_Entry)); - - /* find a free handle mapping slot */ - for (i = in_ptr; i != (in_ptr - 1) && hostdata->handle_ptrs[i]; i = ((i + 1) % (QLOGICFC_REQ_QUEUE_LEN + 1))); - - if (!hostdata->handle_ptrs[i]) { - cmd->handle = cpu_to_le32(i); - hostdata->handle_ptrs[i] = Cmnd; - hostdata->handle_serials[i] = Cmnd->serial_number; - } else { - printk("qlogicfc%d : no handle slots, this should not happen.\n", hostdata->host_id); - printk("hostdata->queued is %x, in_ptr: %x\n", hostdata->queued, in_ptr); - for (i = 0; i <= QLOGICFC_REQ_QUEUE_LEN; i++){ - if (!hostdata->handle_ptrs[i]){ - printk("slot %d has %p\n", i, hostdata->handle_ptrs[i]); - } - } - return 1; - } - - cmd->hdr.entry_type = ENTRY_COMMAND; - cmd->hdr.entry_cnt = 1; - cmd->target_lun = Cmnd->device->lun; - cmd->expanded_lun = cpu_to_le16(Cmnd->device->lun); -#if ISP2x00_PORTDB - cmd->target_id = hostdata->port_db[Cmnd->device->id].loop_id; -#else - cmd->target_id = Cmnd->target; -#endif - cmd->total_byte_cnt = cpu_to_le32(Cmnd->request_bufflen); - cmd->time_out = 0; - memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); - - if (Cmnd->use_sg) { - sg = (struct scatterlist *) Cmnd->request_buffer; - sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, Cmnd->sc_data_direction); - cmd->segment_cnt = cpu_to_le16(sg_count); - ds = cmd->dataseg; - /* fill in first two sg entries: */ - n = sg_count; - if (n > DATASEGS_PER_COMMAND) - n = DATASEGS_PER_COMMAND; - - for (i = 0; i < n; i++) { - ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma_address(sg))); - ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma_address(sg))); - ds[i].d_count = cpu_to_le32(sg_dma_len(sg)); - ++sg; - } - sg_count -= DATASEGS_PER_COMMAND; - - while (sg_count > 0) { - ++cmd->hdr.entry_cnt; - cont = (struct Continuation_Entry *) - &hostdata->req[in_ptr*QUEUE_ENTRY_LEN]; - memset(cont, 0, sizeof(struct Continuation_Entry)); - in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN; - if (in_ptr == out_ptr) { - DEBUG(printk("qlogicfc%d : unexpected request queue overflow\n", hostdata->host_id)); - return 1; - } - TRACE("queue continuation", in_ptr, 0); - cont->hdr.entry_type = ENTRY_CONTINUATION; - ds = cont->dataseg; - n = sg_count; - if (n > DATASEGS_PER_CONT) - n = DATASEGS_PER_CONT; - for (i = 0; i < n; ++i) { - ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma_address(sg))); - ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma_address(sg))); - ds[i].d_count = cpu_to_le32(sg_dma_len(sg)); - ++sg; - } - sg_count -= n; - } - } else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) { - struct page *page = virt_to_page(Cmnd->request_buffer); - unsigned long offset = offset_in_page(Cmnd->request_buffer); - dma_addr_t busaddr = pci_map_page(hostdata->pci_dev, - page, offset, - Cmnd->request_bufflen, - Cmnd->sc_data_direction); - Cmnd->SCp.dma_handle = busaddr; - - cmd->dataseg[0].d_base = cpu_to_le32(pci64_dma_lo32(busaddr)); - cmd->dataseg[0].d_base_hi = cpu_to_le32(pci64_dma_hi32(busaddr)); - cmd->dataseg[0].d_count = cpu_to_le32(Cmnd->request_bufflen); - cmd->segment_cnt = cpu_to_le16(1); - } else { - cmd->dataseg[0].d_base = 0; - cmd->dataseg[0].d_base_hi = 0; - cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */ - } - - if (Cmnd->sc_data_direction == DMA_TO_DEVICE) - cmd->control_flags = cpu_to_le16(CFLAG_WRITE); - else - cmd->control_flags = cpu_to_le16(CFLAG_READ); - - if (Cmnd->device->tagged_supported) { - if (time_after(jiffies, hostdata->tag_ages[Cmnd->device->id] + (2 * ISP_TIMEOUT))) { - cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); - hostdata->tag_ages[Cmnd->device->id] = jiffies; - } else - switch (Cmnd->tag) { - case HEAD_OF_QUEUE_TAG: - cmd->control_flags |= cpu_to_le16(CFLAG_HEAD_TAG); - break; - case ORDERED_QUEUE_TAG: - cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG); - break; - default: - cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG); - break; - } - } - /* - * TEST_UNIT_READY commands from scsi_scan will fail due to "overlapped - * commands attempted" unless we setup at least a simple queue (midlayer - * will embelish this once it can do an INQUIRY command to the device) - */ - else - cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG); - outw(in_ptr, host->io_port + MBOX4); - hostdata->req_in_ptr = in_ptr; - - hostdata->queued++; - - num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); - num_free = (num_free > 2) ? num_free - 2 : 0; - host->can_queue = host->host_busy + num_free; - if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) - host->can_queue = QLOGICFC_REQ_QUEUE_LEN; - host->sg_tablesize = QLOGICFC_MAX_SG(num_free); - - LEAVE("isp2x00_queuecommand"); - - return 0; -} - - -/* we have received an event, such as a lip or an RSCN, which may mean that - * our port database is incorrect so the port database must be recreated. - */ -static void redo_port_db(unsigned long arg) -{ - - struct Scsi_Host * host = (struct Scsi_Host *) arg; - struct isp2x00_hostdata * hostdata; - unsigned long flags; - int i; - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - hostdata->explore_timer.data = 0; - del_timer(&hostdata->explore_timer); - - spin_lock_irqsave(host->host_lock, flags); - - if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) { - isp2x00_make_portdb(host); - printk("qlogicfc%d : Port Database\n", hostdata->host_id); - for (i = 0; hostdata->port_db[i].wwn != 0; i++) { - printk("wwn: %08x%08x scsi_id: %x loop_id: ", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i); - if (hostdata->port_db[i].loop_id != hostdata->port_db[0].loop_id || i == 0) - printk("%x", hostdata->port_db[i].loop_id); - else - printk("Not Available"); - printk("\n"); - } - - for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++){ - if (hostdata->handle_ptrs[i] && (hostdata->port_db[hostdata->handle_ptrs[i]->device->id].loop_id > QLOGICFC_MAX_LOOP_ID || hostdata->adapter_state & AS_REDO_LOOP_PORTDB)){ - if (hostdata->port_db[hostdata->handle_ptrs[i]->device->id].loop_id != hostdata->port_db[0].loop_id){ - Scsi_Cmnd *Cmnd = hostdata->handle_ptrs[i]; - - if (Cmnd->use_sg) - pci_unmap_sg(hostdata->pci_dev, - (struct scatterlist *)Cmnd->buffer, - Cmnd->use_sg, - Cmnd->sc_data_direction); - else if (Cmnd->request_bufflen && - Cmnd->sc_data_direction != PCI_DMA_NONE) { - pci_unmap_page(hostdata->pci_dev, - Cmnd->SCp.dma_handle, - Cmnd->request_bufflen, - Cmnd->sc_data_direction); - } - - hostdata->handle_ptrs[i]->result = DID_SOFT_ERROR << 16; - - if (hostdata->handle_ptrs[i]->scsi_done){ - (*hostdata->handle_ptrs[i]->scsi_done) (hostdata->handle_ptrs[i]); - } - else printk("qlogicfc%d : done is null?\n", hostdata->host_id); - hostdata->handle_ptrs[i] = NULL; - hostdata->handle_serials[i] = 0; - } - } - } - - hostdata->adapter_state = AS_LOOP_GOOD; - } - - spin_unlock_irqrestore(host->host_lock, flags); - -} - -#define ASYNC_EVENT_INTERRUPT 0x01 - -irqreturn_t do_isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) -{ - struct Scsi_Host *host = dev_id; - unsigned long flags; - - spin_lock_irqsave(host->host_lock, flags); - isp2x00_intr_handler(irq, dev_id, regs); - spin_unlock_irqrestore(host->host_lock, flags); - - return IRQ_HANDLED; -} - -void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs) -{ - Scsi_Cmnd *Cmnd; - struct Status_Entry *sts; - struct Scsi_Host *host = dev_id; - struct isp2x00_hostdata *hostdata; - u_int in_ptr, out_ptr, handle, num_free; - u_short status; - - ENTER_INTR("isp2x00_intr_handler"); - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - DEBUG_INTR(printk("qlogicfc%d : interrupt on line %d\n", hostdata->host_id, irq)); - - if (!(inw(host->io_port + PCI_INTER_STS) & 0x08)) { - /* spurious interrupts can happen legally */ - DEBUG_INTR(printk("qlogicfc%d : got spurious interrupt\n", hostdata->host_id)); - return; - } - in_ptr = inw(host->io_port + MBOX5); - out_ptr = hostdata->res_out_ptr; - - if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) { - status = inw(host->io_port + MBOX0); - - DEBUG_INTR(printk("qlogicfc%d : mbox completion status: %x\n", - hostdata->host_id, status)); - - switch (status) { - case LOOP_UP: - case POINT_TO_POINT_UP: - printk("qlogicfc%d : Link is Up\n", hostdata->host_id); - hostdata->adapter_state = AS_REDO_FABRIC_PORTDB | AS_REDO_LOOP_PORTDB; - break; - case LOOP_DOWN: - printk("qlogicfc%d : Link is Down\n", hostdata->host_id); - hostdata->adapter_state = AS_LOOP_DOWN; - break; - case CONNECTION_MODE: - printk("received CONNECTION_MODE irq %x\n", inw(host->io_port + MBOX1)); - break; - case CHANGE_NOTIFICATION: - printk("qlogicfc%d : RSCN Received\n", hostdata->host_id); - if (hostdata->adapter_state == AS_LOOP_GOOD) - hostdata->adapter_state = AS_REDO_FABRIC_PORTDB; - break; - case LIP_OCCURRED: - case LIP_RECEIVED: - printk("qlogicfc%d : Loop Reinitialized\n", hostdata->host_id); - if (hostdata->adapter_state == AS_LOOP_GOOD) - hostdata->adapter_state = AS_REDO_LOOP_PORTDB; - break; - case SYSTEM_ERROR: - printk("qlogicfc%d : The firmware just choked.\n", hostdata->host_id); - hostdata->adapter_state = AS_FIRMWARE_DEAD; - break; - case SCSI_COMMAND_COMPLETE: - handle = inw(host->io_port + MBOX1) | (inw(host->io_port + MBOX2) << 16); - Cmnd = hostdata->handle_ptrs[handle]; - hostdata->handle_ptrs[handle] = NULL; - hostdata->handle_serials[handle] = 0; - hostdata->queued--; - if (Cmnd != NULL) { - if (Cmnd->use_sg) - pci_unmap_sg(hostdata->pci_dev, - (struct scatterlist *)Cmnd->buffer, - Cmnd->use_sg, - Cmnd->sc_data_direction); - else if (Cmnd->request_bufflen && - Cmnd->sc_data_direction != PCI_DMA_NONE) - pci_unmap_page(hostdata->pci_dev, - Cmnd->SCp.dma_handle, - Cmnd->request_bufflen, - Cmnd->sc_data_direction); - Cmnd->result = 0x0; - (*Cmnd->scsi_done) (Cmnd); - } else - printk("qlogicfc%d.c : got a null value out of handle_ptrs, this sucks\n", hostdata->host_id); - break; - case MBOX_COMMAND_COMPLETE: - case INVALID_COMMAND: - case HOST_INTERFACE_ERROR: - case TEST_FAILED: - case COMMAND_ERROR: - case COMMAND_PARAM_ERROR: - case PORT_ID_USED: - case LOOP_ID_USED: - case ALL_IDS_USED: - hostdata->mbox_done = 1; - outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); - return; - default: - printk("qlogicfc%d : got an unknown status? %x\n", hostdata->host_id, status); - } - if ((hostdata->adapter_state & AS_REDO_LOOP_PORTDB || hostdata->adapter_state & AS_REDO_FABRIC_PORTDB) && hostdata->explore_timer.data == 0){ - hostdata->explore_timer.function = redo_port_db; - hostdata->explore_timer.data = (unsigned long)host; - hostdata->explore_timer.expires = jiffies + (HZ/4); - init_timer(&hostdata->explore_timer); - add_timer(&hostdata->explore_timer); - } - outw(0x0, host->io_port + PCI_SEMAPHORE); - } else { - DEBUG_INTR(printk("qlogicfc%d : response queue update\n", hostdata->host_id)); - DEBUG_INTR(printk("qlogicfc%d : response queue depth %d\n", hostdata->host_id, RES_QUEUE_DEPTH(in_ptr, out_ptr))); - - while (out_ptr != in_ptr) { - unsigned le_hand; - sts = (struct Status_Entry *) &hostdata->res[out_ptr*QUEUE_ENTRY_LEN]; - out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; - - TRACE("done", out_ptr, Cmnd); - DEBUG_INTR(isp2x00_print_status_entry(sts)); - le_hand = le32_to_cpu(sts->handle); - if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[le_hand])) { - Cmnd->result = isp2x00_return_status(Cmnd, sts); - hostdata->queued--; - - if (Cmnd->use_sg) - pci_unmap_sg(hostdata->pci_dev, - (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg, - Cmnd->sc_data_direction); - else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) - pci_unmap_page(hostdata->pci_dev, - Cmnd->SCp.dma_handle, - Cmnd->request_bufflen, - Cmnd->sc_data_direction); - - /* - * if any of the following are true we do not - * call scsi_done. if the status is CS_ABORTED - * we don't have to call done because the upper - * level should already know its aborted. - */ - if (hostdata->handle_serials[le_hand] != Cmnd->serial_number - || le16_to_cpu(sts->completion_status) == CS_ABORTED){ - hostdata->handle_serials[le_hand] = 0; - hostdata->handle_ptrs[le_hand] = NULL; - outw(out_ptr, host->io_port + MBOX5); - continue; - } - /* - * if we get back an error indicating the port - * is not there or if the link is down and - * this is a device that used to be there - * allow the command to timeout. - * the device may well be back in a couple of - * seconds. - */ - if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == cpu_to_le16(CS_PORT_UNAVAILABLE) || sts->completion_status == cpu_to_le16(CS_PORT_LOGGED_OUT) || sts->completion_status == cpu_to_le16(CS_PORT_CONFIG_CHANGED)) && hostdata->port_db[Cmnd->device->id].wwn){ - outw(out_ptr, host->io_port + MBOX5); - continue; - } - } else { - outw(out_ptr, host->io_port + MBOX5); - continue; - } - - hostdata->handle_ptrs[le_hand] = NULL; - - if (sts->completion_status == cpu_to_le16(CS_RESET_OCCURRED) - || (sts->status_flags & cpu_to_le16(STF_BUS_RESET))) - hostdata->send_marker = 1; - - if (le16_to_cpu(sts->scsi_status) & 0x0200) - memcpy(Cmnd->sense_buffer, sts->req_sense_data, - sizeof(Cmnd->sense_buffer)); - - outw(out_ptr, host->io_port + MBOX5); - - if (Cmnd->scsi_done != NULL) { - (*Cmnd->scsi_done) (Cmnd); - } else - printk("qlogicfc%d : Ouch, scsi done is NULL\n", hostdata->host_id); - } - hostdata->res_out_ptr = out_ptr; - } - - - out_ptr = inw(host->io_port + MBOX4); - in_ptr = hostdata->req_in_ptr; - - num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); - num_free = (num_free > 2) ? num_free - 2 : 0; - host->can_queue = host->host_busy + num_free; - if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN) - host->can_queue = QLOGICFC_REQ_QUEUE_LEN; - host->sg_tablesize = QLOGICFC_MAX_SG(num_free); - - outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); - LEAVE_INTR("isp2x00_intr_handler"); -} - - -static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts) -{ - int host_status = DID_ERROR; -#if DEBUG_ISP2x00_INTR - static char *reason[] = - { - "DID_OK", - "DID_NO_CONNECT", - "DID_BUS_BUSY", - "DID_TIME_OUT", - "DID_BAD_TARGET", - "DID_ABORT", - "DID_PARITY", - "DID_ERROR", - "DID_RESET", - "DID_BAD_INTR" - }; -#endif /* DEBUG_ISP2x00_INTR */ - - ENTER("isp2x00_return_status"); - - DEBUG(printk("qlogicfc : completion status = 0x%04x\n", - le16_to_cpu(sts->completion_status))); - - switch (le16_to_cpu(sts->completion_status)) { - case CS_COMPLETE: - host_status = DID_OK; - break; - case CS_DMA_ERROR: - host_status = DID_ERROR; - break; - case CS_RESET_OCCURRED: - host_status = DID_RESET; - break; - case CS_ABORTED: - host_status = DID_ABORT; - break; - case CS_TIMEOUT: - host_status = DID_TIME_OUT; - break; - case CS_DATA_OVERRUN: - host_status = DID_ERROR; - break; - case CS_DATA_UNDERRUN: - if (Cmnd->underflow <= (Cmnd->request_bufflen - le32_to_cpu(sts->residual))) - host_status = DID_OK; - else - host_status = DID_ERROR; - break; - case CS_PORT_UNAVAILABLE: - case CS_PORT_LOGGED_OUT: - case CS_PORT_CONFIG_CHANGED: - host_status = DID_BAD_TARGET; - break; - case CS_QUEUE_FULL: - host_status = DID_ERROR; - break; - default: - printk("qlogicfc : unknown completion status 0x%04x\n", - le16_to_cpu(sts->completion_status)); - host_status = DID_ERROR; - break; - } - - DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n", - reason[host_status], le16_to_cpu(sts->scsi_status))); - - LEAVE("isp2x00_return_status"); - - return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16); -} - - -static int isp2x00_abort(Scsi_Cmnd * Cmnd) -{ - u_short param[8]; - int i; - struct Scsi_Host *host; - struct isp2x00_hostdata *hostdata; - int return_status = SUCCESS; - - ENTER("isp2x00_abort"); - - host = Cmnd->device->host; - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++) - if (hostdata->handle_ptrs[i] == Cmnd) - break; - - if (i == QLOGICFC_REQ_QUEUE_LEN){ - return SUCCESS; - } - - isp2x00_disable_irqs(host); - - param[0] = MBOX_ABORT_IOCB; -#if ISP2x00_PORTDB - param[1] = (((u_short) hostdata->port_db[Cmnd->device->id].loop_id) << 8) | Cmnd->device->lun; -#else - param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; -#endif - param[2] = i & 0xffff; - param[3] = i >> 16; - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc%d : scsi abort failure: %x\n", hostdata->host_id, param[0]); - if (param[0] == 0x4005) - Cmnd->result = DID_ERROR << 16; - if (param[0] == 0x4006) - Cmnd->result = DID_BAD_TARGET << 16; - return_status = FAILED; - } - - if (return_status != SUCCESS){ - param[0] = MBOX_GET_FIRMWARE_STATE; - isp2x00_mbox_command(host, param); - printk("qlogicfc%d : abort failed\n", hostdata->host_id); - printk("qlogicfc%d : firmware status is %x %x\n", hostdata->host_id, param[0], param[1]); - } - - isp2x00_enable_irqs(host); - - LEAVE("isp2x00_abort"); - - return return_status; -} - - -static int isp2x00_biosparam(struct scsi_device *sdev, struct block_device *n, - sector_t capacity, int ip[]) -{ - int size = capacity; - - ENTER("isp2x00_biosparam"); - - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - if (ip[2] > 1024) { - ip[0] = 255; - ip[1] = 63; - ip[2] = size / (ip[0] * ip[1]); - } - LEAVE("isp2x00_biosparam"); - - return 0; -} - -static int isp2x00_reset_hardware(struct Scsi_Host *host) -{ - u_short param[8]; - struct isp2x00_hostdata *hostdata; - int loop_count; - dma_addr_t busaddr; - - ENTER("isp2x00_reset_hardware"); - - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - /* - * This cannot be right - PCI writes are posted - * (apparently this is hardware design flaw not software ?) - */ - - outw(0x01, host->io_port + ISP_CTRL_STATUS); - udelay(100); - outw(HCCR_RESET, host->io_port + HOST_HCCR); - udelay(100); - outw(HCCR_RELEASE, host->io_port + HOST_HCCR); - outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR); - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY) { - barrier(); - cpu_relax(); - } - if (!loop_count) - printk("qlogicfc%d : reset_hardware loop timeout\n", hostdata->host_id); - - - -#if DEBUG_ISP2x00 - printk("qlogicfc%d : mbox 0 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX0)); - printk("qlogicfc%d : mbox 1 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX1)); - printk("qlogicfc%d : mbox 2 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX2)); - printk("qlogicfc%d : mbox 3 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX3)); - printk("qlogicfc%d : mbox 4 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX4)); - printk("qlogicfc%d : mbox 5 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX5)); - printk("qlogicfc%d : mbox 6 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX6)); - printk("qlogicfc%d : mbox 7 0x%04x \n", hostdata->host_id, inw(host->io_port + MBOX7)); -#endif /* DEBUG_ISP2x00 */ - - DEBUG(printk("qlogicfc%d : verifying checksum\n", hostdata->host_id)); - -#if defined(CONFIG_SCSI_QLOGIC_FC_FIRMWARE) - { - int i; - unsigned short * risc_code = NULL; - unsigned short risc_code_len = 0; - if (hostdata->pci_dev->device == PCI_DEVICE_ID_QLOGIC_ISP2100){ - risc_code = risc_code2100; - risc_code_len = risc_code_length2100; - } - else if (hostdata->pci_dev->device == PCI_DEVICE_ID_QLOGIC_ISP2200){ - risc_code = risc_code2200; - risc_code_len = risc_code_length2200; - } - - for (i = 0; i < risc_code_len; i++) { - param[0] = MBOX_WRITE_RAM_WORD; - param[1] = risc_code_addr01 + i; - param[2] = risc_code[i]; - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc%d : firmware load failure\n", hostdata->host_id); - return 1; - } - } - } -#endif /* RELOAD_FIRMWARE */ - - param[0] = MBOX_VERIFY_CHECKSUM; - param[1] = risc_code_addr01; - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc%d : ram checksum failure\n", hostdata->host_id); - return 1; - } - DEBUG(printk("qlogicfc%d : executing firmware\n", hostdata->host_id)); - - param[0] = MBOX_EXEC_FIRMWARE; - param[1] = risc_code_addr01; - - isp2x00_mbox_command(host, param); - - param[0] = MBOX_ABOUT_FIRMWARE; - - isp2x00_mbox_command(host, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc%d : about firmware failure\n", hostdata->host_id); - return 1; - } - DEBUG(printk("qlogicfc%d : firmware major revision %d\n", hostdata->host_id, param[1])); - DEBUG(printk("qlogicfc%d : firmware minor revision %d\n", hostdata->host_id, param[2])); - -#ifdef USE_NVRAM_DEFAULTS - - if (isp2x00_get_nvram_defaults(host, &hostdata->control_block) != 0) { - printk("qlogicfc%d : Could not read from NVRAM\n", hostdata->host_id); - } -#endif - - hostdata->wwn = (u64) (cpu_to_le16(hostdata->control_block.node_name[0])) << 56; - hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[0]) & 0xff00) << 48; - hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[1]) & 0xff00) << 24; - hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[1]) & 0x00ff) << 48; - hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[2]) & 0x00ff) << 24; - hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[2]) & 0xff00) << 8; - hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0x00ff) << 8; - hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0xff00) >> 8; - - /* FIXME: If the DMA transfer goes one way only, this should use - * PCI_DMA_TODEVICE and below as well. - */ - busaddr = pci_map_page(hostdata->pci_dev, - virt_to_page(&hostdata->control_block), - offset_in_page(&hostdata->control_block), - sizeof(hostdata->control_block), - PCI_DMA_BIDIRECTIONAL); - - param[0] = MBOX_INIT_FIRMWARE; - param[2] = (u_short) (pci64_dma_lo32(busaddr) >> 16); - param[3] = (u_short) (pci64_dma_lo32(busaddr) & 0xffff); - param[4] = 0; - param[5] = 0; - param[6] = (u_short) (pci64_dma_hi32(busaddr) >> 16); - param[7] = (u_short) (pci64_dma_hi32(busaddr) & 0xffff); - isp2x00_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id, param[0]); - pci_unmap_page(hostdata->pci_dev, busaddr, - sizeof(hostdata->control_block), - PCI_DMA_BIDIRECTIONAL); - return 1; - } - param[0] = MBOX_GET_FIRMWARE_STATE; - isp2x00_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id, param[0]); - pci_unmap_page(hostdata->pci_dev, busaddr, - sizeof(hostdata->control_block), - PCI_DMA_BIDIRECTIONAL); - return 1; - } - - pci_unmap_page(hostdata->pci_dev, busaddr, - sizeof(hostdata->control_block), - PCI_DMA_BIDIRECTIONAL); - LEAVE("isp2x00_reset_hardware"); - - return 0; -} - -#ifdef USE_NVRAM_DEFAULTS - -static int isp2x00_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *control_block) -{ - - u_short value; - if (isp2x00_read_nvram_word(host, 0) != 0x5349) - return 1; - - value = isp2x00_read_nvram_word(host, 8); - control_block->node_name[0] = cpu_to_le16(isp2x00_read_nvram_word(host, 9)); - control_block->node_name[1] = cpu_to_le16(isp2x00_read_nvram_word(host, 10)); - control_block->node_name[2] = cpu_to_le16(isp2x00_read_nvram_word(host, 11)); - control_block->node_name[3] = cpu_to_le16(isp2x00_read_nvram_word(host, 12)); - control_block->hard_addr = cpu_to_le16(isp2x00_read_nvram_word(host, 13)); - - return 0; - -} - -#endif - -static int isp2x00_init(struct Scsi_Host *sh) -{ - u_long io_base; - struct isp2x00_hostdata *hostdata; - u_char revision; - u_int irq; - u_short command; - struct pci_dev *pdev; - - - ENTER("isp2x00_init"); - - hostdata = (struct isp2x00_hostdata *) sh->hostdata; - pdev = hostdata->pci_dev; - - if (pci_read_config_word(pdev, PCI_COMMAND, &command) - || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision)) { - printk("qlogicfc%d : error reading PCI configuration\n", hostdata->host_id); - return 1; - } - io_base = pci_resource_start(pdev, 0); - irq = pdev->irq; - - - if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) { - printk("qlogicfc%d : 0x%04x is not QLogic vendor ID\n", hostdata->host_id, - pdev->vendor); - return 1; - } - if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100 && pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2200) { - printk("qlogicfc%d : 0x%04x does not match ISP2100 or ISP2200 device id\n", hostdata->host_id, - pdev->device); - return 1; - } - if (!(command & PCI_COMMAND_IO) || - !(pdev->resource[0].flags & IORESOURCE_IO)) { - printk("qlogicfc%d : i/o mapping is disabled\n", hostdata->host_id); - return 1; - } - - pci_set_master(pdev); - if (revision != ISP2100_REV_ID1 && revision != ISP2100_REV_ID3 && revision != ISP2200_REV_ID5) - printk("qlogicfc%d : new isp2x00 revision ID (%d)\n", hostdata->host_id, revision); - - - hostdata->revision = revision; - - sh->irq = irq; - sh->io_port = io_base; - - LEAVE("isp2x00_init"); - - return 0; -} - -#if USE_NVRAM_DEFAULTS - -#define NVRAM_DELAY() udelay(10) /* 10 microsecond delay */ - - -u_short isp2x00_read_nvram_word(struct Scsi_Host * host, u_short byte) -{ - int i; - u_short value, output, input; - - outw(0x2, host->io_port + PCI_NVRAM); - NVRAM_DELAY(); - outw(0x3, host->io_port + PCI_NVRAM); - NVRAM_DELAY(); - - byte &= 0xff; - byte |= 0x0600; - for (i = 10; i >= 0; i--) { - output = ((byte >> i) & 0x1) ? 0x4 : 0x0; - outw(output | 0x2, host->io_port + PCI_NVRAM); - NVRAM_DELAY(); - outw(output | 0x3, host->io_port + PCI_NVRAM); - NVRAM_DELAY(); - outw(output | 0x2, host->io_port + PCI_NVRAM); - NVRAM_DELAY(); - } - - for (i = 0xf, value = 0; i >= 0; i--) { - value <<= 1; - outw(0x3, host->io_port + PCI_NVRAM); - NVRAM_DELAY(); - input = inw(host->io_port + PCI_NVRAM); - NVRAM_DELAY(); - outw(0x2, host->io_port + PCI_NVRAM); - NVRAM_DELAY(); - if (input & 0x8) - value |= 1; - } - - outw(0x0, host->io_port + PCI_NVRAM); - NVRAM_DELAY(); - - return value; -} - - -#endif /* USE_NVRAM_DEFAULTS */ - - - -/* - * currently, this is only called during initialization or abort/reset, - * at which times interrupts are disabled, so polling is OK, I guess... - */ -static int isp2x00_mbox_command(struct Scsi_Host *host, u_short param[]) -{ - int loop_count; - struct isp2x00_hostdata *hostdata = (struct isp2x00_hostdata *) host->hostdata; - - if (mbox_param[param[0]] == 0 || hostdata->adapter_state == AS_FIRMWARE_DEAD) - return 1; - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080) { - barrier(); - cpu_relax(); - } - if (!loop_count) { - printk("qlogicfc%d : mbox_command loop timeout #1\n", hostdata->host_id); - param[0] = 0x4006; - hostdata->adapter_state = AS_FIRMWARE_DEAD; - return 1; - } - hostdata->mbox_done = 0; - - if (mbox_param[param[0]] == 0) - printk("qlogicfc%d : invalid mbox command\n", hostdata->host_id); - - if (mbox_param[param[0]] & 0x80) - outw(param[7], host->io_port + MBOX7); - if (mbox_param[param[0]] & 0x40) - outw(param[6], host->io_port + MBOX6); - if (mbox_param[param[0]] & 0x20) - outw(param[5], host->io_port + MBOX5); - if (mbox_param[param[0]] & 0x10) - outw(param[4], host->io_port + MBOX4); - if (mbox_param[param[0]] & 0x08) - outw(param[3], host->io_port + MBOX3); - if (mbox_param[param[0]] & 0x04) - outw(param[2], host->io_port + MBOX2); - if (mbox_param[param[0]] & 0x02) - outw(param[1], host->io_port + MBOX1); - if (mbox_param[param[0]] & 0x01) - outw(param[0], host->io_port + MBOX0); - - - outw(HCCR_SET_HOST_INTR, host->io_port + HOST_HCCR); - - while (1) { - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && !(inw(host->io_port + PCI_INTER_STS) & 0x08)) { - barrier(); - cpu_relax(); - } - - if (!loop_count) { - hostdata->adapter_state = AS_FIRMWARE_DEAD; - printk("qlogicfc%d : mbox_command loop timeout #2\n", hostdata->host_id); - break; - } - isp2x00_intr_handler(host->irq, host, NULL); - - if (hostdata->mbox_done == 1) - break; - - } - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && inw(host->io_port + MBOX0) == 0x04) { - barrier(); - cpu_relax(); - } - if (!loop_count) - printk("qlogicfc%d : mbox_command loop timeout #3\n", hostdata->host_id); - - param[7] = inw(host->io_port + MBOX7); - param[6] = inw(host->io_port + MBOX6); - param[5] = inw(host->io_port + MBOX5); - param[4] = inw(host->io_port + MBOX4); - param[3] = inw(host->io_port + MBOX3); - param[2] = inw(host->io_port + MBOX2); - param[1] = inw(host->io_port + MBOX1); - param[0] = inw(host->io_port + MBOX0); - - - outw(0x0, host->io_port + PCI_SEMAPHORE); - - if (inw(host->io_port + HOST_HCCR) & 0x0080) { - hostdata->adapter_state = AS_FIRMWARE_DEAD; - printk("qlogicfc%d : mbox op is still pending\n", hostdata->host_id); - } - return 0; -} - -#if DEBUG_ISP2x00_INTR - -void isp2x00_print_status_entry(struct Status_Entry *status) -{ - printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", - status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); - printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n", - le16_to_cpu(status->scsi_status), le16_to_cpu(status->completion_status)); - printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", - le16_to_cpu(status->state_flags), le16_to_cpu(status->status_flags)); - printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n", - le16_to_cpu(status->res_info_len), le16_to_cpu(status->req_sense_len)); - printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", le32_to_cpu(status->residual), status->res_info[3]); - -} - -#endif /* DEBUG_ISP2x00_INTR */ - - -#if DEBUG_ISP2x00 - -void isp2x00_print_scsi_cmd(Scsi_Cmnd * cmd) -{ - int i; - - printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", - cmd->target, cmd->lun, cmd->cmd_len); - printk("qlogicfc : command = "); - for (i = 0; i < cmd->cmd_len; i++) - printk("0x%02x ", cmd->cmnd[i]); - printk("\n"); -} - -#endif /* DEBUG_ISP2x00 */ - -MODULE_LICENSE("GPL"); - -static struct scsi_host_template driver_template = { - .detect = isp2x00_detect, - .release = isp2x00_release, - .info = isp2x00_info, - .queuecommand = isp2x00_queuecommand, - .eh_abort_handler = isp2x00_abort, - .bios_param = isp2x00_biosparam, - .can_queue = QLOGICFC_REQ_QUEUE_LEN, - .this_id = -1, - .sg_tablesize = QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN), - .cmd_per_lun = QLOGICFC_CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/drivers/scsi/qlogicfc_asm.c b/drivers/scsi/qlogicfc_asm.c deleted file mode 100644 index b1d45102d388..000000000000 --- a/drivers/scsi/qlogicfc_asm.c +++ /dev/null @@ -1,9751 +0,0 @@ -/************************************************************************ - * * - * --- ISP2100 Fabric Initiator/Target Firmware --- * - * with expanded LUN addressing * - * and FcTape (FCP-2) support * - * * - * * - ************************************************************************ - Copyright (C) 2000 and 2001 Qlogic Corporation - (www.qlogic.com) - - 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. -************************************************************************/ - -/* - * Firmware Version 1.19.16 (10:36 Nov 02, 2000) - */ - -static unsigned short risc_code_addr01 = 0x1000 ; - -static unsigned short risc_code_length2100 = 0x9260; -static unsigned short risc_code2100[] = { - 0x0078, 0x102d, 0x0000, 0x9260, 0x0000, 0x0001, 0x0013, 0x0010, - 0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, - 0x3920, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, - 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3231, 0x3030, 0x2046, 0x6972, - 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, - 0x312e, 0x3139, 0x2020, 0x2020, 0x2400, 0x2091, 0x2000, 0x20c1, - 0x0021, 0x2039, 0xffff, 0x2019, 0xaaaa, 0x2760, 0x2069, 0x7fff, - 0x20c1, 0x0020, 0x2c2c, 0x2d34, 0x2762, 0x236a, 0x2c24, 0x2d04, - 0x266a, 0x2562, 0xa406, 0x00c0, 0x1052, 0x20c1, 0x0021, 0x2c2c, - 0x2362, 0x2c04, 0x2562, 0xa306, 0x0040, 0x1052, 0x20c1, 0x0020, - 0x2039, 0x8fff, 0x20a1, 0xaa00, 0x2708, 0x810d, 0x810d, 0x810d, - 0x810d, 0xa18c, 0x000f, 0x2001, 0x000a, 0xa112, 0xa00e, 0x21a8, - 0x41a4, 0x3400, 0x8211, 0x00c0, 0x105f, 0x2708, 0x3400, 0xa102, - 0x0040, 0x106f, 0x0048, 0x106f, 0x20a8, 0xa00e, 0x41a4, 0x20a1, - 0xa260, 0x2009, 0x0000, 0x20a9, 0x07a0, 0x41a4, 0x3400, 0x20c9, - 0xa7ff, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x255d, - 0x2051, 0xa300, 0x2a70, 0x775e, 0xa786, 0x8fff, 0x0040, 0x1092, - 0x705b, 0xca00, 0x7057, 0xc9f1, 0x7063, 0x0200, 0x7067, 0x0200, - 0x0078, 0x109a, 0x7057, 0xba01, 0x7063, 0x0100, 0x7067, 0x0100, - 0x705b, 0xba00, 0x1078, 0x12df, 0x1078, 0x13c0, 0x1078, 0x1569, - 0x1078, 0x1ca4, 0x1078, 0x4229, 0x1078, 0x74cf, 0x1078, 0x134b, - 0x1078, 0x2a3f, 0x1078, 0x4da2, 0x1078, 0x48b2, 0x1078, 0x57df, - 0x1078, 0x21f7, 0x1078, 0x5abf, 0x1078, 0x5369, 0x1078, 0x210d, - 0x1078, 0x21d4, 0x2091, 0x3009, 0x7823, 0x0000, 0x0090, 0x10cf, - 0x7820, 0xa086, 0x0002, 0x00c0, 0x10cf, 0x7823, 0x4000, 0x0068, - 0x10c7, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, - 0x7003, 0x0000, 0x2001, 0x017f, 0x2003, 0x0000, 0x2a70, 0x7000, - 0xa08e, 0x0003, 0x00c0, 0x10ef, 0x1078, 0x35bc, 0x1078, 0x2a67, - 0x1078, 0x4df2, 0x1078, 0x4a75, 0x2009, 0x0100, 0x2104, 0xa082, - 0x0002, 0x0048, 0x10f3, 0x1078, 0x57fb, 0x0078, 0x10d6, 0x1079, - 0x10f7, 0x0078, 0x10dc, 0x1078, 0x6fa9, 0x0078, 0x10eb, 0x1101, - 0x1102, 0x11be, 0x10ff, 0x1246, 0x12dc, 0x12dd, 0x12de, 0x1078, - 0x1328, 0x007c, 0x127e, 0x0f7e, 0x2091, 0x8000, 0x7000, 0xa086, - 0x0001, 0x00c0, 0x1198, 0x1078, 0x3a43, 0x2079, 0x0100, 0x7844, - 0xa005, 0x00c0, 0x1198, 0x2011, 0x4129, 0x1078, 0x58d4, 0x1078, - 0x1ab1, 0x780f, 0x00ff, 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011, - 0x8010, 0x73c0, 0x1078, 0x3579, 0x2001, 0xffff, 0x1078, 0x5975, - 0x7238, 0xc284, 0x723a, 0x2001, 0xa30c, 0x2014, 0xc2ac, 0x2202, - 0x1078, 0x6db5, 0x2011, 0x0004, 0x1078, 0x8a59, 0x1078, 0x47ce, - 0x1078, 0x4211, 0x0040, 0x1144, 0x7083, 0x0001, 0x70bb, 0x0000, - 0x1078, 0x3bf5, 0x0078, 0x1198, 0x1078, 0x4897, 0x0040, 0x114d, - 0x7a0c, 0xc2b4, 0x7a0e, 0x0078, 0x1159, 0x1078, 0x8ddf, 0x70c8, - 0xd09c, 0x00c0, 0x1159, 0x7094, 0xa005, 0x0040, 0x1159, 0x1078, - 0x41f5, 0x70d3, 0x0000, 0x70cf, 0x0000, 0x72c8, 0x2079, 0xa351, - 0x7804, 0xd0ac, 0x0040, 0x1165, 0xc295, 0x72ca, 0xa296, 0x0004, - 0x0040, 0x1186, 0x2011, 0x0001, 0x1078, 0x8a59, 0x708f, 0x0000, - 0x7093, 0xffff, 0x7003, 0x0002, 0x0f7f, 0x1078, 0x260d, 0x2011, - 0x0005, 0x1078, 0x6ef2, 0x1078, 0x6109, 0x0c7e, 0x2061, 0x0100, - 0x60e3, 0x0008, 0x0c7f, 0x127f, 0x0078, 0x119a, 0x708f, 0x0000, - 0x7093, 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, 0x1078, 0x6ef2, - 0x1078, 0x6109, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f, - 0x0f7f, 0x127f, 0x007c, 0x0c7e, 0x20a9, 0x0082, 0x2009, 0x007e, - 0x017e, 0x027e, 0x037e, 0x2110, 0x027e, 0x2019, 0x0029, 0x1078, - 0x71e0, 0x027f, 0x1078, 0xa190, 0x037f, 0x027f, 0x017f, 0x1078, - 0x2921, 0x8108, 0x00f0, 0x11a0, 0x0c7f, 0x706b, 0x0000, 0x706c, - 0xa084, 0x00ff, 0x706e, 0x7097, 0x0000, 0x007c, 0x127e, 0x2091, - 0x8000, 0x7000, 0xa086, 0x0002, 0x00c0, 0x1244, 0x7090, 0xa086, - 0xffff, 0x0040, 0x11d1, 0x1078, 0x260d, 0x1078, 0x6109, 0x0078, - 0x1244, 0x70c8, 0xd09c, 0x0040, 0x11fd, 0xd084, 0x0040, 0x11fd, - 0x0f7e, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, 0x0f7f, 0xd08c, - 0x0040, 0x11fd, 0x70cc, 0xa086, 0xffff, 0x0040, 0x11f9, 0x1078, - 0x278a, 0x1078, 0x6109, 0x70c8, 0xd094, 0x00c0, 0x1244, 0x2011, - 0x0001, 0x2019, 0x0000, 0x1078, 0x27c2, 0x1078, 0x6109, 0x0078, - 0x1244, 0x70d0, 0xa005, 0x00c0, 0x1244, 0x708c, 0xa005, 0x00c0, - 0x1244, 0x1078, 0x4897, 0x00c0, 0x1244, 0x2001, 0xa352, 0x2004, - 0xd0ac, 0x0040, 0x1227, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009, - 0x0000, 0x017e, 0x1078, 0x4501, 0x00c0, 0x121a, 0x6000, 0xd0ec, - 0x00c0, 0x1222, 0x017f, 0x8108, 0x00f0, 0x1211, 0x0c7f, 0x157f, - 0x0078, 0x1227, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x1244, 0x7003, - 0x0003, 0x7093, 0xffff, 0x2001, 0x0000, 0x1078, 0x2480, 0x1078, - 0x35f7, 0x2001, 0xa5ac, 0x2004, 0xa086, 0x0005, 0x00c0, 0x123c, - 0x2011, 0x0000, 0x1078, 0x6ef2, 0x2011, 0x0000, 0x1078, 0x6efc, - 0x1078, 0x6109, 0x1078, 0x61d3, 0x127f, 0x007c, 0x017e, 0x0f7e, - 0x127e, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0x00f7, 0x1078, - 0x41de, 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0040, - 0x125b, 0x7827, 0x0040, 0xd19c, 0x0040, 0x1260, 0x7827, 0x0008, - 0x007e, 0x037e, 0x157e, 0xa006, 0x1078, 0x5975, 0x7900, 0xa18a, - 0x0003, 0x0050, 0x1289, 0x7954, 0xd1ac, 0x00c0, 0x1289, 0x2009, - 0x00f8, 0x1078, 0x41de, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, - 0x09c4, 0x7820, 0xd09c, 0x00c0, 0x1281, 0x7824, 0xd0ac, 0x00c0, - 0x12ca, 0x00f0, 0x1279, 0x2001, 0x0001, 0x1078, 0x2480, 0x0078, - 0x12d5, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0050, 0x00e0, - 0x128f, 0x2091, 0x6000, 0x00f0, 0x128f, 0x7853, 0x0400, 0x782f, - 0x0000, 0x2009, 0x00f8, 0x1078, 0x41de, 0x20a9, 0x000e, 0x0005, - 0x00f0, 0x129f, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, 0x0010, - 0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, 0x12b4, - 0x7824, 0xd0ac, 0x00c0, 0x12ca, 0x8319, 0x00c0, 0x12aa, 0x2009, - 0xa331, 0x2104, 0x8000, 0x200a, 0xa084, 0xfff0, 0x0040, 0x12c4, - 0x200b, 0x0000, 0x1078, 0x251e, 0x2001, 0x0001, 0x1078, 0x2480, - 0x0078, 0x12d3, 0x2001, 0xa331, 0x2003, 0x0000, 0x7828, 0xc09d, - 0x782a, 0x7827, 0x0048, 0x7853, 0x0400, 0x157f, 0x037f, 0x007f, - 0x127f, 0x0f7f, 0x017f, 0x007c, 0x007c, 0x007c, 0x007c, 0x2a70, - 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, 0x12eb, 0x704f, - 0xffff, 0x0078, 0x12ed, 0x704f, 0x0000, 0x7053, 0xffff, 0x706b, - 0x0000, 0x706f, 0x0000, 0x1078, 0x8ddf, 0x2061, 0xa58c, 0x6003, - 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013, - 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061, - 0xa594, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f, - 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f, - 0x0000, 0x2061, 0xa5a3, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b, - 0x4943, 0x600f, 0x2020, 0x2001, 0xa325, 0x2003, 0x0000, 0x007c, - 0x2091, 0x8000, 0x0068, 0x132a, 0x007e, 0x017e, 0x2079, 0x0000, - 0x7818, 0xd084, 0x00c0, 0x1330, 0x017f, 0x792e, 0x007f, 0x782a, - 0x007f, 0x7826, 0x3900, 0x783a, 0x7823, 0x8002, 0x781b, 0x0001, - 0x2091, 0x5000, 0x2091, 0x4080, 0x2079, 0xa300, 0x7803, 0x0005, - 0x0078, 0x1348, 0x007c, 0x2071, 0xa300, 0x7158, 0x712e, 0x2021, - 0x0001, 0xa190, 0x002d, 0xa298, 0x002d, 0x0048, 0x1361, 0x705c, - 0xa302, 0x00c8, 0x1361, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078, - 0x1353, 0x200b, 0x0000, 0x74a6, 0x74aa, 0x007c, 0x0e7e, 0x127e, - 0x2091, 0x8000, 0x2071, 0xa300, 0x70a8, 0xa0ea, 0x0010, 0x00c8, - 0x1374, 0xa06e, 0x0078, 0x137e, 0x8001, 0x70aa, 0x702c, 0x2068, - 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f, - 0x007c, 0x0e7e, 0x2071, 0xa300, 0x127e, 0x2091, 0x8000, 0x70a8, - 0x8001, 0x00c8, 0x138e, 0xa06e, 0x0078, 0x1397, 0x70aa, 0x702c, - 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, - 0x0e7f, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa300, - 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a8, 0x8000, 0x70aa, 0x127f, - 0x0e7f, 0x007c, 0x8dff, 0x0040, 0x13b6, 0x6804, 0x6807, 0x0000, - 0x007e, 0x1078, 0x139a, 0x0d7f, 0x0078, 0x13aa, 0x007c, 0x0e7e, - 0x2071, 0xa300, 0x70a8, 0xa08a, 0x0010, 0xa00d, 0x0e7f, 0x007c, - 0x0e7e, 0x2071, 0xa5d0, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f, - 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x0e7f, - 0x007c, 0x0e7e, 0x2270, 0x700b, 0x0000, 0x2071, 0xa5d0, 0x7018, - 0xa088, 0xa5d9, 0x220a, 0x8000, 0xa084, 0x0007, 0x701a, 0x7004, - 0xa005, 0x00c0, 0x13e9, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13fa, - 0x0f7f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa5d0, 0x7004, 0xa005, - 0x00c0, 0x13f8, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13fa, 0x0f7f, - 0x0e7f, 0x007c, 0x7000, 0x0079, 0x13fd, 0x1401, 0x146b, 0x1488, - 0x1488, 0x7018, 0x711c, 0xa106, 0x00c0, 0x1409, 0x7007, 0x0000, - 0x007c, 0x0d7e, 0xa180, 0xa5d9, 0x2004, 0x700a, 0x2068, 0x8108, - 0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828, - 0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c, - 0x7016, 0x6804, 0x0d7f, 0xd084, 0x0040, 0x142b, 0x7007, 0x0001, - 0x1078, 0x1430, 0x007c, 0x7007, 0x0002, 0x1078, 0x1446, 0x007c, - 0x017e, 0x027e, 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, - 0x143b, 0x2110, 0xa006, 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, - 0x0020, 0x7803, 0x0041, 0x027f, 0x017f, 0x007c, 0x017e, 0x027e, - 0x137e, 0x147e, 0x157e, 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, - 0x0026, 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x145a, - 0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, - 0x0020, 0x3300, 0x7016, 0x7803, 0x0001, 0x157f, 0x147f, 0x137f, - 0x027f, 0x017f, 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0xa3f9, - 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, - 0x2091, 0x8000, 0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084, - 0x7002, 0x700b, 0xa3f4, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, - 0x137e, 0x147e, 0x157e, 0x2001, 0xa428, 0x209c, 0x20a1, 0x0014, - 0x7803, 0x0026, 0x2001, 0xa429, 0x20ac, 0x53a6, 0x2099, 0xa42a, - 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, - 0x2091, 0x8000, 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c, - 0x7002, 0x700b, 0xa425, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, - 0x017e, 0x0e7e, 0x2071, 0xa5d0, 0x0f7e, 0x2079, 0x0010, 0x7904, - 0x7803, 0x0002, 0xd1fc, 0x0040, 0x14c2, 0xa18c, 0x0700, 0x7004, - 0x1079, 0x14c6, 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x13fa, 0x14ce, - 0x14fb, 0x1523, 0x1556, 0x14cc, 0x0078, 0x14cc, 0xa18c, 0x0700, - 0x00c0, 0x14f4, 0x137e, 0x147e, 0x157e, 0x7014, 0x20a0, 0x2099, - 0x0014, 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, - 0x157f, 0x147f, 0x137f, 0x700c, 0xa005, 0x0040, 0x1510, 0x1078, - 0x1430, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007, - 0x0000, 0x1078, 0x13fa, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, - 0x0200, 0x0078, 0x14ef, 0xa18c, 0x0700, 0x00c0, 0x1506, 0x700c, - 0xa005, 0x0040, 0x1510, 0x1078, 0x1446, 0x007c, 0x7008, 0xa080, - 0x0002, 0x2003, 0x0200, 0x7007, 0x0000, 0x1078, 0x13fa, 0x007c, - 0x0d7e, 0x7008, 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, - 0x682e, 0x783c, 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, - 0x1078, 0x13fa, 0x007c, 0xa18c, 0x0700, 0x00c0, 0x1550, 0x137e, - 0x147e, 0x157e, 0x2001, 0xa3f7, 0x2004, 0xa080, 0x000d, 0x20a0, - 0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, 0x53a5, 0x2001, - 0xa3f9, 0x2004, 0xd0bc, 0x0040, 0x1546, 0x2001, 0xa402, 0x2004, - 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, 0x53a5, 0x157f, 0x147f, - 0x137f, 0x7007, 0x0000, 0x1078, 0x4e9b, 0x1078, 0x13fa, 0x007c, - 0x2011, 0x8003, 0x1078, 0x3579, 0x0078, 0x1554, 0xa18c, 0x0700, - 0x00c0, 0x1563, 0x2001, 0xa427, 0x2003, 0x0100, 0x7007, 0x0000, - 0x1078, 0x13fa, 0x007c, 0x2011, 0x8004, 0x1078, 0x3579, 0x0078, - 0x1567, 0x127e, 0x2091, 0x2100, 0x2079, 0x0030, 0x2071, 0xa5e1, - 0x7803, 0x0004, 0x7003, 0x0000, 0x700f, 0xa5e7, 0x7013, 0xa5e7, - 0x780f, 0x0076, 0x7803, 0x0004, 0x127f, 0x007c, 0x6934, 0xa184, - 0x0007, 0x0079, 0x1583, 0x158b, 0x15d1, 0x158b, 0x158b, 0x158b, - 0x15b6, 0x159a, 0x158f, 0xa085, 0x0001, 0x0078, 0x15eb, 0x684c, - 0xd0bc, 0x0040, 0x158b, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, - 0x0078, 0x15d9, 0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x158b, - 0x684c, 0xd0bc, 0x0040, 0x158b, 0x6860, 0x682e, 0x685c, 0x682a, - 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, - 0x2015, 0x2004, 0x6832, 0x6858, 0x0078, 0x15e1, 0xa18c, 0x00ff, - 0xa186, 0x0015, 0x00c0, 0x158b, 0x684c, 0xd0ac, 0x0040, 0x158b, - 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, - 0x2015, 0x2004, 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078, - 0x15e1, 0x684c, 0xd0ac, 0x0040, 0x158b, 0xa006, 0x682e, 0x682a, - 0x6858, 0xa18c, 0x000f, 0xa188, 0x2015, 0x210c, 0x6932, 0x2d08, - 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c, - 0x6912, 0x6980, 0x6916, 0x007c, 0x20e1, 0x0007, 0x20e1, 0x2000, - 0x2001, 0x020a, 0x2004, 0x82ff, 0x0040, 0x160e, 0xa280, 0x0004, - 0x0d7e, 0x206c, 0x684c, 0xd0dc, 0x00c0, 0x160a, 0x1078, 0x157e, - 0x0040, 0x160a, 0x0d7f, 0xa280, 0x0000, 0x2003, 0x0002, 0xa016, - 0x0078, 0x160e, 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, - 0x037e, 0x027e, 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, - 0xa005, 0x00c0, 0x1622, 0x7206, 0x2001, 0x1643, 0x007e, 0x2260, - 0x0078, 0x17be, 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, - 0x8108, 0xa182, 0xa602, 0x0048, 0x162f, 0x2009, 0xa5e7, 0x710e, - 0x7010, 0xa102, 0xa082, 0x0009, 0x0040, 0x163a, 0xa080, 0x001b, - 0x00c0, 0x163d, 0x2009, 0x0138, 0x200a, 0x7000, 0xa005, 0x00c0, - 0x1643, 0x1078, 0x179f, 0x127f, 0x007c, 0x127e, 0x027e, 0x037e, - 0x0c7e, 0x007e, 0x2091, 0x2100, 0x007f, 0x047f, 0x037f, 0x027f, - 0x0d7e, 0x0c7e, 0x2460, 0x6110, 0x2168, 0x6a62, 0x6b5e, 0xa005, - 0x0040, 0x16cf, 0x6808, 0xa005, 0x0040, 0x173c, 0x7000, 0xa005, - 0x00c0, 0x1664, 0x0078, 0x16c4, 0x700c, 0x7110, 0xa106, 0x00c0, - 0x1745, 0x7004, 0xa406, 0x00c0, 0x16c4, 0x2001, 0x0005, 0x2004, - 0xd08c, 0x0040, 0x1681, 0x047e, 0x1078, 0x18e2, 0x047f, 0x2460, - 0x6010, 0xa080, 0x0002, 0x2004, 0xa005, 0x0040, 0x173c, 0x0078, - 0x165e, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x166d, 0x7804, - 0xa084, 0x6000, 0x0040, 0x1692, 0xa086, 0x6000, 0x0040, 0x1692, - 0x0078, 0x166d, 0x7100, 0xa186, 0x0002, 0x00c0, 0x16b2, 0x0e7e, - 0x2b68, 0x6818, 0x2060, 0x1078, 0x1fea, 0x2804, 0xac70, 0x6034, - 0xd09c, 0x00c0, 0x16a7, 0x7108, 0x720c, 0x0078, 0x16a9, 0x7110, - 0x7214, 0x6810, 0xa100, 0x6812, 0x6814, 0xa201, 0x6816, 0x0e7f, - 0x0078, 0x16b6, 0xa186, 0x0001, 0x00c0, 0x16be, 0x7820, 0x6910, - 0xa100, 0x6812, 0x7824, 0x6914, 0xa101, 0x6816, 0x7803, 0x0004, - 0x7003, 0x0000, 0x7004, 0x2060, 0x6100, 0xa18e, 0x0004, 0x00c0, - 0x1745, 0x2009, 0x0048, 0x1078, 0x756c, 0x0078, 0x1745, 0x6808, - 0xa005, 0x0040, 0x173c, 0x7000, 0xa005, 0x00c0, 0x16d9, 0x0078, - 0x173c, 0x700c, 0x7110, 0xa106, 0x00c0, 0x16e2, 0x7004, 0xa406, - 0x00c0, 0x173c, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, 0x16f6, - 0x047e, 0x1078, 0x18e2, 0x047f, 0x2460, 0x6010, 0xa080, 0x0002, - 0x2004, 0xa005, 0x0040, 0x173c, 0x0078, 0x16d3, 0x2001, 0x0207, - 0x2004, 0xd09c, 0x00c0, 0x16e2, 0x2001, 0x0005, 0x2004, 0xd08c, - 0x00c0, 0x16e8, 0x7804, 0xa084, 0x6000, 0x0040, 0x170d, 0xa086, - 0x6000, 0x0040, 0x170d, 0x0078, 0x16e2, 0x7007, 0x0000, 0xa016, - 0x2218, 0x7000, 0xa08e, 0x0001, 0x0040, 0x172e, 0xa08e, 0x0002, - 0x00c0, 0x173c, 0x0c7e, 0x0e7e, 0x6818, 0x2060, 0x1078, 0x1fea, - 0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0, 0x172a, 0x7308, 0x720c, - 0x0078, 0x172c, 0x7310, 0x7214, 0x0e7f, 0x0c7f, 0x7820, 0xa318, - 0x7824, 0xa211, 0x6810, 0xa300, 0x6812, 0x6814, 0xa201, 0x6816, - 0x7803, 0x0004, 0x7003, 0x0000, 0x6100, 0xa18e, 0x0004, 0x00c0, - 0x1745, 0x2009, 0x0048, 0x1078, 0x756c, 0x0c7f, 0x0d7f, 0x127f, - 0x007c, 0x0f7e, 0x0e7e, 0x027e, 0x037e, 0x047e, 0x1078, 0x1af7, - 0x027e, 0x2071, 0xa5e1, 0x7000, 0xa086, 0x0000, 0x0040, 0x1790, - 0x7004, 0xac06, 0x00c0, 0x1781, 0x2079, 0x0030, 0x7000, 0xa086, - 0x0003, 0x0040, 0x1781, 0x7804, 0xd0fc, 0x00c0, 0x177d, 0x2001, - 0x0207, 0x2004, 0xd09c, 0x00c0, 0x1763, 0x7803, 0x0004, 0x7804, - 0xd0ac, 0x00c0, 0x176f, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, - 0x0003, 0x7007, 0x0000, 0x0078, 0x1781, 0x1078, 0x18e2, 0x0078, - 0x1753, 0x157e, 0x20a9, 0x0009, 0x2009, 0xa5e7, 0x2104, 0xac06, - 0x00c0, 0x178b, 0x200a, 0xa188, 0x0003, 0x00f0, 0x1786, 0x157f, - 0x027f, 0x2001, 0x015d, 0x201c, 0x831a, 0x2302, 0x2001, 0x0138, - 0x2202, 0x047f, 0x037f, 0x027f, 0x0e7f, 0x0f7f, 0x007c, 0x700c, - 0x7110, 0xa106, 0x00c0, 0x17a7, 0x7003, 0x0000, 0x007c, 0x2104, - 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, 0x8108, 0xa182, - 0xa602, 0x0048, 0x17b5, 0x2009, 0xa5e7, 0x7112, 0x700c, 0xa106, - 0x00c0, 0x17be, 0x2001, 0x0138, 0x2003, 0x0008, 0x8cff, 0x00c0, - 0x17c5, 0x1078, 0x1b22, 0x0078, 0x1823, 0x6010, 0x2068, 0x2d58, - 0x6828, 0xa406, 0x00c0, 0x17d0, 0x682c, 0xa306, 0x0040, 0x17fe, - 0x601c, 0xa086, 0x0008, 0x0040, 0x17fe, 0x6024, 0xd0f4, 0x00c0, - 0x17fa, 0xd0d4, 0x0040, 0x17f6, 0x6038, 0xa402, 0x6034, 0xa303, - 0x0040, 0x17e4, 0x00c8, 0x17f6, 0x643a, 0x6336, 0x6c2a, 0x6b2e, - 0x047e, 0x037e, 0x2400, 0x6c7c, 0xa402, 0x6812, 0x2300, 0x6b80, - 0xa303, 0x6816, 0x037f, 0x047f, 0x0078, 0x17fa, 0x1078, 0x8d8e, - 0x0040, 0x17c1, 0x1078, 0x2035, 0x00c0, 0x17c1, 0x0c7e, 0x7004, - 0x2060, 0x6024, 0xc0d4, 0x6026, 0x0c7f, 0x684c, 0xd0f4, 0x0040, - 0x180f, 0x6817, 0xffff, 0x6813, 0xffff, 0x0078, 0x17c1, 0x6824, - 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, - 0x2009, 0x0011, 0x1078, 0x1824, 0x0040, 0x1822, 0x2009, 0x0001, - 0x1078, 0x1824, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x18bb, 0xa03e, - 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x1846, 0xd0f4, 0x00c0, 0x1856, - 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1836, 0x189d, 0x185d, - 0x185d, 0x189d, 0x189d, 0x1895, 0x189d, 0x185d, 0x189d, 0x1863, - 0x1863, 0x189d, 0x189d, 0x189d, 0x188c, 0x1863, 0xc0fc, 0x6852, - 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x0d7e, 0xd99c, 0x0040, 0x18a0, - 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x18a0, 0xc0f4, 0x6852, - 0x6b6c, 0x6a70, 0x0d7e, 0x0078, 0x18a7, 0x6b08, 0x6a0c, 0x6d00, - 0x6c04, 0x0078, 0x18a0, 0x7b0c, 0xd3bc, 0x0040, 0x1884, 0x7004, - 0x0e7e, 0x2070, 0x701c, 0x0e7f, 0xa086, 0x0008, 0x00c0, 0x1884, - 0x7b08, 0xa39c, 0x0fff, 0x2d20, 0x0d7f, 0x0d7e, 0x6a14, 0x82ff, - 0x00c0, 0x187f, 0x6810, 0xa302, 0x0048, 0x187f, 0x6b10, 0x2011, - 0x0000, 0x2468, 0x0078, 0x1886, 0x6b10, 0x6a14, 0x6d00, 0x6c04, - 0x6f08, 0x6e0c, 0x0078, 0x18a0, 0x0d7f, 0x0d7e, 0x6834, 0xa084, - 0x00ff, 0xa086, 0x001e, 0x00c0, 0x189d, 0x0d7f, 0x1078, 0x1fd1, - 0x00c0, 0x1824, 0xa00e, 0x0078, 0x18bb, 0x0d7f, 0x1078, 0x1328, - 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, - 0x8000, 0x7002, 0x0d7f, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, - 0x682e, 0x2300, 0x6b10, 0xa302, 0x6812, 0x2200, 0x6a14, 0xa203, - 0x6816, 0x1078, 0x1fd1, 0x007c, 0x1078, 0x1328, 0x1078, 0x1c52, - 0x7004, 0x2060, 0x0d7e, 0x6010, 0x2068, 0x7003, 0x0000, 0x1078, - 0x1ac6, 0x1078, 0x8a44, 0x0040, 0x18db, 0x6808, 0x8001, 0x680a, - 0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff, 0x682f, 0xffff, - 0x6850, 0xc0bd, 0x6852, 0x0d7f, 0x1078, 0x8758, 0x0078, 0x1aad, - 0x1078, 0x1328, 0x127e, 0x2091, 0x2100, 0x007e, 0x017e, 0x2b68, - 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0, - 0x18be, 0xa184, 0x0003, 0xa086, 0x0003, 0x0040, 0x18e0, 0x7000, - 0x0079, 0x18fa, 0x1902, 0x1904, 0x1a06, 0x1a84, 0x1a9b, 0x1902, - 0x1902, 0x1902, 0x1078, 0x1328, 0x8001, 0x7002, 0xa184, 0x0880, - 0x00c0, 0x1919, 0x8aff, 0x0040, 0x199b, 0x2009, 0x0001, 0x1078, - 0x1824, 0x0040, 0x1aad, 0x2009, 0x0001, 0x1078, 0x1824, 0x0078, - 0x1aad, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x00c0, 0x1979, - 0x027e, 0x037e, 0x7808, 0xd0ec, 0x00c0, 0x1930, 0x7c20, 0x7d24, - 0x7e30, 0x7f34, 0x7803, 0x0009, 0x7003, 0x0004, 0x0078, 0x1932, - 0x1078, 0x1b9f, 0x6b28, 0x6a2c, 0x2400, 0x686e, 0xa31a, 0x2500, - 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x0c7e, 0x7004, 0x2060, 0x6024, - 0xd0f4, 0x00c0, 0x1945, 0x633a, 0x6236, 0x0c7f, 0x2400, 0x6910, - 0xa100, 0x6812, 0x2500, 0x6914, 0xa101, 0x6816, 0x037f, 0x027f, - 0x2600, 0x681e, 0x2700, 0x6822, 0x1078, 0x1fea, 0x2a00, 0x6826, - 0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852, 0x6808, - 0x8001, 0x680a, 0x00c0, 0x196e, 0x684c, 0xd0e4, 0x0040, 0x196e, - 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x756c, 0x7000, 0xa086, - 0x0004, 0x0040, 0x1aad, 0x7003, 0x0000, 0x1078, 0x179f, 0x0078, - 0x1aad, 0x057e, 0x7d0c, 0xd5bc, 0x00c0, 0x1980, 0x1078, 0xa20c, - 0x057f, 0x1078, 0x1ac6, 0x0f7e, 0x7004, 0x2078, 0x1078, 0x4893, - 0x0040, 0x198d, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, 0xffff, - 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, 0x6980, - 0x6916, 0x0078, 0x1aad, 0x7004, 0x0c7e, 0x2060, 0x6024, 0x0c7f, - 0xd0f4, 0x0040, 0x19a8, 0x6808, 0x8001, 0x680a, 0x0078, 0x1aad, - 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x19c0, 0x7003, - 0x0000, 0x6808, 0x8001, 0x680a, 0x00c0, 0x19bc, 0x7004, 0x2060, - 0x2009, 0x0048, 0x1078, 0x756c, 0x1078, 0x179f, 0x0078, 0x1aad, - 0x7814, 0x6910, 0xa102, 0x6812, 0x6914, 0xa183, 0x0000, 0x6816, - 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa188, 0x0007, 0x8114, 0x8214, - 0x8214, 0xa10a, 0x8104, 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, - 0x810b, 0x1078, 0x1b4d, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, - 0x0001, 0x7804, 0xd0fc, 0x0040, 0x19e1, 0x7803, 0x0002, 0x7803, - 0x0004, 0x780f, 0x0076, 0x7004, 0x7007, 0x0000, 0x2060, 0x2009, - 0x0048, 0x1078, 0x756c, 0x1078, 0x1b81, 0x0040, 0x19bc, 0x7908, - 0xd1ec, 0x00c0, 0x19ff, 0x2009, 0x0009, 0x0078, 0x1a01, 0x2009, - 0x0019, 0x7902, 0x7003, 0x0003, 0x0078, 0x1aad, 0x8001, 0x7002, - 0xd194, 0x0040, 0x1a18, 0x7804, 0xd0fc, 0x00c0, 0x18ea, 0x8aff, - 0x0040, 0x1aad, 0x2009, 0x0001, 0x1078, 0x1824, 0x0078, 0x1aad, - 0xa184, 0x0880, 0x00c0, 0x1a25, 0x8aff, 0x0040, 0x1aad, 0x2009, - 0x0001, 0x1078, 0x1824, 0x0078, 0x1aad, 0x7803, 0x0004, 0x7003, - 0x0000, 0xd1bc, 0x00c0, 0x1a65, 0x027e, 0x037e, 0x7808, 0xd0ec, - 0x00c0, 0x1a38, 0x7803, 0x0009, 0x7003, 0x0004, 0x0078, 0x1a3a, - 0x1078, 0x1b9f, 0x6b28, 0x6a2c, 0x1078, 0x1fea, 0x0d7e, 0x0f7e, - 0x2d78, 0x2804, 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1a55, 0x6808, - 0x2008, 0xa31a, 0x680c, 0xa213, 0x7810, 0xa100, 0x7812, 0x690c, - 0x7814, 0xa101, 0x7816, 0x0078, 0x1a61, 0x6810, 0x2008, 0xa31a, - 0x6814, 0xa213, 0x7810, 0xa100, 0x7812, 0x6914, 0x7814, 0xa101, - 0x7816, 0x0f7f, 0x0d7f, 0x0078, 0x1934, 0x057e, 0x7d0c, 0x1078, - 0xa20c, 0x057f, 0x1078, 0x1ac6, 0x0f7e, 0x7004, 0x2078, 0x1078, - 0x4893, 0x0040, 0x1a76, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, - 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, - 0x6980, 0x6916, 0x0078, 0x1aad, 0x7803, 0x0004, 0x7003, 0x0000, - 0x7004, 0xa00d, 0x0040, 0x1a97, 0x6808, 0x8001, 0x680a, 0x00c0, - 0x1a97, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x756c, 0x1078, - 0x179f, 0x0078, 0x1aad, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, - 0x2060, 0x6010, 0xa005, 0x0040, 0x1a97, 0x2068, 0x6808, 0x8000, - 0x680a, 0x6c28, 0x6b2c, 0x1078, 0x17be, 0x017f, 0x007f, 0x127f, - 0x007c, 0x127e, 0x2091, 0x2100, 0x7000, 0xa086, 0x0003, 0x00c0, - 0x1ac4, 0x700c, 0x7110, 0xa106, 0x0040, 0x1ac4, 0x20e1, 0x9028, - 0x700f, 0xa5e7, 0x7013, 0xa5e7, 0x127f, 0x007c, 0x0c7e, 0x1078, - 0x1af7, 0x20e1, 0x9028, 0x700c, 0x7110, 0xa106, 0x0040, 0x1aed, - 0x2104, 0xa005, 0x0040, 0x1ada, 0x2060, 0x6010, 0x2060, 0x6008, - 0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0xa602, 0x0048, 0x1ae2, - 0x2009, 0xa5e7, 0x7112, 0x700c, 0xa106, 0x00c0, 0x1acb, 0x2001, - 0x0138, 0x2003, 0x0008, 0x0078, 0x1acb, 0x2001, 0x015d, 0x200c, - 0x810a, 0x2102, 0x2001, 0x0138, 0x2202, 0x0c7f, 0x007c, 0x2001, - 0x0138, 0x2014, 0x2003, 0x0000, 0x2021, 0xb015, 0x2001, 0x0141, - 0x201c, 0xd3dc, 0x00c0, 0x1b14, 0x2001, 0x0109, 0x201c, 0xa39c, - 0x0048, 0x00c0, 0x1b14, 0x2001, 0x0111, 0x201c, 0x83ff, 0x00c0, - 0x1b14, 0x8421, 0x00c0, 0x1afe, 0x007c, 0x2011, 0x0201, 0x2009, - 0x003c, 0x2204, 0xa005, 0x00c0, 0x1b21, 0x8109, 0x00c0, 0x1b19, - 0x007c, 0x007c, 0x1078, 0x1b15, 0x0040, 0x1b4a, 0x7908, 0xd1ec, - 0x00c0, 0x1b3a, 0x1078, 0x1b81, 0x0040, 0x1b3a, 0x7803, 0x0009, - 0x7904, 0xd1fc, 0x0040, 0x1b30, 0x7803, 0x0006, 0x1078, 0x1b15, - 0x0040, 0x1b4a, 0x780c, 0xd0a4, 0x00c0, 0x1b4a, 0x7007, 0x0000, - 0x1078, 0x1b81, 0x0040, 0x1b4c, 0x7803, 0x0019, 0x7003, 0x0003, - 0x0078, 0x1b4c, 0x1078, 0x1ac6, 0x007c, 0x0e7e, 0x2071, 0x0200, - 0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x1af7, 0x2019, 0x5000, - 0x8319, 0x0040, 0x1b6b, 0x2001, 0xa602, 0x2004, 0xa086, 0x0000, - 0x0040, 0x1b6b, 0x2001, 0x0021, 0xd0fc, 0x0040, 0x1b58, 0x1078, - 0x1e5d, 0x0078, 0x1b56, 0x20e1, 0x7000, 0x7324, 0x7420, 0x7028, - 0x7028, 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f, 0x0100, - 0x7037, 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202, 0x0e7f, - 0x007c, 0x7908, 0xa18c, 0x0fff, 0xa182, 0x0009, 0x0048, 0x1b8c, - 0xa085, 0x0001, 0x0078, 0x1b9e, 0x2001, 0x020a, 0x81ff, 0x0040, - 0x1b97, 0x20e1, 0x6000, 0x200c, 0x200c, 0x200c, 0x200c, 0x20e1, - 0x7000, 0x200c, 0x200c, 0x7003, 0x0000, 0xa006, 0x007c, 0x7c20, - 0x7d24, 0x7e30, 0x7f34, 0x700c, 0x7110, 0xa106, 0x0040, 0x1c24, - 0x7004, 0x017e, 0x210c, 0xa106, 0x017f, 0x0040, 0x1c24, 0x0d7e, - 0x0c7e, 0x216c, 0x2d00, 0xa005, 0x0040, 0x1c22, 0x6824, 0xd0d4, - 0x00c0, 0x1c22, 0x6810, 0x2068, 0x6850, 0xd0fc, 0x0040, 0x1bec, - 0x8108, 0x2104, 0x6b2c, 0xa306, 0x00c0, 0x1c22, 0x8108, 0x2104, - 0x6a28, 0xa206, 0x00c0, 0x1c22, 0x6850, 0xc0fc, 0xc0f5, 0x6852, - 0x686c, 0x7822, 0x6870, 0x7826, 0x681c, 0x7832, 0x6820, 0x7836, - 0x6818, 0x2060, 0x6034, 0xd09c, 0x0040, 0x1be7, 0x6830, 0x2004, - 0xac68, 0x6808, 0x783a, 0x680c, 0x783e, 0x0078, 0x1c20, 0xa006, - 0x783a, 0x783e, 0x0078, 0x1c20, 0x8108, 0x2104, 0xa005, 0x00c0, - 0x1c22, 0x8108, 0x2104, 0xa005, 0x00c0, 0x1c22, 0x6850, 0xc0f5, - 0x6852, 0x6830, 0x2004, 0x6918, 0xa160, 0xa180, 0x000d, 0x2004, - 0xd09c, 0x00c0, 0x1c12, 0x6008, 0x7822, 0x686e, 0x600c, 0x7826, - 0x6872, 0x6000, 0x7832, 0x6004, 0x7836, 0xa006, 0x783a, 0x783e, - 0x0078, 0x1c20, 0x6010, 0x7822, 0x686e, 0x6014, 0x7826, 0x6872, - 0x6000, 0x7832, 0x6004, 0x7836, 0x6008, 0x783a, 0x600c, 0x783e, - 0x7803, 0x0011, 0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x017e, - 0x027e, 0x2071, 0xa5e1, 0x2079, 0x0030, 0x2011, 0x0050, 0x7000, - 0xa086, 0x0000, 0x0040, 0x1c4d, 0x8211, 0x0040, 0x1c4b, 0x2001, - 0x0005, 0x2004, 0xd08c, 0x0040, 0x1c34, 0x7904, 0xa18c, 0x0780, - 0x017e, 0x1078, 0x18e2, 0x017f, 0x81ff, 0x00c0, 0x1c4b, 0x2011, - 0x0050, 0x0078, 0x1c2f, 0xa085, 0x0001, 0x027f, 0x017f, 0x0e7f, - 0x0f7f, 0x007c, 0x7803, 0x0004, 0x2009, 0x0064, 0x7804, 0xd0ac, - 0x0040, 0x1ca3, 0x8109, 0x00c0, 0x1c56, 0x2009, 0x0100, 0x210c, - 0xa18a, 0x0003, 0x1048, 0x1328, 0x1078, 0x1f75, 0x0e7e, 0x0f7e, - 0x2071, 0xa5d0, 0x2079, 0x0010, 0x7004, 0xa086, 0x0000, 0x0040, - 0x1c9b, 0x7800, 0x007e, 0x7820, 0x007e, 0x7830, 0x007e, 0x7834, - 0x007e, 0x7838, 0x007e, 0x783c, 0x007e, 0x7803, 0x0004, 0x7823, - 0x0000, 0x0005, 0x0005, 0x2079, 0x0030, 0x7804, 0xd0ac, 0x10c0, - 0x1328, 0x2079, 0x0010, 0x007f, 0x783e, 0x007f, 0x783a, 0x007f, - 0x7836, 0x007f, 0x7832, 0x007f, 0x7822, 0x007f, 0x7802, 0x0f7f, - 0x0e7f, 0x0078, 0x1ca1, 0x0f7f, 0x0e7f, 0x7804, 0xd0ac, 0x10c0, - 0x1328, 0x1078, 0x61d3, 0x007c, 0x0e7e, 0x2071, 0xa602, 0x7003, - 0x0000, 0x0e7f, 0x007c, 0x0d7e, 0xa280, 0x0004, 0x206c, 0x694c, - 0xd1dc, 0x00c0, 0x1d26, 0x6934, 0xa184, 0x0007, 0x0079, 0x1cb8, - 0x1cc0, 0x1d11, 0x1cc0, 0x1cc0, 0x1cc0, 0x1cf6, 0x1cd3, 0x1cc2, - 0x1078, 0x1328, 0x684c, 0xd0b4, 0x0040, 0x1e34, 0x6860, 0x682e, - 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, - 0x6958, 0x0078, 0x1d19, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, - 0x00c0, 0x1cc0, 0x684c, 0xd0b4, 0x0040, 0x1e34, 0x6860, 0x682e, - 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e, - 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, - 0x2015, 0x2004, 0x6832, 0x6958, 0x0078, 0x1d22, 0xa18c, 0x00ff, - 0xa186, 0x0015, 0x00c0, 0x1d26, 0x684c, 0xd0b4, 0x0040, 0x1e34, - 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, - 0x2015, 0x2004, 0x6832, 0x6958, 0xa006, 0x682e, 0x682a, 0x0078, - 0x1d22, 0x684c, 0xd0b4, 0x0040, 0x18bc, 0x6958, 0xa006, 0x682e, - 0x682a, 0x2d00, 0x681a, 0x6834, 0xa084, 0x000f, 0xa080, 0x2015, - 0x2004, 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x0d7f, 0x007c, - 0x0f7e, 0x2079, 0x0020, 0x7804, 0xd0fc, 0x10c0, 0x1e5d, 0x0e7e, - 0x0d7e, 0x2071, 0xa602, 0x7000, 0xa005, 0x00c0, 0x1dab, 0x0c7e, - 0x7206, 0xa280, 0x0004, 0x205c, 0x7004, 0x2068, 0x7803, 0x0004, - 0x6818, 0x0d7e, 0x2068, 0x686c, 0x7812, 0x6890, 0x0f7e, 0x20e1, - 0x9040, 0x2079, 0x0200, 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, - 0x0f7f, 0x0d7f, 0x2b68, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, - 0x2040, 0x6034, 0xa0cc, 0x000f, 0x6908, 0x2001, 0x04fd, 0x2004, - 0xa086, 0x0007, 0x0040, 0x1d6d, 0xa184, 0x0007, 0x0040, 0x1d6d, - 0x017e, 0x2009, 0x0008, 0xa102, 0x017f, 0xa108, 0x791a, 0x7116, - 0x701e, 0x680c, 0xa081, 0x0000, 0x781e, 0x701a, 0xa006, 0x700e, - 0x7012, 0x7004, 0x692c, 0x6814, 0xa106, 0x00c0, 0x1d84, 0x6928, - 0x6810, 0xa106, 0x0040, 0x1d91, 0x037e, 0x047e, 0x6b14, 0x6c10, - 0x1078, 0x2035, 0x047f, 0x037f, 0x0040, 0x1d91, 0x0c7f, 0x0078, - 0x1dab, 0x8aff, 0x00c0, 0x1d99, 0x0c7f, 0xa085, 0x0001, 0x0078, - 0x1dab, 0x127e, 0x2091, 0x8000, 0x2079, 0x0020, 0x2009, 0x0001, - 0x1078, 0x1daf, 0x0040, 0x1da8, 0x2009, 0x0001, 0x1078, 0x1daf, - 0x127f, 0x0c7f, 0xa006, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x077e, - 0x067e, 0x057e, 0x047e, 0x037e, 0x027e, 0x8aff, 0x0040, 0x1e2d, - 0x700c, 0x7214, 0xa23a, 0x7010, 0x7218, 0xa203, 0x0048, 0x1e2c, - 0xa705, 0x0040, 0x1e2c, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, - 0x1ddf, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1dcf, 0x1e0e, - 0x1def, 0x1def, 0x1e0e, 0x1e0e, 0x1e06, 0x1e0e, 0x1def, 0x1e0e, - 0x1df5, 0x1df5, 0x1e0e, 0x1e0e, 0x1e0e, 0x1dfd, 0x1df5, 0xc0fc, - 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, 0x0040, 0x1e12, - 0x0d7e, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x1e11, 0x6b08, - 0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x1e11, 0x6b10, 0x6a14, 0x6d00, - 0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x1e11, 0x0d7f, 0x0d7e, 0x6834, - 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1e0e, 0x0d7f, 0x1078, - 0x1fd1, 0x00c0, 0x1db5, 0xa00e, 0x0078, 0x1e2d, 0x0d7f, 0x1078, - 0x1328, 0x0d7f, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, - 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, 0x682a, 0x682c, - 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, 0xa201, 0x7012, - 0x1078, 0x1fd1, 0x0078, 0x1e2d, 0xa006, 0x027f, 0x037f, 0x047f, - 0x057f, 0x067f, 0x077f, 0x007c, 0x1078, 0x1328, 0x027e, 0x2001, - 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, - 0x0000, 0x7004, 0x2060, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, - 0x0040, 0x1e4d, 0x6850, 0xc0bd, 0x6852, 0x0d7f, 0x1078, 0x8758, - 0x20e1, 0x9040, 0x1078, 0x719a, 0x2011, 0x0000, 0x1078, 0x6efc, - 0x1078, 0x61d3, 0x027f, 0x0078, 0x1f29, 0x127e, 0x2091, 0x2200, - 0x007e, 0x017e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x2079, 0x0020, - 0x2071, 0xa602, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, - 0xa184, 0x0700, 0x00c0, 0x1e36, 0x7000, 0x0079, 0x1e77, 0x1f29, - 0x1e7b, 0x1ef6, 0x1f27, 0x8001, 0x7002, 0xd19c, 0x00c0, 0x1e8f, - 0x8aff, 0x0040, 0x1eae, 0x2009, 0x0001, 0x1078, 0x1daf, 0x0040, - 0x1f29, 0x2009, 0x0001, 0x1078, 0x1daf, 0x0078, 0x1f29, 0x7803, - 0x0004, 0xd194, 0x0040, 0x1e9f, 0x6850, 0xc0fc, 0x6852, 0x8aff, - 0x00c0, 0x1ea4, 0x684c, 0xc0f5, 0x684e, 0x0078, 0x1ea4, 0x1078, - 0x1fea, 0x6850, 0xc0fd, 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, - 0x2800, 0x6832, 0x7003, 0x0000, 0x0078, 0x1f29, 0x711c, 0x81ff, - 0x0040, 0x1ec4, 0x7918, 0x7922, 0x7827, 0x0000, 0x7803, 0x0001, - 0x7000, 0x8000, 0x7002, 0x700c, 0xa100, 0x700e, 0x7010, 0xa081, - 0x0000, 0x7012, 0x0078, 0x1f29, 0x0f7e, 0x027e, 0x781c, 0x007e, - 0x7818, 0x007e, 0x2079, 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, - 0x0012, 0x7816, 0x037e, 0x2019, 0x1000, 0x8319, 0x1040, 0x1328, - 0x7820, 0xd0bc, 0x00c0, 0x1ed5, 0x037f, 0x79c8, 0x007f, 0xa102, - 0x017f, 0x007e, 0x017e, 0x79c4, 0x007f, 0xa103, 0x78c6, 0x007f, - 0x78ca, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x027f, 0x0f7f, - 0x7803, 0x0008, 0x7003, 0x0000, 0x0078, 0x1f29, 0x8001, 0x7002, - 0xd194, 0x0040, 0x1f0b, 0x7804, 0xd0fc, 0x00c0, 0x1e6d, 0xd19c, - 0x00c0, 0x1f25, 0x8aff, 0x0040, 0x1f29, 0x2009, 0x0001, 0x1078, - 0x1daf, 0x0078, 0x1f29, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x1078, - 0x1fea, 0x0d7e, 0x2804, 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1f1e, - 0x6808, 0xa31a, 0x680c, 0xa213, 0x0078, 0x1f22, 0x6810, 0xa31a, - 0x6814, 0xa213, 0x0d7f, 0x0078, 0x1e9f, 0x0078, 0x1e9f, 0x1078, - 0x1328, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x017f, 0x007f, 0x127f, - 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0xa602, 0x7000, 0xa086, 0x0000, - 0x0040, 0x1f72, 0x2079, 0x0020, 0x017e, 0x2009, 0x0207, 0x210c, - 0xd194, 0x0040, 0x1f4f, 0x2009, 0x020c, 0x210c, 0xa184, 0x0003, - 0x0040, 0x1f4f, 0x20e1, 0x9040, 0x2001, 0x020c, 0x2102, 0x2009, - 0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0xa106, 0x00c0, 0x1f5a, - 0x20e1, 0x9040, 0x7804, 0xd0fc, 0x0040, 0x1f3d, 0x1078, 0x1e5d, - 0x7000, 0xa086, 0x0000, 0x00c0, 0x1f3d, 0x017f, 0x7803, 0x0004, - 0x7804, 0xd0ac, 0x00c0, 0x1f68, 0x20e1, 0x9040, 0x7803, 0x0002, - 0x7003, 0x0000, 0x0e7f, 0x0f7f, 0x007c, 0x027e, 0x0c7e, 0x0d7e, - 0x0e7e, 0x0f7e, 0x2071, 0xa602, 0x2079, 0x0020, 0x7000, 0xa086, - 0x0000, 0x0040, 0x1fae, 0x7004, 0x2060, 0x6010, 0x2068, 0x1078, - 0x8a44, 0x0040, 0x1f98, 0x6850, 0xc0b5, 0x6852, 0x680c, 0x7a1c, - 0xa206, 0x00c0, 0x1f98, 0x6808, 0x7a18, 0xa206, 0x0040, 0x1fb4, - 0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, - 0x7003, 0x0000, 0x7004, 0x2060, 0x1078, 0x8758, 0x20e1, 0x9040, - 0x1078, 0x719a, 0x2011, 0x0000, 0x1078, 0x6efc, 0x0f7f, 0x0e7f, - 0x0d7f, 0x0c7f, 0x027f, 0x007c, 0x6810, 0x6a14, 0xa205, 0x00c0, - 0x1f98, 0x684c, 0xc0dc, 0x684e, 0x2c10, 0x1078, 0x1cab, 0x2001, - 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, - 0x0000, 0x2069, 0xa5ab, 0x6833, 0x0000, 0x683f, 0x0000, 0x0078, - 0x1fae, 0x8840, 0x2804, 0xa005, 0x00c0, 0x1fe5, 0x6004, 0xa005, - 0x0040, 0x1fe7, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, - 0x2015, 0x2044, 0x88ff, 0x1040, 0x1328, 0x8a51, 0x007c, 0x2051, - 0x0000, 0x007c, 0x8a50, 0x8841, 0x2804, 0xa005, 0x00c0, 0x2004, - 0x2c00, 0xad06, 0x0040, 0x1ff9, 0x6000, 0xa005, 0x00c0, 0x1ff9, - 0x2d00, 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, 0x2025, - 0x2044, 0x88ff, 0x1040, 0x1328, 0x007c, 0x0000, 0x0011, 0x0015, - 0x0019, 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, 0x0015, - 0x001b, 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x200a, 0x2006, - 0x0000, 0x0000, 0x2014, 0x0000, 0x200a, 0x0000, 0x2011, 0x200e, - 0x0000, 0x0000, 0x0000, 0x2014, 0x2011, 0x0000, 0x200c, 0x200c, - 0x0000, 0x0000, 0x2014, 0x0000, 0x200c, 0x0000, 0x2012, 0x2012, - 0x0000, 0x0000, 0x0000, 0x2014, 0x2012, 0x0a7e, 0x097e, 0x087e, - 0x6b2e, 0x6c2a, 0x6858, 0xa055, 0x0040, 0x20d8, 0x2d60, 0x6034, - 0xa0cc, 0x000f, 0xa9c0, 0x2015, 0xa986, 0x0007, 0x0040, 0x2050, - 0xa986, 0x000e, 0x0040, 0x2050, 0xa986, 0x000f, 0x00c0, 0x2054, - 0x605c, 0xa422, 0x6060, 0xa31a, 0x2804, 0xa045, 0x00c0, 0x2062, - 0x0050, 0x205c, 0x0078, 0x20d8, 0x6004, 0xa065, 0x0040, 0x20d8, - 0x0078, 0x203f, 0x2804, 0xa005, 0x0040, 0x2080, 0xac68, 0xd99c, - 0x00c0, 0x2070, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0078, 0x2074, - 0x6810, 0xa422, 0x6814, 0xa31b, 0x0048, 0x209f, 0x2300, 0xa405, - 0x0040, 0x2086, 0x8a51, 0x0040, 0x20d8, 0x8840, 0x0078, 0x2062, - 0x6004, 0xa065, 0x0040, 0x20d8, 0x0078, 0x203f, 0x8a51, 0x0040, - 0x20d8, 0x8840, 0x2804, 0xa005, 0x00c0, 0x2099, 0x6004, 0xa065, - 0x0040, 0x20d8, 0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x2015, 0x2804, - 0x2040, 0x2b68, 0x6850, 0xc0fc, 0x6852, 0x0078, 0x20cc, 0x8422, - 0x8420, 0x831a, 0xa399, 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, - 0x0d7f, 0xd99c, 0x00c0, 0x20ba, 0x6908, 0x2400, 0xa122, 0x690c, - 0x2300, 0xa11b, 0x1048, 0x1328, 0x6800, 0xa420, 0x6804, 0xa319, - 0x0078, 0x20c6, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, - 0x1048, 0x1328, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, - 0x6b22, 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, - 0x2a00, 0x6826, 0x007f, 0x007f, 0x007f, 0xa006, 0x0078, 0x20dd, - 0x087f, 0x097f, 0x0a7f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0005, - 0x2004, 0xa084, 0x0007, 0x0079, 0x20e5, 0x20ed, 0x20ee, 0x20f1, - 0x20f4, 0x20f9, 0x20fc, 0x2101, 0x2106, 0x007c, 0x1078, 0x1e5d, - 0x007c, 0x1078, 0x18e2, 0x007c, 0x1078, 0x18e2, 0x1078, 0x1e5d, - 0x007c, 0x1078, 0x14b0, 0x007c, 0x1078, 0x1e5d, 0x1078, 0x14b0, - 0x007c, 0x1078, 0x18e2, 0x1078, 0x14b0, 0x007c, 0x1078, 0x18e2, - 0x1078, 0x1e5d, 0x1078, 0x14b0, 0x007c, 0x127e, 0x2091, 0x2300, - 0x2079, 0x0200, 0x2071, 0xa880, 0x2069, 0xa300, 0x2009, 0x0004, - 0x7912, 0x7817, 0x0004, 0x1078, 0x24b5, 0x781b, 0x0002, 0x20e1, - 0x8700, 0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x781c, 0xa084, - 0x0007, 0x0079, 0x212b, 0x214f, 0x2133, 0x2137, 0x213b, 0x2141, - 0x2145, 0x2149, 0x214d, 0x1078, 0x5372, 0x0078, 0x214f, 0x1078, - 0x53b3, 0x0078, 0x214f, 0x1078, 0x5372, 0x1078, 0x53b3, 0x0078, - 0x214f, 0x1078, 0x2151, 0x0078, 0x214f, 0x1078, 0x2151, 0x0078, - 0x214f, 0x1078, 0x2151, 0x0078, 0x214f, 0x1078, 0x2151, 0x127f, - 0x007c, 0x007e, 0x017e, 0x027e, 0x7930, 0xa184, 0x0003, 0x0040, - 0x215d, 0x20e1, 0x9040, 0x0078, 0x2186, 0xa184, 0x0030, 0x0040, - 0x216e, 0x6a00, 0xa286, 0x0003, 0x00c0, 0x2168, 0x0078, 0x216a, - 0x1078, 0x4171, 0x20e1, 0x9010, 0x0078, 0x2186, 0xa184, 0x00c0, - 0x0040, 0x2180, 0x0e7e, 0x037e, 0x047e, 0x057e, 0x2071, 0xa5e1, - 0x1078, 0x1ac6, 0x057f, 0x047f, 0x037f, 0x0e7f, 0x0078, 0x2186, - 0xa184, 0x0300, 0x0040, 0x2186, 0x20e1, 0x9020, 0x7932, 0x027f, - 0x017f, 0x007f, 0x007c, 0x017e, 0x0e7e, 0x0f7e, 0x2071, 0xa300, - 0x7128, 0x2001, 0xa58f, 0x2102, 0x2001, 0xa597, 0x2102, 0xa182, - 0x0211, 0x00c8, 0x219f, 0x2009, 0x0008, 0x0078, 0x21c9, 0xa182, - 0x0259, 0x00c8, 0x21a7, 0x2009, 0x0007, 0x0078, 0x21c9, 0xa182, - 0x02c1, 0x00c8, 0x21af, 0x2009, 0x0006, 0x0078, 0x21c9, 0xa182, - 0x0349, 0x00c8, 0x21b7, 0x2009, 0x0005, 0x0078, 0x21c9, 0xa182, - 0x0421, 0x00c8, 0x21bf, 0x2009, 0x0004, 0x0078, 0x21c9, 0xa182, - 0x0581, 0x00c8, 0x21c7, 0x2009, 0x0003, 0x0078, 0x21c9, 0x2009, - 0x0002, 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x1078, 0x24b5, - 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x127e, 0x2091, 0x2200, 0x2061, - 0x0100, 0x2071, 0xa300, 0x6024, 0x6026, 0x6053, 0x0030, 0x6033, - 0x00ef, 0x60e7, 0x0000, 0x60eb, 0x00ef, 0x60e3, 0x0008, 0x604b, - 0xf7f7, 0x6043, 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, 0x6007, - 0x0eaf, 0x600f, 0x00ff, 0x602b, 0x002f, 0x127f, 0x007c, 0x2001, - 0xa32f, 0x2003, 0x0000, 0x2001, 0xa32e, 0x2003, 0x0001, 0x007c, - 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, 0x6124, 0xa184, - 0x002c, 0x00c0, 0x220f, 0xa184, 0x0007, 0x0079, 0x2215, 0xa195, - 0x0004, 0xa284, 0x0007, 0x0079, 0x2215, 0x2241, 0x221d, 0x2221, - 0x2225, 0x222b, 0x222f, 0x2235, 0x223b, 0x1078, 0x5ad2, 0x0078, - 0x2241, 0x1078, 0x5bc1, 0x0078, 0x2241, 0x1078, 0x5bc1, 0x1078, - 0x5ad2, 0x0078, 0x2241, 0x1078, 0x2246, 0x0078, 0x2241, 0x1078, - 0x5ad2, 0x1078, 0x2246, 0x0078, 0x2241, 0x1078, 0x5bc1, 0x1078, - 0x2246, 0x0078, 0x2241, 0x1078, 0x5bc1, 0x1078, 0x5ad2, 0x1078, - 0x2246, 0x027f, 0x017f, 0x007f, 0x127f, 0x007c, 0x6124, 0xd1ac, - 0x0040, 0x2342, 0x017e, 0x047e, 0x0c7e, 0x644c, 0xa486, 0xf0f0, - 0x00c0, 0x2259, 0x2061, 0x0100, 0x644a, 0x6043, 0x0090, 0x6043, - 0x0010, 0x74c2, 0xa48c, 0xff00, 0x7034, 0xd084, 0x0040, 0x2271, - 0xa186, 0xf800, 0x00c0, 0x2271, 0x7038, 0xd084, 0x00c0, 0x2271, - 0xc085, 0x703a, 0x037e, 0x2418, 0x2011, 0x8016, 0x1078, 0x3579, - 0x037f, 0xa196, 0xff00, 0x0040, 0x22b3, 0x6030, 0xa084, 0x00ff, - 0x810f, 0xa116, 0x0040, 0x22b3, 0x7130, 0xd184, 0x00c0, 0x22b3, - 0x2011, 0xa352, 0x2214, 0xd2ec, 0x0040, 0x228e, 0xc18d, 0x7132, - 0x2011, 0xa352, 0x2214, 0xd2ac, 0x00c0, 0x22b3, 0x6240, 0xa294, - 0x0010, 0x0040, 0x229a, 0x6248, 0xa294, 0xff00, 0xa296, 0xff00, - 0x0040, 0x22b3, 0x7030, 0xd08c, 0x0040, 0x2305, 0x7034, 0xd08c, - 0x00c0, 0x22aa, 0x2001, 0xa30c, 0x200c, 0xd1ac, 0x00c0, 0x2305, - 0xc1ad, 0x2102, 0x037e, 0x73c0, 0x2011, 0x8013, 0x1078, 0x3579, - 0x037f, 0x0078, 0x2305, 0x7034, 0xd08c, 0x00c0, 0x22bf, 0x2001, - 0xa30c, 0x200c, 0xd1ac, 0x00c0, 0x2305, 0xc1ad, 0x2102, 0x037e, - 0x73c0, 0x2011, 0x8013, 0x1078, 0x3579, 0x037f, 0x7130, 0xc185, - 0x7132, 0x2011, 0xa352, 0x220c, 0xd1a4, 0x0040, 0x22e9, 0x017e, - 0x2009, 0x0001, 0x2011, 0x0100, 0x1078, 0x5a6d, 0x2019, 0x000e, - 0x1078, 0x9e3b, 0xa484, 0x00ff, 0xa080, 0x293f, 0x200c, 0xa18c, - 0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x1078, 0x9ec0, - 0x017f, 0xd1ac, 0x00c0, 0x22f6, 0x017e, 0x2009, 0x0000, 0x2019, - 0x0004, 0x1078, 0x27e2, 0x017f, 0x0078, 0x2305, 0x157e, 0x20a9, - 0x007f, 0x2009, 0x0000, 0x1078, 0x4501, 0x00c0, 0x2301, 0x1078, - 0x4235, 0x8108, 0x00f0, 0x22fb, 0x157f, 0x0c7f, 0x047f, 0x0f7e, - 0x2079, 0xa5be, 0x783c, 0xa086, 0x0000, 0x0040, 0x2317, 0x6027, - 0x0004, 0x783f, 0x0000, 0x2079, 0x0140, 0x7803, 0x0000, 0x0f7f, - 0x2011, 0x0003, 0x1078, 0x6ef2, 0x2011, 0x0002, 0x1078, 0x6efc, - 0x1078, 0x6dda, 0x1078, 0x595a, 0x037e, 0x2019, 0x0000, 0x1078, - 0x6e6c, 0x037f, 0x60e3, 0x0000, 0x017f, 0x2001, 0xa300, 0x2014, - 0xa296, 0x0004, 0x00c0, 0x233a, 0xd19c, 0x00c0, 0x233a, 0x6228, - 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xa321, 0x2003, 0x0000, - 0x6027, 0x0020, 0xd194, 0x0040, 0x2426, 0x0f7e, 0x2079, 0xa5be, - 0x783c, 0xa086, 0x0001, 0x00c0, 0x2366, 0x017e, 0x6027, 0x0004, - 0x783f, 0x0000, 0x2079, 0x0140, 0x7803, 0x1000, 0x7803, 0x0000, - 0x2079, 0xa5ab, 0x7807, 0x0000, 0x7833, 0x0000, 0x1078, 0x6109, - 0x1078, 0x61d3, 0x017f, 0x0f7f, 0x0078, 0x2426, 0x0f7f, 0x017e, - 0x3900, 0xa082, 0xa6cd, 0x00c8, 0x2371, 0x017e, 0x1078, 0x728a, - 0x017f, 0x6220, 0xd2b4, 0x0040, 0x23dc, 0x1078, 0x595a, 0x1078, - 0x6c41, 0x6027, 0x0004, 0x0f7e, 0x2019, 0xa5b4, 0x2304, 0xa07d, - 0x0040, 0x23b2, 0x7804, 0xa086, 0x0032, 0x00c0, 0x23b2, 0x0d7e, - 0x0c7e, 0x0e7e, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e, - 0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x00c0, - 0x2396, 0x6043, 0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e, - 0x628a, 0x1078, 0x6010, 0x1078, 0x6109, 0x7810, 0x2070, 0x7037, - 0x0103, 0x2f60, 0x1078, 0x753d, 0x0e7f, 0x0c7f, 0x0d7f, 0x0f7f, - 0x017f, 0x007c, 0x0f7f, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, - 0x4000, 0x0040, 0x23bf, 0x6803, 0x1000, 0x6803, 0x0000, 0x0d7f, - 0x0c7e, 0x2061, 0xa5ab, 0x6028, 0xa09a, 0x00c8, 0x00c8, 0x23cf, - 0x8000, 0x602a, 0x0c7f, 0x1078, 0x6c33, 0x0078, 0x2425, 0x2019, - 0xa5b4, 0x2304, 0xa065, 0x0040, 0x23d9, 0x2009, 0x0027, 0x1078, - 0x756c, 0x0c7f, 0x0078, 0x2425, 0xd2bc, 0x0040, 0x2425, 0x1078, - 0x5967, 0x6017, 0x0010, 0x6027, 0x0004, 0x0d7e, 0x2069, 0x0140, - 0x6804, 0xa084, 0x4000, 0x0040, 0x23f1, 0x6803, 0x1000, 0x6803, - 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0xa5ab, 0x6044, 0xa09a, 0x00c8, - 0x00c8, 0x2414, 0x8000, 0x6046, 0x603c, 0x0c7f, 0xa005, 0x0040, - 0x2425, 0x2009, 0x07d0, 0x1078, 0x595f, 0xa080, 0x0007, 0x2004, - 0xa086, 0x0006, 0x00c0, 0x2410, 0x6017, 0x0012, 0x0078, 0x2425, - 0x6017, 0x0016, 0x0078, 0x2425, 0x037e, 0x2019, 0x0001, 0x1078, - 0x6e6c, 0x037f, 0x2019, 0xa5ba, 0x2304, 0xa065, 0x0040, 0x2424, - 0x2009, 0x004f, 0x1078, 0x756c, 0x0c7f, 0x017f, 0xd19c, 0x0040, - 0x247c, 0x7034, 0xd0ac, 0x00c0, 0x2457, 0x017e, 0x157e, 0x6027, - 0x0008, 0x602f, 0x0020, 0x20a9, 0x000a, 0x00f0, 0x2435, 0x602f, - 0x0000, 0x6150, 0xa185, 0x1400, 0x6052, 0x20a9, 0x0320, 0x00e0, - 0x243f, 0x2091, 0x6000, 0x6020, 0xd09c, 0x00c0, 0x244e, 0x157f, - 0x6152, 0x017f, 0x6027, 0x0008, 0x0078, 0x247c, 0x1078, 0x250d, - 0x00f0, 0x243f, 0x157f, 0x6152, 0x017f, 0x6027, 0x0008, 0x017e, - 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x1078, 0x6ef2, 0x2011, - 0x0002, 0x1078, 0x6efc, 0x1078, 0x6dda, 0x1078, 0x595a, 0x037e, - 0x2019, 0x0000, 0x1078, 0x6e6c, 0x037f, 0x60e3, 0x0000, 0x1078, - 0xa22a, 0x1078, 0xa248, 0x2001, 0xa300, 0x2003, 0x0004, 0x6027, - 0x0008, 0x1078, 0x1246, 0x017f, 0xa18c, 0xffd0, 0x6126, 0x007c, - 0x007e, 0x017e, 0x027e, 0x0e7e, 0x0f7e, 0x127e, 0x2091, 0x8000, - 0x2071, 0xa300, 0x71b8, 0x70ba, 0xa116, 0x0040, 0x24ae, 0x81ff, - 0x0040, 0x2498, 0x2011, 0x8011, 0x1078, 0x3579, 0x0078, 0x24ae, - 0x2011, 0x8012, 0x1078, 0x3579, 0x2001, 0xa371, 0x2004, 0xd0fc, - 0x00c0, 0x24ae, 0x037e, 0x0c7e, 0x2061, 0x0100, 0x2019, 0x0028, - 0x2009, 0x0000, 0x1078, 0x27e2, 0x0c7f, 0x037f, 0x127f, 0x0f7f, - 0x0e7f, 0x027f, 0x017f, 0x007f, 0x007c, 0x0c7e, 0x0f7e, 0x007e, - 0x027e, 0x2061, 0x0100, 0xa190, 0x24d1, 0x2204, 0x60f2, 0x2011, - 0x24de, 0x6000, 0xa082, 0x0003, 0x00c8, 0x24ca, 0x2001, 0x00ff, - 0x0078, 0x24cb, 0x2204, 0x60ee, 0x027f, 0x007f, 0x0f7f, 0x0c7f, - 0x007c, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, 0x0348, 0x02c0, - 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, 0x0140, 0x00f8, - 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff, 0x2130, 0xa094, - 0xff00, 0x00c0, 0x24ee, 0x81ff, 0x0040, 0x24f2, 0x1078, 0x5623, - 0x0078, 0x24f9, 0xa080, 0x293f, 0x200c, 0xa18c, 0xff00, 0x810f, - 0xa006, 0x007c, 0xa080, 0x293f, 0x200c, 0xa18c, 0x00ff, 0x007c, - 0x0c7e, 0x2061, 0xa300, 0x6030, 0x0040, 0x2509, 0xc09d, 0x0078, - 0x250a, 0xc09c, 0x6032, 0x0c7f, 0x007c, 0x007e, 0x157e, 0x0f7e, - 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd08c, 0x00c0, 0x251a, - 0x00f0, 0x2514, 0x0f7f, 0x157f, 0x007f, 0x007c, 0x0c7e, 0x007e, - 0x2061, 0x0100, 0x6030, 0x007e, 0x6048, 0x007e, 0x60e4, 0x007e, - 0x60e8, 0x007e, 0x6050, 0x007e, 0x60f0, 0x007e, 0x60ec, 0x007e, - 0x600c, 0x007e, 0x6004, 0x007e, 0x6028, 0x007e, 0x60e0, 0x007e, - 0x602f, 0x0100, 0x602f, 0x0000, 0x0005, 0x0005, 0x0005, 0x0005, - 0x602f, 0x0040, 0x602f, 0x0000, 0x007f, 0x60e2, 0x007f, 0x602a, - 0x007f, 0x6006, 0x007f, 0x600e, 0x007f, 0x60ee, 0x007f, 0x60f2, - 0x007f, 0x6052, 0x007f, 0x60ea, 0x007f, 0x60e6, 0x007f, 0x604a, - 0x007f, 0x6032, 0x007f, 0x0c7f, 0x007c, 0x257d, 0x2581, 0x2585, - 0x258b, 0x2591, 0x2597, 0x259d, 0x25a5, 0x25ad, 0x25b3, 0x25b9, - 0x25c1, 0x25c9, 0x25d1, 0x25d9, 0x25e3, 0x25ed, 0x25ed, 0x25ed, - 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, - 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x107e, 0x007e, 0x0078, - 0x2606, 0x107e, 0x007e, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, - 0x2200, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x0078, - 0x2606, 0x107e, 0x007e, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, - 0x007e, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, - 0x2200, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, - 0x2200, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, - 0x2123, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, 0x2123, 0x0078, - 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, 0x2123, 0x0078, - 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, 0x2123, 0x0078, - 0x2606, 0x107e, 0x007e, 0x1078, 0x20de, 0x1078, 0x2123, 0x0078, - 0x2606, 0x107e, 0x007e, 0x1078, 0x20de, 0x1078, 0x2123, 0x0078, - 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, 0x20de, 0x1078, - 0x2123, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, - 0x20de, 0x1078, 0x2123, 0x0078, 0x2606, 0x0005, 0x0078, 0x25ed, - 0xb084, 0x003c, 0x8004, 0x8004, 0x0079, 0x25f6, 0x2606, 0x2583, - 0x2587, 0x258d, 0x2593, 0x2599, 0x259f, 0x25a7, 0x25af, 0x25b5, - 0x25bb, 0x25c3, 0x25cb, 0x25d3, 0x25db, 0x25e5, 0x0008, 0x25f0, - 0x007f, 0x107f, 0x2091, 0x8001, 0x007c, 0x0c7e, 0x027e, 0x047e, - 0x2021, 0x0000, 0x1078, 0x4897, 0x00c0, 0x2705, 0x70c8, 0xd09c, - 0x0040, 0x2624, 0xd084, 0x00c0, 0x2624, 0xd0bc, 0x00c0, 0x2705, - 0x1078, 0x2709, 0x0078, 0x2705, 0xd094, 0x0040, 0x262b, 0x7093, - 0xffff, 0x0078, 0x2705, 0x2001, 0x010c, 0x203c, 0x7280, 0xd284, - 0x0040, 0x2694, 0xd28c, 0x00c0, 0x2694, 0x037e, 0x7390, 0xa38e, - 0xffff, 0x0040, 0x263e, 0x83ff, 0x00c0, 0x2640, 0x2019, 0x0001, - 0x8314, 0xa2e0, 0xa9c0, 0x2c04, 0xa38c, 0x0001, 0x0040, 0x264d, - 0xa084, 0xff00, 0x8007, 0x0078, 0x264f, 0xa084, 0x00ff, 0xa70e, - 0x0040, 0x2689, 0xa08e, 0x0000, 0x0040, 0x2689, 0xa08e, 0x00ff, - 0x00c0, 0x2666, 0x7230, 0xd284, 0x00c0, 0x268f, 0x7280, 0xc28d, - 0x7282, 0x7093, 0xffff, 0x037f, 0x0078, 0x2694, 0x2009, 0x0000, - 0x1078, 0x24e3, 0x1078, 0x4499, 0x00c0, 0x268c, 0x6004, 0xa084, - 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2683, 0x7030, 0xd08c, 0x0040, - 0x267d, 0x6000, 0xd0bc, 0x0040, 0x2683, 0x1078, 0x271f, 0x0040, - 0x268c, 0x0078, 0x2689, 0x1078, 0x2857, 0x1078, 0x274c, 0x0040, - 0x268c, 0x8318, 0x0078, 0x2640, 0x7392, 0x0078, 0x2691, 0x7093, - 0xffff, 0x037f, 0x0078, 0x2705, 0xa780, 0x293f, 0x203c, 0xa7bc, - 0xff00, 0x873f, 0x2041, 0x007e, 0x7090, 0xa096, 0xffff, 0x00c0, - 0x26a6, 0x2009, 0x0000, 0x28a8, 0x0078, 0x26b2, 0xa812, 0x0048, - 0x26ae, 0x2008, 0xa802, 0x20a8, 0x0078, 0x26b2, 0x7093, 0xffff, - 0x0078, 0x2705, 0x2700, 0x157e, 0x017e, 0xa106, 0x0040, 0x26f9, - 0xc484, 0x1078, 0x4501, 0x0040, 0x26c3, 0x1078, 0x4499, 0x00c0, - 0x2702, 0x0078, 0x26c4, 0xc485, 0x6004, 0xa084, 0x00ff, 0xa086, - 0x0006, 0x00c0, 0x26d3, 0x7030, 0xd08c, 0x0040, 0x26f1, 0x6000, - 0xd0bc, 0x00c0, 0x26f1, 0x7280, 0xd28c, 0x0040, 0x26e9, 0x6004, - 0xa084, 0x00ff, 0xa082, 0x0006, 0x0048, 0x26f9, 0xd484, 0x00c0, - 0x26e5, 0x1078, 0x44bc, 0x0078, 0x26e7, 0x1078, 0x2921, 0x0078, - 0x26f9, 0x1078, 0x2857, 0x1078, 0x274c, 0x0040, 0x2702, 0x0078, - 0x26f9, 0x1078, 0x28ec, 0x0040, 0x26f9, 0x1078, 0x271f, 0x0040, - 0x2702, 0x017f, 0x8108, 0x157f, 0x00f0, 0x26b2, 0x7093, 0xffff, - 0x0078, 0x2705, 0x017f, 0x157f, 0x7192, 0x047f, 0x027f, 0x0c7f, - 0x007c, 0x0c7e, 0x017e, 0x7093, 0x0000, 0x2009, 0x007e, 0x1078, - 0x4499, 0x00c0, 0x271c, 0x1078, 0x2857, 0x1078, 0x274c, 0x0040, - 0x271c, 0x70c8, 0xc0bd, 0x70ca, 0x017f, 0x0c7f, 0x007c, 0x017e, - 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x2001, 0xa356, 0x2004, 0xa084, - 0x00ff, 0x6842, 0x1078, 0x74d7, 0x0040, 0x2747, 0x2d00, 0x601a, - 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0000, - 0x1078, 0x443f, 0x127e, 0x2091, 0x8000, 0x708c, 0x8000, 0x708e, - 0x127f, 0x2009, 0x0004, 0x1078, 0x756c, 0xa085, 0x0001, 0x0c7f, - 0x0d7f, 0x077f, 0x017f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, - 0x2c68, 0x2001, 0xa356, 0x2004, 0xa084, 0x00ff, 0x6842, 0x1078, - 0x74d7, 0x0040, 0x2785, 0x2d00, 0x601a, 0x6800, 0xc0c4, 0x6802, - 0x68a0, 0xa086, 0x007e, 0x0040, 0x276e, 0x6804, 0xa084, 0x00ff, - 0xa086, 0x0006, 0x00c0, 0x276e, 0x1078, 0x2813, 0x601f, 0x0001, - 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, 0x443f, - 0x127e, 0x2091, 0x8000, 0x708c, 0x8000, 0x708e, 0x127f, 0x2009, - 0x0002, 0x1078, 0x756c, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, - 0x017f, 0x007c, 0x0c7e, 0x027e, 0x2009, 0x0080, 0x1078, 0x4499, - 0x00c0, 0x2798, 0x1078, 0x279b, 0x0040, 0x2798, 0x70cf, 0xffff, - 0x027f, 0x0c7f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, - 0x1078, 0x74d7, 0x0040, 0x27bd, 0x2d00, 0x601a, 0x601f, 0x0001, - 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, 0x443f, - 0x127e, 0x2091, 0x8000, 0x70d0, 0x8000, 0x70d2, 0x127f, 0x2009, - 0x0002, 0x1078, 0x756c, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, - 0x017f, 0x007c, 0x0c7e, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2009, - 0x007f, 0x1078, 0x4499, 0x00c0, 0x27de, 0x2c68, 0x1078, 0x74d7, - 0x0040, 0x27de, 0x2d00, 0x601a, 0x6312, 0x601f, 0x0001, 0x620a, - 0x2009, 0x0022, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x0d7f, - 0x0c7f, 0x007c, 0x0e7e, 0x0c7e, 0x067e, 0x037e, 0x027e, 0x1078, - 0x5d60, 0x1078, 0x5d02, 0x1078, 0x7ddf, 0x2130, 0x81ff, 0x0040, - 0x27f7, 0x20a9, 0x007e, 0x2009, 0x0000, 0x0078, 0x27fb, 0x20a9, - 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x4501, 0x00c0, 0x2804, - 0x1078, 0x471b, 0x1078, 0x4235, 0x017f, 0x8108, 0x00f0, 0x27fb, - 0x86ff, 0x00c0, 0x280d, 0x1078, 0x119b, 0x027f, 0x037f, 0x067f, - 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, - 0x6218, 0x2270, 0x72a0, 0x027e, 0x2019, 0x0029, 0x1078, 0x5d53, - 0x077e, 0x2039, 0x0000, 0x1078, 0x5c78, 0x2c08, 0x1078, 0x9c38, - 0x077f, 0x017f, 0x2e60, 0x1078, 0x471b, 0x6210, 0x6314, 0x1078, - 0x4235, 0x6212, 0x6316, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, - 0x007c, 0x0e7e, 0x007e, 0x6018, 0xa080, 0x0028, 0x2004, 0xd0bc, - 0x00c0, 0x284d, 0x2071, 0xa300, 0x708c, 0xa005, 0x0040, 0x284a, - 0x8001, 0x708e, 0x007f, 0x0e7f, 0x007c, 0x2071, 0xa300, 0x70d0, - 0xa005, 0x0040, 0x284a, 0x8001, 0x70d2, 0x0078, 0x284a, 0x6000, - 0xc08c, 0x6002, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x037e, 0x027e, - 0x017e, 0x157e, 0x2178, 0x81ff, 0x00c0, 0x286a, 0x20a9, 0x0001, - 0x0078, 0x2885, 0x2001, 0xa352, 0x2004, 0xd0c4, 0x0040, 0x2881, - 0xd0a4, 0x0040, 0x2881, 0x047e, 0x6018, 0xa080, 0x0028, 0x2024, - 0xa4a4, 0x00ff, 0x8427, 0xa006, 0x2009, 0x002d, 0x1078, 0x9ec0, - 0x047f, 0x20a9, 0x00ff, 0x2011, 0x0000, 0x027e, 0xa28e, 0x007e, - 0x0040, 0x28c9, 0xa28e, 0x007f, 0x0040, 0x28c9, 0xa28e, 0x0080, - 0x0040, 0x28c9, 0xa288, 0xa434, 0x210c, 0x81ff, 0x0040, 0x28c9, - 0x8fff, 0x1040, 0x28d5, 0x0c7e, 0x2160, 0x2001, 0x0001, 0x1078, - 0x48a2, 0x0c7f, 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, - 0x0000, 0x1078, 0x5c78, 0x0c7e, 0x027e, 0x2160, 0x6204, 0xa294, - 0x00ff, 0xa286, 0x0006, 0x00c0, 0x28b9, 0x6007, 0x0404, 0x0078, - 0x28be, 0x2001, 0x0004, 0x8007, 0xa215, 0x6206, 0x027f, 0x0c7f, - 0x017e, 0x2c08, 0x1078, 0x9c38, 0x017f, 0x077f, 0x2160, 0x1078, - 0x471b, 0x027f, 0x8210, 0x00f0, 0x2885, 0x157f, 0x017f, 0x027f, - 0x037f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x047e, 0x027e, 0x017e, - 0x2001, 0xa352, 0x2004, 0xd0c4, 0x0040, 0x28e8, 0xd0a4, 0x0040, - 0x28e8, 0xa006, 0x2220, 0x8427, 0x2009, 0x0029, 0x1078, 0x9ec0, - 0x017f, 0x027f, 0x047f, 0x007c, 0x017e, 0x027e, 0x037e, 0x0c7e, - 0x7280, 0x82ff, 0x0040, 0x291a, 0xa290, 0xa352, 0x2214, 0xd2ac, - 0x00c0, 0x291a, 0x2100, 0x1078, 0x24fa, 0x81ff, 0x0040, 0x291c, - 0x2019, 0x0001, 0x8314, 0xa2e0, 0xa9c0, 0x2c04, 0xd384, 0x0040, - 0x290e, 0xa084, 0xff00, 0x8007, 0x0078, 0x2910, 0xa084, 0x00ff, - 0xa116, 0x0040, 0x291c, 0xa096, 0x00ff, 0x0040, 0x291a, 0x8318, - 0x0078, 0x2902, 0xa085, 0x0001, 0x0c7f, 0x037f, 0x027f, 0x017f, - 0x007c, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0xa180, 0xa434, - 0x2004, 0xa065, 0x0040, 0x293b, 0x017e, 0x0c7e, 0x1078, 0x8ec0, - 0x017f, 0x1040, 0x1328, 0x611a, 0x1078, 0x2813, 0x1078, 0x753d, - 0x017f, 0x1078, 0x44bc, 0x127f, 0x0c7f, 0x017f, 0x007c, 0x7eef, - 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, - 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, - 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, - 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, - 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, - 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, - 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, 0x8081, 0x8080, - 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, - 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, - 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, 0x8056, 0x8055, - 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, - 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, - 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, - 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, 0x8026, 0x8025, - 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, - 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, 0x8000, 0x3800, - 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, 0x8000, 0x3400, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3300, 0x3200, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3100, 0x3000, - 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, - 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, - 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, 0x8000, 0x8000, - 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, - 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, 0x8000, 0x8000, - 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, 0x1500, 0x8000, - 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, - 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, - 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, 0x8000, 0x0500, - 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, 0x8000, 0x0100, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x8000, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x2071, - 0xa381, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, 0x703a, 0x703e, - 0x7033, 0xa391, 0x7037, 0xa391, 0x7007, 0x0001, 0x2061, 0xa3d1, - 0x6003, 0x0002, 0x007c, 0x0090, 0x2a66, 0x0068, 0x2a66, 0x2071, - 0xa381, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x2a66, 0x2a60, 0x7820, - 0xa08e, 0x0069, 0x00c0, 0x2b56, 0x0079, 0x2aea, 0x007c, 0x2071, - 0xa381, 0x7004, 0x0079, 0x2a6c, 0x2a70, 0x2a71, 0x2a7b, 0x2a8d, - 0x007c, 0x0090, 0x2a7a, 0x0068, 0x2a7a, 0x2b78, 0x7818, 0xd084, - 0x0040, 0x2a99, 0x007c, 0x2b78, 0x2061, 0xa3d1, 0x6008, 0xa08e, - 0x0100, 0x0040, 0x2a88, 0xa086, 0x0200, 0x0040, 0x2b4e, 0x007c, - 0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, 0x2068, 0x6834, - 0xa086, 0x0103, 0x0040, 0x2a95, 0x007c, 0x2a60, 0x2b78, 0x7018, - 0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, 0x2aa2, 0x61b8, - 0x0079, 0x2aaa, 0x2100, 0xa08a, 0x003f, 0x00c8, 0x2b4a, 0x61b8, - 0x0079, 0x2aea, 0x2b2c, 0x2b5e, 0x2b66, 0x2b6a, 0x2b72, 0x2b78, - 0x2b7c, 0x2b88, 0x2b8c, 0x2b96, 0x2b9a, 0x2b4a, 0x2b4a, 0x2b4a, - 0x2b9e, 0x2b4a, 0x2bae, 0x2bc5, 0x2bdc, 0x2c58, 0x2c5d, 0x2c8a, - 0x2ce4, 0x2cf5, 0x2d13, 0x2d54, 0x2d5e, 0x2d6b, 0x2d7e, 0x2d9d, - 0x2da6, 0x2de3, 0x2de9, 0x2b4a, 0x2e05, 0x2b4a, 0x2b4a, 0x2b4a, - 0x2b4a, 0x2b4a, 0x2e0c, 0x2e16, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, - 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2e1e, 0x2b4a, 0x2b4a, 0x2b4a, - 0x2b4a, 0x2b4a, 0x2e30, 0x2e47, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, - 0x2b4a, 0x2b4a, 0x2e59, 0x2eb0, 0x2f0e, 0x2f1f, 0x2b4a, 0x2b4a, - 0x2b4a, 0x38f1, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, - 0x2b4a, 0x2b4a, 0x2b96, 0x2b9a, 0x2f36, 0x2b4a, 0x2f43, 0x397d, - 0x39da, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, - 0x2b4a, 0x2b4a, 0x2f90, 0x30c5, 0x30e1, 0x30ed, 0x3150, 0x31a9, - 0x31b4, 0x31f3, 0x3202, 0x3211, 0x3214, 0x2f47, 0x3238, 0x3284, - 0x3291, 0x33a2, 0x34cd, 0x34f7, 0x3604, 0x3614, 0x3621, 0x365b, - 0x372a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x3792, 0x37ae, 0x3828, - 0x38e2, 0x713c, 0x0078, 0x2b2c, 0x2021, 0x4000, 0x1078, 0x3553, - 0x127e, 0x2091, 0x8000, 0x0068, 0x2b39, 0x7818, 0xd084, 0x0040, - 0x2b3c, 0x127f, 0x0078, 0x2b30, 0x7c22, 0x7926, 0x7a2a, 0x7b2e, - 0x781b, 0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, 0x5000, - 0x127f, 0x007c, 0x2021, 0x4001, 0x0078, 0x2b2e, 0x2021, 0x4002, - 0x0078, 0x2b2e, 0x2021, 0x4003, 0x0078, 0x2b2e, 0x2021, 0x4005, - 0x0078, 0x2b2e, 0x2021, 0x4006, 0x0078, 0x2b2e, 0xa02e, 0x2520, - 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, 0x3562, 0x7823, 0x0004, - 0x7824, 0x007a, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, - 0x0078, 0x3566, 0x7924, 0x7828, 0x2114, 0x200a, 0x0078, 0x2b2c, - 0x7924, 0x2114, 0x0078, 0x2b2c, 0x2099, 0x0009, 0x20a1, 0x0009, - 0x20a9, 0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0078, 0x2b2c, - 0x7824, 0x2060, 0x0078, 0x2ba0, 0x2009, 0x0001, 0x2011, 0x0013, - 0x2019, 0x0010, 0x783b, 0x0017, 0x0078, 0x2b2c, 0x7d38, 0x7c3c, - 0x0078, 0x2b60, 0x7d38, 0x7c3c, 0x0078, 0x2b6c, 0x2061, 0x1000, - 0x610c, 0xa006, 0x2c14, 0xa200, 0x8c60, 0x8109, 0x00c0, 0x2ba2, - 0x2010, 0xa005, 0x0040, 0x2b2c, 0x0078, 0x2b52, 0x2069, 0xa351, - 0x7824, 0x7930, 0xa11a, 0x00c8, 0x2b5a, 0x8019, 0x0040, 0x2b5a, - 0x684a, 0x6942, 0x782c, 0x6852, 0x7828, 0x6856, 0xa006, 0x685a, - 0x685e, 0x1078, 0x4dbd, 0x0078, 0x2b2c, 0x2069, 0xa351, 0x7824, - 0x7934, 0xa11a, 0x00c8, 0x2b5a, 0x8019, 0x0040, 0x2b5a, 0x684e, - 0x6946, 0x782c, 0x6862, 0x7828, 0x6866, 0xa006, 0x686a, 0x686e, - 0x1078, 0x494d, 0x0078, 0x2b2c, 0xa02e, 0x2520, 0x81ff, 0x00c0, - 0x2b56, 0x7924, 0x7b28, 0x7a2c, 0x20a9, 0x0005, 0x20a1, 0xa388, - 0x41a1, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, 0x0020, 0x1078, - 0x3562, 0x701b, 0x2bf4, 0x007c, 0x6834, 0x2008, 0xa084, 0x00ff, - 0xa096, 0x0011, 0x0040, 0x2c00, 0xa096, 0x0019, 0x00c0, 0x2b56, - 0x810f, 0xa18c, 0x00ff, 0x0040, 0x2b56, 0x710e, 0x700c, 0x8001, - 0x0040, 0x2c31, 0x700e, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, - 0x0020, 0x2061, 0xa3d1, 0x6224, 0x6328, 0x642c, 0x6530, 0xa290, - 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x1078, - 0x3562, 0x701b, 0x2c24, 0x007c, 0x6834, 0xa084, 0x00ff, 0xa096, - 0x0002, 0x0040, 0x2c2f, 0xa096, 0x000a, 0x00c0, 0x2b56, 0x0078, - 0x2c06, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x436e, - 0x00c0, 0x2c3f, 0x7007, 0x0003, 0x701b, 0x2c41, 0x007c, 0x1078, - 0x4a60, 0x127e, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, 0xa388, - 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, - 0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x127f, 0x0078, 0x3566, - 0x61a0, 0x7824, 0x60a2, 0x0078, 0x2b2c, 0x2091, 0x8000, 0x7823, - 0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, 0x2020, 0x2009, - 0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100, 0x6200, - 0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, 0x2009, 0x04fd, - 0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, - 0x2071, 0x0010, 0x20c1, 0x00f0, 0xa08a, 0x0003, 0x00c8, 0x0427, - 0x0078, 0x0423, 0x81ff, 0x00c0, 0x2b56, 0x7924, 0x810f, 0xa18c, - 0x00ff, 0x1078, 0x4501, 0x00c0, 0x2b5a, 0x7e38, 0xa684, 0x3fff, - 0xa082, 0x4000, 0x0048, 0x2c9e, 0x0078, 0x2b5a, 0x7c28, 0x7d2c, - 0x1078, 0x46d6, 0xd28c, 0x00c0, 0x2ca9, 0x1078, 0x466a, 0x0078, - 0x2cab, 0x1078, 0x46a4, 0x00c0, 0x2cd5, 0x2061, 0xaa00, 0x127e, - 0x2091, 0x8000, 0x6000, 0xa086, 0x0000, 0x0040, 0x2cc3, 0x6010, - 0xa06d, 0x0040, 0x2cc3, 0x683c, 0xa406, 0x00c0, 0x2cc3, 0x6840, - 0xa506, 0x0040, 0x2cce, 0x127f, 0xace0, 0x0010, 0x2001, 0xa315, - 0x2004, 0xac02, 0x00c8, 0x2b56, 0x0078, 0x2caf, 0x1078, 0x8758, - 0x127f, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0xa00e, 0x2001, 0x0005, - 0x1078, 0x4a60, 0x127e, 0x2091, 0x8000, 0x1078, 0x8cc0, 0x1078, - 0x4982, 0x127f, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x1078, - 0x3530, 0x0040, 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, - 0x46e4, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, - 0x1078, 0x3542, 0x0040, 0x2b5a, 0x1078, 0x475f, 0x0040, 0x2b56, - 0x2019, 0x0005, 0x1078, 0x4705, 0x0040, 0x2b56, 0x7828, 0xa08a, - 0x1000, 0x00c8, 0x2b5a, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, - 0x58e1, 0x0078, 0x2b2c, 0x127e, 0x2091, 0x8000, 0x81ff, 0x0040, - 0x2d1d, 0x2009, 0x0001, 0x0078, 0x2d4e, 0x2029, 0x00ff, 0x644c, - 0x2400, 0xa506, 0x0040, 0x2d48, 0x2508, 0x1078, 0x4501, 0x00c0, - 0x2d48, 0x1078, 0x475f, 0x00c0, 0x2d33, 0x2009, 0x0002, 0x62a8, - 0x2518, 0x0078, 0x2d4e, 0x2019, 0x0004, 0x1078, 0x4705, 0x00c0, - 0x2d3d, 0x2009, 0x0006, 0x0078, 0x2d4e, 0x7824, 0xa08a, 0x1000, - 0x00c8, 0x2d51, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, 0x58e1, - 0x8529, 0x00c8, 0x2d20, 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, - 0x2b56, 0x127f, 0x0078, 0x2b5a, 0x1078, 0x3530, 0x0040, 0x2b5a, - 0x1078, 0x461b, 0x1078, 0x46d6, 0x0078, 0x2b2c, 0x81ff, 0x00c0, - 0x2b56, 0x1078, 0x3530, 0x0040, 0x2b5a, 0x1078, 0x460a, 0x1078, - 0x46d6, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, - 0x0040, 0x2b5a, 0x1078, 0x46a7, 0x0040, 0x2b56, 0x1078, 0x43c1, - 0x1078, 0x4663, 0x1078, 0x46d6, 0x0078, 0x2b2c, 0x1078, 0x3530, - 0x0040, 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x62a0, 0x2019, - 0x0005, 0x0c7e, 0x1078, 0x471b, 0x0c7f, 0x1078, 0x5d53, 0x077e, - 0x2039, 0x0000, 0x1078, 0x5c78, 0x2009, 0x0000, 0x1078, 0x9c38, - 0x077f, 0x1078, 0x46d6, 0x0078, 0x2b2c, 0x1078, 0x3530, 0x0040, - 0x2b5a, 0x1078, 0x46d6, 0x2208, 0x0078, 0x2b2c, 0x157e, 0x0d7e, - 0x0e7e, 0x2069, 0xa413, 0x6810, 0x6914, 0xa10a, 0x00c8, 0x2db2, - 0x2009, 0x0000, 0x6816, 0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, - 0x00ff, 0x2069, 0xa434, 0x2d04, 0xa075, 0x0040, 0x2dc7, 0x704c, - 0x1078, 0x2dd1, 0xa210, 0x7080, 0x1078, 0x2dd1, 0xa318, 0x8d68, - 0x00f0, 0x2dbb, 0x2300, 0xa218, 0x0e7f, 0x0d7f, 0x157f, 0x0078, - 0x2b2c, 0x0f7e, 0x017e, 0xa07d, 0x0040, 0x2de0, 0x2001, 0x0000, - 0x8000, 0x2f0c, 0x81ff, 0x0040, 0x2de0, 0x2178, 0x0078, 0x2dd8, - 0x017f, 0x0f7f, 0x007c, 0x2069, 0xa413, 0x6910, 0x62a4, 0x0078, - 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x614c, 0xa190, 0x293f, 0x2214, - 0xa294, 0x00ff, 0x606c, 0xa084, 0xff00, 0xa215, 0x6368, 0x67c8, - 0xd79c, 0x0040, 0x2dff, 0x2031, 0x0001, 0x0078, 0x2e01, 0x2031, - 0x0000, 0x7e3a, 0x7f3e, 0x0078, 0x2b2c, 0x613c, 0x6240, 0x2019, - 0xa5a0, 0x231c, 0x0078, 0x2b2c, 0x127e, 0x2091, 0x8000, 0x6134, - 0xa006, 0x2010, 0x2018, 0x127f, 0x0078, 0x2b2c, 0x1078, 0x3542, - 0x0040, 0x2b5a, 0x6244, 0x6338, 0x0078, 0x2b2c, 0x613c, 0x6240, - 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0xa351, 0x831f, 0xa305, - 0x6816, 0x782c, 0x2069, 0xa5a0, 0x2d1c, 0x206a, 0x0078, 0x2b2c, - 0x017e, 0x127e, 0x2091, 0x8000, 0x7824, 0x6036, 0xd094, 0x0040, - 0x2e43, 0x7828, 0xa085, 0x0001, 0x2009, 0xa5a9, 0x200a, 0x2001, - 0xffff, 0x1078, 0x5975, 0x127f, 0x017f, 0x0078, 0x2b2c, 0x1078, - 0x3542, 0x0040, 0x2b5a, 0x7828, 0xa00d, 0x0040, 0x2b5a, 0x782c, - 0xa005, 0x0040, 0x2b5a, 0x6244, 0x6146, 0x6338, 0x603a, 0x0078, - 0x2b2c, 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, - 0x0c7e, 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, - 0x00ff, 0x00c0, 0x2e70, 0x6030, 0xa085, 0xff00, 0x0078, 0x2e7f, - 0xa182, 0x007f, 0x00c8, 0x2ea9, 0xa188, 0x293f, 0x210c, 0xa18c, - 0x00ff, 0x6030, 0xa116, 0x0040, 0x2ea9, 0x810f, 0xa105, 0x127e, - 0x2091, 0x8000, 0x007e, 0x1078, 0x74d7, 0x007f, 0x0040, 0x2ea5, - 0x601a, 0x600b, 0xbc09, 0x601f, 0x0001, 0x1078, 0x3518, 0x0040, - 0x2eac, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, - 0xc0fd, 0x683a, 0x701b, 0x2f07, 0x2d00, 0x6012, 0x2009, 0x0032, - 0x1078, 0x756c, 0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078, - 0x2b56, 0x0c7f, 0x0078, 0x2b5a, 0x1078, 0x753d, 0x0078, 0x2ea5, - 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, 0x0c7e, - 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, - 0x00c0, 0x2ec7, 0x6030, 0xa085, 0xff00, 0x0078, 0x2ed6, 0xa182, - 0x007f, 0x00c8, 0x2f00, 0xa188, 0x293f, 0x210c, 0xa18c, 0x00ff, - 0x6030, 0xa116, 0x0040, 0x2f00, 0x810f, 0xa105, 0x127e, 0x2091, - 0x8000, 0x007e, 0x1078, 0x74d7, 0x007f, 0x0040, 0x2efc, 0x601a, - 0x600b, 0xbc05, 0x601f, 0x0001, 0x1078, 0x3518, 0x0040, 0x2f03, - 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, - 0x683a, 0x701b, 0x2f07, 0x2d00, 0x6012, 0x2009, 0x0032, 0x1078, - 0x756c, 0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078, 0x2b56, - 0x0c7f, 0x0078, 0x2b5a, 0x1078, 0x753d, 0x0078, 0x2efc, 0x6830, - 0xa086, 0x0100, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0x2061, 0xa62d, - 0x127e, 0x2091, 0x8000, 0x6000, 0xd084, 0x0040, 0x2f1c, 0x6104, - 0x6208, 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, 0x2b5a, 0x81ff, - 0x00c0, 0x2b56, 0x127e, 0x2091, 0x8000, 0x6244, 0x6060, 0xa202, - 0x0048, 0x2f33, 0xa085, 0x0001, 0x1078, 0x2500, 0x1078, 0x3bf5, - 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, 0x2b5a, 0x127e, 0x2091, - 0x8000, 0x20a9, 0x0011, 0x2001, 0xa340, 0x20a0, 0xa006, 0x40a4, - 0x127f, 0x0078, 0x2b2c, 0x7d38, 0x7c3c, 0x0078, 0x2bde, 0x7824, - 0xa09c, 0x00ff, 0xa39a, 0x0003, 0x00c8, 0x2b56, 0x624c, 0xa084, - 0xff00, 0x8007, 0xa206, 0x00c0, 0x2f5f, 0x2001, 0xa340, 0x2009, - 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x3566, 0x81ff, - 0x00c0, 0x2b56, 0x1078, 0x3542, 0x0040, 0x2b5a, 0x6004, 0xa084, - 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2b56, 0x0c7e, 0x1078, 0x3518, - 0x0c7f, 0x0040, 0x2b56, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, - 0x1078, 0x8b85, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, 0x2f81, - 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x2b56, 0xad80, 0x000e, - 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x3566, - 0x1078, 0x3518, 0x0040, 0x2b56, 0x1078, 0x421a, 0x2009, 0x001c, - 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3562, 0x701b, 0x2fa1, - 0x007c, 0xade8, 0x000d, 0x6800, 0xa005, 0x0040, 0x2b5a, 0x6804, - 0xd0ac, 0x0040, 0x2fae, 0xd0a4, 0x0040, 0x2b5a, 0xd094, 0x0040, - 0x2fb9, 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18c, 0xffdf, 0x6106, - 0x0c7f, 0xd08c, 0x0040, 0x2fc4, 0x0c7e, 0x2061, 0x0100, 0x6104, - 0xa18d, 0x0010, 0x6106, 0x0c7f, 0x2009, 0x0100, 0x210c, 0xa18a, - 0x0002, 0x0048, 0x2fd9, 0xd084, 0x0040, 0x2fd9, 0x6a28, 0xa28a, - 0x007f, 0x00c8, 0x2b5a, 0xa288, 0x293f, 0x210c, 0xa18c, 0x00ff, - 0x6152, 0xd0dc, 0x0040, 0x2fe2, 0x6828, 0xa08a, 0x007f, 0x00c8, - 0x2b5a, 0x604e, 0x6808, 0xa08a, 0x0100, 0x0048, 0x2b5a, 0xa08a, - 0x0841, 0x00c8, 0x2b5a, 0xa084, 0x0007, 0x00c0, 0x2b5a, 0x680c, - 0xa005, 0x0040, 0x2b5a, 0x6810, 0xa005, 0x0040, 0x2b5a, 0x6848, - 0x6940, 0xa10a, 0x00c8, 0x2b5a, 0x8001, 0x0040, 0x2b5a, 0x684c, - 0x6944, 0xa10a, 0x00c8, 0x2b5a, 0x8001, 0x0040, 0x2b5a, 0x6804, - 0xd0fc, 0x0040, 0x3038, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, - 0x0014, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0xa290, 0x0038, 0xa399, - 0x0000, 0x1078, 0x3562, 0x701b, 0x301e, 0x007c, 0xade8, 0x000d, - 0x20a9, 0x0014, 0x2d98, 0x2069, 0xa36d, 0x2da0, 0x53a3, 0x7010, - 0xa0e8, 0x000d, 0x2001, 0xa371, 0x200c, 0xd1e4, 0x0040, 0x3038, - 0x0c7e, 0x2061, 0x0100, 0x6004, 0xa085, 0x0b00, 0x6006, 0x0c7f, - 0x20a9, 0x001c, 0x2d98, 0x2069, 0xa351, 0x2da0, 0x53a3, 0x6814, - 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, 0x00ff, 0x6042, 0x1078, - 0x4dbd, 0x1078, 0x48dd, 0x1078, 0x494d, 0x6000, 0xa086, 0x0000, - 0x00c0, 0x30c3, 0x6808, 0x602a, 0x1078, 0x218b, 0x6818, 0x691c, - 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a, - 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0040, 0x3070, 0x6830, 0x6934, - 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f, 0x0078, 0x3072, - 0xa084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, 0x1078, 0x59a8, - 0x6904, 0xd1fc, 0x0040, 0x30a5, 0x0c7e, 0x2009, 0x0000, 0x20a9, - 0x0001, 0x6b70, 0xd384, 0x0040, 0x30a2, 0x0078, 0x308c, 0x839d, - 0x00c8, 0x30a2, 0x3508, 0x8109, 0x1078, 0x5364, 0x6878, 0x6016, - 0x6874, 0x2008, 0xa084, 0xff00, 0x8007, 0x600a, 0xa184, 0x00ff, - 0x6006, 0x8108, 0x00c0, 0x30a0, 0x6003, 0x0003, 0x0078, 0x30a2, - 0x6003, 0x0001, 0x00f0, 0x3087, 0x0c7f, 0x0c7e, 0x2061, 0x0100, - 0x602f, 0x0040, 0x602f, 0x0000, 0x0c7f, 0x1078, 0x3784, 0x0040, - 0x30b3, 0x1078, 0x2500, 0x60bc, 0xa005, 0x0040, 0x30bf, 0x6003, - 0x0001, 0x2091, 0x301d, 0x1078, 0x4171, 0x0078, 0x30c3, 0x6003, - 0x0004, 0x2091, 0x301d, 0x0078, 0x2b2c, 0x6000, 0xa086, 0x0000, - 0x0040, 0x2b56, 0x2069, 0xa351, 0x7830, 0x6842, 0x7834, 0x6846, - 0x6804, 0xd0fc, 0x0040, 0x30d8, 0x2009, 0x0030, 0x0078, 0x30da, - 0x2009, 0x001c, 0x2d00, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, - 0x3566, 0xa006, 0x1078, 0x2500, 0x81ff, 0x00c0, 0x2b56, 0x1078, - 0x421a, 0x1078, 0x4171, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, - 0x6180, 0x81ff, 0x0040, 0x3107, 0x703f, 0x0000, 0x2001, 0xa9c0, - 0x2009, 0x0040, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x127e, 0x2091, - 0x8000, 0x1078, 0x3566, 0x701b, 0x2b29, 0x127f, 0x007c, 0x703f, - 0x0001, 0x0d7e, 0x2069, 0xa9c0, 0x20a9, 0x0040, 0x20a1, 0xa9c0, - 0x2019, 0xffff, 0x43a4, 0x654c, 0xa588, 0x293f, 0x210c, 0xa18c, - 0x00ff, 0x216a, 0xa00e, 0x2011, 0x0002, 0x2100, 0xa506, 0x0040, - 0x3139, 0x1078, 0x4501, 0x00c0, 0x3139, 0x6014, 0x821c, 0x0048, - 0x3131, 0xa398, 0xa9c0, 0xa085, 0xff00, 0x8007, 0x201a, 0x0078, - 0x3138, 0xa398, 0xa9c0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, - 0x8210, 0x8108, 0xa182, 0x0080, 0x00c8, 0x3140, 0x0078, 0x311d, - 0x8201, 0x8007, 0x2d0c, 0xa105, 0x206a, 0x0d7f, 0x20a9, 0x0040, - 0x20a1, 0xa9c0, 0x2099, 0xa9c0, 0x1078, 0x41be, 0x0078, 0x30f6, - 0x1078, 0x3542, 0x0040, 0x2b5a, 0x0c7e, 0x1078, 0x3518, 0x0c7f, - 0x00c0, 0x315e, 0x2009, 0x0002, 0x0078, 0x2b56, 0x2001, 0xa352, - 0x2004, 0xd0b4, 0x0040, 0x3185, 0x6000, 0xd08c, 0x00c0, 0x3185, - 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x3185, 0x6837, - 0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x8bd9, 0x00c0, 0x317c, - 0x2009, 0x0003, 0x0078, 0x2b56, 0x7007, 0x0003, 0x701b, 0x3181, - 0x007c, 0x1078, 0x3542, 0x0040, 0x2b5a, 0x20a9, 0x002b, 0x2c98, - 0xade8, 0x0002, 0x2da0, 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, - 0x2098, 0xad80, 0x0006, 0x20a0, 0x1078, 0x41be, 0x20a9, 0x0004, - 0xac80, 0x000a, 0x2098, 0xad80, 0x000a, 0x20a0, 0x1078, 0x41be, - 0x2d00, 0x2009, 0x002b, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, - 0x3566, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, 0x0040, 0x2b5a, - 0x1078, 0x46ef, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x7828, - 0xa08a, 0x1000, 0x00c8, 0x2b5a, 0x1078, 0x3542, 0x0040, 0x2b5a, - 0x1078, 0x475f, 0x0040, 0x2b56, 0x2019, 0x0004, 0x1078, 0x4705, - 0x7924, 0x810f, 0x7a28, 0x1078, 0x31cf, 0x0078, 0x2b2c, 0xa186, - 0x00ff, 0x0040, 0x31d7, 0x1078, 0x31e7, 0x0078, 0x31e6, 0x2029, - 0x007e, 0x2061, 0xa300, 0x644c, 0x2400, 0xa506, 0x0040, 0x31e3, - 0x2508, 0x1078, 0x31e7, 0x8529, 0x00c8, 0x31dc, 0x007c, 0x1078, - 0x4501, 0x00c0, 0x31f2, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108, - 0x1078, 0x58e1, 0x007c, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, - 0x0040, 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, 0x46fa, - 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, 0x0040, - 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, 0x46e4, 0x0078, - 0x2b2c, 0x6100, 0x0078, 0x2b2c, 0x1078, 0x3542, 0x0040, 0x2b5a, - 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, 0x0d7e, - 0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x3228, 0xace8, 0x0006, - 0x680c, 0x8007, 0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, - 0x6a00, 0x8217, 0x0d7f, 0x6100, 0xa18c, 0x0200, 0x0078, 0x2b2c, - 0xa006, 0x1078, 0x2500, 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff, - 0x0040, 0x3245, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x421a, 0x7828, - 0xa08a, 0x1000, 0x00c8, 0x2b5a, 0x7924, 0xa18c, 0xff00, 0x810f, - 0xa186, 0x00ff, 0x0040, 0x325b, 0xa182, 0x007f, 0x00c8, 0x2b5a, - 0x2100, 0x1078, 0x24fa, 0x027e, 0x0c7e, 0x127e, 0x2091, 0x8000, - 0x2061, 0xa5be, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0x0100, - 0x6030, 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, 0x0090, - 0x6043, 0x0010, 0x2009, 0x002d, 0x2011, 0x4196, 0x1078, 0x596c, - 0x7924, 0xa18c, 0xff00, 0x810f, 0x7a28, 0x1078, 0x31cf, 0x127f, - 0x0c7f, 0x027f, 0x0078, 0x2b2c, 0x7924, 0xa18c, 0xff00, 0x810f, - 0x0c7e, 0x1078, 0x4499, 0x2c08, 0x0c7f, 0x00c0, 0x2b5a, 0x0078, - 0x2b2c, 0x81ff, 0x0040, 0x3298, 0x2009, 0x0001, 0x0078, 0x2b56, - 0x60c8, 0xd09c, 0x00c0, 0x32a0, 0x2009, 0x0005, 0x0078, 0x2b56, - 0x1078, 0x3518, 0x00c0, 0x32a8, 0x2009, 0x0002, 0x0078, 0x2b56, - 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3562, 0x701b, - 0x32b2, 0x007c, 0x2009, 0x0080, 0x1078, 0x4501, 0x00c0, 0x32bf, - 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0040, 0x32c3, 0x2021, - 0x400a, 0x0078, 0x2b2e, 0x0d7e, 0xade8, 0x000d, 0x6900, 0x6a08, - 0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, 0x0100, 0x0040, - 0x3336, 0xa0be, 0x0112, 0x0040, 0x3336, 0xa0be, 0x0113, 0x0040, - 0x3336, 0xa0be, 0x0114, 0x0040, 0x3336, 0xa0be, 0x0117, 0x0040, - 0x3336, 0xa0be, 0x011a, 0x0040, 0x3336, 0xa0be, 0x0121, 0x0040, - 0x332c, 0xa0be, 0x0131, 0x0040, 0x332c, 0xa0be, 0x0171, 0x0040, - 0x3336, 0xa0be, 0x0173, 0x0040, 0x3336, 0xa0be, 0x01a1, 0x00c0, - 0x32fe, 0x6830, 0x8007, 0x6832, 0x0078, 0x333c, 0xa0be, 0x0212, - 0x0040, 0x3332, 0xa0be, 0x0213, 0x0040, 0x3332, 0xa0be, 0x0214, - 0x0040, 0x3324, 0xa0be, 0x0217, 0x0040, 0x331e, 0xa0be, 0x021a, - 0x00c0, 0x3317, 0x6838, 0x8007, 0x683a, 0x0078, 0x3336, 0xa0be, - 0x0300, 0x0040, 0x3336, 0x0d7f, 0x0078, 0x2b5a, 0xad80, 0x0010, - 0x20a9, 0x0007, 0x1078, 0x337e, 0xad80, 0x000e, 0x20a9, 0x0001, - 0x1078, 0x337e, 0x0078, 0x3336, 0xad80, 0x000c, 0x1078, 0x338c, - 0x0078, 0x333c, 0xad80, 0x000e, 0x1078, 0x338c, 0xad80, 0x000c, - 0x20a9, 0x0001, 0x1078, 0x337e, 0x0c7e, 0x1078, 0x3518, 0x0040, - 0x336f, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119, 0x6853, 0x0000, - 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, 0x0000, - 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, 0x0c7f, - 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, - 0x6804, 0x2068, 0x1078, 0x8ba1, 0x00c0, 0x336a, 0x2009, 0x0003, - 0x0078, 0x2b56, 0x7007, 0x0003, 0x701b, 0x3375, 0x007c, 0x0c7f, - 0x0d7f, 0x2009, 0x0002, 0x0078, 0x2b56, 0x6820, 0xa086, 0x8001, - 0x00c0, 0x2b2c, 0x2009, 0x0004, 0x0078, 0x2b56, 0x017e, 0x2008, - 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108, - 0x00f0, 0x3380, 0x017f, 0x007c, 0x017e, 0x0a7e, 0x0b7e, 0x2008, - 0x2044, 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a, - 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, 0x0b7f, 0x0a7f, - 0x017f, 0x007c, 0x81ff, 0x0040, 0x33a9, 0x2009, 0x0001, 0x0078, - 0x2b56, 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, - 0x0048, 0x2b5a, 0xa182, 0x00ff, 0x00c8, 0x2b5a, 0x7a2c, 0x7b28, - 0x6068, 0xa306, 0x00c0, 0x33c4, 0x606c, 0xa24e, 0x0040, 0x2b5a, - 0xa9cc, 0xff00, 0x0040, 0x2b5a, 0x0c7e, 0x1078, 0x346d, 0x2c68, - 0x0c7f, 0x0040, 0x33fc, 0xa0c6, 0x4000, 0x00c0, 0x33e2, 0x0c7e, - 0x007e, 0x2d60, 0x2009, 0x0000, 0x1078, 0x47cb, 0x00c0, 0x33d9, - 0xc185, 0x6000, 0xd0bc, 0x0040, 0x33de, 0xc18d, 0x007f, 0x0c7f, - 0x0078, 0x33f9, 0xa0c6, 0x4007, 0x00c0, 0x33e9, 0x2408, 0x0078, - 0x33f9, 0xa0c6, 0x4008, 0x00c0, 0x33f1, 0x2708, 0x2610, 0x0078, - 0x33f9, 0xa0c6, 0x4009, 0x00c0, 0x33f7, 0x0078, 0x33f9, 0x2001, - 0x4006, 0x2020, 0x0078, 0x2b2e, 0x2d00, 0x7022, 0x017e, 0x0b7e, - 0x0c7e, 0x0e7e, 0x2c70, 0x1078, 0x74d7, 0x0040, 0x3442, 0x2d00, - 0x601a, 0x2001, 0xa356, 0x2004, 0xa084, 0x00ff, 0x6842, 0x2e58, - 0x0e7f, 0x0e7e, 0x0c7e, 0x1078, 0x3518, 0x0c7f, 0x2b70, 0x00c0, - 0x3423, 0x1078, 0x753d, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x2009, - 0x0002, 0x0078, 0x2b56, 0x6837, 0x0000, 0x2d00, 0x6012, 0x6833, - 0x0000, 0x6838, 0xc0fd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, - 0x2813, 0x127f, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x442b, - 0x2001, 0x0002, 0x1078, 0x443f, 0x2009, 0x0002, 0x1078, 0x756c, - 0xa085, 0x0001, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x00c0, 0x344c, - 0x2009, 0x0003, 0x0078, 0x2b56, 0x7007, 0x0003, 0x701b, 0x3451, - 0x007c, 0x6830, 0xa086, 0x0100, 0x7020, 0x2060, 0x00c0, 0x345f, - 0x2009, 0x0004, 0x6204, 0xa294, 0x00ff, 0x0078, 0x2b56, 0x2009, - 0x0000, 0x1078, 0x47cb, 0x00c0, 0x3466, 0xc185, 0x6000, 0xd0bc, - 0x0040, 0x346b, 0xc18d, 0x0078, 0x2b2c, 0x0e7e, 0x0d7e, 0x2029, - 0x0000, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, 0xa4b4, 0x2e04, - 0xa005, 0x00c0, 0x3482, 0x2100, 0xa406, 0x00c0, 0x34b3, 0x2428, - 0x0078, 0x34b3, 0x2068, 0x6f10, 0x2700, 0xa306, 0x00c0, 0x34a4, - 0x6e14, 0x2600, 0xa206, 0x00c0, 0x34a4, 0x2400, 0xa106, 0x00c0, - 0x34a0, 0x2d60, 0xd884, 0x0040, 0x34c8, 0x6004, 0xa084, 0x00ff, - 0xa086, 0x0006, 0x00c0, 0x34c8, 0x2001, 0x4000, 0x0078, 0x34c9, - 0x2001, 0x4007, 0x0078, 0x34c9, 0x2400, 0xa106, 0x00c0, 0x34b3, - 0x6e14, 0x87ff, 0x00c0, 0x34af, 0x86ff, 0x0040, 0x347f, 0x2001, - 0x4008, 0x0078, 0x34c9, 0x8420, 0x8e70, 0x00f0, 0x3477, 0x85ff, - 0x00c0, 0x34c2, 0x2001, 0x4009, 0x0078, 0x34c9, 0x2001, 0x0001, - 0x0078, 0x34c9, 0x1078, 0x4499, 0x00c0, 0x34be, 0x6312, 0x6216, - 0xa006, 0xa005, 0x0d7f, 0x0e7f, 0x007c, 0x81ff, 0x00c0, 0x2b56, - 0x1078, 0x3518, 0x0040, 0x2b56, 0x6837, 0x0000, 0x6838, 0xc0fd, - 0x683a, 0x7824, 0xa005, 0x0040, 0x2b5a, 0xa096, 0x00ff, 0x0040, - 0x34e5, 0xa092, 0x0004, 0x00c8, 0x2b5a, 0x2010, 0x2d18, 0x1078, - 0x27c2, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, 0x34f0, 0x007c, - 0x6830, 0xa086, 0x0100, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0x7924, - 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, 0x0048, 0x2b5a, 0xa182, - 0x00ff, 0x00c8, 0x2b5a, 0x127e, 0x2091, 0x8000, 0x1078, 0x8a89, - 0x00c0, 0x3515, 0xa190, 0xa434, 0x2204, 0xa065, 0x0040, 0x3515, - 0x1078, 0x4235, 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, 0x2b56, - 0x1078, 0x1381, 0x0040, 0x352f, 0xa006, 0x6802, 0x7010, 0xa005, - 0x00c0, 0x3527, 0x2d00, 0x7012, 0x7016, 0x0078, 0x352d, 0x7014, - 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80, 0x000d, 0x007c, - 0x7924, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x4501, 0x00c0, 0x353f, - 0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0048, 0x3540, 0xa066, - 0x8cff, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x1078, 0x4501, - 0x00c0, 0x3550, 0xa6b4, 0x00ff, 0xa682, 0x4000, 0x0048, 0x3551, - 0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff, 0x0040, 0x355e, - 0x2168, 0x6904, 0x1078, 0x139a, 0x0078, 0x3555, 0x7112, 0x7116, - 0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x3568, 0x2031, 0x0000, - 0x2061, 0xa3d1, 0x6606, 0x6112, 0x600e, 0x6226, 0x632a, 0x642e, - 0x6532, 0x2c10, 0x1078, 0x13d1, 0x7007, 0x0002, 0x701b, 0x2b2c, - 0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, 0x0000, 0x2001, - 0xa38f, 0x2004, 0xa005, 0x00c0, 0x3594, 0x0068, 0x3594, 0x7818, - 0xd084, 0x00c0, 0x3594, 0x7a22, 0x7b26, 0x7c2a, 0x781b, 0x0001, - 0x2091, 0x4080, 0x0078, 0x35b9, 0x017e, 0x0c7e, 0x0e7e, 0x2071, - 0xa381, 0x7138, 0xa182, 0x0008, 0x0048, 0x35a2, 0x7030, 0x2060, - 0x0078, 0x35b3, 0x7030, 0xa0e0, 0x0008, 0xac82, 0xa3d1, 0x0048, - 0x35ab, 0x2061, 0xa391, 0x2c00, 0x7032, 0x81ff, 0x00c0, 0x35b1, - 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, 0x0e7f, 0x0c7f, - 0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071, 0xa381, 0x7038, - 0xa005, 0x0040, 0x35f5, 0x127e, 0x2091, 0x8000, 0x0068, 0x35f4, - 0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, 0x35f3, 0x0c7e, - 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826, 0x6008, 0x782a, - 0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001, 0x703a, 0xa005, - 0x00c0, 0x35e9, 0x7033, 0xa391, 0x7037, 0xa391, 0x0c7f, 0x0078, - 0x35f3, 0xac80, 0x0008, 0xa0fa, 0xa3d1, 0x0048, 0x35f1, 0x2001, - 0xa391, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f, 0x007c, 0x027e, - 0x2001, 0xa352, 0x2004, 0xd0c4, 0x0040, 0x3602, 0x2011, 0x8014, - 0x1078, 0x3579, 0x027f, 0x007c, 0x81ff, 0x00c0, 0x2b56, 0x127e, - 0x2091, 0x8000, 0x6030, 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x1078, - 0x4171, 0x127f, 0x0078, 0x2b2c, 0x7824, 0x2008, 0xa18c, 0xfffd, - 0x00c0, 0x361f, 0x61d4, 0xa10d, 0x61d6, 0x0078, 0x2b2c, 0x0078, - 0x2b5a, 0x81ff, 0x00c0, 0x2b56, 0x6000, 0xa086, 0x0003, 0x00c0, - 0x2b56, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x2b56, 0x1078, - 0x3542, 0x0040, 0x2b5a, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, - 0x00c0, 0x363e, 0x7828, 0xa005, 0x0040, 0x2b2c, 0x0c7e, 0x1078, - 0x3518, 0x0c7f, 0x0040, 0x2b56, 0x6837, 0x0000, 0x6833, 0x0000, - 0x6838, 0xc0fd, 0x683a, 0x1078, 0x8c4d, 0x0040, 0x2b56, 0x7007, - 0x0003, 0x701b, 0x3654, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, - 0x2b56, 0x0078, 0x2b2c, 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, - 0x00c0, 0x2b56, 0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, - 0x3518, 0x0040, 0x2b56, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, - 0x0000, 0x702f, 0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x1078, - 0x4501, 0x00c0, 0x36d8, 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, - 0x0040, 0x3688, 0xa0c4, 0xff00, 0xa8c6, 0x0600, 0x00c0, 0x36d8, - 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x3695, 0x1078, 0x47cb, - 0x00c0, 0x3695, 0xd79c, 0x0040, 0x36d8, 0xd794, 0x00c0, 0x369b, - 0xd784, 0x0040, 0x36a7, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, - 0x0004, 0x53a3, 0x1078, 0x338c, 0xd794, 0x0040, 0x36b0, 0xac80, - 0x000a, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x1078, 0x338c, - 0x21a2, 0xd794, 0x0040, 0x36d0, 0xac80, 0x0000, 0x2098, 0x94a0, - 0x20a9, 0x0002, 0x53a3, 0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80, - 0x0004, 0x2098, 0x3400, 0x20a9, 0x0002, 0x53a3, 0x1078, 0x337e, - 0xac80, 0x0026, 0x2098, 0x20a9, 0x0002, 0x53a3, 0x0078, 0x36d1, - 0x94a0, 0xd794, 0x0040, 0x36d6, 0xa6b0, 0x000b, 0xa6b0, 0x0005, - 0x8108, 0xd78c, 0x0040, 0x36e2, 0xa186, 0x0100, 0x0040, 0x36f3, - 0x0078, 0x36e6, 0xa186, 0x007e, 0x0040, 0x36f3, 0xd794, 0x0040, - 0x36ed, 0xa686, 0x0020, 0x0078, 0x36ef, 0xa686, 0x0028, 0x0040, - 0x36fc, 0x0078, 0x3677, 0x86ff, 0x00c0, 0x36fa, 0x7120, 0x810b, - 0x0078, 0x2b2c, 0x702f, 0x0001, 0x711e, 0x7020, 0xa600, 0x7022, - 0x772a, 0x2061, 0xa3d1, 0x6007, 0x0000, 0x6612, 0x7024, 0x600e, - 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x13d1, 0x7007, - 0x0002, 0x701b, 0x3714, 0x007c, 0x702c, 0xa005, 0x00c0, 0x3726, - 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, 0x0000, 0x2061, 0xa3d1, - 0x6224, 0x6328, 0x642c, 0x6530, 0x0078, 0x3677, 0x7120, 0x810b, - 0x0078, 0x2b2c, 0x2029, 0x007e, 0x7924, 0x7a28, 0x7b2c, 0x7c38, - 0xa184, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2b5a, 0xa502, - 0x0048, 0x2b5a, 0xa184, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2b5a, - 0xa502, 0x0048, 0x2b5a, 0xa284, 0xff00, 0x8007, 0xa0e2, 0x0020, - 0x0048, 0x2b5a, 0xa502, 0x0048, 0x2b5a, 0xa284, 0x00ff, 0xa0e2, - 0x0020, 0x0048, 0x2b5a, 0xa502, 0x0048, 0x2b5a, 0xa384, 0xff00, - 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2b5a, 0xa502, 0x0048, 0x2b5a, - 0xa384, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2b5a, 0xa502, 0x0048, - 0x2b5a, 0xa484, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2b5a, - 0xa502, 0x0048, 0x2b5a, 0xa484, 0x00ff, 0xa0e2, 0x0020, 0x0048, - 0x2b5a, 0xa502, 0x0048, 0x2b5a, 0x2061, 0xa5a3, 0x6102, 0x6206, - 0x630a, 0x640e, 0x0078, 0x2b2c, 0x007e, 0x2001, 0xa352, 0x2004, - 0xd0cc, 0x007f, 0x007c, 0x007e, 0x2001, 0xa371, 0x2004, 0xd0bc, - 0x007f, 0x007c, 0x6160, 0x7a24, 0x6300, 0x82ff, 0x00c0, 0x379b, - 0x7926, 0x0078, 0x2b2c, 0x83ff, 0x00c0, 0x2b5a, 0x2001, 0xfff0, - 0xa200, 0x00c8, 0x2b5a, 0x2019, 0xffff, 0x6064, 0xa302, 0xa200, - 0x0048, 0x2b5a, 0x7926, 0x6262, 0x0078, 0x2b2c, 0x2001, 0xa300, - 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, 0x7c28, 0x7d24, 0x7e38, - 0x7f2c, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, 0x0000, 0x2019, - 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80, 0x0003, 0x7026, - 0x20a0, 0xa1e0, 0xa434, 0x2c64, 0x8cff, 0x0040, 0x37e8, 0x6004, - 0xa084, 0x00ff, 0xa086, 0x0006, 0x0040, 0x37dd, 0x6004, 0xa084, - 0xff00, 0xa086, 0x0600, 0x00c0, 0x37e8, 0x6014, 0x20a2, 0x94a0, - 0x6010, 0x8007, 0xa105, 0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002, - 0x8108, 0xa182, 0x00ff, 0x0040, 0x37f3, 0xa386, 0x002a, 0x0040, - 0x37fc, 0x0078, 0x37c9, 0x83ff, 0x00c0, 0x37fa, 0x7120, 0x810c, - 0x0078, 0x2b2c, 0x702f, 0x0001, 0x711e, 0x7020, 0xa300, 0x7022, - 0x2061, 0xa3d1, 0x6007, 0x0000, 0x6312, 0x7024, 0x600e, 0x6426, - 0x652a, 0x662e, 0x6732, 0x2c10, 0x1078, 0x13d1, 0x7007, 0x0002, - 0x701b, 0x3813, 0x007c, 0x702c, 0xa005, 0x00c0, 0x3824, 0x711c, - 0x7024, 0x20a0, 0x2019, 0x0000, 0x2061, 0xa3d1, 0x6424, 0x6528, - 0x662c, 0x6730, 0x0078, 0x37c9, 0x7120, 0x810c, 0x0078, 0x2b2c, - 0x81ff, 0x00c0, 0x2b56, 0x60c8, 0xd09c, 0x0040, 0x2b56, 0x1078, - 0x3518, 0x0040, 0x2b56, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, - 0x1078, 0x3562, 0x701b, 0x383d, 0x007c, 0x0d7e, 0xade8, 0x000d, - 0x6828, 0xa0be, 0x7000, 0x0040, 0x3850, 0xa0be, 0x7100, 0x0040, - 0x3850, 0xa0be, 0x7200, 0x0040, 0x3850, 0x0d7f, 0x0078, 0x2b5a, - 0x6820, 0x6924, 0x1078, 0x24e3, 0x00c0, 0x387b, 0x1078, 0x4499, - 0x00c0, 0x387b, 0x7122, 0x6612, 0x6516, 0x6e18, 0x0c7e, 0x1078, - 0x3518, 0x0040, 0x387b, 0x1078, 0x3518, 0x0040, 0x387b, 0x0c7f, - 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, - 0x6804, 0x2068, 0x1078, 0x8bbd, 0x0040, 0x2b56, 0x7007, 0x0003, - 0x701b, 0x387e, 0x007c, 0x0d7f, 0x0078, 0x2b56, 0x7120, 0x1078, - 0x2921, 0x6820, 0xa086, 0x8001, 0x0040, 0x2b56, 0x2d00, 0x701e, - 0x6804, 0xa080, 0x0002, 0x007e, 0x20a9, 0x002a, 0x2098, 0x20a0, - 0x1078, 0x41be, 0x007f, 0xade8, 0x000d, 0x6a08, 0x6b0c, 0x6c10, - 0x6d14, 0x2061, 0xa3d1, 0x6007, 0x0000, 0x6e00, 0x6f28, 0xa7c6, - 0x7000, 0x00c0, 0x38a5, 0x0078, 0x38a9, 0xa7c6, 0x7100, 0x00c0, - 0x38b1, 0xa6c2, 0x0004, 0x0048, 0x2b5a, 0x2009, 0x0004, 0x0078, - 0x3566, 0xa7c6, 0x7200, 0x00c0, 0x2b5a, 0xa6c2, 0x0054, 0x0048, - 0x2b5a, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a, 0x642e, 0x6532, - 0x2c10, 0x1078, 0x13d1, 0x7007, 0x0002, 0x701b, 0x38c8, 0x007c, - 0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004, 0xa080, 0x0002, - 0x007e, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x1078, 0x41be, 0x007f, - 0x2009, 0x002a, 0x2061, 0xa3d1, 0x6224, 0x6328, 0x642c, 0x6530, - 0x0078, 0x3566, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, 0x0040, - 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, 0x4710, 0x0078, - 0x2b2c, 0x7824, 0xd084, 0x0040, 0x3150, 0x1078, 0x3542, 0x0040, - 0x2b5a, 0x0c7e, 0x1078, 0x3518, 0x0c7f, 0x00c0, 0x3903, 0x2009, - 0x0002, 0x0078, 0x2b56, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, - 0x0040, 0x3910, 0xa08e, 0x0004, 0x0040, 0x3910, 0xa08e, 0x0005, - 0x00c0, 0x3934, 0x2001, 0xa352, 0x2004, 0xd0b4, 0x0040, 0x3185, - 0x6000, 0xd08c, 0x00c0, 0x3185, 0x6837, 0x0000, 0x6838, 0xc0fd, - 0x683a, 0x1078, 0x8bd9, 0x00c0, 0x3929, 0x2009, 0x0003, 0x0078, - 0x2b56, 0x7007, 0x0003, 0x701b, 0x392e, 0x007c, 0x1078, 0x3542, - 0x0040, 0x2b5a, 0x0078, 0x3185, 0x2009, 0xa32e, 0x210c, 0x81ff, - 0x0040, 0x393e, 0x2009, 0x0001, 0x0078, 0x2b56, 0x2001, 0xa300, - 0x2004, 0xa086, 0x0003, 0x0040, 0x3949, 0x2009, 0x0007, 0x0078, - 0x2b56, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x0040, 0x3953, 0x2009, - 0x0008, 0x0078, 0x2b56, 0x609c, 0xd0a4, 0x00c0, 0x395a, 0xd0ac, - 0x00c0, 0x3185, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, - 0x683a, 0x1078, 0x8c4d, 0x00c0, 0x3969, 0x2009, 0x0003, 0x0078, - 0x2b56, 0x7007, 0x0003, 0x701b, 0x396e, 0x007c, 0x6830, 0xa086, - 0x0100, 0x00c0, 0x3977, 0x2009, 0x0004, 0x0078, 0x2b56, 0x1078, - 0x3542, 0x0040, 0x2b5a, 0x0078, 0x3912, 0x81ff, 0x2009, 0x0001, - 0x00c0, 0x2b56, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x00c0, - 0x2b56, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x2009, 0x0008, 0x00c0, - 0x2b56, 0x1078, 0x3542, 0x0040, 0x2b5a, 0x6004, 0xa084, 0x00ff, - 0xa086, 0x0006, 0x2009, 0x0009, 0x00c0, 0x2b56, 0x0c7e, 0x1078, - 0x3518, 0x0c7f, 0x2009, 0x0002, 0x0040, 0x2b56, 0x6837, 0x0000, - 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7928, 0xa194, 0xff00, - 0xa18c, 0x00ff, 0xa006, 0x82ff, 0x00c0, 0x39bc, 0xc0ed, 0x6952, - 0x792c, 0x6956, 0x0078, 0x39c5, 0xa28e, 0x0100, 0x00c0, 0x2b5a, - 0xc0e5, 0x6853, 0x0000, 0x6857, 0x0000, 0x683e, 0x1078, 0x8df6, - 0x2009, 0x0003, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, 0x39d1, - 0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0040, 0x2b56, - 0x0078, 0x2b2c, 0x81ff, 0x2009, 0x0001, 0x00c0, 0x2b56, 0x6000, - 0xa086, 0x0003, 0x2009, 0x0007, 0x00c0, 0x2b56, 0x1078, 0x3542, - 0x0040, 0x2b5a, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x2009, - 0x0009, 0x00c0, 0x2b56, 0x0c7e, 0x1078, 0x3518, 0x0c7f, 0x2009, - 0x0002, 0x0040, 0x2b56, 0xad80, 0x000f, 0x2009, 0x0008, 0x7a2c, - 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3562, 0x701b, 0x3a08, 0x007c, - 0x0d7e, 0xade8, 0x000f, 0x6800, 0xa086, 0x0500, 0x00c0, 0x3a1b, - 0x6804, 0xa005, 0x00c0, 0x3a1b, 0x6808, 0xa084, 0xff00, 0x00c0, - 0x3a1b, 0x0078, 0x3a1e, 0x0d7f, 0x00c0, 0x2b5a, 0x0d7f, 0x6837, - 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x0c7e, 0x1078, - 0x3542, 0x00c0, 0x3a2e, 0x0c7f, 0x0078, 0x2b5a, 0x1078, 0x8e52, - 0x2009, 0x0003, 0x0c7f, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, - 0x3a3a, 0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0040, - 0x2b56, 0x0078, 0x2b2c, 0x127e, 0x0c7e, 0x0e7e, 0x2061, 0x0100, - 0x2071, 0xa300, 0x6044, 0xd0a4, 0x00c0, 0x3a6c, 0xd084, 0x0040, - 0x3a55, 0x1078, 0x3bcc, 0x0078, 0x3a68, 0xd08c, 0x0040, 0x3a5c, - 0x1078, 0x3ae3, 0x0078, 0x3a68, 0xd094, 0x0040, 0x3a63, 0x1078, - 0x3ab7, 0x0078, 0x3a68, 0xd09c, 0x0040, 0x3a68, 0x1078, 0x3a76, - 0x0e7f, 0x0c7f, 0x127f, 0x007c, 0x017e, 0x6128, 0xd19c, 0x00c0, - 0x3a73, 0xc19d, 0x612a, 0x017f, 0x0078, 0x3a68, 0x624c, 0xa286, - 0xf0f0, 0x00c0, 0x3a87, 0x6048, 0xa086, 0xf0f0, 0x0040, 0x3a87, - 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, 0x3ab6, 0xa294, - 0xff00, 0xa296, 0xf700, 0x0040, 0x3a9c, 0x7134, 0xd1a4, 0x00c0, - 0x3a9c, 0x6240, 0xa294, 0x0010, 0x0040, 0x3a9c, 0x2009, 0x00f7, - 0x1078, 0x41de, 0x0078, 0x3ab6, 0x6043, 0x0040, 0x6043, 0x0000, - 0x7073, 0x0000, 0x708b, 0x0001, 0x70af, 0x0000, 0x70cb, 0x0000, - 0x2009, 0xa9c0, 0x200b, 0x0000, 0x7083, 0x0000, 0x7077, 0x000f, - 0x2009, 0x000f, 0x2011, 0x4122, 0x1078, 0x596c, 0x007c, 0x157e, - 0x7074, 0xa005, 0x00c0, 0x3ae1, 0x2011, 0x4122, 0x1078, 0x58d4, - 0x6040, 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9, 0x00c8, - 0x6044, 0xd08c, 0x00c0, 0x3ada, 0x00f0, 0x3ac8, 0x6242, 0x7087, - 0x0000, 0x6040, 0xa094, 0x0010, 0xa285, 0x0080, 0x6042, 0x6242, - 0x0078, 0x3ae1, 0x6242, 0x7087, 0x0000, 0x707b, 0x0000, 0x0078, - 0x3ae1, 0x157f, 0x007c, 0x7078, 0xa08a, 0x0003, 0x00c8, 0x3aec, - 0x1079, 0x3aef, 0x0078, 0x3aee, 0x1078, 0x1328, 0x007c, 0x3af2, - 0x3b41, 0x3bcb, 0x0f7e, 0x707b, 0x0001, 0x20e1, 0xa000, 0x20e1, - 0x8700, 0x1078, 0x218b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2079, - 0xa800, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, 0x0000, 0x780f, - 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b, 0x0000, 0x781f, - 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b, 0x0000, 0x782f, - 0x0000, 0x2079, 0xa80c, 0x207b, 0x1101, 0x7807, 0x0000, 0x2099, - 0xa305, 0x20a1, 0xa80e, 0x20a9, 0x0004, 0x53a3, 0x2079, 0xa812, - 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0xa800, 0x20a1, 0x020b, - 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f, 0x0000, 0x1078, - 0x4158, 0x0f7f, 0x707f, 0x0000, 0x6043, 0x0008, 0x6043, 0x0000, - 0x007c, 0x0d7e, 0x707c, 0x707f, 0x0000, 0xa025, 0x0040, 0x3bb5, - 0x6020, 0xd0b4, 0x00c0, 0x3bb3, 0x7188, 0x81ff, 0x0040, 0x3ba2, - 0xa486, 0x000c, 0x00c0, 0x3bad, 0xa480, 0x0018, 0x8004, 0x20a8, - 0x2011, 0xa880, 0x2019, 0xa800, 0x220c, 0x2304, 0xa106, 0x00c0, - 0x3b79, 0x8210, 0x8318, 0x00f0, 0x3b5c, 0x6043, 0x0004, 0x608b, - 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x707b, 0x0002, 0x7087, - 0x0002, 0x2009, 0x07d0, 0x2011, 0x4129, 0x1078, 0x596c, 0x0078, - 0x3bb3, 0x2069, 0xa880, 0x6930, 0xa18e, 0x1101, 0x00c0, 0x3bad, - 0x6834, 0xa005, 0x00c0, 0x3bad, 0x6900, 0xa18c, 0x00ff, 0x00c0, - 0x3b8d, 0x6804, 0xa005, 0x0040, 0x3ba2, 0x2011, 0xa88e, 0x2019, - 0xa305, 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, 0x0048, 0x3ba0, - 0x00c0, 0x3bad, 0x8210, 0x8318, 0x00f0, 0x3b93, 0x0078, 0x3bad, - 0x708b, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, - 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, 0x0008, 0x6043, - 0x0000, 0x0078, 0x3bb5, 0x0d7f, 0x007c, 0x6020, 0xd0b4, 0x00c0, - 0x3bb3, 0x60c3, 0x000c, 0x2011, 0xa5b5, 0x2013, 0x0000, 0x707f, - 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078, - 0x6c38, 0x0078, 0x3bb3, 0x007c, 0x7084, 0xa08a, 0x001d, 0x00c8, - 0x3bd5, 0x1079, 0x3bd8, 0x0078, 0x3bd7, 0x1078, 0x1328, 0x007c, - 0x3c02, 0x3c11, 0x3c40, 0x3c59, 0x3c85, 0x3cb1, 0x3cdd, 0x3d13, - 0x3d3f, 0x3d67, 0x3daa, 0x3dd4, 0x3df6, 0x3e0c, 0x3e32, 0x3e45, - 0x3e4e, 0x3e7e, 0x3eaa, 0x3ed6, 0x3f02, 0x3f38, 0x3f7d, 0x3fac, - 0x3fce, 0x4010, 0x4036, 0x404f, 0x4050, 0x0c7e, 0x2061, 0xa300, - 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9, 0x6006, - 0x0c7f, 0x007c, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002, - 0x7087, 0x0001, 0x2009, 0x07d0, 0x2011, 0x4129, 0x1078, 0x596c, - 0x007c, 0x0f7e, 0x707c, 0xa086, 0x0014, 0x00c0, 0x3c3e, 0x6043, - 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x3c3e, 0x2079, 0xa880, 0x7a30, - 0xa296, 0x1102, 0x00c0, 0x3c3c, 0x7834, 0xa005, 0x00c0, 0x3c3c, - 0x7a38, 0xd2fc, 0x0040, 0x3c32, 0x70ac, 0xa005, 0x00c0, 0x3c32, - 0x70af, 0x0001, 0x2011, 0x4129, 0x1078, 0x58d4, 0x7087, 0x0010, - 0x1078, 0x3e4e, 0x0078, 0x3c3e, 0x1078, 0x4171, 0x0f7f, 0x007c, - 0x7087, 0x0003, 0x6043, 0x0004, 0x2011, 0x4129, 0x1078, 0x58d4, - 0x1078, 0x41c6, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a, - 0x20a3, 0x0000, 0x00f0, 0x3c50, 0x60c3, 0x0014, 0x1078, 0x4158, - 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3c83, 0x2011, 0x4129, - 0x1078, 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3c81, 0x2079, 0xa880, - 0x7a30, 0xa296, 0x1102, 0x00c0, 0x3c81, 0x7834, 0xa005, 0x00c0, - 0x3c81, 0x7a38, 0xd2fc, 0x0040, 0x3c7b, 0x70ac, 0xa005, 0x00c0, - 0x3c7b, 0x70af, 0x0001, 0x7087, 0x0004, 0x1078, 0x3c85, 0x0078, - 0x3c83, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x0005, 0x1078, - 0x41c6, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, - 0x1078, 0x4211, 0x00c0, 0x3ca3, 0x7070, 0xa005, 0x00c0, 0x3ca3, - 0x714c, 0xa186, 0xffff, 0x0040, 0x3ca3, 0x1078, 0x40ea, 0x0040, - 0x3ca3, 0x1078, 0x41f5, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, - 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3cdb, 0x2011, 0x4129, - 0x1078, 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3cd9, 0x2079, 0xa880, - 0x7a30, 0xa296, 0x1103, 0x00c0, 0x3cd9, 0x7834, 0xa005, 0x00c0, - 0x3cd9, 0x7a38, 0xd2fc, 0x0040, 0x3cd3, 0x70ac, 0xa005, 0x00c0, - 0x3cd3, 0x70af, 0x0001, 0x7087, 0x0006, 0x1078, 0x3cdd, 0x0078, - 0x3cdb, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x0007, 0x1078, - 0x41c6, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, - 0x1078, 0x4211, 0x00c0, 0x3d05, 0x7070, 0xa005, 0x00c0, 0x3d05, - 0x7150, 0xa186, 0xffff, 0x0040, 0x3d05, 0xa180, 0x293f, 0x200c, - 0xa18c, 0xff00, 0x810f, 0x1078, 0x40ea, 0x0040, 0x3d05, 0x1078, - 0x378b, 0x0040, 0x3d05, 0x1078, 0x2500, 0x20a9, 0x0008, 0x2298, - 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, - 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3d3d, - 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3d3b, - 0x2079, 0xa880, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3d3b, 0x7834, - 0xa005, 0x00c0, 0x3d3b, 0x7a38, 0xd2fc, 0x0040, 0x3d35, 0x70ac, - 0xa005, 0x00c0, 0x3d35, 0x70af, 0x0001, 0x7087, 0x0008, 0x1078, - 0x3d3f, 0x0078, 0x3d3d, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, - 0x0009, 0x1078, 0x41c6, 0x20a3, 0x1105, 0x20a3, 0x0100, 0x3430, - 0x1078, 0x4211, 0x00c0, 0x3d58, 0x7070, 0xa005, 0x00c0, 0x3d58, - 0x1078, 0x4051, 0x00c0, 0x3d62, 0xa085, 0x0001, 0x1078, 0x2500, - 0x20a9, 0x0008, 0x2099, 0xa88e, 0x26a0, 0x53a6, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, - 0x707c, 0xa005, 0x0040, 0x3da8, 0x2011, 0x4129, 0x1078, 0x58d4, - 0xa086, 0x0014, 0x00c0, 0x3da6, 0x2079, 0xa880, 0x7a30, 0xa296, - 0x1105, 0x00c0, 0x3da6, 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0, - 0x3d91, 0x7a38, 0xd2fc, 0x0040, 0x3d8b, 0x70ac, 0xa005, 0x00c0, - 0x3d8b, 0x70af, 0x0001, 0x7087, 0x000a, 0x1078, 0x3daa, 0x0078, - 0x3da8, 0xa005, 0x00c0, 0x3da6, 0x7a38, 0xd2fc, 0x0040, 0x3d9e, - 0x70ac, 0xa005, 0x00c0, 0x3d9e, 0x70af, 0x0001, 0x7083, 0x0000, - 0x7087, 0x000e, 0x1078, 0x3e32, 0x0078, 0x3da8, 0x1078, 0x4171, - 0x0f7f, 0x007c, 0x7087, 0x000b, 0x2011, 0xa80e, 0x22a0, 0x20a9, - 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, 0x0002, 0x2009, 0x0000, - 0x41a4, 0x1078, 0x41c6, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x1078, - 0x4211, 0x0040, 0x3dc7, 0x2013, 0x0000, 0x0078, 0x3dcb, 0x6030, - 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6, 0x60c3, - 0x0084, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, - 0x3df4, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0084, 0x00c0, - 0x3df2, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x3df2, - 0x7834, 0xa005, 0x00c0, 0x3df2, 0x7087, 0x000c, 0x1078, 0x3df6, - 0x0078, 0x3df4, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x000d, - 0x1078, 0x41c6, 0x20a3, 0x1107, 0x20a3, 0x0000, 0x2099, 0xa88e, - 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, - 0x0084, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, - 0x3e30, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0084, 0x00c0, - 0x3e2e, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1107, 0x00c0, 0x3e2e, - 0x7834, 0xa005, 0x00c0, 0x3e2e, 0x7083, 0x0001, 0x1078, 0x41b8, - 0x7087, 0x000e, 0x1078, 0x3e32, 0x0078, 0x3e30, 0x1078, 0x4171, - 0x0f7f, 0x007c, 0x7087, 0x000f, 0x707f, 0x0000, 0x608b, 0xbc85, - 0x608f, 0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, - 0x2011, 0x4129, 0x1078, 0x58c7, 0x007c, 0x707c, 0xa005, 0x0040, - 0x3e4d, 0x2011, 0x4129, 0x1078, 0x58d4, 0x007c, 0x7087, 0x0011, - 0x1078, 0x4211, 0x00c0, 0x3e67, 0x7168, 0x81ff, 0x0040, 0x3e67, - 0x2009, 0x0000, 0x706c, 0xa084, 0x00ff, 0x1078, 0x24e3, 0xa186, - 0x0080, 0x0040, 0x3e67, 0x2011, 0xa88e, 0x1078, 0x40ea, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, 0x20a1, 0x020b, 0x747c, - 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, - 0x53a6, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, - 0xa005, 0x0040, 0x3ea8, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, - 0x0014, 0x00c0, 0x3ea6, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1103, - 0x00c0, 0x3ea6, 0x7834, 0xa005, 0x00c0, 0x3ea6, 0x7a38, 0xd2fc, - 0x0040, 0x3ea0, 0x70ac, 0xa005, 0x00c0, 0x3ea0, 0x70af, 0x0001, - 0x7087, 0x0012, 0x1078, 0x3eaa, 0x0078, 0x3ea8, 0x1078, 0x4171, - 0x0f7f, 0x007c, 0x7087, 0x0013, 0x1078, 0x41d2, 0x20a3, 0x1103, - 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, 0x1078, 0x4211, 0x00c0, - 0x3ec8, 0x7070, 0xa005, 0x00c0, 0x3ec8, 0x714c, 0xa186, 0xffff, - 0x0040, 0x3ec8, 0x1078, 0x40ea, 0x0040, 0x3ec8, 0x1078, 0x41f5, - 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, - 0xa005, 0x0040, 0x3f00, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, - 0x0014, 0x00c0, 0x3efe, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1104, - 0x00c0, 0x3efe, 0x7834, 0xa005, 0x00c0, 0x3efe, 0x7a38, 0xd2fc, - 0x0040, 0x3ef8, 0x70ac, 0xa005, 0x00c0, 0x3ef8, 0x70af, 0x0001, - 0x7087, 0x0014, 0x1078, 0x3f02, 0x0078, 0x3f00, 0x1078, 0x4171, - 0x0f7f, 0x007c, 0x7087, 0x0015, 0x1078, 0x41d2, 0x20a3, 0x1104, - 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, 0x1078, 0x4211, 0x00c0, - 0x3f2a, 0x7070, 0xa005, 0x00c0, 0x3f2a, 0x7150, 0xa186, 0xffff, - 0x0040, 0x3f2a, 0xa180, 0x293f, 0x200c, 0xa18c, 0xff00, 0x810f, - 0x1078, 0x40ea, 0x0040, 0x3f2a, 0x1078, 0x378b, 0x0040, 0x3f2a, - 0x1078, 0x2500, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, - 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3f7b, 0x2011, 0x4129, 0x1078, - 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3f79, 0x2079, 0xa880, 0x7a30, - 0xa296, 0x1105, 0x00c0, 0x3f79, 0x7834, 0x2011, 0x0100, 0xa21e, - 0x00c0, 0x3f5e, 0x7a38, 0xd2fc, 0x0040, 0x3f5c, 0x70ac, 0xa005, - 0x00c0, 0x3f5c, 0x70af, 0x0001, 0x0078, 0x3f6d, 0xa005, 0x00c0, - 0x3f79, 0x7a38, 0xd2fc, 0x0040, 0x3f6b, 0x70ac, 0xa005, 0x00c0, - 0x3f6b, 0x70af, 0x0001, 0x7083, 0x0000, 0x7a38, 0xd2f4, 0x0040, - 0x3f73, 0x70cb, 0x0008, 0x7087, 0x0016, 0x1078, 0x3f7d, 0x0078, - 0x3f7b, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x20e1, 0x9080, 0x20e1, - 0x4000, 0x2099, 0xa880, 0x20a1, 0x020b, 0x20a9, 0x000e, 0x53a6, - 0x3430, 0x2011, 0xa88e, 0x7087, 0x0017, 0x1078, 0x4211, 0x00c0, - 0x3f9d, 0x7070, 0xa005, 0x00c0, 0x3f9d, 0x1078, 0x4051, 0x00c0, - 0x3fa7, 0xa085, 0x0001, 0x1078, 0x2500, 0x20a9, 0x0008, 0x2099, - 0xa88e, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, - 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, - 0x3fcc, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0084, 0x00c0, - 0x3fca, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x3fca, - 0x7834, 0xa005, 0x00c0, 0x3fca, 0x7087, 0x0018, 0x1078, 0x3fce, - 0x0078, 0x3fcc, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x0019, - 0x1078, 0x41d2, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x3430, 0x2099, - 0xa88e, 0x2039, 0xa80e, 0x27a0, 0x20a9, 0x0040, 0x53a3, 0x1078, - 0x4211, 0x00c0, 0x4002, 0x2728, 0x2514, 0x8207, 0xa084, 0x00ff, - 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, 0xa205, 0x202a, 0x6030, - 0x2310, 0x8214, 0xa2a0, 0xa80e, 0x2414, 0xa38c, 0x0001, 0x0040, - 0x3ffd, 0xa294, 0xff00, 0x0078, 0x4000, 0xa294, 0x00ff, 0x8007, - 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, 0x53a6, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x1078, 0x4158, 0x007c, - 0x0f7e, 0x707c, 0xa005, 0x0040, 0x4034, 0x2011, 0x4129, 0x1078, - 0x58d4, 0xa086, 0x0084, 0x00c0, 0x4032, 0x2079, 0xa880, 0x7a30, - 0xa296, 0x1107, 0x00c0, 0x4032, 0x7834, 0xa005, 0x00c0, 0x4032, - 0x7083, 0x0001, 0x1078, 0x41b8, 0x7087, 0x001a, 0x1078, 0x4036, - 0x0078, 0x4034, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x001b, - 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, 0x20a1, 0x020b, - 0x747c, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, - 0x20a8, 0x53a6, 0x60c3, 0x0084, 0x1078, 0x4158, 0x007c, 0x007c, - 0x007c, 0x087e, 0x097e, 0x2029, 0xa352, 0x252c, 0x20a9, 0x0008, - 0x2041, 0xa80e, 0x28a0, 0x2099, 0xa88e, 0x53a3, 0x20a9, 0x0008, - 0x2011, 0x0007, 0xd5d4, 0x0040, 0x4067, 0x2011, 0x0000, 0x2800, - 0xa200, 0x200c, 0xa1a6, 0xffff, 0x00c0, 0x4079, 0xd5d4, 0x0040, - 0x4074, 0x8210, 0x0078, 0x4075, 0x8211, 0x00f0, 0x4067, 0x0078, - 0x40e1, 0x82ff, 0x00c0, 0x408b, 0xd5d4, 0x0040, 0x4085, 0xa1a6, - 0x3fff, 0x0040, 0x4071, 0x0078, 0x4089, 0xa1a6, 0x3fff, 0x0040, - 0x40e1, 0xa18d, 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, 0xd5d4, - 0x0040, 0x4094, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0040, 0x409b, - 0x8423, 0x0078, 0x409c, 0x8424, 0x00c8, 0x40a9, 0xd5d4, 0x0040, - 0x40a4, 0x8319, 0x0078, 0x40a5, 0x8318, 0x00f0, 0x4095, 0x0078, - 0x40e1, 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x00f0, 0x40ad, - 0x2328, 0x8529, 0xa2be, 0x0007, 0x0040, 0x40c1, 0x007e, 0x2039, - 0x0007, 0x2200, 0xa73a, 0x007f, 0x27a8, 0xa5a8, 0x0010, 0x00f0, - 0x40bd, 0x754e, 0xa5c8, 0x293f, 0x292c, 0xa5ac, 0x00ff, 0x6532, - 0x60e7, 0x0000, 0x65ea, 0x706b, 0x0000, 0x756e, 0x2018, 0x2304, - 0xa405, 0x201a, 0x7073, 0x0001, 0x26a0, 0x2898, 0x20a9, 0x0008, - 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0xa085, 0x0001, 0x0078, - 0x40e7, 0xa006, 0x0078, 0x40e7, 0xa006, 0x1078, 0x1328, 0x097f, - 0x087f, 0x007c, 0x2118, 0x2021, 0x0000, 0x2001, 0x0007, 0xa39a, - 0x0010, 0x0048, 0x40f7, 0x8420, 0x8001, 0x0078, 0x40ef, 0x2118, - 0x84ff, 0x0040, 0x4100, 0xa39a, 0x0010, 0x8421, 0x00c0, 0x40fb, - 0x2021, 0x0001, 0x83ff, 0x0040, 0x4109, 0x8423, 0x8319, 0x00c0, - 0x4105, 0xa238, 0x2704, 0xa42c, 0x00c0, 0x4121, 0xa405, 0x203a, - 0x714e, 0xa1a0, 0x293f, 0x242c, 0xa5ac, 0x00ff, 0x6532, 0x60e7, - 0x0000, 0x65ea, 0x706b, 0x0000, 0x756e, 0x7073, 0x0001, 0xa084, - 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa300, 0x7077, 0x0000, 0x0e7f, - 0x007c, 0x0e7e, 0x0f7e, 0x2001, 0x0002, 0x1078, 0x5975, 0x2079, - 0x0100, 0x2071, 0x0140, 0x1078, 0x6c41, 0x7004, 0xa084, 0x4000, - 0x0040, 0x413e, 0x7003, 0x1000, 0x7003, 0x0000, 0x127e, 0x2091, - 0x8000, 0x2071, 0xa321, 0x2073, 0x0000, 0x7840, 0x027e, 0x017e, - 0x2009, 0x00f7, 0x1078, 0x41de, 0x017f, 0xa094, 0x0010, 0xa285, - 0x0080, 0x7842, 0x7a42, 0x027f, 0x127f, 0x0f7f, 0x0e7f, 0x007c, - 0x127e, 0x2091, 0x8000, 0x2011, 0xa5b5, 0x2013, 0x0000, 0x707f, - 0x0000, 0x127f, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, - 0x1078, 0x6c38, 0x2009, 0x07d0, 0x2011, 0x4129, 0x1078, 0x596c, - 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x2009, - 0x00f7, 0x1078, 0x41de, 0x2061, 0xa5be, 0x601b, 0x0000, 0x601f, - 0x0000, 0x2061, 0xa300, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, - 0x0090, 0x6043, 0x0010, 0x2009, 0x002d, 0x2011, 0x4196, 0x1078, - 0x58c7, 0x127f, 0x0c7f, 0x027f, 0x017f, 0x007c, 0x0e7e, 0x007e, - 0x127e, 0x2091, 0x8000, 0x2001, 0x0001, 0x1078, 0x5975, 0x2071, - 0x0100, 0x1078, 0x6c41, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000, - 0x0040, 0x41ae, 0x7003, 0x1000, 0x7003, 0x0000, 0x2001, 0x0001, - 0x1078, 0x2480, 0x1078, 0x4171, 0x127f, 0x007f, 0x0e7f, 0x007c, - 0x20a9, 0x0040, 0x20a1, 0xa9c0, 0x2099, 0xa88e, 0x3304, 0x8007, - 0x20a2, 0x9398, 0x94a0, 0x00f0, 0x41be, 0x007c, 0x20e1, 0x9080, - 0x20e1, 0x4000, 0x2099, 0xa800, 0x20a1, 0x020b, 0x20a9, 0x000c, - 0x53a6, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, - 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x0c7e, 0x007e, - 0x2061, 0x0100, 0x810f, 0x2001, 0xa32e, 0x2004, 0xa005, 0x00c0, - 0x41ef, 0x6030, 0xa084, 0x00ff, 0xa105, 0x0078, 0x41f1, 0xa185, - 0x00f7, 0x604a, 0x007f, 0x0c7f, 0x007c, 0x017e, 0x047e, 0x2001, - 0xa352, 0x2004, 0xd0a4, 0x0040, 0x4208, 0xa006, 0x2020, 0x2009, - 0x002a, 0x1078, 0x9ec0, 0x2001, 0xa30c, 0x200c, 0xc195, 0x2102, - 0x2019, 0x002a, 0x2009, 0x0000, 0x1078, 0x27e2, 0x047f, 0x017f, - 0x007c, 0x007e, 0x2001, 0xa30c, 0x2004, 0xd09c, 0x0040, 0x4218, - 0x007f, 0x007c, 0x007e, 0x017e, 0x127e, 0x2091, 0x8000, 0x2001, - 0x0101, 0x200c, 0xa18d, 0x0006, 0x2102, 0x127f, 0x017f, 0x007f, - 0x007c, 0x157e, 0x20a9, 0x00ff, 0x2009, 0xa434, 0xa006, 0x200a, - 0x8108, 0x00f0, 0x422f, 0x157f, 0x007c, 0x0d7e, 0x037e, 0x157e, - 0x137e, 0x147e, 0x2069, 0xa351, 0xa006, 0x6002, 0x6007, 0x0707, - 0x600a, 0x600e, 0x6012, 0xa198, 0x293f, 0x231c, 0xa39c, 0x00ff, - 0x6316, 0x20a9, 0x0004, 0xac98, 0x0006, 0x23a0, 0x40a4, 0x20a9, - 0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4, 0x603e, 0x6042, 0x604e, - 0x6052, 0x6056, 0x605a, 0x605e, 0x6062, 0x6066, 0x606a, 0x606e, - 0x6072, 0x6076, 0x607a, 0x607e, 0x6082, 0x6086, 0x608a, 0x608e, - 0x6092, 0x6096, 0x609a, 0x609e, 0x60ae, 0x61a2, 0x0d7e, 0x60a4, - 0xa06d, 0x0040, 0x4275, 0x1078, 0x139a, 0x60a7, 0x0000, 0x60a8, - 0xa06d, 0x0040, 0x427d, 0x1078, 0x139a, 0x60ab, 0x0000, 0x0d7f, - 0xa006, 0x604a, 0x6810, 0x603a, 0x680c, 0x6046, 0x6814, 0xa084, - 0x00ff, 0x6042, 0x147f, 0x137f, 0x157f, 0x037f, 0x0d7f, 0x007c, - 0x127e, 0x2091, 0x8000, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082, - 0x4000, 0x00c8, 0x4361, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, - 0x00c8, 0x4367, 0x2001, 0xa30c, 0x2004, 0xa084, 0x0003, 0x0040, - 0x42c2, 0x2001, 0xa30c, 0x2004, 0xd084, 0x00c0, 0x4342, 0xa188, - 0xa434, 0x2104, 0xa065, 0x0040, 0x4342, 0x6004, 0xa084, 0x00ff, - 0xa08e, 0x0006, 0x00c0, 0x4342, 0x6000, 0xd0c4, 0x0040, 0x4342, - 0x0078, 0x42cf, 0xa188, 0xa434, 0x2104, 0xa065, 0x0040, 0x4326, - 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x432c, 0x60a4, - 0xa00d, 0x0040, 0x42d7, 0x1078, 0x4749, 0x0040, 0x4320, 0x60a8, - 0xa00d, 0x0040, 0x42f1, 0x1078, 0x479a, 0x00c0, 0x42f1, 0x694c, - 0xd1fc, 0x00c0, 0x42e7, 0x1078, 0x441c, 0x0078, 0x431b, 0x1078, - 0x43d6, 0x694c, 0xd1ec, 0x00c0, 0x431b, 0x1078, 0x460a, 0x0078, - 0x431b, 0x694c, 0xa184, 0xa000, 0x0040, 0x430b, 0xd1ec, 0x0040, - 0x4304, 0xd1fc, 0x0040, 0x4300, 0x1078, 0x461b, 0x0078, 0x4307, - 0x1078, 0x461b, 0x0078, 0x430b, 0xd1fc, 0x0040, 0x430b, 0x1078, - 0x43d6, 0x0078, 0x431b, 0x6050, 0xa00d, 0x0040, 0x4316, 0x2d00, - 0x200a, 0x6803, 0x0000, 0x6052, 0x0078, 0x431b, 0x2d00, 0x6052, - 0x604e, 0x6803, 0x0000, 0x1078, 0x5c17, 0xa006, 0x127f, 0x007c, - 0x2001, 0x0005, 0x2009, 0x0000, 0x0078, 0x436b, 0x2001, 0x0028, - 0x2009, 0x0000, 0x0078, 0x436b, 0xa082, 0x0006, 0x00c8, 0x4342, - 0x60a0, 0xd0bc, 0x00c0, 0x433e, 0x6100, 0xd1fc, 0x0040, 0x42cf, - 0x2001, 0x0029, 0x2009, 0x1000, 0x0078, 0x436b, 0x2001, 0x0028, - 0x0078, 0x435d, 0x2009, 0xa30c, 0x210c, 0xd18c, 0x0040, 0x434c, - 0x2001, 0x0004, 0x0078, 0x435d, 0xd184, 0x0040, 0x4353, 0x2001, - 0x0004, 0x0078, 0x435d, 0x2001, 0x0029, 0x6100, 0xd1fc, 0x0040, - 0x435d, 0x2009, 0x1000, 0x0078, 0x436b, 0x2009, 0x0000, 0x0078, - 0x436b, 0x2001, 0x0029, 0x2009, 0x0000, 0x0078, 0x436b, 0x2001, - 0x0029, 0x2009, 0x0000, 0xa005, 0x127f, 0x007c, 0x6944, 0x6e48, - 0xa684, 0x3fff, 0xa082, 0x4000, 0x00c8, 0x43bb, 0xa18c, 0xff00, - 0x810f, 0xa182, 0x00ff, 0x00c8, 0x43a1, 0xa188, 0xa434, 0x2104, - 0xa065, 0x0040, 0x43a1, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, - 0x00c0, 0x43a7, 0x684c, 0xd0ec, 0x0040, 0x4394, 0x1078, 0x461b, - 0x1078, 0x43d6, 0x0078, 0x439c, 0x1078, 0x43d6, 0x684c, 0xd0fc, - 0x0040, 0x439c, 0x1078, 0x460a, 0x1078, 0x4663, 0xa006, 0x0078, - 0x43bf, 0x2001, 0x0028, 0x2009, 0x0000, 0x0078, 0x43bf, 0xa082, - 0x0006, 0x00c8, 0x43b5, 0x6100, 0xd1fc, 0x0040, 0x438a, 0x2001, - 0x0029, 0x2009, 0x1000, 0x0078, 0x43bf, 0x2001, 0x0029, 0x2009, - 0x0000, 0x0078, 0x43bf, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, - 0x007c, 0x127e, 0x2091, 0x8000, 0x6050, 0xa00d, 0x0040, 0x43cf, - 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x127f, 0x007c, 0x2d00, - 0x6052, 0x604e, 0x6803, 0x0000, 0x0078, 0x43cd, 0x127e, 0x2091, - 0x8000, 0x604c, 0xa005, 0x0040, 0x43ec, 0x0e7e, 0x2071, 0xa5ab, - 0x7004, 0xa086, 0x0002, 0x0040, 0x43f3, 0x0e7f, 0x604c, 0x6802, - 0x2d00, 0x604e, 0x127f, 0x007c, 0x2d00, 0x6052, 0x604e, 0x6803, - 0x0000, 0x0078, 0x43ea, 0x701c, 0xac06, 0x00c0, 0x43e5, 0x604c, - 0x2070, 0x7000, 0x6802, 0x2d00, 0x7002, 0x0e7f, 0x127f, 0x007c, - 0x127e, 0x2091, 0x8000, 0x604c, 0xa06d, 0x0040, 0x440e, 0x6800, - 0xa005, 0x00c0, 0x440c, 0x6052, 0x604e, 0xad05, 0x127f, 0x007c, - 0x604c, 0xa06d, 0x0040, 0x441b, 0x6800, 0xa005, 0x00c0, 0x4419, - 0x6052, 0x604e, 0xad05, 0x007c, 0x6803, 0x0000, 0x6084, 0xa00d, - 0x0040, 0x4426, 0x2d00, 0x200a, 0x6086, 0x007c, 0x2d00, 0x6086, - 0x6082, 0x0078, 0x4425, 0x127e, 0x0c7e, 0x027e, 0x2091, 0x8000, - 0x6218, 0x2260, 0x6200, 0xa005, 0x0040, 0x4439, 0xc285, 0x0078, - 0x443a, 0xc284, 0x6202, 0x027f, 0x0c7f, 0x127f, 0x007c, 0x127e, - 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, 0x007e, 0xa086, - 0x0006, 0x00c0, 0x445e, 0x609c, 0xd0ac, 0x0040, 0x445e, 0x2001, - 0xa352, 0x2004, 0xd0a4, 0x0040, 0x445e, 0xa284, 0xff00, 0x8007, - 0xa086, 0x0007, 0x00c0, 0x445e, 0x2011, 0x0600, 0x007f, 0xa294, - 0xff00, 0xa215, 0x6206, 0x007e, 0xa086, 0x0006, 0x00c0, 0x446e, - 0x6290, 0x82ff, 0x00c0, 0x446e, 0x1078, 0x1328, 0x007f, 0x0c7f, - 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, - 0x6204, 0x007e, 0xa086, 0x0006, 0x00c0, 0x4490, 0x609c, 0xd0a4, - 0x0040, 0x4490, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x4490, - 0xa284, 0x00ff, 0xa086, 0x0007, 0x00c0, 0x4490, 0x2011, 0x0006, - 0x007f, 0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x0c7f, 0x127f, - 0x007c, 0x027e, 0xa182, 0x00ff, 0x0048, 0x44a2, 0xa085, 0x0001, - 0x0078, 0x44ba, 0xa190, 0xa434, 0x2204, 0xa065, 0x00c0, 0x44b9, - 0x017e, 0x0d7e, 0x1078, 0x1366, 0x2d60, 0x0d7f, 0x017f, 0x0040, - 0x449e, 0x2c00, 0x2012, 0x60a7, 0x0000, 0x60ab, 0x0000, 0x1078, - 0x4235, 0xa006, 0x027f, 0x007c, 0x127e, 0x2091, 0x8000, 0x027e, - 0xa182, 0x00ff, 0x0048, 0x44c8, 0xa085, 0x0001, 0x0078, 0x44fe, - 0x0d7e, 0xa190, 0xa434, 0x2204, 0xa06d, 0x0040, 0x44fc, 0x2013, - 0x0000, 0x0d7e, 0x0c7e, 0x2d60, 0x60a4, 0xa06d, 0x0040, 0x44da, - 0x1078, 0x139a, 0x60a8, 0xa06d, 0x0040, 0x44e0, 0x1078, 0x139a, - 0x0c7f, 0x0d7f, 0x0d7e, 0x0c7e, 0x68ac, 0x2060, 0x8cff, 0x0040, - 0x44f8, 0x600c, 0x007e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, - 0x44f3, 0x1078, 0x13aa, 0x1078, 0x753d, 0x0c7f, 0x0078, 0x44e6, - 0x0c7f, 0x0d7f, 0x1078, 0x139a, 0x0d7f, 0xa006, 0x027f, 0x127f, - 0x007c, 0x017e, 0xa182, 0x00ff, 0x0048, 0x450a, 0xa085, 0x0001, - 0x0078, 0x4511, 0xa188, 0xa434, 0x2104, 0xa065, 0x0040, 0x4506, - 0xa006, 0x017f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x600b, - 0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, 0x6002, 0x2069, 0xa88e, - 0x6808, 0x605e, 0x6810, 0x6062, 0x6138, 0xa10a, 0x0048, 0x4529, - 0x603a, 0x6814, 0x6066, 0x2099, 0xa896, 0xac88, 0x000a, 0x21a0, - 0x20a9, 0x0004, 0x53a3, 0x2099, 0xa89a, 0xac88, 0x0006, 0x21a0, - 0x20a9, 0x0004, 0x53a3, 0x2069, 0xa8ae, 0x6808, 0x606a, 0x690c, - 0x616e, 0x6810, 0x6072, 0x6818, 0x6076, 0xa182, 0x0211, 0x00c8, - 0x454d, 0x2009, 0x0008, 0x0078, 0x4577, 0xa182, 0x0259, 0x00c8, - 0x4555, 0x2009, 0x0007, 0x0078, 0x4577, 0xa182, 0x02c1, 0x00c8, - 0x455d, 0x2009, 0x0006, 0x0078, 0x4577, 0xa182, 0x0349, 0x00c8, - 0x4565, 0x2009, 0x0005, 0x0078, 0x4577, 0xa182, 0x0421, 0x00c8, - 0x456d, 0x2009, 0x0004, 0x0078, 0x4577, 0xa182, 0x0581, 0x00c8, - 0x4575, 0x2009, 0x0003, 0x0078, 0x4577, 0x2009, 0x0002, 0x6192, - 0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x017e, 0x027e, 0x0e7e, - 0x2071, 0xa88d, 0x2e04, 0x6896, 0x2071, 0xa88e, 0x7004, 0x689a, - 0x701c, 0x689e, 0x6a00, 0x2009, 0xa371, 0x210c, 0xd0bc, 0x0040, - 0x4597, 0xd1ec, 0x0040, 0x4597, 0xc2ad, 0x0078, 0x4598, 0xc2ac, - 0xd0c4, 0x0040, 0x45a1, 0xd1e4, 0x0040, 0x45a1, 0xc2bd, 0x0078, - 0x45a2, 0xc2bc, 0x6a02, 0x0e7f, 0x027f, 0x017f, 0x007c, 0x0d7e, - 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x0040, 0x45cb, 0x6900, - 0x81ff, 0x00c0, 0x45df, 0x6a04, 0xa282, 0x0010, 0x00c8, 0x45e4, - 0xad88, 0x0004, 0x20a9, 0x0010, 0x2104, 0xa086, 0xffff, 0x0040, - 0x45c6, 0x8108, 0x00f0, 0x45bc, 0x1078, 0x1328, 0x260a, 0x8210, - 0x6a06, 0x0078, 0x45df, 0x1078, 0x1381, 0x0040, 0x45e4, 0x2d00, - 0x60a6, 0x6803, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, - 0xffff, 0x8108, 0x00f0, 0x45d7, 0x6807, 0x0001, 0x6e12, 0xa085, - 0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006, 0x0078, 0x45e1, 0x127e, - 0x2091, 0x8000, 0x0d7e, 0x60a4, 0xa00d, 0x0040, 0x4607, 0x2168, - 0x6800, 0xa005, 0x00c0, 0x4603, 0x1078, 0x4749, 0x00c0, 0x4607, - 0x200b, 0xffff, 0x6804, 0xa08a, 0x0002, 0x0048, 0x4603, 0x8001, - 0x6806, 0x0078, 0x4607, 0x1078, 0x139a, 0x60a7, 0x0000, 0x0d7f, - 0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x47af, 0x0078, - 0x4613, 0x1078, 0x43c1, 0x1078, 0x46a7, 0x00c0, 0x4611, 0x1078, - 0x4663, 0x127f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a8, - 0xa06d, 0x0040, 0x463f, 0x6950, 0x81ff, 0x00c0, 0x4653, 0x6a54, - 0xa282, 0x0010, 0x00c8, 0x4660, 0xad88, 0x0018, 0x20a9, 0x0010, - 0x2104, 0xa086, 0xffff, 0x0040, 0x463a, 0x8108, 0x00f0, 0x4630, - 0x1078, 0x1328, 0x260a, 0x8210, 0x6a56, 0x0078, 0x4653, 0x1078, - 0x1381, 0x0040, 0x4660, 0x2d00, 0x60aa, 0x6853, 0x0000, 0xad88, - 0x0018, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, 0x00f0, 0x464b, - 0x6857, 0x0001, 0x6e62, 0x0078, 0x4657, 0x1078, 0x441c, 0x1078, - 0x466d, 0x00c0, 0x4655, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c, - 0xa006, 0x0078, 0x465d, 0x127e, 0x2091, 0x8000, 0x1078, 0x5c17, - 0x127f, 0x007c, 0xa01e, 0x0078, 0x466f, 0x2019, 0x0001, 0xa00e, - 0x127e, 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x00c0, - 0x468d, 0x8dff, 0x0040, 0x46a2, 0x83ff, 0x0040, 0x4685, 0x6848, - 0xa606, 0x0040, 0x4692, 0x0078, 0x468d, 0x683c, 0xa406, 0x00c0, - 0x468d, 0x6840, 0xa506, 0x0040, 0x4692, 0x2d08, 0x6800, 0x2068, - 0x0078, 0x4679, 0x6a00, 0x604c, 0xad06, 0x00c0, 0x469a, 0x624e, - 0x0078, 0x469d, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x46a2, - 0x6152, 0x8dff, 0x127f, 0x007c, 0xa01e, 0x0078, 0x46a9, 0x2019, - 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x0040, 0x46d5, 0x83ff, - 0x0040, 0x46b8, 0x6848, 0xa606, 0x0040, 0x46c5, 0x0078, 0x46c0, - 0x683c, 0xa406, 0x00c0, 0x46c0, 0x6840, 0xa506, 0x0040, 0x46c5, - 0x2d08, 0x6800, 0x2068, 0x0078, 0x46ac, 0x6a00, 0x6080, 0xad06, - 0x00c0, 0x46cd, 0x6282, 0x0078, 0x46d0, 0xa180, 0x0000, 0x2202, - 0x82ff, 0x00c0, 0x46d5, 0x6186, 0x8dff, 0x007c, 0xa016, 0x1078, - 0x4742, 0x00c0, 0x46dd, 0x2011, 0x0001, 0x1078, 0x4793, 0x00c0, - 0x46e3, 0xa295, 0x0002, 0x007c, 0x1078, 0x47cb, 0x0040, 0x46ec, - 0x1078, 0x8b12, 0x0078, 0x46ee, 0xa085, 0x0001, 0x007c, 0x1078, - 0x47cb, 0x0040, 0x46f7, 0x1078, 0x8aaa, 0x0078, 0x46f9, 0xa085, - 0x0001, 0x007c, 0x1078, 0x47cb, 0x0040, 0x4702, 0x1078, 0x8af4, - 0x0078, 0x4704, 0xa085, 0x0001, 0x007c, 0x1078, 0x47cb, 0x0040, - 0x470d, 0x1078, 0x8ac6, 0x0078, 0x470f, 0xa085, 0x0001, 0x007c, - 0x1078, 0x47cb, 0x0040, 0x4718, 0x1078, 0x8b30, 0x0078, 0x471a, - 0xa085, 0x0001, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x8000, - 0x6080, 0xa06d, 0x0040, 0x473a, 0x6800, 0x007e, 0x6837, 0x0103, - 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8cb8, 0x007e, 0x6000, 0xd0fc, - 0x0040, 0x4734, 0x1078, 0xa18c, 0x007f, 0x1078, 0x4982, 0x007f, - 0x0078, 0x4721, 0x6083, 0x0000, 0x6087, 0x0000, 0x0d7f, 0x007f, - 0x127f, 0x007c, 0x60a4, 0xa00d, 0x00c0, 0x4749, 0xa085, 0x0001, - 0x007c, 0x0e7e, 0x2170, 0x7000, 0xa005, 0x00c0, 0x475c, 0x20a9, - 0x0010, 0xae88, 0x0004, 0x2104, 0xa606, 0x0040, 0x475c, 0x8108, - 0x00f0, 0x4753, 0xa085, 0x0001, 0xa006, 0x0e7f, 0x007c, 0x0d7e, - 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x00c0, 0x476d, 0x1078, - 0x1381, 0x0040, 0x477f, 0x2d00, 0x60a6, 0x6803, 0x0001, 0x6807, - 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, - 0x00f0, 0x4775, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006, - 0x0078, 0x477c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, - 0x0040, 0x4790, 0x60a7, 0x0000, 0x1078, 0x139a, 0xa085, 0x0001, - 0x127f, 0x0d7f, 0x007c, 0x60a8, 0xa00d, 0x00c0, 0x479a, 0xa085, - 0x0001, 0x007c, 0x0e7e, 0x2170, 0x7050, 0xa005, 0x00c0, 0x47ad, - 0x20a9, 0x0010, 0xae88, 0x0018, 0x2104, 0xa606, 0x0040, 0x47ad, - 0x8108, 0x00f0, 0x47a4, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x127e, - 0x2091, 0x8000, 0x1078, 0x4793, 0x00c0, 0x47c9, 0x200b, 0xffff, - 0x0d7e, 0x60a8, 0x2068, 0x6854, 0xa08a, 0x0002, 0x0048, 0x47c4, - 0x8001, 0x6856, 0x0078, 0x47c8, 0x1078, 0x139a, 0x60ab, 0x0000, - 0x0d7f, 0x127f, 0x007c, 0x609c, 0xd0a4, 0x007c, 0x0f7e, 0x71ac, - 0x81ff, 0x00c0, 0x47e9, 0x71c8, 0xd19c, 0x0040, 0x47e9, 0x2001, - 0x007e, 0xa080, 0xa434, 0x2004, 0xa07d, 0x0040, 0x47e9, 0x7804, - 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x47e9, 0x7800, 0xc0ed, - 0x7802, 0x2079, 0xa351, 0x7804, 0xd0a4, 0x0040, 0x480f, 0x157e, - 0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x4501, - 0x00c0, 0x4809, 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004, - 0x0040, 0x4806, 0xa086, 0x0006, 0x00c0, 0x4809, 0x6000, 0xc0ed, - 0x6002, 0x017f, 0x8108, 0x00f0, 0x47f5, 0x0c7f, 0x157f, 0x1078, - 0x4897, 0x0040, 0x4818, 0x2001, 0xa59f, 0x200c, 0x0078, 0x4820, - 0x2079, 0xa351, 0x7804, 0xd0a4, 0x0040, 0x4824, 0x2009, 0x07d0, - 0x2011, 0x4826, 0x1078, 0x596c, 0x0f7f, 0x007c, 0x2011, 0x4826, - 0x1078, 0x58d4, 0x1078, 0x4897, 0x0040, 0x484e, 0x2001, 0xa4b2, - 0x2004, 0xa080, 0x0000, 0x200c, 0xc1ec, 0x2102, 0x2001, 0xa352, - 0x2004, 0xd0a4, 0x0040, 0x4842, 0x2009, 0x07d0, 0x2011, 0x4826, - 0x1078, 0x596c, 0x0e7e, 0x2071, 0xa300, 0x706b, 0x0000, 0x706f, - 0x0000, 0x1078, 0x260d, 0x0e7f, 0x0078, 0x4886, 0x157e, 0x0c7e, - 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x4501, 0x00c0, - 0x4880, 0x6000, 0xd0ec, 0x0040, 0x4880, 0x047e, 0x62a0, 0xa294, - 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0x9ec0, 0x6000, - 0xc0e5, 0xc0ec, 0x6002, 0x6004, 0xa084, 0x00ff, 0xa085, 0x0700, - 0x6006, 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, 0x0000, - 0x1078, 0x5c78, 0x2009, 0x0000, 0x1078, 0x9c38, 0x077f, 0x047f, - 0x017f, 0x8108, 0x00f0, 0x4854, 0x0c7f, 0x157f, 0x007c, 0x0c7e, - 0x6018, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x0c7f, 0x007c, 0x7818, - 0x2004, 0xd0ac, 0x007c, 0x7818, 0x2004, 0xd0bc, 0x007c, 0x0f7e, - 0x2001, 0xa4b2, 0x2004, 0xa07d, 0x0040, 0x48a0, 0x7800, 0xd0ec, - 0x0f7f, 0x007c, 0x127e, 0x027e, 0x2091, 0x8000, 0x6200, 0xa005, - 0x0040, 0x48ad, 0xc2fd, 0x0078, 0x48ae, 0xc2fc, 0x6202, 0x027f, - 0x127f, 0x007c, 0x2071, 0xa413, 0x7003, 0x0001, 0x7007, 0x0000, - 0x7013, 0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, - 0x700b, 0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b, 0x0020, - 0x705f, 0x0040, 0x707f, 0x0000, 0x2071, 0xa57c, 0x7003, 0xa413, - 0x7007, 0x0000, 0x700b, 0x0000, 0x700f, 0xa55c, 0x7013, 0x0020, - 0x7017, 0x0040, 0x7037, 0x0000, 0x007c, 0x017e, 0x0e7e, 0x2071, - 0xa534, 0xa00e, 0x7186, 0x718a, 0x7097, 0x0001, 0x2001, 0xa352, - 0x2004, 0xd0fc, 0x00c0, 0x48f7, 0x2001, 0xa352, 0x2004, 0xa00e, - 0xd09c, 0x0040, 0x48f4, 0x8108, 0x7102, 0x0078, 0x494a, 0x2001, - 0xa371, 0x200c, 0xa184, 0x000f, 0x2009, 0xa372, 0x210c, 0x0079, - 0x4901, 0x48ec, 0x4922, 0x492a, 0x4935, 0x493b, 0x48ec, 0x48ec, - 0x48ec, 0x4911, 0x48ec, 0x48ec, 0x48ec, 0x48ec, 0x48ec, 0x48ec, - 0x48ec, 0x7003, 0x0004, 0x137e, 0x147e, 0x157e, 0x2099, 0xa375, - 0x20a1, 0xa585, 0x20a9, 0x0004, 0x53a3, 0x157f, 0x147f, 0x137f, - 0x0078, 0x494a, 0x708f, 0x0005, 0x7007, 0x0122, 0x2001, 0x0002, - 0x0078, 0x4930, 0x708f, 0x0002, 0x7007, 0x0121, 0x2001, 0x0003, - 0x7002, 0x7097, 0x0001, 0x0078, 0x4947, 0x7007, 0x0122, 0x2001, - 0x0002, 0x0078, 0x493f, 0x7007, 0x0121, 0x2001, 0x0003, 0x7002, - 0xa006, 0x7096, 0x708e, 0xa184, 0xff00, 0x8007, 0x709a, 0xa184, - 0x00ff, 0x7092, 0x0e7f, 0x017f, 0x007c, 0x0e7e, 0x2071, 0xa413, - 0x684c, 0xa005, 0x00c0, 0x495b, 0x7028, 0xc085, 0x702a, 0xa085, - 0x0001, 0x0078, 0x4980, 0x6a60, 0x7236, 0x6b64, 0x733a, 0x6868, - 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, 0x6844, - 0x7032, 0x2009, 0x000d, 0x200a, 0x700b, 0x0000, 0x8007, 0x8006, - 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, - 0x726e, 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006, - 0x0e7f, 0x007c, 0x0e7e, 0x027e, 0x6838, 0xd0fc, 0x00c0, 0x49d8, - 0x6804, 0xa00d, 0x0040, 0x499e, 0x0d7e, 0x2071, 0xa300, 0xa016, - 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x00c0, - 0x4991, 0x702e, 0x70a8, 0xa200, 0x70aa, 0x0d7f, 0x2071, 0xa413, - 0x701c, 0xa005, 0x00c0, 0x49ea, 0x0068, 0x49e8, 0x2071, 0xa534, - 0x7200, 0x82ff, 0x0040, 0x49e8, 0x6934, 0xa186, 0x0103, 0x00c0, - 0x49fb, 0x6948, 0x6844, 0xa105, 0x00c0, 0x49db, 0x2009, 0x8020, - 0x2200, 0x0079, 0x49bb, 0x49e8, 0x49c0, 0x4a18, 0x4a26, 0x49e8, - 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x49e8, 0x7122, 0x683c, - 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x2071, - 0xa300, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a8, 0x8000, 0x70aa, - 0x027f, 0x0e7f, 0x007c, 0x6844, 0xa086, 0x0100, 0x00c0, 0x49e8, - 0x6868, 0xa005, 0x00c0, 0x49e8, 0x2009, 0x8020, 0x0078, 0x49b8, - 0x2071, 0xa413, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, 0x7012, - 0x7018, 0xa06d, 0x711a, 0x0040, 0x49f8, 0x6902, 0x0078, 0x49f9, - 0x711e, 0x0078, 0x49d8, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0040, - 0x4a09, 0xa186, 0x001e, 0x0040, 0x4a09, 0xa18e, 0x001f, 0x00c0, - 0x49e8, 0x684c, 0xd0cc, 0x0040, 0x49e8, 0x6850, 0xa084, 0x00ff, - 0xa086, 0x0001, 0x00c0, 0x49e8, 0x2009, 0x8021, 0x0078, 0x49b8, - 0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x49e8, 0x7186, 0xae90, - 0x0003, 0xa210, 0x683c, 0x2012, 0x0078, 0x4a36, 0x7084, 0x8008, - 0xa092, 0x000f, 0x00c8, 0x49e8, 0x7186, 0xae90, 0x0003, 0x8003, - 0xa210, 0x683c, 0x2012, 0x8210, 0x6840, 0x2012, 0x7088, 0xa10a, - 0x0048, 0x49cf, 0x718c, 0x7084, 0xa10a, 0x0048, 0x49cf, 0x2071, - 0x0000, 0x7018, 0xd084, 0x00c0, 0x49cf, 0x2071, 0xa534, 0x7000, - 0xa086, 0x0002, 0x00c0, 0x4a56, 0x1078, 0x4cd2, 0x2071, 0x0000, - 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x49cf, 0x1078, 0x4cfd, - 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x49cf, - 0x007e, 0x684c, 0x007e, 0x6837, 0x0103, 0x20a9, 0x001c, 0xad80, - 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x007f, 0xa084, 0x00ff, - 0x684e, 0x007f, 0x684a, 0x6952, 0x007c, 0x2071, 0xa413, 0x7004, - 0x0079, 0x4a7a, 0x4a84, 0x4a95, 0x4ca3, 0x4ca4, 0x4ccb, 0x4cd1, - 0x4a85, 0x4c91, 0x4c32, 0x4cb4, 0x007c, 0x127e, 0x2091, 0x8000, - 0x0068, 0x4a94, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, - 0x7007, 0x0001, 0x700b, 0x0000, 0x127f, 0x2069, 0xa5be, 0x6844, - 0xa005, 0x0050, 0x4abd, 0x00c0, 0x4abd, 0x127e, 0x2091, 0x8000, - 0x2069, 0x0000, 0x6934, 0x2001, 0xa41f, 0x2004, 0xa10a, 0x0040, - 0x4ab8, 0x0068, 0x4abc, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, - 0x4abc, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, - 0x2069, 0xa5be, 0x6847, 0xffff, 0x127f, 0x2069, 0xa300, 0x6844, - 0x6960, 0xa102, 0x2069, 0xa534, 0x688a, 0x6984, 0x701c, 0xa06d, - 0x0040, 0x4acf, 0x81ff, 0x0040, 0x4b17, 0x0078, 0x4ae5, 0x81ff, - 0x0040, 0x4be9, 0x2071, 0xa534, 0x7184, 0x7088, 0xa10a, 0x00c8, - 0x4ae5, 0x7190, 0x2071, 0xa5be, 0x7040, 0xa005, 0x0040, 0x4ae5, - 0x00d0, 0x4be9, 0x7142, 0x0078, 0x4be9, 0x2071, 0xa534, 0x718c, - 0x127e, 0x2091, 0x8000, 0x7084, 0xa10a, 0x0048, 0x4c06, 0x0068, - 0x4b9b, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x4b9b, 0x2001, - 0xffff, 0x2071, 0xa5be, 0x7042, 0x2071, 0xa534, 0x7000, 0xa086, - 0x0002, 0x00c0, 0x4b0d, 0x1078, 0x4cd2, 0x2071, 0x0000, 0x701b, - 0x0001, 0x2091, 0x4080, 0x0078, 0x4b9b, 0x1078, 0x4cfd, 0x2071, - 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x4b9b, 0x2071, - 0xa534, 0x7000, 0xa005, 0x0040, 0x4bc8, 0x6934, 0xa186, 0x0103, - 0x00c0, 0x4b9e, 0x684c, 0xd0bc, 0x00c0, 0x4bc8, 0x6948, 0x6844, - 0xa105, 0x00c0, 0x4bbb, 0x2009, 0x8020, 0x2071, 0xa534, 0x7000, - 0x0079, 0x4b32, 0x4bc8, 0x4b80, 0x4b58, 0x4b6a, 0x4b37, 0x137e, - 0x147e, 0x157e, 0x2099, 0xa375, 0x20a1, 0xa585, 0x20a9, 0x0004, - 0x53a3, 0x157f, 0x147f, 0x137f, 0x2071, 0xa57c, 0xad80, 0x000f, - 0x700e, 0x7013, 0x0002, 0x7007, 0x0002, 0x700b, 0x0000, 0x2e10, - 0x1078, 0x13d1, 0x2071, 0xa413, 0x7007, 0x0009, 0x0078, 0x4be9, - 0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x4be9, 0xae90, 0x0003, - 0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0xa413, 0x1078, 0x4d5b, - 0x0078, 0x4be9, 0x7084, 0x8008, 0xa092, 0x000f, 0x00c8, 0x4be9, - 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, 0x6840, - 0x2012, 0x7186, 0x2071, 0xa413, 0x1078, 0x4d5b, 0x0078, 0x4be9, - 0x127e, 0x2091, 0x8000, 0x0068, 0x4b9b, 0x2071, 0x0000, 0x7018, - 0xd084, 0x00c0, 0x4b9b, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, - 0x701b, 0x0001, 0x2091, 0x4080, 0x127f, 0x2071, 0xa413, 0x1078, - 0x4d5b, 0x0078, 0x4be9, 0x127f, 0x0078, 0x4be9, 0xa18c, 0x00ff, - 0xa186, 0x0017, 0x0040, 0x4bac, 0xa186, 0x001e, 0x0040, 0x4bac, - 0xa18e, 0x001f, 0x00c0, 0x4bc8, 0x684c, 0xd0cc, 0x0040, 0x4bc8, - 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, 0x4bc8, 0x2009, - 0x8021, 0x0078, 0x4b2d, 0x6844, 0xa086, 0x0100, 0x00c0, 0x4bc8, - 0x6868, 0xa005, 0x00c0, 0x4bc8, 0x2009, 0x8020, 0x0078, 0x4b2d, - 0x2071, 0xa413, 0x1078, 0x4d6f, 0x0040, 0x4be9, 0x2071, 0xa413, - 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, 0x00c0, - 0x4be0, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x4be0, 0x710e, - 0x7007, 0x0003, 0x1078, 0x4d8f, 0x7050, 0xa086, 0x0100, 0x0040, - 0x4ca4, 0x127e, 0x2091, 0x8000, 0x2071, 0xa413, 0x7008, 0xa086, - 0x0001, 0x00c0, 0x4c04, 0x0068, 0x4c04, 0x2009, 0x000d, 0x7030, - 0x200a, 0x2091, 0x4080, 0x700b, 0x0000, 0x7004, 0xa086, 0x0006, - 0x00c0, 0x4c04, 0x7007, 0x0001, 0x127f, 0x007c, 0x2071, 0xa413, - 0x1078, 0x4d6f, 0x0040, 0x4c2f, 0x2071, 0xa534, 0x7084, 0x700a, - 0x20a9, 0x0020, 0x2099, 0xa535, 0x20a1, 0xa55c, 0x53a3, 0x7087, - 0x0000, 0x2071, 0xa413, 0x2069, 0xa57c, 0x706c, 0x6826, 0x7070, - 0x682a, 0x7074, 0x682e, 0x7078, 0x6832, 0x2d10, 0x1078, 0x13d1, - 0x7007, 0x0008, 0x2001, 0xffff, 0x2071, 0xa5be, 0x7042, 0x127f, - 0x0078, 0x4be9, 0x2069, 0xa57c, 0x6808, 0xa08e, 0x0000, 0x0040, - 0x4c90, 0xa08e, 0x0200, 0x0040, 0x4c8e, 0xa08e, 0x0100, 0x00c0, - 0x4c90, 0x127e, 0x2091, 0x8000, 0x0068, 0x4c8b, 0x2069, 0x0000, - 0x6818, 0xd084, 0x00c0, 0x4c8b, 0x702c, 0x7130, 0x8108, 0xa102, - 0x0048, 0x4c59, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0078, - 0x4c63, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x4c63, 0x7070, - 0xa081, 0x0000, 0x7072, 0x7132, 0x6936, 0x700b, 0x0000, 0x2001, - 0xa559, 0x2004, 0xa005, 0x00c0, 0x4c82, 0x6934, 0x2069, 0xa534, - 0x689c, 0x699e, 0x2069, 0xa5be, 0xa102, 0x00c0, 0x4c7b, 0x6844, - 0xa005, 0x00d0, 0x4c89, 0x2001, 0xa55a, 0x200c, 0x810d, 0x6946, - 0x0078, 0x4c89, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, - 0x4080, 0x7007, 0x0001, 0x127f, 0x0078, 0x4c90, 0x7007, 0x0005, - 0x007c, 0x701c, 0xa06d, 0x0040, 0x4ca2, 0x1078, 0x4d6f, 0x0040, - 0x4ca2, 0x7007, 0x0003, 0x1078, 0x4d8f, 0x7050, 0xa086, 0x0100, - 0x0040, 0x4ca4, 0x007c, 0x007c, 0x7050, 0xa09e, 0x0100, 0x00c0, - 0x4cad, 0x7007, 0x0004, 0x0078, 0x4ccb, 0xa086, 0x0200, 0x00c0, - 0x4cb3, 0x7007, 0x0005, 0x007c, 0x2001, 0xa57e, 0x2004, 0xa08e, - 0x0100, 0x00c0, 0x4cc0, 0x7007, 0x0001, 0x1078, 0x4d5b, 0x007c, - 0xa08e, 0x0000, 0x0040, 0x4cbf, 0xa08e, 0x0200, 0x00c0, 0x4cbf, - 0x7007, 0x0005, 0x007c, 0x1078, 0x4d25, 0x7006, 0x1078, 0x4d5b, - 0x007c, 0x007c, 0x0e7e, 0x157e, 0x2071, 0xa534, 0x7184, 0x81ff, - 0x0040, 0x4cfa, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, 0x0000, - 0x21a8, 0x2014, 0x7226, 0x8000, 0x0070, 0x4cf7, 0x2014, 0x722a, - 0x8000, 0x0070, 0x4cf7, 0x2014, 0x722e, 0x8000, 0x0070, 0x4cf7, - 0x2014, 0x723a, 0x8000, 0x0070, 0x4cf7, 0x2014, 0x723e, 0xa180, - 0x8030, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x0e7e, 0x157e, 0x2071, - 0xa534, 0x7184, 0x81ff, 0x0040, 0x4d22, 0xa006, 0x7086, 0xae80, - 0x0003, 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x2014, - 0x722a, 0x8000, 0x0070, 0x4d1b, 0x2014, 0x723a, 0x8000, 0x2014, - 0x723e, 0x0078, 0x4d1f, 0x2001, 0x8020, 0x0078, 0x4d21, 0x2001, - 0x8042, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x702c, 0x7130, 0x8108, - 0xa102, 0x0048, 0x4d32, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, - 0x0078, 0x4d3c, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x4d3c, - 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, 0x700e, - 0x00c0, 0x4d52, 0x127e, 0x2091, 0x8000, 0x0068, 0x4d55, 0x2001, - 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x700b, 0x0000, - 0x127f, 0x007c, 0x2001, 0x0007, 0x007c, 0x2001, 0x0006, 0x700b, - 0x0001, 0x127f, 0x007c, 0x701c, 0xa06d, 0x0040, 0x4d6e, 0x127e, - 0x2091, 0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, 0xa005, - 0x00c0, 0x4d6b, 0x701a, 0x127f, 0x1078, 0x139a, 0x007c, 0x2019, - 0x000d, 0x2304, 0x230c, 0xa10e, 0x0040, 0x4d7e, 0x2304, 0x230c, - 0xa10e, 0x0040, 0x4d7e, 0xa006, 0x0078, 0x4d8e, 0x732c, 0x8319, - 0x7130, 0xa102, 0x00c0, 0x4d88, 0x2300, 0xa005, 0x0078, 0x4d8e, - 0x0048, 0x4d8d, 0xa302, 0x0078, 0x4d8e, 0x8002, 0x007c, 0x2d00, - 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x127e, 0x2091, - 0x8000, 0x2009, 0xa5d0, 0x2104, 0xc08d, 0x200a, 0x127f, 0x1078, - 0x13eb, 0x007c, 0x2071, 0xa3e1, 0x7003, 0x0000, 0x7007, 0x0000, - 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001, - 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000, - 0x708f, 0x0001, 0x70bf, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa3e1, - 0x6848, 0xa005, 0x00c0, 0x4dcb, 0x7028, 0xc085, 0x702a, 0xa085, - 0x0001, 0x0078, 0x4df0, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, - 0x703e, 0x707a, 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, - 0x7032, 0x2009, 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, - 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, - 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, - 0x0e7f, 0x007c, 0x2b78, 0x2071, 0xa3e1, 0x7004, 0x1079, 0x4e50, - 0x700c, 0x0079, 0x4dfb, 0x4e00, 0x4df5, 0x4df5, 0x4df5, 0x4df5, - 0x007c, 0x700c, 0x0079, 0x4e04, 0x4e09, 0x4e4e, 0x4e4e, 0x4e4f, - 0x4e4f, 0x7830, 0x7930, 0xa106, 0x0040, 0x4e13, 0x7830, 0x7930, - 0xa106, 0x00c0, 0x4e39, 0x7030, 0xa10a, 0x0040, 0x4e39, 0x00c8, - 0x4e1b, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x00c8, 0x4e3a, 0x1078, - 0x1366, 0x0040, 0x4e39, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, - 0x0003, 0x7057, 0x0000, 0x127e, 0x007e, 0x2091, 0x8000, 0x2009, - 0xa5d0, 0x2104, 0xc085, 0x200a, 0x007f, 0x700e, 0x127f, 0x1078, - 0x13eb, 0x007c, 0x1078, 0x1366, 0x0040, 0x4e39, 0x2d00, 0x705a, - 0x1078, 0x1366, 0x00c0, 0x4e46, 0x0078, 0x4e25, 0x2d00, 0x7086, - 0x7063, 0x0080, 0x2001, 0x0004, 0x0078, 0x4e29, 0x007c, 0x007c, - 0x4e61, 0x4e62, 0x4e99, 0x4e9a, 0x4e4e, 0x4ed0, 0x4ed5, 0x4f0c, - 0x4f0d, 0x4f28, 0x4f29, 0x4f2a, 0x4f2b, 0x4f2c, 0x4f2d, 0x4fad, - 0x4fd7, 0x007c, 0x700c, 0x0079, 0x4e65, 0x4e6a, 0x4e6d, 0x4e7d, - 0x4e98, 0x4e98, 0x1078, 0x4e01, 0x007c, 0x127e, 0x8001, 0x700e, - 0x7058, 0x007e, 0x1078, 0x5348, 0x0040, 0x4e7a, 0x2091, 0x8000, - 0x1078, 0x4e01, 0x0d7f, 0x0078, 0x4e86, 0x127e, 0x8001, 0x700e, - 0x1078, 0x5348, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, - 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x0020, 0x00c8, - 0x4e95, 0x1079, 0x4eb0, 0x127f, 0x007c, 0x127f, 0x1078, 0x4f2e, - 0x007c, 0x007c, 0x007c, 0x0e7e, 0x2071, 0xa3e1, 0x700c, 0x0079, - 0x4ea1, 0x4ea6, 0x4ea6, 0x4ea6, 0x4ea8, 0x4eac, 0x0e7f, 0x007c, - 0x700f, 0x0001, 0x0078, 0x4eae, 0x700f, 0x0002, 0x0e7f, 0x007c, - 0x4f2e, 0x4f2e, 0x4f4a, 0x4f2e, 0x5080, 0x4f2e, 0x4f2e, 0x4f2e, - 0x4f2e, 0x4f2e, 0x4f4a, 0x50ca, 0x5117, 0x5170, 0x5186, 0x4f2e, - 0x4f2e, 0x4f66, 0x4f4a, 0x4f2e, 0x4f2e, 0x4f87, 0x5245, 0x5263, - 0x4f2e, 0x4f66, 0x4f2e, 0x4f2e, 0x4f2e, 0x4f2e, 0x4f7c, 0x5263, - 0x7020, 0x2068, 0x1078, 0x139a, 0x007c, 0x700c, 0x0079, 0x4ed8, - 0x4edd, 0x4ee0, 0x4ef0, 0x4f0b, 0x4f0b, 0x1078, 0x4e01, 0x007c, - 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x5348, 0x0040, - 0x4eed, 0x2091, 0x8000, 0x1078, 0x4e01, 0x0d7f, 0x0078, 0x4ef9, - 0x127e, 0x8001, 0x700e, 0x1078, 0x5348, 0x7058, 0x2068, 0x7084, - 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, - 0xa08a, 0x001a, 0x00c8, 0x4f08, 0x1079, 0x4f0e, 0x127f, 0x007c, - 0x127f, 0x1078, 0x4f2e, 0x007c, 0x007c, 0x007c, 0x4f2e, 0x4f4a, - 0x506a, 0x4f2e, 0x4f4a, 0x4f2e, 0x4f4a, 0x4f4a, 0x4f2e, 0x4f4a, - 0x506a, 0x4f4a, 0x4f4a, 0x4f4a, 0x4f4a, 0x4f4a, 0x4f2e, 0x4f4a, - 0x506a, 0x4f2e, 0x4f2e, 0x4f4a, 0x4f2e, 0x4f2e, 0x4f2e, 0x4f4a, - 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x7007, 0x0001, - 0x6838, 0xa084, 0x00ff, 0xc0d5, 0x683a, 0x127e, 0x2091, 0x8000, - 0x1078, 0x4982, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, - 0x00ff, 0xc0e5, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4982, - 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed, - 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4982, 0x127f, 0x007c, - 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0dd, 0x683a, 0x127e, - 0x2091, 0x8000, 0x1078, 0x4982, 0x127f, 0x007c, 0x6834, 0x8007, - 0xa084, 0x00ff, 0x0040, 0x4f3c, 0x8001, 0x00c0, 0x4f73, 0x7007, - 0x0001, 0x0078, 0x5049, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, - 0x701a, 0x704b, 0x5049, 0x007c, 0x684c, 0xa084, 0x00c0, 0xa086, - 0x00c0, 0x00c0, 0x4f87, 0x7007, 0x0001, 0x0078, 0x5280, 0x2d00, - 0x7016, 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, - 0xa40c, 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x00c8, 0x4f58, - 0x6884, 0xa08a, 0x0002, 0x00c8, 0x4f58, 0x82ff, 0x00c0, 0x4fa9, - 0x6888, 0x698c, 0xa105, 0x0040, 0x4fa9, 0x2001, 0x5019, 0x0078, - 0x4fac, 0xa280, 0x500f, 0x2004, 0x70c6, 0x7010, 0xa015, 0x0040, - 0x4ff7, 0x1078, 0x1366, 0x00c0, 0x4fb8, 0x7007, 0x000f, 0x007c, - 0x2d00, 0x7022, 0x70c4, 0x2060, 0x6000, 0x6836, 0x6004, 0xad00, - 0x7096, 0x6008, 0xa20a, 0x00c8, 0x4fc7, 0xa00e, 0x2200, 0x7112, - 0x620c, 0x8003, 0x800b, 0xa296, 0x0004, 0x0040, 0x4fd0, 0xa108, - 0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x1078, 0x13d1, 0x7090, - 0xa08e, 0x0100, 0x0040, 0x4feb, 0xa086, 0x0200, 0x0040, 0x4fe3, - 0x7007, 0x0010, 0x007c, 0x7020, 0x2068, 0x1078, 0x139a, 0x7014, - 0x2068, 0x0078, 0x4f58, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, - 0x0000, 0x2d08, 0x2068, 0x6906, 0x711a, 0x0078, 0x4fad, 0x7014, - 0x2068, 0x7007, 0x0001, 0x6884, 0xa005, 0x00c0, 0x5006, 0x6888, - 0x698c, 0xa105, 0x0040, 0x5006, 0x1078, 0x501d, 0x6834, 0xa084, - 0x00ff, 0xa086, 0x001e, 0x0040, 0x5280, 0x0078, 0x5049, 0x5011, - 0x5015, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, 0x000f, 0x0005, - 0x0006, 0x000a, 0x0011, 0x0005, 0x0004, 0x0f7e, 0x0e7e, 0x0c7e, - 0x077e, 0x067e, 0x6f88, 0x6e8c, 0x6804, 0x2060, 0xacf0, 0x0021, - 0xacf8, 0x0027, 0x2009, 0x0005, 0x700c, 0x7816, 0x7008, 0x7812, - 0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e, 0x7f0a, 0x8109, 0x0040, - 0x503f, 0xaef2, 0x0004, 0xaffa, 0x0006, 0x0078, 0x502c, 0x6004, - 0xa065, 0x00c0, 0x5026, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x0f7f, - 0x007c, 0x2009, 0xa32e, 0x210c, 0x81ff, 0x00c0, 0x5064, 0x6838, - 0xa084, 0x00ff, 0x683a, 0x1078, 0x4290, 0x00c0, 0x5058, 0x007c, - 0x1078, 0x4a60, 0x127e, 0x2091, 0x8000, 0x1078, 0x8cb8, 0x1078, - 0x4982, 0x127f, 0x0078, 0x5057, 0x2001, 0x0028, 0x2009, 0x0000, - 0x0078, 0x5058, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, 0x711a, - 0x7010, 0x8001, 0x7012, 0x0040, 0x5079, 0x7007, 0x0006, 0x0078, - 0x507f, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a, 0x007c, - 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, 0xa084, - 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x50a9, 0x2009, - 0x0000, 0x20a9, 0x00ff, 0xa096, 0x0002, 0x0040, 0x50a9, 0xa005, - 0x00c0, 0x50bc, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x4501, - 0x00c0, 0x50bc, 0x067e, 0x6e50, 0x1078, 0x45e7, 0x067f, 0x0078, - 0x50bc, 0x047e, 0x2011, 0xa30c, 0x2224, 0xc484, 0xc48c, 0x2412, - 0x047f, 0x0c7e, 0x1078, 0x4501, 0x00c0, 0x50b8, 0x1078, 0x4782, - 0x8108, 0x00f0, 0x50b2, 0x0c7f, 0x684c, 0xd084, 0x00c0, 0x50c3, - 0x1078, 0x139a, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4982, - 0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, - 0xa352, 0x2004, 0xd0a4, 0x0040, 0x510e, 0x2061, 0xa62d, 0x6100, - 0xd184, 0x0040, 0x50ee, 0x6858, 0xa084, 0x00ff, 0x00c0, 0x5111, - 0x6000, 0xd084, 0x0040, 0x510e, 0x6004, 0xa005, 0x00c0, 0x5114, - 0x6003, 0x0000, 0x600b, 0x0000, 0x0078, 0x510b, 0x2011, 0x0001, - 0x6860, 0xa005, 0x00c0, 0x50f6, 0x2001, 0x001e, 0x8000, 0x6016, - 0x6858, 0xa084, 0x00ff, 0x0040, 0x510e, 0x6006, 0x6858, 0x8007, - 0xa084, 0x00ff, 0x0040, 0x510e, 0x600a, 0x6858, 0x8000, 0x00c0, - 0x510a, 0xc28d, 0x6202, 0x127f, 0x0078, 0x5337, 0x127f, 0x0078, - 0x532f, 0x127f, 0x0078, 0x5327, 0x127f, 0x0078, 0x532b, 0x127e, - 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xa352, 0x2004, 0xd0a4, - 0x0040, 0x516d, 0x2061, 0xa62d, 0x6000, 0xd084, 0x0040, 0x516d, - 0x6204, 0x6308, 0xd08c, 0x00c0, 0x515f, 0x6c48, 0xa484, 0x0003, - 0x0040, 0x5145, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x00c0, 0x513e, - 0x2100, 0xa210, 0x0048, 0x516a, 0x0078, 0x5145, 0x8001, 0x00c0, - 0x516a, 0x2100, 0xa212, 0x0048, 0x516a, 0xa484, 0x000c, 0x0040, - 0x515f, 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x00c0, - 0x5157, 0x2100, 0xa318, 0x0048, 0x516a, 0x0078, 0x515f, 0xa082, - 0x0004, 0x00c0, 0x516a, 0x2100, 0xa31a, 0x0048, 0x516a, 0x6860, - 0xa005, 0x0040, 0x5165, 0x8000, 0x6016, 0x6206, 0x630a, 0x127f, - 0x0078, 0x5337, 0x127f, 0x0078, 0x5333, 0x127f, 0x0078, 0x532f, - 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, 0xa62d, 0x6300, - 0xd38c, 0x00c0, 0x5180, 0x6308, 0x8318, 0x0048, 0x5183, 0x630a, - 0x127f, 0x0078, 0x5345, 0x127f, 0x0078, 0x5333, 0x127e, 0x0c7e, - 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, 0xd0ac, 0x0040, 0x519a, - 0x0c7e, 0x2061, 0xa62d, 0x6000, 0xa084, 0xfcff, 0x6002, 0x0c7f, - 0x0078, 0x51c9, 0x6858, 0xa005, 0x0040, 0x51e0, 0x685c, 0xa065, - 0x0040, 0x51dc, 0x2001, 0xa32e, 0x2004, 0xa005, 0x0040, 0x51ac, - 0x1078, 0x8c01, 0x0078, 0x51ba, 0x6013, 0x0400, 0x6037, 0x0000, - 0x694c, 0xd1a4, 0x0040, 0x51b6, 0x6950, 0x6136, 0x2009, 0x0041, - 0x1078, 0x756c, 0x6958, 0xa18c, 0xff00, 0xa186, 0x2000, 0x00c0, - 0x51c9, 0x027e, 0x2009, 0x0000, 0x2011, 0xfdff, 0x1078, 0x5a6d, - 0x027f, 0x684c, 0xd0c4, 0x0040, 0x51d8, 0x2061, 0xa62d, 0x6000, - 0xd08c, 0x00c0, 0x51d8, 0x6008, 0x8000, 0x0048, 0x51dc, 0x600a, - 0x0c7f, 0x127f, 0x0078, 0x5337, 0x0c7f, 0x127f, 0x0078, 0x532f, - 0x6954, 0xa186, 0x0045, 0x0040, 0x5213, 0xa186, 0x002a, 0x00c0, - 0x51f0, 0x2001, 0xa30c, 0x200c, 0xc194, 0x2102, 0x0078, 0x51c9, - 0xa186, 0x0020, 0x0040, 0x5209, 0xa186, 0x0029, 0x0040, 0x51fc, - 0xa186, 0x002d, 0x00c0, 0x51dc, 0x6944, 0xa18c, 0xff00, 0x810f, - 0x1078, 0x4501, 0x00c0, 0x51c9, 0x6000, 0xc0e4, 0x6002, 0x0078, - 0x51c9, 0x685c, 0xa065, 0x0040, 0x51dc, 0x2001, 0xa5a1, 0x2004, - 0x6016, 0x0078, 0x51c9, 0x685c, 0xa065, 0x0040, 0x51dc, 0x0e7e, - 0x6860, 0xa075, 0x2001, 0xa32e, 0x2004, 0xa005, 0x0040, 0x522b, - 0x1078, 0x8c01, 0x8eff, 0x0040, 0x5228, 0x2e60, 0x1078, 0x8c01, - 0x0e7f, 0x0078, 0x51c9, 0x6024, 0xc0dc, 0xc0d5, 0x6026, 0x2e60, - 0x6007, 0x003a, 0x6870, 0xa005, 0x0040, 0x523c, 0x6007, 0x003b, - 0x6874, 0x602a, 0x6878, 0x6012, 0x6003, 0x0001, 0x1078, 0x5bf8, - 0x1078, 0x6109, 0x0e7f, 0x0078, 0x51c9, 0x2061, 0xa62d, 0x6000, - 0xd084, 0x0040, 0x525f, 0xd08c, 0x00c0, 0x5345, 0x2091, 0x8000, - 0x6204, 0x8210, 0x0048, 0x5259, 0x6206, 0x2091, 0x8001, 0x0078, - 0x5345, 0x2091, 0x8001, 0x6853, 0x0016, 0x0078, 0x533e, 0x6853, - 0x0007, 0x0078, 0x533e, 0x6834, 0x8007, 0xa084, 0x00ff, 0x00c0, - 0x526d, 0x1078, 0x4f3c, 0x0078, 0x527f, 0x2030, 0x8001, 0x00c0, - 0x5277, 0x7007, 0x0001, 0x1078, 0x5280, 0x0078, 0x527f, 0x7007, - 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5280, 0x007c, - 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2009, 0xa32e, 0x210c, 0x81ff, - 0x00c0, 0x530b, 0x2009, 0xa30c, 0x210c, 0xd194, 0x00c0, 0x5315, - 0x6848, 0x2070, 0xae82, 0xaa00, 0x0048, 0x52fb, 0x2001, 0xa315, - 0x2004, 0xae02, 0x00c8, 0x52fb, 0x2061, 0xa62d, 0x6100, 0xa184, - 0x0301, 0xa086, 0x0001, 0x00c0, 0x52de, 0x711c, 0xa186, 0x0006, - 0x00c0, 0x52e6, 0x7018, 0xa005, 0x0040, 0x530b, 0x2004, 0xd0e4, - 0x00c0, 0x530f, 0x7024, 0xd0dc, 0x00c0, 0x5319, 0x6853, 0x0000, - 0x6803, 0x0000, 0x2d08, 0x7010, 0xa005, 0x00c0, 0x52ca, 0x7112, - 0x684c, 0xd0f4, 0x00c0, 0x531d, 0x2e60, 0x1078, 0x59b6, 0x127f, - 0x0e7f, 0x007c, 0x2068, 0x6800, 0xa005, 0x00c0, 0x52ca, 0x6902, - 0x2168, 0x684c, 0xd0f4, 0x00c0, 0x531d, 0x127f, 0x0e7f, 0x007c, - 0x127f, 0x0e7f, 0x6853, 0x0006, 0x0078, 0x533e, 0xd184, 0x0040, - 0x52d8, 0xd1c4, 0x00c0, 0x52ff, 0x0078, 0x5303, 0x6944, 0xa18c, - 0xff00, 0x810f, 0x1078, 0x4501, 0x00c0, 0x530f, 0x6000, 0xd0e4, - 0x00c0, 0x530f, 0x711c, 0xa186, 0x0007, 0x00c0, 0x52fb, 0x6853, - 0x0002, 0x0078, 0x5311, 0x6853, 0x0008, 0x0078, 0x5311, 0x6853, - 0x000e, 0x0078, 0x5311, 0x6853, 0x0017, 0x0078, 0x5311, 0x6853, - 0x0035, 0x0078, 0x5311, 0x6853, 0x0028, 0x0078, 0x5311, 0x6853, - 0x0029, 0x127f, 0x0e7f, 0x0078, 0x533e, 0x6853, 0x002a, 0x0078, - 0x5311, 0x6853, 0x0045, 0x0078, 0x5311, 0x2e60, 0x2019, 0x0002, - 0x6017, 0x0014, 0x1078, 0x9a6a, 0x127f, 0x0e7f, 0x007c, 0x2009, - 0x003e, 0x0078, 0x5339, 0x2009, 0x0004, 0x0078, 0x5339, 0x2009, - 0x0006, 0x0078, 0x5339, 0x2009, 0x0016, 0x0078, 0x5339, 0x2009, - 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, 0x6856, 0x2091, 0x8000, - 0x1078, 0x4982, 0x2091, 0x8001, 0x007c, 0x1078, 0x139a, 0x007c, - 0x702c, 0x7130, 0x8108, 0xa102, 0x0048, 0x5355, 0xa00e, 0x7034, - 0x7072, 0x7038, 0x7076, 0x0078, 0x5361, 0x7070, 0xa080, 0x0040, - 0x7072, 0x00c8, 0x5361, 0x7074, 0xa081, 0x0000, 0x7076, 0xa085, - 0x0001, 0x7932, 0x7132, 0x007c, 0x0d7e, 0x1078, 0x59ad, 0x0d7f, - 0x007c, 0x0d7e, 0x2011, 0x0004, 0x2204, 0xa085, 0x8002, 0x2012, - 0x0d7f, 0x007c, 0x20e1, 0x0002, 0x3d08, 0x20e1, 0x2000, 0x3d00, - 0xa084, 0x7000, 0x0040, 0x5380, 0xa086, 0x1000, 0x00c0, 0x53ac, - 0x20e1, 0x0000, 0x3d00, 0xa094, 0xff00, 0x8217, 0xa084, 0xf000, - 0xa086, 0x3000, 0x00c0, 0x5390, 0x1078, 0x5570, 0x0078, 0x53a7, - 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x00c0, 0x5397, 0x3e60, 0xac84, - 0x000f, 0x00c0, 0x53ac, 0xac82, 0xaa00, 0x0048, 0x53ac, 0x6854, - 0xac02, 0x00c8, 0x53ac, 0x2009, 0x0047, 0x1078, 0x756c, 0x7a1c, - 0xd284, 0x00c0, 0x5372, 0x007c, 0xa016, 0x1078, 0x15ec, 0x0078, - 0x53a7, 0x0078, 0x53ac, 0x781c, 0xd08c, 0x0040, 0x53db, 0x157e, - 0x137e, 0x147e, 0x20e1, 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0076, - 0x00c0, 0x53f1, 0xa484, 0x7000, 0xa086, 0x1000, 0x00c0, 0x53e0, - 0x1078, 0x540c, 0x0040, 0x53f1, 0x20e1, 0x3000, 0x7828, 0x7828, - 0x1078, 0x542a, 0x147f, 0x137f, 0x157f, 0x2009, 0xa5b3, 0x2104, - 0xa005, 0x00c0, 0x53dc, 0x007c, 0x1078, 0x6109, 0x0078, 0x53db, - 0xa484, 0x7000, 0x00c0, 0x53f1, 0x1078, 0x540c, 0x0040, 0x5403, - 0x7000, 0xa084, 0xff00, 0xa086, 0x8100, 0x0040, 0x53cc, 0x0078, - 0x5403, 0x1078, 0xa1ee, 0xd5a4, 0x0040, 0x53ff, 0x1078, 0x1af7, - 0x20e1, 0x9010, 0x2001, 0x0138, 0x2202, 0x0078, 0x5407, 0x1078, - 0x540c, 0x687f, 0x0000, 0x20e1, 0x3000, 0x7828, 0x7828, 0x147f, - 0x137f, 0x157f, 0x0078, 0x53db, 0xa484, 0x01ff, 0x687e, 0xa005, - 0x0040, 0x541e, 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac, 0x20e1, - 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x007c, 0x20a9, 0x000c, - 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001, - 0x0078, 0x541d, 0x7000, 0xa084, 0xff00, 0xa08c, 0xf000, 0x8007, - 0xa196, 0x0000, 0x00c0, 0x5437, 0x0078, 0x567c, 0x007c, 0xa196, - 0x2000, 0x00c0, 0x5448, 0x6900, 0xa18e, 0x0001, 0x00c0, 0x5444, - 0x1078, 0x3a43, 0x0078, 0x5436, 0x1078, 0x5450, 0x0078, 0x5436, - 0xa196, 0x8000, 0x00c0, 0x5436, 0x1078, 0x570c, 0x0078, 0x5436, - 0x0c7e, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0040, - 0x545d, 0xa196, 0x0023, 0x00c0, 0x5568, 0xa08e, 0x0023, 0x00c0, - 0x5492, 0x1078, 0x57b2, 0x0040, 0x5568, 0x7124, 0x610a, 0x7030, - 0xa08e, 0x0200, 0x00c0, 0x5476, 0x7034, 0xa005, 0x00c0, 0x5568, - 0x2009, 0x0015, 0x1078, 0x756c, 0x0078, 0x5568, 0xa08e, 0x0214, - 0x0040, 0x547e, 0xa08e, 0x0210, 0x00c0, 0x5484, 0x2009, 0x0015, - 0x1078, 0x756c, 0x0078, 0x5568, 0xa08e, 0x0100, 0x00c0, 0x5568, - 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009, 0x0016, 0x1078, 0x756c, - 0x0078, 0x5568, 0xa08e, 0x0022, 0x00c0, 0x5568, 0x7030, 0xa08e, - 0x0300, 0x00c0, 0x54a3, 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009, - 0x0017, 0x0078, 0x5534, 0xa08e, 0x0500, 0x00c0, 0x54af, 0x7034, - 0xa005, 0x00c0, 0x5568, 0x2009, 0x0018, 0x0078, 0x5534, 0xa08e, - 0x2010, 0x00c0, 0x54b7, 0x2009, 0x0019, 0x0078, 0x5534, 0xa08e, - 0x2110, 0x00c0, 0x54bf, 0x2009, 0x001a, 0x0078, 0x5534, 0xa08e, - 0x5200, 0x00c0, 0x54cb, 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009, - 0x001b, 0x0078, 0x5534, 0xa08e, 0x5000, 0x00c0, 0x54d7, 0x7034, - 0xa005, 0x00c0, 0x5568, 0x2009, 0x001c, 0x0078, 0x5534, 0xa08e, - 0x1300, 0x00c0, 0x54df, 0x2009, 0x0034, 0x0078, 0x5534, 0xa08e, - 0x1200, 0x00c0, 0x54eb, 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009, - 0x0024, 0x0078, 0x5534, 0xa08c, 0xff00, 0xa18e, 0x2400, 0x00c0, - 0x54f5, 0x2009, 0x002d, 0x0078, 0x5534, 0xa08c, 0xff00, 0xa18e, - 0x5300, 0x00c0, 0x54ff, 0x2009, 0x002a, 0x0078, 0x5534, 0xa08e, - 0x0f00, 0x00c0, 0x5507, 0x2009, 0x0020, 0x0078, 0x5534, 0xa08e, - 0x5300, 0x00c0, 0x550d, 0x0078, 0x552a, 0xa08e, 0x6104, 0x00c0, - 0x552a, 0x2011, 0xa88d, 0x8208, 0x2204, 0xa082, 0x0004, 0x20a8, - 0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108, 0x047e, 0x2124, - 0x1078, 0x3579, 0x047f, 0x8108, 0x00f0, 0x551a, 0x2009, 0x0023, - 0x0078, 0x5534, 0xa08e, 0x6000, 0x00c0, 0x5532, 0x2009, 0x003f, - 0x0078, 0x5534, 0x2009, 0x001d, 0x017e, 0x2011, 0xa883, 0x2204, - 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, 0x556a, 0x1078, 0x4499, - 0x00c0, 0x556a, 0x6612, 0x6516, 0x86ff, 0x0040, 0x555a, 0x017f, - 0x017e, 0xa186, 0x0017, 0x00c0, 0x555a, 0x6868, 0xa606, 0x00c0, - 0x555a, 0x686c, 0xa506, 0xa084, 0xff00, 0x00c0, 0x555a, 0x6000, - 0xc0f5, 0x6002, 0x0c7e, 0x1078, 0x74d7, 0x0040, 0x556d, 0x017f, - 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x756c, - 0x0c7f, 0x007c, 0x017f, 0x0078, 0x5568, 0x0c7f, 0x0078, 0x556a, - 0x0c7e, 0x1078, 0x55d4, 0x00c0, 0x55d2, 0xa184, 0xff00, 0x8007, - 0xa086, 0x0008, 0x00c0, 0x55d2, 0xa28e, 0x0033, 0x00c0, 0x55a3, - 0x1078, 0x57b2, 0x0040, 0x55d2, 0x7124, 0x610a, 0x7030, 0xa08e, - 0x0200, 0x00c0, 0x5595, 0x7034, 0xa005, 0x00c0, 0x55d2, 0x2009, - 0x0015, 0x1078, 0x756c, 0x0078, 0x55d2, 0xa08e, 0x0100, 0x00c0, - 0x55d2, 0x7034, 0xa005, 0x00c0, 0x55d2, 0x2009, 0x0016, 0x1078, - 0x756c, 0x0078, 0x55d2, 0xa28e, 0x0032, 0x00c0, 0x55d2, 0x7030, - 0xa08e, 0x1400, 0x00c0, 0x55d2, 0x2009, 0x0038, 0x017e, 0x2011, - 0xa883, 0x2204, 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, 0x55d1, - 0x1078, 0x4499, 0x00c0, 0x55d1, 0x6612, 0x6516, 0x0c7e, 0x1078, - 0x74d7, 0x0040, 0x55d0, 0x017f, 0x611a, 0x601f, 0x0004, 0x7120, - 0x610a, 0x017f, 0x1078, 0x756c, 0x1078, 0x6109, 0x0078, 0x55d2, - 0x0c7f, 0x017f, 0x0c7f, 0x007c, 0x0f7e, 0x0d7e, 0x027e, 0x017e, - 0x137e, 0x147e, 0x157e, 0x3c00, 0x007e, 0x2079, 0x0030, 0x2069, - 0x0200, 0x1078, 0x1c25, 0x00c0, 0x5615, 0x1078, 0x1b15, 0x0040, - 0x561f, 0x7908, 0xa18c, 0x1fff, 0xa182, 0x0011, 0x00c8, 0x561f, - 0x20a9, 0x000c, 0x20e1, 0x0000, 0x2ea0, 0x2099, 0x020a, 0x53a5, - 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x7a0c, 0x7808, 0xa080, - 0x0007, 0xa084, 0x1ff8, 0xa08a, 0x0140, 0x10c8, 0x1328, 0x80ac, - 0x20e1, 0x6000, 0x2099, 0x020a, 0x53a5, 0x20e1, 0x7000, 0x6828, - 0x6828, 0x7803, 0x0004, 0xa294, 0x0070, 0x007f, 0x20e0, 0x157f, - 0x147f, 0x137f, 0x017f, 0x027f, 0x0d7f, 0x0f7f, 0x007c, 0xa085, - 0x0001, 0x0078, 0x5615, 0x047e, 0x0e7e, 0x0d7e, 0x2028, 0x2130, - 0xa696, 0x00ff, 0x00c0, 0x5644, 0xa596, 0xfffd, 0x00c0, 0x5634, - 0x2009, 0x007f, 0x0078, 0x5677, 0xa596, 0xfffe, 0x00c0, 0x563c, - 0x2009, 0x007e, 0x0078, 0x5677, 0xa596, 0xfffc, 0x00c0, 0x5644, - 0x2009, 0x0080, 0x0078, 0x5677, 0x2011, 0x0000, 0x2021, 0x0081, - 0x20a9, 0x007e, 0x2071, 0xa4b5, 0x2e1c, 0x83ff, 0x00c0, 0x5656, - 0x82ff, 0x00c0, 0x566b, 0x2410, 0x0078, 0x566b, 0x2368, 0x6f10, - 0x007e, 0x2100, 0xa706, 0x007f, 0x6b14, 0x00c0, 0x5665, 0xa346, - 0x00c0, 0x5665, 0x2408, 0x0078, 0x5677, 0x87ff, 0x00c0, 0x566b, - 0x83ff, 0x0040, 0x5650, 0x8420, 0x8e70, 0x00f0, 0x564c, 0x82ff, - 0x00c0, 0x5676, 0xa085, 0x0001, 0x0078, 0x5678, 0x2208, 0xa006, - 0x0d7f, 0x0e7f, 0x047f, 0x007c, 0xa084, 0x0007, 0x0079, 0x5681, - 0x007c, 0x5689, 0x5689, 0x5689, 0x57c8, 0x5689, 0x568a, 0x56a3, - 0x56f3, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x56a2, 0x7120, 0x2160, - 0xac8c, 0x000f, 0x00c0, 0x56a2, 0xac8a, 0xaa00, 0x0048, 0x56a2, - 0x6854, 0xac02, 0x00c8, 0x56a2, 0x7124, 0x610a, 0x2009, 0x0046, - 0x1078, 0x756c, 0x007c, 0x0c7e, 0x7110, 0xd1bc, 0x00c0, 0x56f1, - 0x2011, 0xa883, 0x2204, 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, - 0x56f1, 0x1078, 0x4499, 0x00c0, 0x56f1, 0x6612, 0x6516, 0x6000, - 0xd0ec, 0x00c0, 0x56f1, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, - 0x0006, 0x00c0, 0x56d6, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, - 0x56f1, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6122, - 0x2009, 0x0044, 0x1078, 0x756c, 0x0078, 0x56f1, 0x0c7e, 0x1078, - 0x74d7, 0x017f, 0x0040, 0x56f1, 0x611a, 0x601f, 0x0004, 0x7120, - 0x610a, 0xa286, 0x0004, 0x00c0, 0x56e9, 0x6007, 0x0005, 0x0078, - 0x56eb, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x5c45, 0x1078, - 0x6109, 0x0c7f, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x570b, 0x7020, - 0x2060, 0xac84, 0x000f, 0x00c0, 0x570b, 0xac82, 0xaa00, 0x0048, - 0x570b, 0x6854, 0xac02, 0x00c8, 0x570b, 0x7124, 0x610a, 0x2009, - 0x0045, 0x1078, 0x756c, 0x007c, 0x7110, 0xa18c, 0xff00, 0x810f, - 0xa18e, 0x0000, 0x00c0, 0x571c, 0xa084, 0x000f, 0xa08a, 0x0006, - 0x00c8, 0x571c, 0x1079, 0x571d, 0x007c, 0x5723, 0x5724, 0x5723, - 0x5723, 0x5794, 0x57a3, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x572c, - 0x702c, 0xd084, 0x0040, 0x5793, 0x700c, 0x7108, 0x1078, 0x24e3, - 0x00c0, 0x5793, 0x1078, 0x4499, 0x00c0, 0x5793, 0x6612, 0x6516, - 0x6204, 0x7110, 0xd1bc, 0x0040, 0x575e, 0xa28c, 0x00ff, 0xa186, - 0x0004, 0x0040, 0x5747, 0xa186, 0x0006, 0x00c0, 0x5784, 0x0c7e, - 0x1078, 0x57b2, 0x0c7f, 0x0040, 0x5793, 0x0c7e, 0x1078, 0x74d7, - 0x017f, 0x0040, 0x5793, 0x611a, 0x601f, 0x0002, 0x7120, 0x610a, - 0x2009, 0x0088, 0x1078, 0x756c, 0x0078, 0x5793, 0xa28c, 0x00ff, - 0xa186, 0x0006, 0x0040, 0x5773, 0xa186, 0x0004, 0x0040, 0x5773, - 0xa294, 0xff00, 0x8217, 0xa286, 0x0004, 0x0040, 0x5773, 0xa286, - 0x0006, 0x00c0, 0x5784, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, - 0x5793, 0x611a, 0x601f, 0x0005, 0x7120, 0x610a, 0x2009, 0x0088, - 0x1078, 0x756c, 0x0078, 0x5793, 0x0c7e, 0x1078, 0x74d7, 0x017f, - 0x0040, 0x5793, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x2009, - 0x0001, 0x1078, 0x756c, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x57a2, - 0x1078, 0x57b2, 0x0040, 0x57a2, 0x7124, 0x610a, 0x2009, 0x0089, - 0x1078, 0x756c, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x57b1, 0x1078, - 0x57b2, 0x0040, 0x57b1, 0x7124, 0x610a, 0x2009, 0x008a, 0x1078, - 0x756c, 0x007c, 0x7020, 0x2060, 0xac84, 0x000f, 0x00c0, 0x57c5, - 0xac82, 0xaa00, 0x0048, 0x57c5, 0x2001, 0xa315, 0x2004, 0xac02, - 0x00c8, 0x57c5, 0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x57c4, - 0x7110, 0xd1bc, 0x00c0, 0x57de, 0x7024, 0x2060, 0xac84, 0x000f, - 0x00c0, 0x57de, 0xac82, 0xaa00, 0x0048, 0x57de, 0x6854, 0xac02, - 0x00c8, 0x57de, 0x2009, 0x0051, 0x1078, 0x756c, 0x007c, 0x2071, - 0xa5be, 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, 0x7012, - 0x7017, 0xaa00, 0x7007, 0x0000, 0x7026, 0x702b, 0x6c4e, 0x7032, - 0x7037, 0x6ca0, 0x703b, 0x0002, 0x703f, 0x0000, 0x7043, 0xffff, - 0x7047, 0xffff, 0x007c, 0x2071, 0xa5be, 0x00e0, 0x58c1, 0x2091, - 0x6000, 0x700c, 0x8001, 0x700e, 0x00c0, 0x5873, 0x700f, 0x0361, - 0x7007, 0x0001, 0x127e, 0x2091, 0x8000, 0x7138, 0x8109, 0x713a, - 0x00c0, 0x5871, 0x703b, 0x0002, 0x2009, 0x0100, 0x2104, 0xa082, - 0x0003, 0x00c8, 0x5871, 0x703c, 0xa086, 0x0001, 0x00c0, 0x584e, - 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x582c, - 0x6803, 0x1000, 0x0078, 0x5833, 0x6804, 0xa084, 0x1000, 0x0040, - 0x5833, 0x6803, 0x0100, 0x6803, 0x0000, 0x703f, 0x0000, 0x2069, - 0xa5ab, 0x6804, 0xa082, 0x0006, 0x00c0, 0x5840, 0x6807, 0x0000, - 0x6830, 0xa082, 0x0003, 0x00c0, 0x5847, 0x6833, 0x0000, 0x1078, - 0x6109, 0x1078, 0x61d3, 0x0d7f, 0x0078, 0x5871, 0x0d7e, 0x2069, - 0xa300, 0x6944, 0x6860, 0xa102, 0x00c8, 0x5870, 0x2069, 0xa5ab, - 0x6804, 0xa086, 0x0000, 0x00c0, 0x5870, 0x6830, 0xa086, 0x0000, - 0x00c0, 0x5870, 0x703f, 0x0001, 0x6807, 0x0006, 0x6833, 0x0003, - 0x2069, 0x0100, 0x6830, 0x689e, 0x2069, 0x0140, 0x6803, 0x0600, - 0x0d7f, 0x0078, 0x5876, 0x127e, 0x2091, 0x8000, 0x7024, 0xa00d, - 0x0040, 0x588e, 0x7020, 0x8001, 0x7022, 0x00c0, 0x588e, 0x7023, - 0x0009, 0x8109, 0x7126, 0xa186, 0x03e8, 0x00c0, 0x5889, 0x7028, - 0x107a, 0x81ff, 0x00c0, 0x588e, 0x7028, 0x107a, 0x7030, 0xa00d, - 0x0040, 0x589f, 0x702c, 0x8001, 0x702e, 0x00c0, 0x589f, 0x702f, - 0x0009, 0x8109, 0x7132, 0x00c0, 0x589f, 0x7034, 0x107a, 0x7040, - 0xa005, 0x0040, 0x58a7, 0x0050, 0x58a7, 0x8001, 0x7042, 0x7044, - 0xa005, 0x0040, 0x58af, 0x0050, 0x58af, 0x8001, 0x7046, 0x7018, - 0xa00d, 0x0040, 0x58c0, 0x7008, 0x8001, 0x700a, 0x00c0, 0x58c0, - 0x700b, 0x0009, 0x8109, 0x711a, 0x00c0, 0x58c0, 0x701c, 0x107a, - 0x127f, 0x7004, 0x0079, 0x58c4, 0x58eb, 0x58ec, 0x5908, 0x0e7e, - 0x2071, 0xa5be, 0x7018, 0xa005, 0x00c0, 0x58d2, 0x711a, 0x721e, - 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0e7e, 0x007e, 0x2071, 0xa5be, - 0x701c, 0xa206, 0x00c0, 0x58de, 0x701a, 0x701e, 0x007f, 0x0e7f, - 0x007c, 0x0e7e, 0x2071, 0xa5be, 0x6088, 0xa102, 0x0048, 0x58e9, - 0x618a, 0x0e7f, 0x007c, 0x007c, 0x7110, 0x1078, 0x4501, 0x00c0, - 0x58fe, 0x6088, 0x8001, 0x0048, 0x58fe, 0x608a, 0x00c0, 0x58fe, - 0x127e, 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x8108, 0xa182, - 0x00ff, 0x0048, 0x5906, 0xa00e, 0x7007, 0x0002, 0x7112, 0x007c, - 0x7014, 0x2060, 0x127e, 0x2091, 0x8000, 0x603c, 0xa005, 0x0040, - 0x5917, 0x8001, 0x603e, 0x00c0, 0x5917, 0x1078, 0x8cd7, 0x6014, - 0xa005, 0x0040, 0x5941, 0x8001, 0x6016, 0x00c0, 0x5941, 0x611c, - 0xa186, 0x0003, 0x0040, 0x5928, 0xa186, 0x0006, 0x00c0, 0x593f, - 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0048, 0x593f, 0xa082, - 0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, 0x5938, 0x2001, 0x1999, - 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0078, 0x5941, 0x1078, - 0x8810, 0x127f, 0xac88, 0x0010, 0x7116, 0x2001, 0xca00, 0xa102, - 0x0048, 0x594e, 0x7017, 0xaa00, 0x7007, 0x0000, 0x007c, 0x0e7e, - 0x2071, 0xa5be, 0x7027, 0x07d0, 0x7023, 0x0009, 0x703b, 0x0002, - 0x0e7f, 0x007c, 0x2001, 0xa5c7, 0x2003, 0x0000, 0x007c, 0x0e7e, - 0x2071, 0xa5be, 0x7132, 0x702f, 0x0009, 0x0e7f, 0x007c, 0x2011, - 0xa5ca, 0x2013, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa5be, 0x711a, - 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x027e, 0x0e7e, 0x0f7e, - 0x2079, 0xa300, 0x7a34, 0xd294, 0x0040, 0x59a4, 0x2071, 0xa5aa, - 0x2e14, 0xa0fe, 0x0000, 0x0040, 0x5991, 0xa0fe, 0x0001, 0x0040, - 0x5995, 0xa0fe, 0x0002, 0x00c0, 0x59a0, 0xa292, 0x0085, 0x0078, - 0x5997, 0xa292, 0x0005, 0x0078, 0x5997, 0xa292, 0x0002, 0x2272, - 0x0040, 0x599c, 0x00c8, 0x59a4, 0x2011, 0x8037, 0x1078, 0x3579, - 0x2011, 0xa5a9, 0x2204, 0x2072, 0x0f7f, 0x0e7f, 0x027f, 0x007c, - 0x0c7e, 0x2061, 0xa62d, 0x0c7f, 0x007c, 0xa184, 0x000f, 0x8003, - 0x8003, 0x8003, 0xa080, 0xa62d, 0x2060, 0x007c, 0x6854, 0xa08a, - 0x199a, 0x0048, 0x59bd, 0x2001, 0x1999, 0xa005, 0x00c0, 0x59cc, - 0x0c7e, 0x2061, 0xa62d, 0x6014, 0x0c7f, 0xa005, 0x00c0, 0x59d1, - 0x2001, 0x001e, 0x0078, 0x59d1, 0xa08e, 0xffff, 0x00c0, 0x59d1, - 0xa006, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c, - 0x00c0, 0xa18e, 0x00c0, 0x0040, 0x5a24, 0xd0b4, 0x00c0, 0x59e8, - 0xd0bc, 0x00c0, 0x5a14, 0x2009, 0x0006, 0x1078, 0x5a43, 0x007c, - 0xd0fc, 0x0040, 0x59f3, 0xa084, 0x0003, 0x0040, 0x59f3, 0xa086, - 0x0003, 0x00c0, 0x5a3c, 0x6024, 0xd0d4, 0x0040, 0x59fd, 0xc0d4, - 0x6026, 0x6860, 0x602a, 0x685c, 0x602e, 0x2009, 0xa373, 0x2104, - 0xd084, 0x0040, 0x5a0f, 0x6118, 0xa188, 0x0027, 0x2104, 0xd08c, - 0x00c0, 0x5a0f, 0x2009, 0x0042, 0x1078, 0x756c, 0x007c, 0x2009, - 0x0043, 0x1078, 0x756c, 0x007c, 0xd0fc, 0x0040, 0x5a1f, 0xa084, - 0x0003, 0x0040, 0x5a1f, 0xa086, 0x0003, 0x00c0, 0x5a3c, 0x2009, - 0x0042, 0x1078, 0x756c, 0x007c, 0xd0fc, 0x0040, 0x5a32, 0xa084, - 0x0003, 0xa08e, 0x0002, 0x0040, 0x5a36, 0x2009, 0x0041, 0x1078, - 0x756c, 0x007c, 0x1078, 0x5a41, 0x0078, 0x5a31, 0x2009, 0x0043, - 0x1078, 0x756c, 0x0078, 0x5a31, 0x2009, 0x0004, 0x1078, 0x5a43, - 0x007c, 0x2009, 0x0001, 0x0d7e, 0x6010, 0xa0ec, 0xf000, 0x0040, - 0x5a6b, 0x2068, 0x6952, 0x6800, 0x6012, 0xa186, 0x0001, 0x00c0, - 0x5a65, 0x694c, 0xa18c, 0x8100, 0xa18e, 0x8100, 0x00c0, 0x5a65, - 0x0c7e, 0x2061, 0xa62d, 0x6200, 0xd28c, 0x00c0, 0x5a64, 0x6204, - 0x8210, 0x0048, 0x5a64, 0x6206, 0x0c7f, 0x1078, 0x4982, 0x6010, - 0xa06d, 0x10c0, 0x59b6, 0x0d7f, 0x007c, 0x157e, 0x0c7e, 0x2061, - 0xa62d, 0x6000, 0x81ff, 0x0040, 0x5a78, 0xa205, 0x0078, 0x5a79, - 0xa204, 0x6002, 0x0c7f, 0x157f, 0x007c, 0x6800, 0xd08c, 0x00c0, - 0x5a89, 0x6808, 0xa005, 0x0040, 0x5a89, 0x8001, 0x680a, 0xa085, - 0x0001, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, - 0x00c8, 0x5a93, 0xa200, 0x00f0, 0x5a8e, 0x8086, 0x818e, 0x007c, - 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x5ab9, 0xa11a, 0x00c8, - 0x5ab9, 0x8213, 0x818d, 0x0048, 0x5aac, 0xa11a, 0x00c8, 0x5aad, - 0x00f0, 0x5aa1, 0x0078, 0x5ab1, 0xa11a, 0x2308, 0x8210, 0x00f0, - 0x5aa1, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, - 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x5ab5, 0x127e, - 0x2091, 0x2200, 0x2079, 0xa5ab, 0x127f, 0x0d7e, 0x2069, 0xa5ab, - 0x6803, 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, 0x8001, 0x206a, - 0x0d7f, 0x007c, 0x0c7e, 0x6027, 0x0001, 0x7804, 0xa084, 0x0007, - 0x0079, 0x5ada, 0x5ae4, 0x5b09, 0x5b64, 0x5aea, 0x5b09, 0x5ae4, - 0x5ae2, 0x5ae2, 0x1078, 0x1328, 0x1078, 0x595a, 0x1078, 0x6109, - 0x0c7f, 0x007c, 0x62c0, 0x82ff, 0x00c0, 0x5af0, 0x0c7f, 0x007c, - 0x2011, 0x4129, 0x1078, 0x58d4, 0x7828, 0xa092, 0x00c8, 0x00c8, - 0x5aff, 0x8000, 0x782a, 0x1078, 0x4168, 0x0078, 0x5aee, 0x1078, - 0x4129, 0x7807, 0x0003, 0x7827, 0x0000, 0x782b, 0x0000, 0x0078, - 0x5aee, 0x1078, 0x595a, 0x3c00, 0x007e, 0x2011, 0x0209, 0x20e1, - 0x4000, 0x2214, 0x007f, 0x20e0, 0x82ff, 0x0040, 0x5b27, 0x62c0, - 0x82ff, 0x00c0, 0x5b27, 0x782b, 0x0000, 0x7824, 0xa065, 0x1040, - 0x1328, 0x2009, 0x0013, 0x1078, 0x756c, 0x0c7f, 0x007c, 0x3900, - 0xa082, 0xa6cd, 0x00c8, 0x5b2e, 0x1078, 0x728a, 0x0c7e, 0x7824, - 0xa065, 0x1040, 0x1328, 0x7804, 0xa086, 0x0004, 0x0040, 0x5ba9, - 0x7828, 0xa092, 0x2710, 0x00c8, 0x5b44, 0x8000, 0x782a, 0x0c7f, - 0x1078, 0x6c33, 0x0078, 0x5b25, 0x6104, 0xa186, 0x0003, 0x00c0, - 0x5b5b, 0x0e7e, 0x2071, 0xa300, 0x70d4, 0x0e7f, 0xd08c, 0x0040, - 0x5b5b, 0x0c7e, 0x0e7e, 0x2061, 0x0100, 0x2071, 0xa300, 0x1078, - 0x4171, 0x0e7f, 0x0c7f, 0x1078, 0xa241, 0x2009, 0x0014, 0x1078, - 0x756c, 0x0c7f, 0x0078, 0x5b25, 0x2001, 0xa5c7, 0x2003, 0x0000, - 0x62c0, 0x82ff, 0x00c0, 0x5b78, 0x782b, 0x0000, 0x7824, 0xa065, - 0x1040, 0x1328, 0x2009, 0x0013, 0x1078, 0x75c3, 0x0c7f, 0x007c, - 0x0c7e, 0x0d7e, 0x3900, 0xa082, 0xa6cd, 0x00c8, 0x5b81, 0x1078, - 0x728a, 0x7824, 0xa005, 0x1040, 0x1328, 0x781c, 0xa06d, 0x1040, - 0x1328, 0x6800, 0xc0dc, 0x6802, 0x7924, 0x2160, 0x1078, 0x753d, - 0x693c, 0x81ff, 0x1040, 0x1328, 0x8109, 0x693e, 0x6854, 0xa015, - 0x0040, 0x5b9d, 0x7a1e, 0x0078, 0x5b9f, 0x7918, 0x791e, 0x7807, - 0x0000, 0x7827, 0x0000, 0x0d7f, 0x0c7f, 0x1078, 0x6109, 0x0078, - 0x5b76, 0x6104, 0xa186, 0x0002, 0x0040, 0x5bb4, 0xa186, 0x0004, - 0x0040, 0x5bb4, 0x0078, 0x5b38, 0x7808, 0xac06, 0x0040, 0x5b38, - 0x1078, 0x6010, 0x1078, 0x5c45, 0x0c7f, 0x1078, 0x6109, 0x0078, - 0x5b25, 0x0c7e, 0x6027, 0x0002, 0x62c8, 0x82ff, 0x00c0, 0x5bdb, - 0x62c4, 0x82ff, 0x00c0, 0x5bdb, 0x793c, 0xa1e5, 0x0000, 0x0040, - 0x5bd5, 0x2009, 0x0049, 0x1078, 0x756c, 0x2011, 0xa5ca, 0x2013, - 0x0000, 0x0c7f, 0x007c, 0x3908, 0xa192, 0xa6cd, 0x00c8, 0x5be2, - 0x1078, 0x728a, 0x6017, 0x0010, 0x793c, 0x81ff, 0x0040, 0x5bd5, - 0x793c, 0xa188, 0x0007, 0x210c, 0xa18e, 0x0006, 0x00c0, 0x5bf4, - 0x6017, 0x0012, 0x0078, 0x5bd9, 0x6017, 0x0016, 0x0078, 0x5bd9, - 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, - 0x2c08, 0x2061, 0xa5ab, 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, - 0x0040, 0x5c13, 0xa080, 0x0003, 0x2102, 0x6112, 0x127f, 0x0c7f, - 0x017f, 0x007f, 0x007c, 0x6116, 0x6112, 0x0078, 0x5c0e, 0x0d7e, - 0x2069, 0xa5ab, 0x6000, 0xd0d4, 0x0040, 0x5c2c, 0x6820, 0x8000, - 0x6822, 0xa086, 0x0001, 0x00c0, 0x5c27, 0x2c00, 0x681e, 0x6804, - 0xa084, 0x0007, 0x0079, 0x6111, 0xc0d5, 0x6002, 0x6818, 0xa005, - 0x0040, 0x5c3e, 0x6056, 0x605b, 0x0000, 0x007e, 0x2c00, 0x681a, - 0x0d7f, 0x685a, 0x2069, 0xa5ab, 0x0078, 0x5c1e, 0x6056, 0x605a, - 0x2c00, 0x681a, 0x681e, 0x0078, 0x5c1e, 0x007e, 0x017e, 0x0c7e, - 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0xa5ab, - 0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0040, 0x5c60, 0xa080, - 0x0003, 0x2102, 0x610a, 0x127f, 0x0c7f, 0x017f, 0x007f, 0x007c, - 0x610e, 0x610a, 0x0078, 0x5c5b, 0x0c7e, 0x600f, 0x0000, 0x2c08, - 0x2061, 0xa5ab, 0x6034, 0xa005, 0x0040, 0x5c74, 0xa080, 0x0003, - 0x2102, 0x6136, 0x0c7f, 0x007c, 0x613a, 0x6136, 0x0078, 0x5c72, - 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x027e, 0x017e, 0x007e, - 0x127e, 0x2071, 0xa5ab, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, - 0x8cff, 0x0040, 0x5ced, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, - 0x00c0, 0x5ce8, 0x87ff, 0x0040, 0x5c99, 0x6020, 0xa106, 0x00c0, - 0x5ce8, 0x703c, 0xac06, 0x00c0, 0x5cab, 0x037e, 0x2019, 0x0001, - 0x1078, 0x6e6c, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, - 0x7047, 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x5cb1, 0x660c, - 0x763a, 0x7034, 0xac36, 0x00c0, 0x5cbf, 0x2c00, 0xaf36, 0x0040, - 0x5cbd, 0x2f00, 0x7036, 0x0078, 0x5cbf, 0x7037, 0x0000, 0x660c, - 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5cc8, 0x7e0e, 0x0078, 0x5cc9, - 0x2678, 0x600f, 0x0000, 0x1078, 0x8a44, 0x0040, 0x5ce3, 0x6010, - 0x2068, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5cf7, 0x6837, 0x0103, - 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8cb8, 0x1078, 0xa181, 0x1078, - 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x0c7f, 0x0078, 0x5c88, - 0x2c78, 0x600c, 0x2060, 0x0078, 0x5c88, 0x127f, 0x007f, 0x017f, - 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, - 0xa086, 0x0006, 0x00c0, 0x5cd6, 0x1078, 0xa181, 0x1078, 0x9e70, - 0x0078, 0x5ce3, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x0f7e, 0x2031, - 0x0000, 0x127e, 0x2091, 0x8000, 0x2079, 0xa5ab, 0x7838, 0xa065, - 0x0040, 0x5d41, 0x600c, 0x007e, 0x600f, 0x0000, 0x783c, 0xac06, - 0x00c0, 0x5d28, 0x037e, 0x2019, 0x0001, 0x1078, 0x6e6c, 0x7833, - 0x0000, 0x783f, 0x0000, 0x7843, 0x0000, 0x7847, 0x0000, 0x037f, - 0x1078, 0x8a44, 0x0040, 0x5d3c, 0x6010, 0x2068, 0x601c, 0xa086, - 0x0003, 0x00c0, 0x5d4a, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, - 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x007f, 0x0078, - 0x5d0f, 0x7e3a, 0x7e36, 0x127f, 0x0f7f, 0x0d7f, 0x0c7f, 0x067f, - 0x007f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5d33, 0x1078, - 0x9e70, 0x0078, 0x5d3c, 0x017e, 0x027e, 0x087e, 0x2041, 0x0000, - 0x1078, 0x5d6d, 0x1078, 0x5e21, 0x087f, 0x027f, 0x017f, 0x007c, - 0x0f7e, 0x127e, 0x2079, 0xa5ab, 0x2091, 0x8000, 0x1078, 0x5ebc, - 0x1078, 0x5f32, 0x127f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, - 0x0c7e, 0x067e, 0x017e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, - 0xa5ab, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5e01, 0x6018, - 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x5dfc, 0x88ff, 0x0040, - 0x5d8d, 0x6020, 0xa106, 0x00c0, 0x5dfc, 0x7024, 0xac06, 0x00c0, - 0x5dbd, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x5db8, 0x1078, - 0x595a, 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, 0x7188, 0x7027, - 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, - 0x5dad, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, - 0xd084, 0x0040, 0x5db5, 0x6827, 0x0001, 0x037f, 0x0078, 0x5dbd, - 0x6003, 0x0009, 0x630a, 0x0078, 0x5dfc, 0x7014, 0xac36, 0x00c0, - 0x5dc3, 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x5dd1, 0x2c00, - 0xaf36, 0x0040, 0x5dcf, 0x2f00, 0x7012, 0x0078, 0x5dd1, 0x7013, - 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5dda, 0x7e0e, - 0x0078, 0x5ddb, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, - 0x8a44, 0x0040, 0x5df5, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5e0a, - 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8cb8, 0x1078, - 0xa181, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x1078, - 0x7045, 0x0c7f, 0x0078, 0x5d7c, 0x2c78, 0x600c, 0x2060, 0x0078, - 0x5d7c, 0x127f, 0x007f, 0x017f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, - 0x0f7f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5e15, 0x1078, - 0xa181, 0x1078, 0x9e70, 0x0078, 0x5df5, 0x601c, 0xa086, 0x0002, - 0x00c0, 0x5df5, 0x6004, 0xa086, 0x0085, 0x0040, 0x5de8, 0x0078, - 0x5df5, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0xa280, 0xa434, - 0x2004, 0xa065, 0x0040, 0x5eb8, 0x0f7e, 0x0e7e, 0x0d7e, 0x067e, - 0x2071, 0xa5ab, 0x6654, 0x7018, 0xac06, 0x00c0, 0x5e38, 0x761a, - 0x701c, 0xac06, 0x00c0, 0x5e44, 0x86ff, 0x00c0, 0x5e43, 0x7018, - 0x701e, 0x0078, 0x5e44, 0x761e, 0x6058, 0xa07d, 0x0040, 0x5e49, - 0x7e56, 0xa6ed, 0x0000, 0x0040, 0x5e4f, 0x2f00, 0x685a, 0x6057, - 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, - 0x4410, 0x0040, 0x5eb4, 0x7624, 0x86ff, 0x0040, 0x5ea2, 0xa680, - 0x0004, 0x2004, 0xad06, 0x00c0, 0x5ea2, 0x0d7e, 0x2069, 0x0100, - 0x68c0, 0xa005, 0x0040, 0x5e99, 0x1078, 0x595a, 0x1078, 0x6c41, - 0x68c3, 0x0000, 0x1078, 0x7188, 0x7027, 0x0000, 0x037e, 0x2069, - 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x5e82, 0x6803, 0x0100, - 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5e8a, - 0x6827, 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, - 0x5e93, 0x8001, 0x603e, 0x2660, 0x1078, 0x8c01, 0x0c7f, 0x0078, - 0x5ea2, 0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, - 0x0078, 0x5e57, 0x8dff, 0x0040, 0x5eb0, 0x6837, 0x0103, 0x6b4a, - 0x6847, 0x0000, 0x1078, 0x8cb8, 0x1078, 0xa181, 0x1078, 0x4982, - 0x1078, 0x7045, 0x0078, 0x5e57, 0x067f, 0x0d7f, 0x0e7f, 0x0f7f, - 0x127f, 0x007f, 0x0c7f, 0x007c, 0x007e, 0x067e, 0x0c7e, 0x0d7e, - 0x2031, 0x0000, 0x7814, 0xa065, 0x0040, 0x5f16, 0x600c, 0x007e, - 0x600f, 0x0000, 0x7824, 0xac06, 0x00c0, 0x5efb, 0x2069, 0x0100, - 0x68c0, 0xa005, 0x0040, 0x5ef5, 0x1078, 0x595a, 0x1078, 0x6c41, - 0x68c3, 0x0000, 0x1078, 0x7188, 0x7827, 0x0000, 0x037e, 0x2069, - 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x5eea, 0x6803, 0x0100, - 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5ef2, - 0x6827, 0x0001, 0x037f, 0x0078, 0x5efb, 0x6003, 0x0009, 0x630a, - 0x2c30, 0x0078, 0x5f13, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, - 0x5f0f, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5f1d, 0x6837, 0x0103, - 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, - 0x8c01, 0x1078, 0x7045, 0x007f, 0x0078, 0x5ec3, 0x7e16, 0x7e12, - 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x601c, 0xa086, 0x0006, - 0x00c0, 0x5f26, 0x1078, 0x9e70, 0x0078, 0x5f0f, 0x601c, 0xa086, - 0x0002, 0x00c0, 0x5f0f, 0x6004, 0xa086, 0x0085, 0x0040, 0x5f06, - 0x0078, 0x5f0f, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x7818, 0xa065, - 0x0040, 0x5fa0, 0x6054, 0x007e, 0x6057, 0x0000, 0x605b, 0x0000, - 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x4410, 0x0040, 0x5f9d, - 0x7e24, 0x86ff, 0x0040, 0x5f8f, 0xa680, 0x0004, 0x2004, 0xad06, - 0x00c0, 0x5f8f, 0x0d7e, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, - 0x5f86, 0x1078, 0x595a, 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, - 0x7188, 0x7827, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, - 0x1000, 0x0040, 0x5f6f, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, - 0x0100, 0x6824, 0xd084, 0x0040, 0x5f77, 0x6827, 0x0001, 0x037f, - 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, 0x5f80, 0x8001, 0x603e, - 0x2660, 0x1078, 0x8c01, 0x0c7f, 0x0078, 0x5f8f, 0x0d7f, 0x0c7e, - 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x5f44, 0x8dff, - 0x0040, 0x5f99, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, - 0x4982, 0x1078, 0x7045, 0x0078, 0x5f44, 0x007f, 0x0078, 0x5f37, - 0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x0e7e, - 0x0d7e, 0x067e, 0x6000, 0xd0dc, 0x0040, 0x5fc4, 0x604c, 0xa06d, - 0x0040, 0x5fc4, 0x6848, 0xa606, 0x00c0, 0x5fc4, 0x2071, 0xa5ab, - 0x7024, 0xa035, 0x0040, 0x5fc4, 0xa080, 0x0004, 0x2004, 0xad06, - 0x00c0, 0x5fc4, 0x1078, 0x5fc8, 0x067f, 0x0d7f, 0x0e7f, 0x007c, - 0x0f7e, 0x2079, 0x0100, 0x78c0, 0xa005, 0x00c0, 0x5fd7, 0x0c7e, - 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x600e, 0x1078, - 0x6c41, 0x78c3, 0x0000, 0x1078, 0x7188, 0x7027, 0x0000, 0x037e, - 0x2079, 0x0140, 0x7b04, 0xa384, 0x1000, 0x0040, 0x5feb, 0x7803, - 0x0100, 0x7803, 0x0000, 0x2079, 0x0100, 0x7824, 0xd084, 0x0040, - 0x5ff3, 0x7827, 0x0001, 0x1078, 0x7188, 0x037f, 0x1078, 0x4410, - 0x0c7e, 0x603c, 0xa005, 0x0040, 0x5fff, 0x8001, 0x603e, 0x2660, - 0x1078, 0x753d, 0x0c7f, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, - 0x1078, 0x8cb8, 0x1078, 0x4982, 0x1078, 0x7045, 0x0f7f, 0x007c, - 0x0e7e, 0x0c7e, 0x2071, 0xa5ab, 0x7004, 0xa084, 0x0007, 0x0079, - 0x6019, 0x6023, 0x6026, 0x603f, 0x605b, 0x60a0, 0x6023, 0x6023, - 0x6021, 0x1078, 0x1328, 0x0c7f, 0x0e7f, 0x007c, 0x7024, 0xa065, - 0x0040, 0x6034, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, 0x0040, - 0x603b, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, - 0x0c7f, 0x0e7f, 0x007c, 0x7216, 0x7212, 0x0078, 0x6034, 0x6018, - 0x2060, 0x1078, 0x4410, 0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001, - 0x7022, 0x0040, 0x6050, 0x6054, 0xa015, 0x0040, 0x6057, 0x721e, - 0x7007, 0x0000, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7218, - 0x721e, 0x0078, 0x6050, 0x7024, 0xa065, 0x0040, 0x609d, 0x700c, - 0xac06, 0x00c0, 0x6072, 0x1078, 0x7045, 0x600c, 0xa015, 0x0040, - 0x606e, 0x720e, 0x600f, 0x0000, 0x0078, 0x609b, 0x720e, 0x720a, - 0x0078, 0x609b, 0x7014, 0xac06, 0x00c0, 0x6085, 0x1078, 0x7045, - 0x600c, 0xa015, 0x0040, 0x6081, 0x7216, 0x600f, 0x0000, 0x0078, - 0x609b, 0x7216, 0x7212, 0x0078, 0x609b, 0x6018, 0x2060, 0x1078, - 0x4410, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x7045, 0x701c, 0xa065, - 0x0040, 0x609b, 0x6054, 0xa015, 0x0040, 0x6099, 0x721e, 0x0078, - 0x609b, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, - 0x7024, 0xa065, 0x0040, 0x60ad, 0x1078, 0x7045, 0x600c, 0xa015, - 0x0040, 0x60b4, 0x720e, 0x600f, 0x0000, 0x1078, 0x7188, 0x7027, - 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x720e, 0x720a, 0x0078, 0x60ad, - 0x0d7e, 0x2069, 0xa5ab, 0x6830, 0xa084, 0x0003, 0x0079, 0x60c0, - 0x60c6, 0x60c8, 0x60ee, 0x60c6, 0x1078, 0x1328, 0x0d7f, 0x007c, - 0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x60e4, 0x683c, 0xa065, - 0x0040, 0x60d9, 0x600c, 0xa015, 0x0040, 0x60e0, 0x6a3a, 0x600f, - 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c7f, 0x0d7f, 0x007c, - 0x683a, 0x6836, 0x0078, 0x60d9, 0x6843, 0x0000, 0x6838, 0xa065, - 0x0040, 0x60d9, 0x6003, 0x0003, 0x0078, 0x60d9, 0x0c7e, 0x6843, - 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0040, 0x6106, 0x600c, - 0xa015, 0x0040, 0x6102, 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000, - 0x0078, 0x6106, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, 0x0d7f, - 0x007c, 0x0d7e, 0x2069, 0xa5ab, 0x6804, 0xa084, 0x0007, 0x0079, - 0x6111, 0x611b, 0x61c2, 0x61c2, 0x61c2, 0x61c2, 0x61c4, 0x61c2, - 0x6119, 0x1078, 0x1328, 0x6820, 0xa005, 0x00c0, 0x6121, 0x0d7f, - 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x6130, 0x6807, 0x0004, - 0x6826, 0x682b, 0x0000, 0x1078, 0x620a, 0x0c7f, 0x0d7f, 0x007c, - 0x6814, 0xa065, 0x0040, 0x613e, 0x6807, 0x0001, 0x6826, 0x682b, - 0x0000, 0x1078, 0x620a, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, 0x037e, - 0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x61bd, 0x704c, 0xa00d, 0x0040, - 0x614d, 0x7088, 0xa005, 0x0040, 0x6165, 0x7054, 0xa075, 0x0040, - 0x6156, 0xa20e, 0x0040, 0x61bd, 0x0078, 0x615b, 0x6818, 0xa20e, - 0x0040, 0x61bd, 0x2070, 0x704c, 0xa00d, 0x0040, 0x614d, 0x7088, - 0xa005, 0x00c0, 0x614d, 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302, - 0x00c8, 0x614d, 0x1078, 0x750c, 0x0040, 0x61bd, 0x8318, 0x733e, - 0x6112, 0x2e10, 0x621a, 0xa180, 0x0014, 0x2004, 0xa084, 0x00ff, - 0x6032, 0xa180, 0x0014, 0x2003, 0x0000, 0xa180, 0x0015, 0x2004, - 0xa08a, 0x199a, 0x0048, 0x6186, 0x2001, 0x1999, 0x8003, 0x801b, - 0x831b, 0xa318, 0x6316, 0x037f, 0x0f7e, 0x2c78, 0x71a0, 0xd1bc, - 0x0040, 0x619f, 0x7100, 0xd1f4, 0x0040, 0x619b, 0x7114, 0xa18c, - 0x00ff, 0x0078, 0x61a4, 0x2009, 0x0000, 0x0078, 0x61a4, 0xa1e0, - 0x293f, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078, - 0x679b, 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26, - 0x682b, 0x0000, 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040, - 0x0f7f, 0x0e7f, 0x0c7f, 0x0d7f, 0x007c, 0x037f, 0x0e7f, 0x0c7f, - 0x0078, 0x61bb, 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, - 0x61d0, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x620a, - 0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0xa5ab, 0x6830, - 0xa086, 0x0000, 0x00c0, 0x61f1, 0x6838, 0xa07d, 0x0040, 0x61f1, - 0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x127e, 0x0f7e, 0x2091, - 0x2200, 0x027f, 0x1078, 0x1d28, 0x00c0, 0x61f4, 0x127f, 0x1078, - 0x6ae5, 0x0d7f, 0x0f7f, 0x007c, 0x127f, 0x6843, 0x0000, 0x7803, - 0x0002, 0x780c, 0xa015, 0x0040, 0x6206, 0x6a3a, 0x780f, 0x0000, - 0x6833, 0x0000, 0x683f, 0x0000, 0x0078, 0x61f1, 0x683a, 0x6836, - 0x0078, 0x6200, 0x601c, 0xa084, 0x000f, 0x1079, 0x6210, 0x007c, - 0x6219, 0x621e, 0x663f, 0x6758, 0x621e, 0x663f, 0x6758, 0x6219, - 0x621e, 0x1078, 0x6010, 0x1078, 0x6109, 0x007c, 0x157e, 0x137e, - 0x147e, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0044, 0x10c8, 0x1328, - 0x6118, 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x623b, 0x7900, 0xd1f4, - 0x0040, 0x6237, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x6240, 0x2009, - 0x0000, 0x0078, 0x6240, 0xa1f8, 0x293f, 0x2f0c, 0xa18c, 0x00ff, - 0x2c78, 0x2061, 0x0100, 0x619a, 0xa08a, 0x0040, 0x00c8, 0x6292, - 0x1079, 0x6250, 0x0f7f, 0x0c7f, 0x147f, 0x137f, 0x157f, 0x007c, - 0x62f8, 0x6340, 0x6368, 0x6403, 0x6433, 0x643b, 0x6462, 0x6473, - 0x6484, 0x648c, 0x64a4, 0x648c, 0x650f, 0x6473, 0x6530, 0x6538, - 0x6484, 0x6538, 0x6549, 0x6290, 0x6290, 0x6290, 0x6290, 0x6290, - 0x6290, 0x6290, 0x6290, 0x6290, 0x6290, 0x6290, 0x6d05, 0x6d2a, - 0x6d3f, 0x6d62, 0x6d83, 0x6462, 0x6290, 0x6462, 0x648c, 0x6290, - 0x6368, 0x6403, 0x6290, 0x72ac, 0x648c, 0x6290, 0x72cc, 0x648c, - 0x6290, 0x6290, 0x62f3, 0x62a1, 0x6290, 0x72f1, 0x7368, 0x7450, - 0x6290, 0x7461, 0x645c, 0x747d, 0x6290, 0x6d98, 0x6290, 0x6290, - 0x1078, 0x1328, 0x2100, 0x1079, 0x629b, 0x0f7f, 0x0c7f, 0x147f, - 0x137f, 0x157f, 0x007c, 0x629f, 0x629f, 0x629f, 0x62d5, 0x1078, - 0x1328, 0x0d7e, 0x20a1, 0x020b, 0x1078, 0x6567, 0x7810, 0x2068, - 0x20a3, 0x2414, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x683c, 0x20a2, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x6850, 0x20a2, 0x6854, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x0018, 0x1078, 0x6c2d, 0x0d7f, 0x007c, 0x0d7e, 0x7818, - 0x2068, 0x68a0, 0xa082, 0x007e, 0x0048, 0x62d2, 0xa085, 0x0001, - 0x0d7f, 0x007c, 0xa006, 0x0078, 0x62d0, 0x0d7e, 0x20a1, 0x020b, - 0x1078, 0x6567, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x7810, 0xa0e8, - 0x000f, 0x6808, 0x20a2, 0x680c, 0x20a2, 0x6810, 0x20a2, 0x6814, - 0x20a2, 0x6818, 0x20a2, 0x681c, 0x20a2, 0x60c3, 0x0010, 0x1078, - 0x6c2d, 0x0d7f, 0x007c, 0x6030, 0x609a, 0x1078, 0x6c2d, 0x007c, - 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, 0x5200, 0x20a3, 0x0000, - 0x0d7e, 0x2069, 0xa351, 0x6804, 0xd084, 0x0040, 0x6312, 0x6828, - 0x20a3, 0x0000, 0x017e, 0x1078, 0x24fa, 0x21a2, 0x017f, 0x0d7f, - 0x0078, 0x6317, 0x0d7f, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, - 0x0004, 0x2099, 0xa305, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xa301, - 0x53a6, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0048, - 0x6331, 0x2001, 0xa31a, 0x20a6, 0x2001, 0xa31b, 0x20a6, 0x0078, - 0x6337, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078, 0x6c2d, 0x007c, - 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, 0x0500, 0x20a3, 0x0000, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0048, 0x6358, - 0x2001, 0xa31a, 0x20a6, 0x2001, 0xa31b, 0x20a6, 0x0078, 0x635e, - 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a9, 0x0004, - 0x2099, 0xa305, 0x53a6, 0x60c3, 0x0010, 0x1078, 0x6c2d, 0x007c, - 0x20a1, 0x020b, 0x1078, 0x6567, 0x0c7e, 0x7818, 0x2060, 0x2001, - 0x0000, 0x1078, 0x48a2, 0x0c7f, 0x7818, 0xa080, 0x0028, 0x2004, - 0xa086, 0x007e, 0x00c0, 0x6383, 0x20a3, 0x0400, 0x620c, 0xc2b4, - 0x620e, 0x0078, 0x6385, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, - 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, 0x63d2, 0x2099, - 0xa58c, 0x33a6, 0x9398, 0x33a6, 0x9398, 0x3304, 0xa084, 0x3fff, - 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0xa305, 0x53a6, - 0x20a9, 0x0004, 0x2099, 0xa301, 0x53a6, 0x20a9, 0x0010, 0x20a3, - 0x0000, 0x00f0, 0x63af, 0x2099, 0xa594, 0x3304, 0xc0dd, 0x20a2, - 0x2001, 0xa371, 0x2004, 0xd0e4, 0x0040, 0x63ca, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x9398, 0x9398, 0x9398, 0x33a6, 0x20a9, 0x0004, - 0x0078, 0x63cc, 0x20a9, 0x0007, 0x20a3, 0x0000, 0x00f0, 0x63cc, - 0x0078, 0x63f2, 0x2099, 0xa58c, 0x20a9, 0x0008, 0x53a6, 0x20a9, - 0x0004, 0x2099, 0xa305, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xa301, - 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x63e3, 0x20a9, - 0x0008, 0x20a3, 0x0000, 0x00f0, 0x63e9, 0x2099, 0xa594, 0x20a9, - 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x63f4, - 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x63fa, 0x60c3, 0x0074, - 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, - 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006, - 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0xa351, - 0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x641f, 0xa085, 0x0020, 0xd1a4, - 0x0040, 0x6424, 0xa085, 0x0010, 0xa085, 0x0002, 0x0d7e, 0x0078, - 0x64ed, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, - 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, - 0x5000, 0x0078, 0x6385, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, - 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, - 0x0014, 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65ef, - 0x0078, 0x6466, 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0200, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, - 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, - 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, - 0x0008, 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65f8, - 0x20a3, 0x0200, 0x0078, 0x6385, 0x20a1, 0x020b, 0x1078, 0x65f8, - 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0xa005, 0x0040, 0x649b, - 0x20a2, 0x0078, 0x649d, 0x20a3, 0x0003, 0x7810, 0x20a2, 0x60c3, - 0x0008, 0x1078, 0x6c2d, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078, - 0x65f8, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x7818, - 0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x64ca, 0x6998, 0xa184, - 0xc000, 0x00c0, 0x64c6, 0xd1ec, 0x0040, 0x64c2, 0x20a3, 0x2100, - 0x0078, 0x64cc, 0x20a3, 0x0100, 0x0078, 0x64cc, 0x20a3, 0x0400, - 0x0078, 0x64cc, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, 0x20a2, - 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0xa351, 0x7904, 0x0f7f, 0xd1ac, - 0x00c0, 0x64dc, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x64e1, 0xa085, - 0x0010, 0x2009, 0xa373, 0x210c, 0xd184, 0x0040, 0x64eb, 0x699c, - 0xd18c, 0x0040, 0x64ed, 0xa085, 0x0002, 0x027e, 0x2009, 0xa371, - 0x210c, 0xd1e4, 0x0040, 0x64fb, 0xc0c5, 0xa094, 0x0030, 0xa296, - 0x0010, 0x0040, 0x6505, 0xd1ec, 0x0040, 0x6505, 0xa094, 0x0030, - 0xa296, 0x0010, 0x0040, 0x6505, 0xc0bd, 0x027f, 0x20a2, 0x20a2, - 0x20a2, 0x60c3, 0x0014, 0x1078, 0x6c2d, 0x0d7f, 0x007c, 0x20a1, - 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, - 0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x6c2d, 0x007c, - 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0200, 0x0078, 0x62fe, - 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0100, 0x20a3, 0x0000, - 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x1078, 0x6c2d, - 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x1078, - 0x65f8, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, - 0x0000, 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x007c, 0x027e, 0x037e, - 0x047e, 0x2019, 0x3200, 0x2021, 0x0800, 0x0078, 0x656e, 0x027e, - 0x037e, 0x047e, 0x2019, 0x2200, 0x2021, 0x0100, 0x20e1, 0x9080, - 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, - 0x00c0, 0x6581, 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffe, 0x0078, - 0x65b6, 0xa286, 0x007f, 0x00c0, 0x658d, 0x0d7e, 0xa385, 0x00ff, - 0x20a2, 0x20a3, 0xfffd, 0x0078, 0x65a4, 0xd2bc, 0x0040, 0x65ac, - 0xa286, 0x0080, 0x0d7e, 0x00c0, 0x659c, 0xa385, 0x00ff, 0x20a2, - 0x20a3, 0xfffc, 0x0078, 0x65a4, 0xa2e8, 0xa434, 0x2d6c, 0x6810, - 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, - 0x2da6, 0x0d7f, 0x0078, 0x65ba, 0x0d7e, 0xa2e8, 0xa434, 0x2d6c, - 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0xa485, 0x0029, 0x20a2, 0x047f, 0x037f, 0x20a3, - 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, - 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x027e, - 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, 0x2011, 0xfffc, - 0x22a2, 0x0d7e, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, - 0x20a3, 0x2029, 0x20a3, 0x0000, 0x0078, 0x65c1, 0x20a3, 0x0100, - 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000, 0x007c, 0x027e, - 0x037e, 0x047e, 0x2019, 0x3300, 0x2021, 0x0800, 0x0078, 0x65ff, - 0x027e, 0x037e, 0x047e, 0x2019, 0x2300, 0x2021, 0x0100, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, - 0x007e, 0x0048, 0x661c, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, - 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, - 0x2da6, 0x0d7f, 0x0078, 0x662a, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, - 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0xa485, 0x0098, 0x20a2, 0x20a3, 0x0000, 0x047f, - 0x037f, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, - 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0c7e, - 0x0f7e, 0x6004, 0xa08a, 0x0085, 0x1048, 0x1328, 0xa08a, 0x008c, - 0x10c8, 0x1328, 0x6118, 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x665d, - 0x7900, 0xd1f4, 0x0040, 0x6659, 0x7914, 0xa18c, 0x00ff, 0x0078, - 0x6662, 0x2009, 0x0000, 0x0078, 0x6662, 0xa1f8, 0x293f, 0x2f0c, - 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0xa082, 0x0085, - 0x1079, 0x666d, 0x0f7f, 0x0c7f, 0x007c, 0x6676, 0x6681, 0x669c, - 0x6674, 0x6674, 0x6674, 0x6676, 0x1078, 0x1328, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x66af, 0x60c3, 0x0000, 0x1078, 0x6c2d, 0x147f, - 0x007c, 0x147e, 0x20a1, 0x020b, 0x1078, 0x66e3, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, 0x20a2, 0x20a3, 0x0000, - 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c, - 0x1078, 0x6c2d, 0x147f, 0x007c, 0x147e, 0x20a1, 0x020b, 0x1078, - 0x6724, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x0004, 0x1078, 0x6c2d, 0x147f, 0x007c, 0x027e, - 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, - 0xa092, 0x007e, 0x0048, 0x66ce, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, - 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, - 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x66dd, 0x0d7e, 0xa0e8, - 0xa434, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, - 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0009, 0x20a3, - 0x0000, 0x0078, 0x65c1, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x6702, - 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, - 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, - 0x0078, 0x6711, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, - 0x8400, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, - 0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, - 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x7a10, 0x22a2, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x027f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, - 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, - 0x6743, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x8500, - 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, - 0x0d7f, 0x0078, 0x6752, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, - 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000, 0x0078, 0x6715, - 0x0c7e, 0x0f7e, 0x2c78, 0x7804, 0xa08a, 0x0040, 0x1048, 0x1328, - 0xa08a, 0x0053, 0x10c8, 0x1328, 0x7918, 0x2160, 0x61a0, 0xd1bc, - 0x0040, 0x6777, 0x6100, 0xd1f4, 0x0040, 0x6773, 0x6114, 0xa18c, - 0x00ff, 0x0078, 0x677c, 0x2009, 0x0000, 0x0078, 0x677c, 0xa1e0, - 0x293f, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0xa082, - 0x0040, 0x1079, 0x6786, 0x0f7f, 0x0c7f, 0x007c, 0x679b, 0x68a9, - 0x684a, 0x6a59, 0x6799, 0x6799, 0x6799, 0x6799, 0x6799, 0x6799, - 0x6799, 0x6f5e, 0x6f6f, 0x6f80, 0x6f91, 0x6799, 0x748e, 0x6799, - 0x6f4d, 0x1078, 0x1328, 0x0d7e, 0x157e, 0x147e, 0x780b, 0xffff, - 0x20a1, 0x020b, 0x1078, 0x6806, 0x7910, 0x2168, 0x6948, 0x7922, - 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, 0x000f, - 0x00c0, 0x67b6, 0x2001, 0x0005, 0x0078, 0x67c0, 0xd184, 0x0040, - 0x67bd, 0x2001, 0x0004, 0x0078, 0x67c0, 0xa084, 0x0006, 0x8004, - 0x017e, 0x2008, 0x7830, 0xa084, 0x00ff, 0x8007, 0xa105, 0x017f, - 0x20a2, 0xd1ac, 0x0040, 0x67d0, 0x20a3, 0x0002, 0x0078, 0x67dc, - 0xd1b4, 0x0040, 0x67d7, 0x20a3, 0x0001, 0x0078, 0x67dc, 0x20a3, - 0x0000, 0x2230, 0x0078, 0x67de, 0x6a80, 0x6e7c, 0x20a9, 0x0008, - 0xad80, 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000, 0x00f0, 0x67e2, - 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, 0x6014, 0xa084, - 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0xa5c7, 0x2003, 0x07d0, - 0x2001, 0xa5c6, 0x2003, 0x0009, 0x2001, 0xa5cc, 0x2003, 0x0002, - 0x1078, 0x157e, 0x147f, 0x157f, 0x0d7f, 0x007c, 0x20e1, 0x9080, - 0x20e1, 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, - 0x00ff, 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, - 0x0040, 0x682c, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, - 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, - 0x2da6, 0x0d7f, 0x0078, 0x683b, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, - 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, - 0x0000, 0x6130, 0x21a2, 0x20a3, 0x0829, 0x20a3, 0x0000, 0x22a2, - 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x20a1, 0x020b, - 0x1078, 0x686a, 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, - 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, - 0x20a2, 0x60c3, 0x000c, 0x1078, 0x6c2d, 0x147f, 0x137f, 0x157f, - 0x0d7f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, - 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6888, 0x0d7e, 0xa0e8, - 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, - 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6897, - 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, - 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, - 0x0889, 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, - 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, - 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x7810, 0xa06d, 0x1078, - 0x488f, 0x0040, 0x68bd, 0x684c, 0xa084, 0x2020, 0xa086, 0x2020, - 0x00c0, 0x68bd, 0x7824, 0xc0cd, 0x7826, 0x20a1, 0x020b, 0x1078, - 0x6a12, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810, - 0xa084, 0xf000, 0x00c0, 0x68d4, 0x7810, 0xa084, 0x0700, 0x8007, - 0x1079, 0x68dc, 0x0078, 0x68d7, 0xa006, 0x1079, 0x68dc, 0x147f, - 0x137f, 0x157f, 0x0d7f, 0x007c, 0x68e6, 0x697e, 0x6989, 0x69b3, - 0x69c7, 0x69e3, 0x69ee, 0x68e4, 0x1078, 0x1328, 0x017e, 0x037e, - 0x694c, 0xa18c, 0x0003, 0x0040, 0x68f1, 0xa186, 0x0003, 0x00c0, - 0x6900, 0x6b78, 0x7824, 0xd0cc, 0x0040, 0x68f7, 0xc3e5, 0x23a2, - 0x6868, 0x20a2, 0x6864, 0x20a2, 0x037f, 0x017f, 0x0078, 0x69be, - 0xa186, 0x0001, 0x10c0, 0x1328, 0x6b78, 0x7824, 0xd0cc, 0x0040, - 0x690a, 0xc3e5, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, - 0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, - 0x0300, 0x0040, 0x6978, 0xd3c4, 0x0040, 0x6920, 0x687c, 0xa108, - 0xd3cc, 0x0040, 0x6925, 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d, - 0xad80, 0x0020, 0x201c, 0x831f, 0x23a2, 0x8000, 0x00f0, 0x692a, - 0x157f, 0x22a2, 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0040, 0x6978, - 0x20a1, 0x020b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x007e, 0x7818, - 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6958, 0x0d7e, 0xa0e8, - 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, - 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6967, - 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, - 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x007f, - 0x7b24, 0xd3cc, 0x0040, 0x6970, 0x20a3, 0x0889, 0x0078, 0x6972, - 0x20a3, 0x0898, 0x20a2, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, - 0x61c2, 0x037f, 0x017f, 0x1078, 0x6c2d, 0x007c, 0x2011, 0x0008, - 0x7824, 0xd0cc, 0x0040, 0x6985, 0xc2e5, 0x22a2, 0xa016, 0x0078, - 0x69bc, 0x2011, 0x0302, 0x7824, 0xd0cc, 0x0040, 0x6990, 0xc2e5, - 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2, - 0x20a3, 0x0008, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000, - 0x20a3, 0x0500, 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3, - 0x2500, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032, - 0x1078, 0x6c2d, 0x007c, 0x2011, 0x0028, 0x7824, 0xd0cc, 0x0040, - 0x69ba, 0xc2e5, 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, - 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x1078, 0x6c2d, 0x007c, 0x2011, - 0x0100, 0x7824, 0xd0cc, 0x0040, 0x69ce, 0xc2e5, 0x22a2, 0xa016, - 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0008, 0x22a2, - 0x7834, 0xa084, 0x00ff, 0x20a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, - 0x1078, 0x6c2d, 0x007c, 0x2011, 0x0008, 0x7824, 0xd0cc, 0x0040, - 0x69ea, 0xc2e5, 0x22a2, 0xa016, 0x0078, 0x69bc, 0x037e, 0x7b10, - 0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x00c0, 0x6a01, - 0x7824, 0xd0cc, 0x0040, 0x69fd, 0xc2e5, 0x22a2, 0x037f, 0x0078, - 0x69bc, 0x047e, 0x2021, 0x0800, 0x007e, 0x7824, 0xd0cc, 0x007f, - 0x0040, 0x6a0b, 0xc4e5, 0x24a2, 0x047f, 0x22a2, 0x20a2, 0x037f, - 0x0078, 0x69be, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, - 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6a30, 0x0d7e, 0xa0e8, - 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, - 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6a3f, - 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, - 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x7824, - 0xd0cc, 0x0040, 0x6a47, 0x20a3, 0x0889, 0x0078, 0x6a49, 0x20a3, - 0x0898, 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, - 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, - 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x017e, 0x037e, 0x7810, - 0xa084, 0x0700, 0x8007, 0x1079, 0x6a6c, 0x037f, 0x017f, 0x147f, - 0x137f, 0x157f, 0x0d7f, 0x007c, 0x6a74, 0x6a74, 0x6a76, 0x6a74, - 0x6a74, 0x6a74, 0x6a9b, 0x6a74, 0x1078, 0x1328, 0x7910, 0xa18c, - 0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003, - 0x1078, 0x6aa5, 0x0d7e, 0x2069, 0xa351, 0x6804, 0xd0bc, 0x0040, - 0x6a90, 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, 0x6a92, - 0x20a3, 0x3f00, 0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, - 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, 0x1078, - 0x6aa5, 0x20a3, 0x7f00, 0x0078, 0x6a93, 0x027e, 0x20e1, 0x9080, - 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, - 0x6ac3, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0100, - 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, - 0x0d7f, 0x0078, 0x6ad2, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, - 0xa085, 0x0100, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, - 0x6230, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x1078, - 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, - 0x057e, 0x047e, 0x037e, 0x2061, 0x0100, 0x2071, 0xa300, 0x6130, - 0x7818, 0x2068, 0x68a0, 0x2028, 0xd0bc, 0x00c0, 0x6afc, 0x6910, - 0x6a14, 0x6430, 0x0078, 0x6b00, 0x6910, 0x6a14, 0x7368, 0x746c, - 0x781c, 0xa086, 0x0006, 0x0040, 0x6b5f, 0xd5bc, 0x0040, 0x6b10, - 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0078, 0x6b17, - 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x6073, - 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, - 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, - 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, - 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, - 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x6b49, 0x6a00, 0xd2f4, - 0x0040, 0x6b47, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6b49, 0x2011, - 0x0000, 0x629e, 0x6017, 0x0016, 0x2009, 0x07d0, 0x60c4, 0xa084, - 0xfff0, 0xa005, 0x0040, 0x6b56, 0x2009, 0x1b58, 0x1078, 0x595f, - 0x037f, 0x047f, 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7810, - 0x2070, 0x704c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, 0x6bb7, - 0xd5bc, 0x0040, 0x6b73, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, - 0x646e, 0x0078, 0x6b7a, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, - 0x0000, 0x646e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, - 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, - 0x6086, 0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, - 0x60c6, 0x707c, 0x60ca, 0x707c, 0x792c, 0xa108, 0x792e, 0x7080, - 0x7928, 0xa109, 0x792a, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, - 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x6bb2, 0x6a00, - 0xd2f4, 0x0040, 0x6bb0, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6bb2, - 0x2011, 0x0000, 0x629e, 0x6017, 0x0012, 0x0078, 0x6b4c, 0xd5bc, - 0x0040, 0x6bc2, 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, - 0x0078, 0x6bc9, 0xa185, 0x0700, 0x6062, 0x6266, 0x606b, 0x0000, - 0x646e, 0x1078, 0x488f, 0x0040, 0x6bdf, 0x0d7e, 0x7810, 0xa06d, - 0x684c, 0x0d7f, 0xa084, 0x2020, 0xa086, 0x2020, 0x00c0, 0x6bdf, - 0x7824, 0xc0cd, 0x7826, 0x6073, 0x0889, 0x0078, 0x6be1, 0x6073, - 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, - 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, - 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, - 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, - 0xa582, 0x0080, 0x0048, 0x6c0f, 0x6a00, 0xd2f4, 0x0040, 0x6c0d, - 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6c0f, 0x2011, 0x0000, 0x629e, - 0x7824, 0xd0cc, 0x0040, 0x6c18, 0x6017, 0x0016, 0x0078, 0x6b4c, - 0x6017, 0x0012, 0x0078, 0x6b4c, 0x7a18, 0xa280, 0x0023, 0x2014, - 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x007c, 0x0d7e, 0x2069, - 0xa5ab, 0x6843, 0x0001, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x60a3, - 0x0056, 0x60a7, 0x9575, 0x1078, 0x6c38, 0x1078, 0x594f, 0x007c, - 0x007e, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x007f, - 0x007c, 0x007e, 0x0c7e, 0x2061, 0x0100, 0x6014, 0xa084, 0x0004, - 0xa085, 0x0008, 0x6016, 0x0c7f, 0x007f, 0x007c, 0x0c7e, 0x0d7e, - 0x017e, 0x027e, 0x2061, 0x0100, 0x2069, 0x0140, 0x6904, 0xa194, - 0x4000, 0x0040, 0x6c89, 0x1078, 0x6c41, 0x6803, 0x1000, 0x6803, - 0x0000, 0x0c7e, 0x2061, 0xa5ab, 0x6128, 0xa192, 0x00c8, 0x00c8, - 0x6c76, 0x8108, 0x612a, 0x6124, 0x0c7f, 0x81ff, 0x0040, 0x6c84, - 0x1078, 0x594f, 0x1078, 0x6c38, 0x0078, 0x6c84, 0x6124, 0xa1e5, - 0x0000, 0x0040, 0x6c81, 0x1078, 0xa241, 0x2009, 0x0014, 0x1078, - 0x756c, 0x0c7f, 0x0078, 0x6c84, 0x027f, 0x017f, 0x0d7f, 0x0c7f, - 0x007c, 0x2001, 0xa5c7, 0x2004, 0xa005, 0x00c0, 0x6c84, 0x0c7e, - 0x2061, 0xa5ab, 0x6128, 0xa192, 0x0003, 0x00c8, 0x6c76, 0x8108, - 0x612a, 0x0c7f, 0x1078, 0x594f, 0x1078, 0x4171, 0x0078, 0x6c84, - 0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x027e, 0x1078, 0x5967, 0x2071, - 0xa5ab, 0x713c, 0x81ff, 0x0040, 0x6cca, 0x2061, 0x0100, 0x2069, - 0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x6cd0, 0x6803, 0x1000, - 0x6803, 0x0000, 0x037e, 0x2019, 0x0001, 0x1078, 0x6e6c, 0x037f, - 0x713c, 0x2160, 0x1078, 0xa241, 0x2009, 0x004a, 0x1078, 0x756c, - 0x0078, 0x6cca, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, - 0x0078, 0x6cba, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e, 0x047e, - 0x007e, 0x127e, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, 0x2071, - 0xa5ab, 0x7018, 0x2068, 0x8dff, 0x0040, 0x6cfc, 0x68a0, 0xa406, - 0x0040, 0x6cee, 0x6854, 0x2068, 0x0078, 0x6ce3, 0x6010, 0x2060, - 0x643c, 0x6540, 0x6e48, 0x2d60, 0x1078, 0x466a, 0x0040, 0x6cfc, - 0x1078, 0x7045, 0xa085, 0x0001, 0x127f, 0x007f, 0x047f, 0x057f, - 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x6567, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x781c, - 0xa086, 0x0004, 0x00c0, 0x6d17, 0x6098, 0x0078, 0x6d18, 0x6030, - 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9, 0x0010, 0xa006, - 0x20a2, 0x00f0, 0x6d20, 0x20a2, 0x20a2, 0x60c3, 0x002c, 0x1078, - 0x6c2d, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x6567, - 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, - 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x147f, 0x157f, 0x007c, 0x157e, - 0x147e, 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0200, 0x20a3, - 0x0000, 0x20a9, 0x0006, 0x2011, 0xa340, 0x2019, 0xa341, 0x23a6, - 0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x00f0, 0x6d4f, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078, 0x6c2d, 0x147f, - 0x157f, 0x007c, 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, - 0x1078, 0x65cf, 0x1078, 0x65e6, 0x7810, 0xa080, 0x0000, 0x2004, - 0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, - 0xa080, 0x0004, 0x8003, 0x60c2, 0x1078, 0x6c2d, 0x027f, 0x017f, - 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, - 0x6567, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, - 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x147f, 0x157f, 0x007c, - 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, 0x1078, 0x6567, - 0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017, 0x2098, 0x7808, - 0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x1078, 0x6c2d, - 0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x0e7e, 0x0c7e, 0x007e, - 0x127e, 0x2091, 0x8000, 0x2071, 0xa5ab, 0x700c, 0x2060, 0x8cff, - 0x0040, 0x6dd1, 0x1078, 0x8c3b, 0x00c0, 0x6dc8, 0x1078, 0x7a05, - 0x600c, 0x007e, 0x1078, 0x753d, 0x1078, 0x7045, 0x0c7f, 0x0078, - 0x6dbf, 0x700f, 0x0000, 0x700b, 0x0000, 0x127f, 0x007f, 0x0c7f, - 0x0e7f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, - 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, - 0x0140, 0x2071, 0xa5ab, 0x7024, 0x2060, 0x8cff, 0x0040, 0x6e2a, - 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, 0x595a, 0x2009, 0x0013, - 0x1078, 0x756c, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x6e0d, - 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x6e1f, 0x7803, - 0x1000, 0x7803, 0x0000, 0x0078, 0x6e1f, 0xd084, 0x0040, 0x6e14, - 0x6827, 0x0001, 0x0078, 0x6e16, 0x00f0, 0x6dfc, 0x7804, 0xa084, - 0x1000, 0x0040, 0x6e1f, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, - 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, - 0x127f, 0x007c, 0x2001, 0xa300, 0x2004, 0xa096, 0x0001, 0x0040, - 0x6e62, 0xa096, 0x0004, 0x0040, 0x6e62, 0x6817, 0x0008, 0x68c3, - 0x0000, 0x2011, 0x4129, 0x1078, 0x58d4, 0x20a9, 0x01f4, 0x6824, - 0xd094, 0x0040, 0x6e50, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, - 0x0040, 0x6e62, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0x6e62, - 0xd084, 0x0040, 0x6e57, 0x6827, 0x0001, 0x0078, 0x6e59, 0x00f0, - 0x6e3f, 0x7804, 0xa084, 0x1000, 0x0040, 0x6e62, 0x7803, 0x0100, - 0x7803, 0x0000, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, - 0x0f7f, 0x157f, 0x127f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, - 0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, - 0x0100, 0x2079, 0x0140, 0x2071, 0xa5ab, 0x703c, 0x2060, 0x8cff, - 0x0040, 0x6ee8, 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, 0x00c0, - 0x6e86, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x1078, 0x5967, 0x1078, - 0x1f31, 0x047e, 0x057e, 0x2009, 0x017f, 0x212c, 0x200b, 0x00a5, - 0x2021, 0x0169, 0x2404, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, - 0x6eb7, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x0e7e, 0x0f7e, 0x2079, - 0x0020, 0x2071, 0xa602, 0x6814, 0xa084, 0x0004, 0xa085, 0x0012, - 0x6816, 0x7803, 0x0008, 0x7003, 0x0000, 0x0f7f, 0x0e7f, 0x250a, - 0x057f, 0x047f, 0xa39d, 0x0000, 0x00c0, 0x6ec2, 0x2009, 0x0049, - 0x1078, 0x756c, 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x6ed5, - 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x6ee7, 0x7803, - 0x1000, 0x7803, 0x0000, 0x0078, 0x6ee7, 0xd08c, 0x0040, 0x6edc, - 0x6827, 0x0002, 0x0078, 0x6ede, 0x00f0, 0x6ec4, 0x7804, 0xa084, - 0x1000, 0x0040, 0x6ee7, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, - 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, - 0x127f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0xa5ab, - 0x6a06, 0x127f, 0x0d7f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, - 0x2069, 0xa5ab, 0x6a32, 0x127f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, - 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2071, 0xa5ab, 0x7614, 0x2660, - 0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x6f46, 0x601c, 0xa206, - 0x00c0, 0x6f41, 0x7014, 0xac36, 0x00c0, 0x6f20, 0x660c, 0x7616, - 0x7010, 0xac36, 0x00c0, 0x6f2e, 0x2c00, 0xaf36, 0x0040, 0x6f2c, - 0x2f00, 0x7012, 0x0078, 0x6f2e, 0x7013, 0x0000, 0x660c, 0x067e, - 0x2c00, 0xaf06, 0x0040, 0x6f37, 0x7e0e, 0x0078, 0x6f38, 0x2678, - 0x600f, 0x0000, 0x1078, 0x8c01, 0x1078, 0x7045, 0x0c7f, 0x0078, - 0x6f13, 0x2c78, 0x600c, 0x2060, 0x0078, 0x6f13, 0x127f, 0x007f, - 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x157e, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, - 0x20a2, 0x20a2, 0x20a3, 0x1000, 0x0078, 0x6fa0, 0x157e, 0x147e, - 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, 0xa006, 0x20a2, - 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x4000, 0x0078, 0x6fa0, 0x157e, - 0x147e, 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, 0xa006, - 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000, 0x0078, 0x6fa0, - 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, - 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, - 0x6fa0, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, - 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, - 0x1078, 0x7050, 0x60c3, 0x0020, 0x1078, 0x6c2d, 0x147f, 0x157f, - 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x2061, 0x0100, 0x6120, - 0xd1b4, 0x00c0, 0x6fb8, 0xd1bc, 0x00c0, 0x7002, 0x0078, 0x7042, - 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, - 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, - 0x0040, 0x6ff9, 0x6020, 0xd0b4, 0x0040, 0x6ff9, 0x6024, 0xd094, - 0x00c0, 0x6ff9, 0x2104, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, - 0x6ff9, 0x00f0, 0x6fc5, 0x027e, 0x6198, 0xa18c, 0x00ff, 0x8107, - 0x6130, 0xa18c, 0x00ff, 0xa10d, 0x6088, 0x628c, 0x618e, 0x608b, - 0xbc91, 0x6043, 0x0001, 0x6043, 0x0000, 0x608a, 0x628e, 0x6024, - 0xd094, 0x00c0, 0x6ff8, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x6fef, - 0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, - 0x0078, 0x7042, 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, - 0x0d7e, 0x2069, 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, - 0xa084, 0x4000, 0x0040, 0x703b, 0x6020, 0xd0bc, 0x0040, 0x703b, - 0x2104, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x703b, 0x00f0, - 0x700f, 0x027e, 0x6164, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, - 0x00ff, 0xa10d, 0x6088, 0x628c, 0x608b, 0xbc91, 0x618e, 0x6043, - 0x0001, 0x6043, 0x0000, 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, - 0x00c0, 0x7035, 0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, - 0x200b, 0x0000, 0x0c7f, 0x127f, 0x007c, 0x0e7e, 0x2071, 0xa5ab, - 0x7020, 0xa005, 0x0040, 0x704e, 0x8001, 0x7022, 0x0e7f, 0x007c, - 0x20a9, 0x0008, 0x20a2, 0x00f0, 0x7052, 0x20a2, 0x20a2, 0x007c, - 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x067e, 0x007e, 0x127e, - 0x2091, 0x8000, 0x2071, 0xa5ab, 0x7614, 0x2660, 0x2678, 0x2039, - 0x0001, 0x87ff, 0x0040, 0x70f4, 0x8cff, 0x0040, 0x70f4, 0x601c, - 0xa086, 0x0006, 0x00c0, 0x70ef, 0x88ff, 0x0040, 0x707f, 0x2800, - 0xac06, 0x00c0, 0x70ef, 0x2039, 0x0000, 0x0078, 0x708a, 0x6018, - 0xa206, 0x00c0, 0x70ef, 0x85ff, 0x0040, 0x708a, 0x6020, 0xa106, - 0x00c0, 0x70ef, 0x7024, 0xac06, 0x00c0, 0x70ba, 0x2069, 0x0100, - 0x68c0, 0xa005, 0x0040, 0x70b5, 0x1078, 0x595a, 0x6817, 0x0008, - 0x68c3, 0x0000, 0x1078, 0x7188, 0x7027, 0x0000, 0x037e, 0x2069, - 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x70aa, 0x6803, 0x0100, - 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x70b2, - 0x6827, 0x0001, 0x037f, 0x0078, 0x70ba, 0x6003, 0x0009, 0x630a, - 0x0078, 0x70ef, 0x7014, 0xac36, 0x00c0, 0x70c0, 0x660c, 0x7616, - 0x7010, 0xac36, 0x00c0, 0x70ce, 0x2c00, 0xaf36, 0x0040, 0x70cc, - 0x2f00, 0x7012, 0x0078, 0x70ce, 0x7013, 0x0000, 0x660c, 0x067e, - 0x2c00, 0xaf06, 0x0040, 0x70d7, 0x7e0e, 0x0078, 0x70d8, 0x2678, - 0x89ff, 0x00c0, 0x70e7, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, - 0x8a44, 0x0040, 0x70e5, 0x1078, 0x9e70, 0x1078, 0x8c01, 0x1078, - 0x7045, 0x88ff, 0x00c0, 0x70fe, 0x0c7f, 0x0078, 0x7069, 0x2c78, - 0x600c, 0x2060, 0x0078, 0x7069, 0xa006, 0x127f, 0x007f, 0x067f, - 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000, - 0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x70f5, 0x0f7e, 0x0e7e, 0x0d7e, - 0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, - 0xa5ab, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x7177, 0x601c, - 0xa086, 0x0006, 0x00c0, 0x7172, 0x87ff, 0x0040, 0x7125, 0x2700, - 0xac06, 0x00c0, 0x7172, 0x0078, 0x7130, 0x6018, 0xa206, 0x00c0, - 0x7172, 0x85ff, 0x0040, 0x7130, 0x6020, 0xa106, 0x00c0, 0x7172, - 0x703c, 0xac06, 0x00c0, 0x7142, 0x037e, 0x2019, 0x0001, 0x1078, - 0x6e6c, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, - 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x7148, 0x660c, 0x763a, - 0x7034, 0xac36, 0x00c0, 0x7156, 0x2c00, 0xaf36, 0x0040, 0x7154, - 0x2f00, 0x7036, 0x0078, 0x7156, 0x7037, 0x0000, 0x660c, 0x067e, - 0x2c00, 0xaf06, 0x0040, 0x715f, 0x7e0e, 0x0078, 0x7160, 0x2678, - 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x716a, - 0x1078, 0x9e70, 0x1078, 0x8c01, 0x87ff, 0x00c0, 0x7181, 0x0c7f, - 0x0078, 0x7114, 0x2c78, 0x600c, 0x2060, 0x0078, 0x7114, 0xa006, - 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, - 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa7bd, 0x0001, 0x0078, 0x7178, - 0x0e7e, 0x2071, 0xa5ab, 0x2001, 0xa300, 0x2004, 0xa086, 0x0002, - 0x00c0, 0x7196, 0x7007, 0x0005, 0x0078, 0x7198, 0x7007, 0x0000, - 0x0e7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, 0x027e, 0x007e, - 0x127e, 0x2091, 0x8000, 0x2071, 0xa5ab, 0x2c10, 0x7638, 0x2660, - 0x2678, 0x8cff, 0x0040, 0x71d8, 0x2200, 0xac06, 0x00c0, 0x71d3, - 0x7038, 0xac36, 0x00c0, 0x71b6, 0x660c, 0x763a, 0x7034, 0xac36, - 0x00c0, 0x71c4, 0x2c00, 0xaf36, 0x0040, 0x71c2, 0x2f00, 0x7036, - 0x0078, 0x71c4, 0x7037, 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0040, - 0x71cc, 0x7e0e, 0x0078, 0x71cd, 0x2678, 0x600f, 0x0000, 0xa085, - 0x0001, 0x0078, 0x71d8, 0x2c78, 0x600c, 0x2060, 0x0078, 0x71a9, - 0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, - 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091, - 0x8000, 0x2071, 0xa5ab, 0x760c, 0x2660, 0x2678, 0x8cff, 0x0040, - 0x7279, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x7274, - 0x7024, 0xac06, 0x00c0, 0x721f, 0x2069, 0x0100, 0x68c0, 0xa005, - 0x0040, 0x724d, 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, 0x7188, - 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, - 0x0040, 0x7216, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, - 0x6824, 0xd084, 0x0040, 0x721e, 0x6827, 0x0001, 0x037f, 0x700c, - 0xac36, 0x00c0, 0x7225, 0x660c, 0x760e, 0x7008, 0xac36, 0x00c0, - 0x7233, 0x2c00, 0xaf36, 0x0040, 0x7231, 0x2f00, 0x700a, 0x0078, - 0x7233, 0x700b, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, - 0x723c, 0x7e0e, 0x0078, 0x723d, 0x2678, 0x600f, 0x0000, 0x1078, - 0x8c27, 0x00c0, 0x7251, 0x1078, 0x2839, 0x1078, 0x8c3b, 0x00c0, - 0x726d, 0x1078, 0x7a05, 0x0078, 0x726d, 0x1078, 0x7188, 0x0078, - 0x721f, 0x1078, 0x8c3b, 0x00c0, 0x7259, 0x1078, 0x7a05, 0x0078, - 0x726d, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x726d, 0x601c, - 0xa086, 0x0003, 0x00c0, 0x7281, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x1078, - 0x7045, 0x0c7f, 0x0078, 0x71ee, 0x2c78, 0x600c, 0x2060, 0x0078, - 0x71ee, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, - 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x726d, 0x1078, 0x9e70, - 0x0078, 0x726d, 0x037e, 0x157e, 0x137e, 0x147e, 0x3908, 0xa006, - 0xa190, 0x0020, 0x221c, 0xa39e, 0x260c, 0x00c0, 0x729b, 0x8210, - 0x8000, 0x0078, 0x7292, 0xa005, 0x0040, 0x72a7, 0x20a9, 0x0020, - 0x2198, 0x8211, 0xa282, 0x0020, 0x20c8, 0x20a0, 0x53a3, 0x147f, - 0x137f, 0x157f, 0x037f, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078, - 0x65f8, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x2099, 0xa5a3, 0x20a9, 0x0004, 0x53a6, - 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x1078, 0x6c2d, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65f8, - 0x20a3, 0x0214, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, 0xa084, - 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff, 0x20a2, 0x7828, 0x20a2, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x1078, 0x6c2d, - 0x007c, 0x0d7e, 0x017e, 0x2f68, 0x2009, 0x0035, 0x1078, 0x8ef5, - 0x00c0, 0x7361, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, 0x1300, - 0x20a3, 0x0000, 0x7828, 0x2068, 0x681c, 0xa086, 0x0003, 0x0040, - 0x733d, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x00c0, - 0x7317, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0078, 0x7352, 0xa286, - 0x007f, 0x00c0, 0x7321, 0x20a3, 0x00ff, 0x20a3, 0xfffd, 0x0078, - 0x7352, 0xd2bc, 0x0040, 0x7337, 0xa286, 0x0080, 0x00c0, 0x732e, - 0x20a3, 0x00ff, 0x20a3, 0xfffc, 0x0078, 0x7352, 0xa2e8, 0xa434, - 0x2d6c, 0x6810, 0x20a2, 0x6814, 0x20a2, 0x0078, 0x7352, 0x20a3, - 0x0000, 0x6098, 0x20a2, 0x0078, 0x7352, 0x7818, 0xa080, 0x0028, - 0x2004, 0xa082, 0x007e, 0x0048, 0x734e, 0x0d7e, 0x2069, 0xa31a, - 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x7352, 0x20a3, 0x0000, - 0x6030, 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x6c2d, 0x017f, 0x0d7f, - 0x007c, 0x7817, 0x0001, 0x7803, 0x0006, 0x017f, 0x0d7f, 0x007c, - 0x0d7e, 0x027e, 0x7928, 0x2168, 0x691c, 0xa186, 0x0006, 0x0040, - 0x738a, 0xa186, 0x0003, 0x0040, 0x73e5, 0xa186, 0x0005, 0x0040, - 0x73c8, 0xa186, 0x0004, 0x0040, 0x73b8, 0xa186, 0x0008, 0x0040, - 0x73d2, 0x7807, 0x0037, 0x7813, 0x1700, 0x1078, 0x7450, 0x027f, - 0x0d7f, 0x007c, 0x1078, 0x740d, 0x2009, 0x4000, 0x6800, 0x0079, - 0x7391, 0x73a4, 0x73b2, 0x73a6, 0x73b2, 0x73ad, 0x73a4, 0x73a4, - 0x73b2, 0x73b2, 0x73b2, 0x73b2, 0x73a4, 0x73a4, 0x73a4, 0x73a4, - 0x73a4, 0x73b2, 0x73a4, 0x73b2, 0x1078, 0x1328, 0x6824, 0xd0e4, - 0x0040, 0x73ad, 0xd0cc, 0x0040, 0x73b0, 0xa00e, 0x0078, 0x73b2, - 0x2009, 0x2000, 0x6828, 0x20a2, 0x682c, 0x20a2, 0x0078, 0x7403, - 0x1078, 0x740d, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, - 0x6a00, 0xa286, 0x0002, 0x00c0, 0x73c6, 0xa00e, 0x0078, 0x7403, - 0x1078, 0x740d, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, - 0x0078, 0x7403, 0x1078, 0x740d, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x2009, 0x4000, 0xa286, 0x0005, 0x0040, 0x73e2, 0xa286, 0x0002, - 0x00c0, 0x73e3, 0xa00e, 0x0078, 0x7403, 0x1078, 0x740d, 0x6810, - 0x2068, 0x697c, 0x6810, 0xa112, 0x6980, 0x6814, 0xa103, 0x20a2, - 0x22a2, 0x7928, 0xa180, 0x0000, 0x2004, 0xa08e, 0x0002, 0x0040, - 0x7401, 0xa08e, 0x0004, 0x0040, 0x7401, 0x2009, 0x4000, 0x0078, - 0x7403, 0x2009, 0x0000, 0x21a2, 0x20a3, 0x0000, 0x60c3, 0x0018, - 0x1078, 0x6c2d, 0x027f, 0x0d7f, 0x007c, 0x037e, 0x047e, 0x057e, - 0x067e, 0x20a1, 0x020b, 0x1078, 0x65f8, 0xa006, 0x20a3, 0x0200, - 0x20a2, 0x7934, 0x21a2, 0x7938, 0x21a2, 0x7818, 0xa080, 0x0028, - 0x2004, 0xa092, 0x007e, 0x0048, 0x7433, 0x0d7e, 0x2069, 0xa31a, - 0x2d2c, 0x8d68, 0x2d34, 0xa0e8, 0xa434, 0x2d6c, 0x6b10, 0x6c14, - 0x0d7f, 0x0078, 0x7439, 0x2019, 0x0000, 0x6498, 0x2029, 0x0000, - 0x6630, 0x7828, 0xa080, 0x0007, 0x2004, 0xa086, 0x0003, 0x00c0, - 0x7447, 0x25a2, 0x26a2, 0x23a2, 0x24a2, 0x0078, 0x744b, 0x23a2, - 0x24a2, 0x25a2, 0x26a2, 0x067f, 0x057f, 0x047f, 0x037f, 0x007c, - 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0100, 0x20a3, 0x0000, - 0x20a3, 0x0009, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6c2d, - 0x007c, 0x20a1, 0x020b, 0x1078, 0x655e, 0x20a3, 0x1400, 0x20a3, - 0x0000, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x7828, 0x20a2, 0x782c, - 0x20a2, 0x7830, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x20a3, 0x0000, - 0x60c3, 0x0010, 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, - 0x65ef, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0x20a2, 0x7810, - 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x007c, 0x147e, 0x20a1, - 0x020b, 0x1078, 0x7499, 0x60c3, 0x0000, 0x1078, 0x6c2d, 0x147f, - 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0xd0bc, 0x0040, 0x74b6, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, - 0x6810, 0xa085, 0x0300, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, - 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x74be, 0x20a3, 0x0300, - 0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0819, - 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x2fa2, - 0x7a08, 0x22a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x007c, 0x2061, - 0xaa00, 0x2a70, 0x7060, 0x7046, 0x704b, 0xaa00, 0x007c, 0x0e7e, - 0x127e, 0x2071, 0xa300, 0x2091, 0x8000, 0x7544, 0xa582, 0x0010, - 0x0048, 0x7509, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040, - 0x74f5, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, 0x74f1, 0x0078, - 0x74e4, 0x2061, 0xaa00, 0x0078, 0x74e4, 0x6003, 0x0008, 0x8529, - 0x7546, 0xaca8, 0x0010, 0x7054, 0xa502, 0x00c8, 0x7505, 0x754a, - 0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704b, 0xaa00, 0x0078, - 0x7500, 0xa006, 0x0078, 0x7502, 0x0e7e, 0x2071, 0xa300, 0x7544, - 0xa582, 0x0010, 0x0048, 0x753a, 0x7048, 0x2060, 0x6000, 0xa086, - 0x0000, 0x0040, 0x7527, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, - 0x7523, 0x0078, 0x7516, 0x2061, 0xaa00, 0x0078, 0x7516, 0x6003, - 0x0008, 0x8529, 0x7546, 0xaca8, 0x0010, 0x7054, 0xa502, 0x00c8, - 0x7536, 0x754a, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x704b, 0xaa00, - 0x0078, 0x7532, 0xa006, 0x0078, 0x7534, 0xac82, 0xaa00, 0x1048, - 0x1328, 0x2001, 0xa315, 0x2004, 0xac02, 0x10c8, 0x1328, 0xa006, - 0x6006, 0x600a, 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000, - 0x6003, 0x0000, 0x6022, 0x6026, 0x602a, 0x602e, 0x6032, 0x6036, - 0x603a, 0x603e, 0x2061, 0xa300, 0x6044, 0x8000, 0x6046, 0xa086, - 0x0001, 0x0040, 0x7564, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, - 0x6109, 0x127f, 0x0078, 0x7563, 0x601c, 0xa084, 0x000f, 0x0079, - 0x7571, 0x757a, 0x758b, 0x75a7, 0x75c3, 0x8f2d, 0x8f49, 0x8f65, - 0x757a, 0x758b, 0xa186, 0x0013, 0x00c0, 0x7583, 0x1078, 0x6010, - 0x1078, 0x6109, 0x007c, 0xa18e, 0x0047, 0x00c0, 0x758a, 0xa016, - 0x1078, 0x15ec, 0x007c, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, - 0x1328, 0x1079, 0x7595, 0x067f, 0x007c, 0x75a5, 0x7891, 0x7a34, - 0x75a5, 0x7ab8, 0x75df, 0x75a5, 0x75a5, 0x7823, 0x7e6d, 0x75a5, - 0x75a5, 0x75a5, 0x75a5, 0x75a5, 0x75a5, 0x1078, 0x1328, 0x067e, - 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1328, 0x1079, 0x75b1, 0x067f, - 0x007c, 0x75c1, 0x8522, 0x75c1, 0x75c1, 0x75c1, 0x75c1, 0x75c1, - 0x75c1, 0x84c5, 0x86a8, 0x75c1, 0x8552, 0x85d8, 0x8552, 0x85d8, - 0x75c1, 0x1078, 0x1328, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, - 0x1328, 0x1079, 0x75cd, 0x067f, 0x007c, 0x75dd, 0x7eb4, 0x7f81, - 0x80c6, 0x8242, 0x75dd, 0x75dd, 0x75dd, 0x7e8d, 0x846d, 0x8471, - 0x75dd, 0x75dd, 0x75dd, 0x75dd, 0x84a1, 0x1078, 0x1328, 0xa1b6, - 0x0015, 0x00c0, 0x75e7, 0x1078, 0x753d, 0x0078, 0x75ed, 0xa1b6, - 0x0016, 0x10c0, 0x1328, 0x1078, 0x753d, 0x007c, 0x20a9, 0x000e, - 0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, - 0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, - 0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x75fc, - 0x0e7e, 0x1078, 0x8a44, 0x0040, 0x7613, 0x6010, 0x2070, 0x7007, - 0x0000, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x753d, 0x007c, 0x0d7e, - 0x037e, 0x7330, 0xa386, 0x0200, 0x00c0, 0x7624, 0x6018, 0x2068, - 0x6813, 0x00ff, 0x6817, 0xfffd, 0x6010, 0xa005, 0x0040, 0x762e, - 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6b32, 0x1078, 0x753d, - 0x037f, 0x0d7f, 0x007c, 0x017e, 0x20a9, 0x002a, 0xae80, 0x000c, - 0x2098, 0x6010, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a, - 0x6010, 0xa080, 0x0001, 0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3, - 0x0e7e, 0x6010, 0x2004, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, - 0x753d, 0x017f, 0x007c, 0x0e7e, 0x0d7e, 0x603f, 0x0000, 0x2c68, - 0x017e, 0x2009, 0x0035, 0x1078, 0x8ef5, 0x017f, 0x00c0, 0x766f, - 0x027e, 0x6228, 0x2268, 0x027f, 0x2071, 0xa88c, 0x6b1c, 0xa386, - 0x0003, 0x0040, 0x7673, 0xa386, 0x0006, 0x0040, 0x7677, 0x1078, - 0x753d, 0x0078, 0x7679, 0x1078, 0x767c, 0x0078, 0x7679, 0x1078, - 0x771e, 0x0d7f, 0x0e7f, 0x007c, 0x0f7e, 0x6810, 0x2078, 0xa186, - 0x0015, 0x0040, 0x7705, 0xa18e, 0x0016, 0x00c0, 0x771c, 0x700c, - 0xa084, 0xff00, 0xa086, 0x1700, 0x00c0, 0x76e0, 0x8fff, 0x0040, - 0x771a, 0x6808, 0xa086, 0xffff, 0x00c0, 0x7709, 0x784c, 0xa084, - 0x0060, 0xa086, 0x0020, 0x00c0, 0x76a7, 0x797c, 0x7810, 0xa106, - 0x00c0, 0x7709, 0x7980, 0x7814, 0xa106, 0x00c0, 0x7709, 0x1078, - 0x8bf4, 0x6830, 0x7852, 0x784c, 0xc0dc, 0xc0f4, 0xc0d4, 0x784e, - 0x027e, 0xa00e, 0x6a14, 0x2001, 0x000a, 0x1078, 0x5a98, 0x7854, - 0xa20a, 0x0048, 0x76bc, 0x8011, 0x7a56, 0x82ff, 0x027f, 0x00c0, - 0x76c8, 0x0c7e, 0x2d60, 0x1078, 0x8832, 0x0c7f, 0x0078, 0x771a, - 0x0c7e, 0x0d7e, 0x2f68, 0x6838, 0xd0fc, 0x00c0, 0x76d3, 0x1078, - 0x4290, 0x0078, 0x76d5, 0x1078, 0x436e, 0x0d7f, 0x0c7f, 0x00c0, - 0x7709, 0x0c7e, 0x2d60, 0x1078, 0x753d, 0x0c7f, 0x0078, 0x771a, - 0x7008, 0xa086, 0x000b, 0x00c0, 0x76fa, 0x6018, 0x200c, 0xc1bc, - 0x2102, 0x0c7e, 0x2d60, 0x7853, 0x0003, 0x6007, 0x0085, 0x6003, - 0x000b, 0x601f, 0x0002, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7f, - 0x0078, 0x771a, 0x700c, 0xa086, 0x2a00, 0x00c0, 0x7709, 0x2001, - 0xa5a2, 0x2004, 0x683e, 0x0078, 0x771a, 0x1078, 0x7739, 0x0078, - 0x771c, 0x8fff, 0x1040, 0x1328, 0x0c7e, 0x0d7e, 0x2d60, 0x2f68, - 0x684b, 0x0003, 0x1078, 0x8726, 0x1078, 0x8bf4, 0x1078, 0x8c01, - 0x0d7f, 0x0c7f, 0x1078, 0x753d, 0x0f7f, 0x007c, 0xa186, 0x0015, - 0x00c0, 0x7728, 0x2001, 0xa5a2, 0x2004, 0x683e, 0x0078, 0x7736, - 0xa18e, 0x0016, 0x00c0, 0x7738, 0x0c7e, 0x2d00, 0x2060, 0x1078, - 0xa134, 0x1078, 0x5a41, 0x1078, 0x753d, 0x0c7f, 0x1078, 0x753d, - 0x007c, 0x027e, 0x037e, 0x047e, 0x7228, 0x7c80, 0x7b7c, 0xd2f4, - 0x0040, 0x7748, 0x2001, 0xa5a2, 0x2004, 0x683e, 0x0078, 0x77ac, - 0x0c7e, 0x2d60, 0x1078, 0x874a, 0x0c7f, 0x6804, 0xa086, 0x0050, - 0x00c0, 0x7760, 0x0c7e, 0x2d00, 0x2060, 0x6003, 0x0001, 0x6007, - 0x0050, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7f, 0x0078, 0x77ac, - 0x6800, 0xa086, 0x000f, 0x0040, 0x7782, 0x8fff, 0x1040, 0x1328, - 0x6824, 0xd0dc, 0x00c0, 0x7782, 0x6800, 0xa086, 0x0004, 0x00c0, - 0x7787, 0x784c, 0xd0ac, 0x0040, 0x7787, 0x784c, 0xc0dc, 0xc0f4, - 0x784e, 0x7850, 0xc0f4, 0xc0fc, 0x7852, 0x2001, 0x0001, 0x682e, - 0x0078, 0x77a6, 0x2001, 0x0007, 0x682e, 0x0078, 0x77a6, 0x784c, - 0xd0b4, 0x00c0, 0x7794, 0xd0ac, 0x0040, 0x7782, 0x784c, 0xd0f4, - 0x00c0, 0x7782, 0x0078, 0x7775, 0xd2ec, 0x00c0, 0x7782, 0x7024, - 0xa306, 0x00c0, 0x779f, 0x7020, 0xa406, 0x0040, 0x7782, 0x7020, - 0x6836, 0x7024, 0x683a, 0x2001, 0x0005, 0x682e, 0x1078, 0x8d2b, - 0x1078, 0x6109, 0x0078, 0x77ae, 0x1078, 0x753d, 0x047f, 0x037f, - 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x027e, 0x6034, 0x2068, 0x6a1c, - 0xa286, 0x0007, 0x0040, 0x7806, 0xa286, 0x0002, 0x0040, 0x7806, - 0xa286, 0x0000, 0x0040, 0x7806, 0x6808, 0x6338, 0xa306, 0x00c0, - 0x7806, 0x2071, 0xa88c, 0xa186, 0x0015, 0x0040, 0x7800, 0xa18e, - 0x0016, 0x00c0, 0x77e8, 0x6030, 0xa084, 0x00ff, 0xa086, 0x0001, - 0x00c0, 0x77e8, 0x700c, 0xa086, 0x2a00, 0x00c0, 0x77e8, 0x6034, - 0xa080, 0x0009, 0x200c, 0xc1dd, 0xc1f5, 0x2102, 0x0078, 0x7800, - 0x0c7e, 0x6034, 0x2060, 0x6010, 0x2068, 0x1078, 0x8a44, 0x1040, - 0x1328, 0x6853, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, - 0x0002, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7f, 0x0078, 0x7806, - 0x6034, 0x2068, 0x2001, 0xa5a2, 0x2004, 0x683e, 0x1078, 0x753d, - 0x027f, 0x0d7f, 0x0e7f, 0x007c, 0x0d7e, 0x20a9, 0x000e, 0x2e98, - 0x6010, 0x20a0, 0x53a3, 0xa1b6, 0x0015, 0x00c0, 0x7820, 0x6018, - 0x2068, 0x7038, 0x680a, 0x703c, 0x680e, 0x6800, 0xc08d, 0x6802, - 0x0d7f, 0x0078, 0x7608, 0x2100, 0xa1b2, 0x0044, 0x10c8, 0x1328, - 0xa1b2, 0x0040, 0x00c8, 0x7888, 0x0079, 0x782e, 0x787c, 0x7870, - 0x787c, 0x787c, 0x787c, 0x787c, 0x786e, 0x786e, 0x786e, 0x786e, - 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, - 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, - 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x787c, 0x786e, 0x787c, - 0x787c, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x787c, 0x786e, - 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, - 0x787c, 0x787c, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, - 0x786e, 0x786e, 0x786e, 0x787c, 0x786e, 0x786e, 0x1078, 0x1328, - 0x6003, 0x0001, 0x6106, 0x1078, 0x5c45, 0x127e, 0x2091, 0x8000, - 0x1078, 0x6109, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, - 0x5c45, 0x127e, 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, - 0x2600, 0x0079, 0x788b, 0x788f, 0x788f, 0x788f, 0x787c, 0x1078, - 0x1328, 0x6004, 0xa0b2, 0x0044, 0x10c8, 0x1328, 0xa1b6, 0x0013, - 0x00c0, 0x78a1, 0xa0b2, 0x0040, 0x00c8, 0x79fb, 0x2008, 0x0079, - 0x7941, 0xa1b6, 0x0027, 0x00c0, 0x78fe, 0x1078, 0x6010, 0x6004, - 0x1078, 0x8c27, 0x0040, 0x78be, 0x1078, 0x8c3b, 0x0040, 0x78f6, - 0xa08e, 0x0021, 0x0040, 0x78fa, 0xa08e, 0x0022, 0x0040, 0x78f6, - 0xa08e, 0x003d, 0x0040, 0x78fa, 0x0078, 0x78f1, 0x1078, 0x2839, - 0x2001, 0x0007, 0x1078, 0x443f, 0x6018, 0xa080, 0x0028, 0x200c, - 0x1078, 0x7a05, 0xa186, 0x007e, 0x00c0, 0x78d3, 0x2001, 0xa332, - 0x2014, 0xc285, 0x2202, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019, - 0x0028, 0x1078, 0x5d53, 0x077e, 0x2039, 0x0000, 0x1078, 0x5c78, - 0x0c7e, 0x6018, 0xa065, 0x0040, 0x78e7, 0x1078, 0x471b, 0x0c7f, - 0x2c08, 0x1078, 0x9c38, 0x077f, 0x037f, 0x027f, 0x017f, 0x1078, - 0x44bc, 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, 0x1078, 0x7a05, - 0x0078, 0x78f1, 0x1078, 0x7a28, 0x0078, 0x78f1, 0xa186, 0x0014, - 0x00c0, 0x78f5, 0x1078, 0x6010, 0x1078, 0x2813, 0x1078, 0x8c27, - 0x00c0, 0x791d, 0x1078, 0x2839, 0x6018, 0xa080, 0x0028, 0x200c, - 0x1078, 0x7a05, 0xa186, 0x007e, 0x00c0, 0x791b, 0x2001, 0xa332, - 0x200c, 0xc185, 0x2102, 0x0078, 0x78f1, 0x1078, 0x8c3b, 0x00c0, - 0x7925, 0x1078, 0x7a05, 0x0078, 0x78f1, 0x6004, 0xa08e, 0x0032, - 0x00c0, 0x7936, 0x0e7e, 0x0f7e, 0x2071, 0xa381, 0x2079, 0x0000, - 0x1078, 0x2b56, 0x0f7f, 0x0e7f, 0x0078, 0x78f1, 0x6004, 0xa08e, - 0x0021, 0x0040, 0x7921, 0xa08e, 0x0022, 0x1040, 0x7a05, 0x0078, - 0x78f1, 0x7983, 0x7985, 0x7989, 0x798d, 0x7991, 0x7995, 0x7981, - 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, - 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, - 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7999, - 0x79ab, 0x7981, 0x79ad, 0x79ab, 0x7981, 0x7981, 0x7981, 0x7981, - 0x7981, 0x79ab, 0x79ab, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, - 0x7981, 0x7981, 0x7981, 0x79de, 0x79ab, 0x7981, 0x79a5, 0x7981, - 0x7981, 0x7981, 0x79a7, 0x7981, 0x7981, 0x7981, 0x79ab, 0x7981, - 0x7981, 0x1078, 0x1328, 0x0078, 0x79ab, 0x2001, 0x000b, 0x0078, - 0x79b8, 0x2001, 0x0003, 0x0078, 0x79b8, 0x2001, 0x0005, 0x0078, - 0x79b8, 0x2001, 0x0001, 0x0078, 0x79b8, 0x2001, 0x0009, 0x0078, - 0x79b8, 0x1078, 0x6010, 0x6003, 0x0005, 0x2001, 0xa5a2, 0x2004, - 0x603e, 0x1078, 0x6109, 0x0078, 0x79b7, 0x0078, 0x79ab, 0x0078, - 0x79ab, 0x1078, 0x443f, 0x0078, 0x79f0, 0x1078, 0x6010, 0x6003, - 0x0004, 0x2001, 0xa5a0, 0x2004, 0x6016, 0x1078, 0x6109, 0x007c, - 0x1078, 0x443f, 0x1078, 0x6010, 0x2001, 0xa5a2, 0x2004, 0x603e, - 0x6003, 0x0002, 0x037e, 0x2019, 0xa35c, 0x2304, 0xa084, 0xff00, - 0x00c0, 0x79cf, 0x2019, 0xa5a0, 0x231c, 0x0078, 0x79d8, 0x8007, - 0xa09a, 0x0004, 0x0048, 0x79ca, 0x8003, 0x801b, 0x831b, 0xa318, - 0x6316, 0x037f, 0x1078, 0x6109, 0x0078, 0x79b7, 0x0e7e, 0x0f7e, - 0x2071, 0xa381, 0x2079, 0x0000, 0x1078, 0x2b56, 0x0f7f, 0x0e7f, - 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, 0x0078, 0x79b7, - 0x1078, 0x6010, 0x6003, 0x0002, 0x2001, 0xa5a0, 0x2004, 0x6016, - 0x1078, 0x6109, 0x007c, 0x2600, 0x2008, 0x0079, 0x79ff, 0x7a03, - 0x7a03, 0x7a03, 0x79f0, 0x1078, 0x1328, 0x0e7e, 0x1078, 0x8a44, - 0x0040, 0x7a21, 0x6010, 0x2070, 0x7038, 0xd0fc, 0x0040, 0x7a21, - 0x7007, 0x0000, 0x017e, 0x6004, 0xa08e, 0x0021, 0x0040, 0x7a23, - 0xa08e, 0x003d, 0x0040, 0x7a23, 0x017f, 0x7037, 0x0103, 0x7033, - 0x0100, 0x0e7f, 0x007c, 0x017f, 0x1078, 0x7a28, 0x0078, 0x7a21, - 0x0e7e, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, - 0x7023, 0x8001, 0x0e7f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, - 0xa084, 0x00ff, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1328, 0x6604, - 0xa6b6, 0x0043, 0x00c0, 0x7a48, 0x1078, 0x8e6d, 0x0078, 0x7aa7, - 0x6604, 0xa6b6, 0x0033, 0x00c0, 0x7a51, 0x1078, 0x8e11, 0x0078, - 0x7aa7, 0x6604, 0xa6b6, 0x0028, 0x00c0, 0x7a5a, 0x1078, 0x8c6a, - 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x0029, 0x00c0, 0x7a63, 0x1078, - 0x8c84, 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x001f, 0x00c0, 0x7a6c, - 0x1078, 0x75ee, 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x0000, 0x00c0, - 0x7a75, 0x1078, 0x780c, 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x0022, - 0x00c0, 0x7a7e, 0x1078, 0x7617, 0x0078, 0x7aa7, 0x6604, 0xa6b6, - 0x0035, 0x00c0, 0x7a87, 0x1078, 0x7653, 0x0078, 0x7aa7, 0x6604, - 0xa6b6, 0x0039, 0x00c0, 0x7a90, 0x1078, 0x77b2, 0x0078, 0x7aa7, - 0x6604, 0xa6b6, 0x003d, 0x00c0, 0x7a99, 0x1078, 0x7633, 0x0078, - 0x7aa7, 0xa1b6, 0x0015, 0x00c0, 0x7aa1, 0x1079, 0x7aac, 0x0078, - 0x7aa7, 0xa1b6, 0x0016, 0x00c0, 0x7aa8, 0x1079, 0x7bfd, 0x007c, - 0x1078, 0x7583, 0x0078, 0x7aa7, 0x7ad0, 0x7ad3, 0x7ad0, 0x7b1e, - 0x7ad0, 0x7b91, 0x7c09, 0x7ad0, 0x7ad0, 0x7bd5, 0x7ad0, 0x7beb, - 0xa1b6, 0x0048, 0x0040, 0x7ac4, 0x20e1, 0x0005, 0x3d18, 0x3e20, - 0x2c10, 0x1078, 0x15ec, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74, - 0x7000, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x753d, 0x007c, - 0x0005, 0x0005, 0x007c, 0x0e7e, 0x2071, 0xa300, 0x707c, 0xa086, - 0x0074, 0x00c0, 0x7b07, 0x1078, 0x9c0c, 0x00c0, 0x7af9, 0x0d7e, - 0x6018, 0x2068, 0x7030, 0xd08c, 0x0040, 0x7aec, 0x6800, 0xd0bc, - 0x0040, 0x7aec, 0xc0c5, 0x6802, 0x1078, 0x7b0b, 0x0d7f, 0x2001, - 0x0006, 0x1078, 0x443f, 0x1078, 0x2839, 0x1078, 0x753d, 0x0078, - 0x7b09, 0x2001, 0x000a, 0x1078, 0x443f, 0x1078, 0x2839, 0x6003, - 0x0001, 0x6007, 0x0001, 0x1078, 0x5c45, 0x0078, 0x7b09, 0x1078, - 0x7b81, 0x0e7f, 0x007c, 0x6800, 0xd084, 0x0040, 0x7b1d, 0x2001, - 0x0000, 0x1078, 0x442b, 0x2069, 0xa351, 0x6804, 0xd0a4, 0x0040, - 0x7b1d, 0x2001, 0x0006, 0x1078, 0x4472, 0x007c, 0x0d7e, 0x2011, - 0xa31f, 0x2204, 0xa086, 0x0074, 0x00c0, 0x7b7d, 0x6018, 0x2068, - 0x6aa0, 0xa286, 0x007e, 0x00c0, 0x7b31, 0x1078, 0x7d17, 0x0078, - 0x7b7f, 0x1078, 0x7d0d, 0x6018, 0x2068, 0xa080, 0x0028, 0x2014, - 0xa286, 0x0080, 0x00c0, 0x7b55, 0x6813, 0x00ff, 0x6817, 0xfffc, - 0x6010, 0xa005, 0x0040, 0x7b4b, 0x2068, 0x6807, 0x0000, 0x6837, - 0x0103, 0x6833, 0x0200, 0x2001, 0x0006, 0x1078, 0x443f, 0x1078, - 0x2839, 0x1078, 0x753d, 0x0078, 0x7b7f, 0x0e7e, 0x2071, 0xa332, - 0x2e04, 0xd09c, 0x0040, 0x7b70, 0x2071, 0xa880, 0x7108, 0x720c, - 0xa18c, 0x00ff, 0x00c0, 0x7b68, 0xa284, 0xff00, 0x0040, 0x7b70, - 0x6018, 0x2070, 0x70a0, 0xd0bc, 0x00c0, 0x7b70, 0x7112, 0x7216, - 0x0e7f, 0x2001, 0x0004, 0x1078, 0x443f, 0x6003, 0x0001, 0x6007, - 0x0003, 0x1078, 0x5c45, 0x0078, 0x7b7f, 0x1078, 0x7b81, 0x0d7f, - 0x007c, 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x0040, 0x7b8c, - 0x2001, 0x0007, 0x1078, 0x443f, 0x1078, 0x2839, 0x1078, 0x753d, - 0x007c, 0x0e7e, 0x2071, 0xa300, 0x707c, 0xa086, 0x0014, 0x00c0, - 0x7bcf, 0x7000, 0xa086, 0x0003, 0x00c0, 0x7ba4, 0x6010, 0xa005, - 0x00c0, 0x7ba4, 0x1078, 0x35f7, 0x0d7e, 0x6018, 0x2068, 0x1078, - 0x457d, 0x1078, 0x7b0b, 0x0d7f, 0x1078, 0x7dba, 0x00c0, 0x7bcf, - 0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f, 0xa005, 0x0040, 0x7bcf, - 0x2001, 0x0006, 0x1078, 0x443f, 0x0e7e, 0x6010, 0xa005, 0x0040, - 0x7bc8, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, 0x7033, 0x0200, - 0x0e7f, 0x1078, 0x2839, 0x1078, 0x753d, 0x0078, 0x7bd3, 0x1078, - 0x7a05, 0x1078, 0x7b81, 0x0e7f, 0x007c, 0x2011, 0xa31f, 0x2204, - 0xa086, 0x0014, 0x00c0, 0x7be8, 0x2001, 0x0002, 0x1078, 0x443f, - 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x5c45, 0x0078, 0x7bea, - 0x1078, 0x7b81, 0x007c, 0x2011, 0xa31f, 0x2204, 0xa086, 0x0004, - 0x00c0, 0x7bfa, 0x2001, 0x0007, 0x1078, 0x443f, 0x1078, 0x753d, - 0x0078, 0x7bfc, 0x1078, 0x7b81, 0x007c, 0x7ad0, 0x7c11, 0x7ad0, - 0x7c4e, 0x7ad0, 0x7cc0, 0x7c09, 0x7ad0, 0x7ad0, 0x7cd5, 0x7ad0, - 0x7ce8, 0x6604, 0xa6b6, 0x001e, 0x00c0, 0x7c10, 0x1078, 0x753d, - 0x007c, 0x0d7e, 0x0c7e, 0x1078, 0x7cfb, 0x00c0, 0x7c27, 0x2001, - 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, 0x443f, 0x6003, - 0x0001, 0x6007, 0x0002, 0x1078, 0x5c45, 0x0078, 0x7c4b, 0x2009, - 0xa88e, 0x2104, 0xa086, 0x0009, 0x00c0, 0x7c3c, 0x6018, 0x2068, - 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x7c49, 0x8001, 0x6842, - 0x6017, 0x000a, 0x0078, 0x7c4b, 0x2009, 0xa88f, 0x2104, 0xa084, - 0xff00, 0xa086, 0x1900, 0x00c0, 0x7c49, 0x1078, 0x753d, 0x0078, - 0x7c4b, 0x1078, 0x7b81, 0x0c7f, 0x0d7f, 0x007c, 0x1078, 0x7d0a, - 0x00c0, 0x7c62, 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, - 0x1078, 0x443f, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x5c45, - 0x0078, 0x7c8e, 0x1078, 0x7a05, 0x2009, 0xa88e, 0x2134, 0xa6b4, - 0x00ff, 0xa686, 0x0005, 0x0040, 0x7c8f, 0xa686, 0x000b, 0x0040, - 0x7c8c, 0x2009, 0xa88f, 0x2104, 0xa084, 0xff00, 0x00c0, 0x7c7c, - 0xa686, 0x0009, 0x0040, 0x7c8f, 0xa086, 0x1900, 0x00c0, 0x7c8c, - 0xa686, 0x0009, 0x0040, 0x7c8f, 0x2001, 0x0004, 0x1078, 0x443f, - 0x1078, 0x753d, 0x0078, 0x7c8e, 0x1078, 0x7b81, 0x007c, 0x0d7e, - 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x7c9d, 0x6838, 0xd0fc, - 0x0040, 0x7c9d, 0x0d7f, 0x0078, 0x7c8c, 0x6018, 0x2068, 0x6840, - 0xa084, 0x00ff, 0xa005, 0x0040, 0x7cae, 0x8001, 0x6842, 0x6017, - 0x000a, 0x6007, 0x0016, 0x0d7f, 0x0078, 0x7c8e, 0x68a0, 0xa086, - 0x007e, 0x00c0, 0x7cbb, 0x0e7e, 0x2071, 0xa300, 0x1078, 0x41f5, - 0x0e7f, 0x0078, 0x7cbd, 0x1078, 0x2813, 0x0d7f, 0x0078, 0x7c8c, - 0x1078, 0x7d0a, 0x00c0, 0x7cd0, 0x2001, 0x0004, 0x1078, 0x443f, - 0x6003, 0x0001, 0x6007, 0x0003, 0x1078, 0x5c45, 0x0078, 0x7cd4, - 0x1078, 0x7a05, 0x1078, 0x7b81, 0x007c, 0x1078, 0x7d0a, 0x00c0, - 0x7ce5, 0x2001, 0x0008, 0x1078, 0x443f, 0x6003, 0x0001, 0x6007, - 0x0005, 0x1078, 0x5c45, 0x0078, 0x7ce7, 0x1078, 0x7b81, 0x007c, - 0x1078, 0x7d0a, 0x00c0, 0x7cf8, 0x2001, 0x000a, 0x1078, 0x443f, - 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x5c45, 0x0078, 0x7cfa, - 0x1078, 0x7b81, 0x007c, 0x2009, 0xa88e, 0x2104, 0xa086, 0x0003, - 0x00c0, 0x7d09, 0x2009, 0xa88f, 0x2104, 0xa084, 0xff00, 0xa086, - 0x2a00, 0x007c, 0xa085, 0x0001, 0x007c, 0x0c7e, 0x017e, 0xac88, - 0x0006, 0x2164, 0x1078, 0x4513, 0x017f, 0x0c7f, 0x007c, 0x0f7e, - 0x0e7e, 0x0d7e, 0x037e, 0x017e, 0x6018, 0x2068, 0x2071, 0xa332, - 0x2e04, 0xa085, 0x0003, 0x2072, 0x1078, 0x7d8b, 0x0040, 0x7d50, - 0x2001, 0xa352, 0x2004, 0xd0a4, 0x0040, 0x7d39, 0xa006, 0x2020, - 0x2009, 0x002a, 0x1078, 0x9ec0, 0x2001, 0xa30c, 0x200c, 0xc195, - 0x2102, 0x2019, 0x002a, 0x2009, 0x0001, 0x1078, 0x27e2, 0x2071, - 0xa300, 0x1078, 0x260d, 0x0c7e, 0x157e, 0x20a9, 0x0081, 0x2009, - 0x007f, 0x1078, 0x2921, 0x8108, 0x00f0, 0x7d49, 0x157f, 0x0c7f, - 0x1078, 0x7d0d, 0x6813, 0x00ff, 0x6817, 0xfffe, 0x2071, 0xa880, - 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, 0x2069, 0xa31a, 0x206a, - 0x78e6, 0x007e, 0x8e70, 0x2e04, 0x2069, 0xa31b, 0x206a, 0x78ea, - 0xa084, 0xff00, 0x017f, 0xa105, 0x2009, 0xa325, 0x200a, 0x2069, - 0xa88e, 0x2071, 0xa59c, 0x6810, 0x2072, 0x6814, 0x7006, 0x6818, - 0x700a, 0x681c, 0x700e, 0x1078, 0x8da9, 0x2001, 0x0006, 0x1078, - 0x443f, 0x1078, 0x2839, 0x1078, 0x753d, 0x017f, 0x037f, 0x0d7f, - 0x0e7f, 0x0f7f, 0x007c, 0x027e, 0x037e, 0x0e7e, 0x157e, 0x2019, - 0xa325, 0x231c, 0x83ff, 0x0040, 0x7db5, 0x2071, 0xa880, 0x2e14, - 0xa294, 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205, 0xa306, 0x00c0, - 0x7db5, 0x2011, 0xa896, 0xad98, 0x000a, 0x20a9, 0x0004, 0x1078, - 0x7e55, 0x00c0, 0x7db5, 0x2011, 0xa89a, 0xad98, 0x0006, 0x20a9, - 0x0004, 0x1078, 0x7e55, 0x00c0, 0x7db5, 0x157f, 0x0e7f, 0x037f, - 0x027f, 0x007c, 0x0e7e, 0x2071, 0xa88c, 0x7004, 0xa086, 0x0014, - 0x00c0, 0x7ddd, 0x7008, 0xa086, 0x0800, 0x00c0, 0x7ddd, 0x700c, - 0xd0ec, 0x0040, 0x7ddb, 0xa084, 0x0f00, 0xa086, 0x0100, 0x00c0, - 0x7ddb, 0x7024, 0xd0a4, 0x00c0, 0x7dd8, 0xd0ac, 0x0040, 0x7ddb, - 0xa006, 0x0078, 0x7ddd, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x0e7e, - 0x0d7e, 0x0c7e, 0x077e, 0x057e, 0x047e, 0x027e, 0x007e, 0x127e, - 0x2091, 0x8000, 0x2029, 0xa5b4, 0x252c, 0x2021, 0xa5ba, 0x2424, - 0x2061, 0xaa00, 0x2071, 0xa300, 0x7244, 0x7060, 0xa202, 0x00c8, - 0x7e43, 0x1078, 0x9ee5, 0x0040, 0x7e3b, 0x671c, 0xa786, 0x0001, - 0x0040, 0x7e3b, 0xa786, 0x0007, 0x0040, 0x7e3b, 0x2500, 0xac06, - 0x0040, 0x7e3b, 0x2400, 0xac06, 0x0040, 0x7e3b, 0x0c7e, 0x6000, - 0xa086, 0x0004, 0x00c0, 0x7e16, 0x1078, 0x1749, 0xa786, 0x0008, - 0x00c0, 0x7e25, 0x1078, 0x8c3b, 0x00c0, 0x7e25, 0x0c7f, 0x1078, - 0x7a05, 0x1078, 0x8c01, 0x0078, 0x7e3b, 0x6010, 0x2068, 0x1078, - 0x8a44, 0x0040, 0x7e38, 0xa786, 0x0003, 0x00c0, 0x7e4d, 0x6837, - 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, - 0x1078, 0x8c01, 0x0c7f, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, - 0x7e43, 0x0078, 0x7df4, 0x127f, 0x007f, 0x027f, 0x047f, 0x057f, - 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0, - 0x7e2f, 0x1078, 0x9e70, 0x0078, 0x7e38, 0x220c, 0x2304, 0xa106, - 0x00c0, 0x7e60, 0x8210, 0x8318, 0x00f0, 0x7e55, 0xa006, 0x007c, - 0x2304, 0xa102, 0x0048, 0x7e68, 0x2001, 0x0001, 0x0078, 0x7e6a, - 0x2001, 0x0000, 0xa18d, 0x0001, 0x007c, 0x6004, 0xa08a, 0x0044, - 0x10c8, 0x1328, 0x1078, 0x8c27, 0x0040, 0x7e7c, 0x1078, 0x8c3b, - 0x0040, 0x7e89, 0x0078, 0x7e82, 0x1078, 0x2839, 0x1078, 0x8c3b, - 0x0040, 0x7e89, 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, - 0x007c, 0x1078, 0x7a05, 0x0078, 0x7e82, 0xa182, 0x0040, 0x0079, - 0x7e91, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, - 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea6, 0x7ea6, 0x7ea6, 0x7ea6, - 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea6, 0x1078, 0x1328, 0x600b, 0xffff, - 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x127e, 0x2091, 0x8000, - 0x1078, 0x6109, 0x127f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x7ebd, - 0x6004, 0xa082, 0x0040, 0x0079, 0x7f48, 0xa186, 0x0027, 0x00c0, - 0x7edf, 0x1078, 0x6010, 0x1078, 0x2813, 0x0d7e, 0x6110, 0x2168, - 0x1078, 0x8a44, 0x0040, 0x7ed9, 0x6837, 0x0103, 0x684b, 0x0029, - 0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e, 0x1078, 0x4982, 0x1078, - 0x8bf4, 0x0d7f, 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, 0xa186, - 0x0014, 0x00c0, 0x7ee8, 0x6004, 0xa082, 0x0040, 0x0079, 0x7f10, - 0xa186, 0x0046, 0x0040, 0x7ef4, 0xa186, 0x0045, 0x0040, 0x7ef4, - 0xa186, 0x0047, 0x10c0, 0x1328, 0x2001, 0x0109, 0x2004, 0xd084, - 0x0040, 0x7f0d, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, - 0x1078, 0x5ad2, 0x027f, 0x017f, 0x007f, 0x127f, 0x6000, 0xa086, - 0x0002, 0x00c0, 0x7f0d, 0x0078, 0x7f81, 0x1078, 0x7583, 0x007c, - 0x7f25, 0x7f23, 0x7f23, 0x7f23, 0x7f23, 0x7f23, 0x7f23, 0x7f23, - 0x7f23, 0x7f23, 0x7f23, 0x7f41, 0x7f41, 0x7f41, 0x7f41, 0x7f23, - 0x7f41, 0x7f23, 0x7f41, 0x1078, 0x1328, 0x1078, 0x6010, 0x0d7e, - 0x6110, 0x2168, 0x1078, 0x8a44, 0x0040, 0x7f3b, 0x6837, 0x0103, - 0x684b, 0x0006, 0x6847, 0x0000, 0x6850, 0xc0ec, 0x6852, 0x1078, - 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, 0x1078, 0x6109, - 0x007c, 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, - 0x7f5d, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, - 0x7f5b, 0x7f5b, 0x7f5b, 0x7f6f, 0x7f6f, 0x7f6f, 0x7f6f, 0x7f5b, - 0x7f7a, 0x7f5b, 0x7f6f, 0x1078, 0x1328, 0x1078, 0x6010, 0x2001, - 0xa5a2, 0x2004, 0x603e, 0x6003, 0x0002, 0x1078, 0x6109, 0x6010, - 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x007c, 0x1078, - 0x6010, 0x2001, 0xa5a2, 0x2004, 0x603e, 0x6003, 0x000f, 0x1078, - 0x6109, 0x007c, 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, - 0x007c, 0xa182, 0x0040, 0x0079, 0x7f85, 0x7f98, 0x7f98, 0x7f98, - 0x7f98, 0x7f98, 0x7f9a, 0x8095, 0x80b7, 0x7f98, 0x7f98, 0x7f98, - 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, - 0x1078, 0x1328, 0x0e7e, 0x0d7e, 0x603f, 0x0000, 0x2071, 0xa880, - 0x7124, 0x610a, 0x2071, 0xa88c, 0x6110, 0x2168, 0x7614, 0xa6b4, - 0x0fff, 0x86ff, 0x0040, 0x8058, 0xa68c, 0x0c00, 0x0040, 0x7fd1, - 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x7fcd, 0x684c, - 0xd0ac, 0x0040, 0x7fcd, 0x6024, 0xd0dc, 0x00c0, 0x7fcd, 0x6850, - 0xd0bc, 0x00c0, 0x7fcd, 0x7318, 0x6814, 0xa306, 0x00c0, 0x806f, - 0x731c, 0x6810, 0xa306, 0x00c0, 0x806f, 0x7318, 0x6b62, 0x731c, - 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x8004, 0xa186, - 0x0028, 0x00c0, 0x7fe1, 0x1078, 0x8c15, 0x684b, 0x001c, 0x0078, - 0x8006, 0xd6dc, 0x0040, 0x7ffd, 0x684b, 0x0015, 0x684c, 0xd0ac, - 0x0040, 0x7ffb, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0040, 0x7ffb, - 0x7018, 0xa106, 0x00c0, 0x7ff8, 0x701c, 0xa206, 0x0040, 0x7ffb, - 0x6962, 0x6a5e, 0xc6dc, 0x0078, 0x8006, 0xd6d4, 0x0040, 0x8004, - 0x684b, 0x0007, 0x0078, 0x8006, 0x684b, 0x0000, 0x6837, 0x0103, - 0x6e46, 0xa01e, 0xd6c4, 0x0040, 0x802f, 0xa686, 0x0100, 0x00c0, - 0x801a, 0x2001, 0xa899, 0x2004, 0xa005, 0x00c0, 0x801a, 0xc6c4, - 0x0078, 0x7fa9, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0040, 0x802f, - 0xa38a, 0x0009, 0x0048, 0x8026, 0x2019, 0x0008, 0x037e, 0x2308, - 0x2019, 0xa898, 0xad90, 0x0019, 0x1078, 0x8739, 0x037f, 0xd6cc, - 0x0040, 0x8085, 0x7124, 0x695a, 0x81ff, 0x0040, 0x8085, 0xa192, - 0x0021, 0x00c8, 0x8046, 0x2071, 0xa898, 0x831c, 0x2300, 0xae18, - 0xad90, 0x001d, 0x1078, 0x8739, 0x0078, 0x8085, 0x6838, 0xd0fc, - 0x0040, 0x804f, 0x2009, 0x0020, 0x695a, 0x0078, 0x803b, 0x0f7e, - 0x2d78, 0x1078, 0x86d1, 0x0f7f, 0x1078, 0x8726, 0x0078, 0x8087, - 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8075, 0x684c, - 0xd0ac, 0x0040, 0x8075, 0x6024, 0xd0dc, 0x00c0, 0x8075, 0x6850, - 0xd0bc, 0x00c0, 0x8075, 0x684c, 0xd0f4, 0x00c0, 0x8075, 0x1078, - 0x8cfa, 0x0d7f, 0x0e7f, 0x0078, 0x8094, 0x684b, 0x0000, 0x6837, - 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0040, 0x8085, 0x6810, 0x6914, - 0xa115, 0x0040, 0x8085, 0x1078, 0x8233, 0x1078, 0x4982, 0x6218, - 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x1078, 0x8cc4, 0x0d7f, 0x0e7f, - 0x00c0, 0x8094, 0x1078, 0x753d, 0x007c, 0x0f7e, 0x6003, 0x0003, - 0x2079, 0xa88c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, - 0x784c, 0xd0ac, 0x0040, 0x80a8, 0x6003, 0x0002, 0x0f7f, 0x007c, - 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x603f, 0x0000, 0x2c10, - 0x1078, 0x1cab, 0x1078, 0x5c64, 0x1078, 0x61d3, 0x007c, 0x2001, - 0xa5a2, 0x2004, 0x603e, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, - 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15ec, 0x007c, 0xa182, 0x0040, - 0x0079, 0x80ca, 0x80dd, 0x80dd, 0x80dd, 0x80dd, 0x80dd, 0x80df, - 0x8182, 0x80dd, 0x80dd, 0x8198, 0x8209, 0x80dd, 0x80dd, 0x80dd, - 0x80dd, 0x8218, 0x80dd, 0x80dd, 0x80dd, 0x1078, 0x1328, 0x077e, - 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, 0xa88c, 0x6110, 0x2178, 0x7614, - 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, - 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x817d, 0xa694, 0xff00, - 0xa284, 0x0c00, 0x0040, 0x8100, 0x7018, 0x7862, 0x701c, 0x785e, - 0xa284, 0x0300, 0x0040, 0x817d, 0x1078, 0x1381, 0x1040, 0x1328, - 0x2d00, 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, - 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, - 0x0040, 0x811e, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, - 0xa186, 0x0002, 0x0040, 0x813a, 0xa186, 0x0028, 0x00c0, 0x812c, - 0x684b, 0x001c, 0x0078, 0x813c, 0xd6dc, 0x0040, 0x8133, 0x684b, - 0x0015, 0x0078, 0x813c, 0xd6d4, 0x0040, 0x813a, 0x684b, 0x0007, - 0x0078, 0x813c, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, - 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x815a, 0x7328, 0x732c, 0x6b56, - 0x83ff, 0x0040, 0x815a, 0xa38a, 0x0009, 0x0048, 0x8151, 0x2019, - 0x0008, 0x037e, 0x2308, 0x2019, 0xa898, 0xad90, 0x0019, 0x1078, - 0x8739, 0x037f, 0xd6cc, 0x0040, 0x817d, 0x7124, 0x695a, 0x81ff, - 0x0040, 0x817d, 0xa192, 0x0021, 0x00c8, 0x8171, 0x2071, 0xa898, - 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, 0x8739, 0x0078, - 0x817d, 0x7838, 0xd0fc, 0x0040, 0x817a, 0x2009, 0x0020, 0x695a, - 0x0078, 0x8166, 0x2d78, 0x1078, 0x86d1, 0x0d7f, 0x0e7f, 0x0f7f, - 0x077f, 0x007c, 0x0f7e, 0x6003, 0x0003, 0x2079, 0xa88c, 0x7c04, - 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, 0x7e0a, - 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x1cab, 0x1078, 0x6c26, 0x007c, - 0x0d7e, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x81a4, - 0x2001, 0xa5a2, 0x2004, 0x603e, 0x6003, 0x0002, 0x1078, 0x60b8, - 0x1078, 0x61d3, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, 0x8207, - 0xd1cc, 0x0040, 0x81de, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x81d6, - 0x017e, 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, 0xa198, - 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318, - 0x8210, 0x00f0, 0x81c5, 0x157f, 0x007f, 0x6852, 0x007f, 0x684e, - 0x017f, 0x2168, 0x1078, 0x13aa, 0x0078, 0x8201, 0x017e, 0x1078, - 0x13aa, 0x0d7f, 0x1078, 0x8726, 0x0078, 0x8201, 0x6837, 0x0103, - 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040, 0x81fd, 0xa086, - 0x0028, 0x00c0, 0x81ef, 0x684b, 0x001c, 0x0078, 0x81ff, 0xd1dc, - 0x0040, 0x81f6, 0x684b, 0x0015, 0x0078, 0x81ff, 0xd1d4, 0x0040, - 0x81fd, 0x684b, 0x0007, 0x0078, 0x81ff, 0x684b, 0x0000, 0x1078, - 0x4982, 0x1078, 0x8cc4, 0x00c0, 0x8207, 0x1078, 0x753d, 0x0d7f, - 0x007c, 0x2019, 0x0001, 0x1078, 0x6e6c, 0x6003, 0x0002, 0x2001, - 0xa5a2, 0x2004, 0x603e, 0x1078, 0x60b8, 0x1078, 0x61d3, 0x007c, - 0x1078, 0x60b8, 0x1078, 0x2813, 0x0d7e, 0x6110, 0x2168, 0x1078, - 0x8a44, 0x0040, 0x822d, 0x6837, 0x0103, 0x684b, 0x0029, 0x6847, - 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, - 0x1078, 0x61d3, 0x007c, 0x684b, 0x0015, 0xd1fc, 0x0040, 0x823f, - 0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, 0x0000, 0x6962, - 0x685e, 0x007c, 0xa182, 0x0040, 0x0079, 0x8246, 0x8259, 0x8259, - 0x8259, 0x8259, 0x8259, 0x825b, 0x8259, 0x8333, 0x833f, 0x8259, - 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, - 0x8259, 0x1078, 0x1328, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, - 0xa88c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x0f7e, 0x2c78, - 0x1078, 0x4893, 0x0f7f, 0x0040, 0x827e, 0xa684, 0x00ff, 0x00c0, - 0x827e, 0x6024, 0xd0f4, 0x00c0, 0x827a, 0x7808, 0xa086, 0x0000, - 0x00c0, 0x827e, 0x1078, 0x8cfa, 0x0078, 0x832e, 0x7e46, 0x7f4c, - 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, - 0x0040, 0x8323, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, 0x8294, - 0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, 0x8320, - 0xa686, 0x0100, 0x00c0, 0x82a6, 0x2001, 0xa899, 0x2004, 0xa005, - 0x00c0, 0x82a6, 0xc6c4, 0x7e46, 0x0078, 0x8287, 0x1078, 0x1381, - 0x1040, 0x1328, 0x2d00, 0x784a, 0x7f4c, 0xa7bd, 0x0200, 0x7f4e, - 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, - 0x6e46, 0xa68c, 0x0c00, 0x0040, 0x82c1, 0x7318, 0x6b62, 0x731c, - 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x82dd, 0xa186, - 0x0028, 0x00c0, 0x82cf, 0x684b, 0x001c, 0x0078, 0x82df, 0xd6dc, - 0x0040, 0x82d6, 0x684b, 0x0015, 0x0078, 0x82df, 0xd6d4, 0x0040, - 0x82dd, 0x684b, 0x0007, 0x0078, 0x82df, 0x684b, 0x0000, 0x6f4e, - 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x82fd, - 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0040, 0x82fd, 0xa38a, 0x0009, - 0x0048, 0x82f4, 0x2019, 0x0008, 0x037e, 0x2308, 0x2019, 0xa898, - 0xad90, 0x0019, 0x1078, 0x8739, 0x037f, 0xd6cc, 0x0040, 0x8320, - 0x7124, 0x695a, 0x81ff, 0x0040, 0x8320, 0xa192, 0x0021, 0x00c8, - 0x8314, 0x2071, 0xa898, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, - 0x1078, 0x8739, 0x0078, 0x8320, 0x7838, 0xd0fc, 0x0040, 0x831d, - 0x2009, 0x0020, 0x695a, 0x0078, 0x8309, 0x2d78, 0x1078, 0x86d1, - 0xd6dc, 0x00c0, 0x8326, 0xa006, 0x0078, 0x832c, 0x2001, 0x0001, - 0x2071, 0xa88c, 0x7218, 0x731c, 0x1078, 0x1645, 0x0d7f, 0x0e7f, - 0x0f7f, 0x077f, 0x007c, 0x2001, 0xa5a2, 0x2004, 0x603e, 0x20e1, - 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15ec, 0x007c, 0x2001, - 0xa5a2, 0x2004, 0x603e, 0x0d7e, 0x6003, 0x0002, 0x6110, 0x2168, - 0x694c, 0xd1e4, 0x0040, 0x846b, 0x603f, 0x0000, 0x0f7e, 0x2c78, - 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8385, 0x6814, 0x6910, 0xa115, - 0x0040, 0x8385, 0x6a60, 0xa206, 0x00c0, 0x8362, 0x685c, 0xa106, - 0x0040, 0x8385, 0x684c, 0xc0e4, 0x684e, 0x6847, 0x0000, 0x6863, - 0x0000, 0x685f, 0x0000, 0x6024, 0xd0f4, 0x00c0, 0x837a, 0x697c, - 0x6810, 0xa102, 0x603a, 0x6980, 0x6814, 0xa103, 0x6036, 0x6024, - 0xc0f5, 0x6026, 0x0d7e, 0x6018, 0x2068, 0x683c, 0x8000, 0x683e, - 0x0d7f, 0x1078, 0x8cfa, 0x0078, 0x846b, 0x694c, 0xd1cc, 0x0040, - 0x8430, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x83ea, 0x017e, 0x684c, - 0x007e, 0x6850, 0x007e, 0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff, - 0xa0b6, 0x0002, 0x0040, 0x83bf, 0xa086, 0x0028, 0x00c0, 0x83a6, - 0x684b, 0x001c, 0x784b, 0x001c, 0x0078, 0x83ca, 0xd1dc, 0x0040, - 0x83b6, 0x684b, 0x0015, 0x784b, 0x0015, 0x1078, 0x8ea5, 0x0040, - 0x83b4, 0x7944, 0xc1dc, 0x7946, 0x0078, 0x83ca, 0xd1d4, 0x0040, - 0x83bf, 0x684b, 0x0007, 0x784b, 0x0007, 0x0078, 0x83ca, 0x684c, - 0xd0ac, 0x0040, 0x83ca, 0x6810, 0x6914, 0xa115, 0x0040, 0x83ca, - 0x1078, 0x8233, 0x6848, 0x784a, 0x6860, 0x7862, 0x685c, 0x785e, - 0xad90, 0x000d, 0xaf98, 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, - 0x2304, 0x2012, 0x8318, 0x8210, 0x00f0, 0x83d8, 0x157f, 0x0f7f, - 0x007f, 0x6852, 0x007f, 0x684e, 0x017f, 0x2168, 0x1078, 0x13aa, - 0x0078, 0x8465, 0x017e, 0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff, - 0xa0b6, 0x0002, 0x0040, 0x8417, 0xa086, 0x0028, 0x00c0, 0x83fe, - 0x684b, 0x001c, 0x784b, 0x001c, 0x0078, 0x8422, 0xd1dc, 0x0040, - 0x840e, 0x684b, 0x0015, 0x784b, 0x0015, 0x1078, 0x8ea5, 0x0040, - 0x840c, 0x7944, 0xc1dc, 0x7946, 0x0078, 0x8422, 0xd1d4, 0x0040, - 0x8417, 0x684b, 0x0007, 0x784b, 0x0007, 0x0078, 0x8422, 0x684c, - 0xd0ac, 0x0040, 0x8422, 0x6810, 0x6914, 0xa115, 0x0040, 0x8422, - 0x1078, 0x8233, 0x6860, 0x7862, 0x685c, 0x785e, 0x684c, 0x784e, - 0x0f7f, 0x1078, 0x13aa, 0x0d7f, 0x1078, 0x8726, 0x0078, 0x8465, - 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040, - 0x8456, 0xa086, 0x0028, 0x00c0, 0x8441, 0x684b, 0x001c, 0x0078, - 0x8463, 0xd1dc, 0x0040, 0x844f, 0x684b, 0x0015, 0x1078, 0x8ea5, - 0x0040, 0x844d, 0x6944, 0xc1dc, 0x6946, 0x0078, 0x8463, 0xd1d4, - 0x0040, 0x8456, 0x684b, 0x0007, 0x0078, 0x8463, 0x684b, 0x0000, - 0x684c, 0xd0ac, 0x0040, 0x8463, 0x6810, 0x6914, 0xa115, 0x0040, - 0x8463, 0x1078, 0x8233, 0x1078, 0x4982, 0x1078, 0x8cc4, 0x00c0, - 0x846b, 0x1078, 0x753d, 0x0d7f, 0x007c, 0x1078, 0x6010, 0x0078, - 0x8473, 0x1078, 0x60b8, 0x1078, 0x8a44, 0x0040, 0x8492, 0x0d7e, - 0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0xa30c, 0x210c, 0xd18c, - 0x00c0, 0x849d, 0xd184, 0x00c0, 0x8499, 0x6108, 0x694a, 0xa18e, - 0x0029, 0x00c0, 0x848d, 0x1078, 0xa181, 0x6847, 0x0000, 0x1078, - 0x4982, 0x0d7f, 0x1078, 0x753d, 0x1078, 0x6109, 0x1078, 0x61d3, - 0x007c, 0x684b, 0x0004, 0x0078, 0x848d, 0x684b, 0x0004, 0x0078, - 0x848d, 0xa182, 0x0040, 0x0079, 0x84a5, 0x84b8, 0x84b8, 0x84b8, - 0x84b8, 0x84b8, 0x84ba, 0x84b8, 0x84bd, 0x84b8, 0x84b8, 0x84b8, - 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, - 0x1078, 0x1328, 0x1078, 0x753d, 0x007c, 0x007e, 0x027e, 0xa016, - 0x1078, 0x15ec, 0x027f, 0x007f, 0x007c, 0xa182, 0x0085, 0x0079, - 0x84c9, 0x84d2, 0x84d0, 0x84d0, 0x84de, 0x84d0, 0x84d0, 0x84d0, - 0x1078, 0x1328, 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x127e, - 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, 0x027e, 0x057e, - 0x0d7e, 0x0e7e, 0x2071, 0xa880, 0x7224, 0x6212, 0x7220, 0x1078, - 0x8a30, 0x0040, 0x8503, 0x2268, 0x6800, 0xa086, 0x0000, 0x0040, - 0x8503, 0x6018, 0x6d18, 0xa52e, 0x00c0, 0x8503, 0x0c7e, 0x2d60, - 0x1078, 0x874a, 0x0c7f, 0x0040, 0x8503, 0x6803, 0x0002, 0x6007, - 0x0086, 0x0078, 0x8505, 0x6007, 0x0087, 0x6003, 0x0001, 0x1078, - 0x5bf8, 0x1078, 0x6109, 0x0f7e, 0x2278, 0x1078, 0x4893, 0x0f7f, - 0x0040, 0x851d, 0x6824, 0xd0ec, 0x0040, 0x851d, 0x0c7e, 0x2260, - 0x603f, 0x0000, 0x1078, 0x8cfa, 0x0c7f, 0x0e7f, 0x0d7f, 0x057f, - 0x027f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x8533, 0x6004, 0xa08a, - 0x0085, 0x1048, 0x1328, 0xa08a, 0x008c, 0x10c8, 0x1328, 0xa082, - 0x0085, 0x0079, 0x8542, 0xa186, 0x0027, 0x0040, 0x853b, 0xa186, - 0x0014, 0x10c0, 0x1328, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, - 0x6109, 0x007c, 0x8549, 0x854b, 0x854b, 0x8549, 0x8549, 0x8549, - 0x8549, 0x1078, 0x1328, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, - 0x6109, 0x007c, 0xa186, 0x0013, 0x00c0, 0x855c, 0x6004, 0xa082, - 0x0085, 0x2008, 0x0078, 0x8597, 0xa186, 0x0027, 0x00c0, 0x857f, - 0x1078, 0x6010, 0x1078, 0x2813, 0x0d7e, 0x6010, 0x2068, 0x1078, - 0x8a44, 0x0040, 0x8575, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, - 0x0029, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, - 0x1078, 0x6109, 0x007c, 0x1078, 0x7583, 0x0078, 0x857a, 0xa186, - 0x0014, 0x00c0, 0x857b, 0x1078, 0x6010, 0x0d7e, 0x6010, 0x2068, - 0x1078, 0x8a44, 0x0040, 0x8575, 0x6837, 0x0103, 0x6847, 0x0000, - 0x684b, 0x0006, 0x6850, 0xc0ec, 0x6852, 0x0078, 0x8571, 0x0079, - 0x8599, 0x85a2, 0x85a0, 0x85a0, 0x85a0, 0x85a0, 0x85a0, 0x85bd, - 0x1078, 0x1328, 0x1078, 0x6010, 0x6030, 0xa08c, 0xff00, 0x810f, - 0xa186, 0x0039, 0x0040, 0x85b0, 0xa186, 0x0035, 0x00c0, 0x85b4, - 0x2001, 0xa5a0, 0x0078, 0x85b6, 0x2001, 0xa5a1, 0x2004, 0x6016, - 0x6003, 0x000c, 0x1078, 0x6109, 0x007c, 0x1078, 0x6010, 0x6030, - 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0040, 0x85cb, 0xa186, - 0x0035, 0x00c0, 0x85cf, 0x2001, 0xa5a0, 0x0078, 0x85d1, 0x2001, - 0xa5a1, 0x2004, 0x6016, 0x6003, 0x000e, 0x1078, 0x6109, 0x007c, - 0xa182, 0x008c, 0x00c8, 0x85e2, 0xa182, 0x0085, 0x0048, 0x85e2, - 0x0079, 0x85e5, 0x1078, 0x7583, 0x007c, 0x85ec, 0x85ec, 0x85ec, - 0x85ec, 0x85ee, 0x8643, 0x85ec, 0x1078, 0x1328, 0x0f7e, 0x2c78, - 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8601, 0x6030, 0xa08c, 0xff00, - 0x810f, 0xa186, 0x0039, 0x0040, 0x865a, 0xa186, 0x0035, 0x0040, - 0x865a, 0x0d7e, 0x1078, 0x8bf4, 0x1078, 0x8a44, 0x0040, 0x8625, - 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, 0x8616, - 0x684b, 0x0006, 0xc0ec, 0x6852, 0x0078, 0x8621, 0xd0bc, 0x0040, - 0x861d, 0x684b, 0x0002, 0x0078, 0x8621, 0x684b, 0x0005, 0x1078, - 0x8cc0, 0x6847, 0x0000, 0x1078, 0x4982, 0x2c68, 0x1078, 0x74d7, - 0x0040, 0x863e, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0xa88e, - 0x210c, 0x6136, 0x2009, 0xa88f, 0x210c, 0x613a, 0x6918, 0x611a, - 0x6920, 0x6122, 0x601f, 0x0001, 0x1078, 0x5bf8, 0x2d60, 0x1078, - 0x753d, 0x0d7f, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, - 0x0040, 0x8680, 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0035, - 0x0040, 0x865a, 0xa186, 0x001e, 0x0040, 0x865a, 0xa186, 0x0039, - 0x00c0, 0x8680, 0x0d7e, 0x2c68, 0x1078, 0x8ef5, 0x00c0, 0x86a4, - 0x1078, 0x74d7, 0x0040, 0x867d, 0x6106, 0x6003, 0x0001, 0x601f, - 0x0001, 0x6918, 0x611a, 0x6928, 0x612a, 0x692c, 0x612e, 0x6930, - 0xa18c, 0x00ff, 0x6132, 0x6934, 0x6136, 0x6938, 0x613a, 0x6920, - 0x6122, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x2d60, 0x0078, 0x86a4, - 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x86a4, 0x6837, - 0x0103, 0x6850, 0xd0b4, 0x0040, 0x8693, 0xc0ec, 0x6852, 0x684b, - 0x0006, 0x0078, 0x869e, 0xd0bc, 0x0040, 0x869a, 0x684b, 0x0002, - 0x0078, 0x869e, 0x684b, 0x0005, 0x1078, 0x8cc0, 0x6847, 0x0000, - 0x1078, 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, 0x007c, - 0x017e, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x86b8, - 0x6837, 0x0103, 0x684b, 0x0028, 0x6847, 0x0000, 0x1078, 0x4982, - 0x0d7f, 0x017f, 0xa186, 0x0013, 0x0040, 0x86ca, 0xa186, 0x0014, - 0x0040, 0x86ca, 0xa186, 0x0027, 0x0040, 0x86ca, 0x1078, 0x7583, - 0x0078, 0x86d0, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, - 0x007c, 0x057e, 0x067e, 0x0d7e, 0x0f7e, 0x2029, 0x0001, 0xa182, - 0x0101, 0x00c8, 0x86dd, 0x0078, 0x86df, 0x2009, 0x0100, 0x2130, - 0x2069, 0xa898, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, - 0x001d, 0x1078, 0x8739, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0040, - 0x86f3, 0x1078, 0x13aa, 0x1078, 0x1381, 0x0040, 0x871d, 0x8528, - 0x6837, 0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, - 0x00c8, 0x8709, 0x2608, 0xad90, 0x000f, 0x1078, 0x8739, 0x0078, - 0x871d, 0xa6b2, 0x003c, 0x2009, 0x003c, 0x2d78, 0xad90, 0x000f, - 0x1078, 0x8739, 0x0078, 0x86f3, 0x0f7f, 0x852f, 0xa5ad, 0x0003, - 0x7d36, 0xa5ac, 0x0000, 0x0078, 0x8722, 0x0f7f, 0x852f, 0xa5ad, - 0x0003, 0x7d36, 0x0d7f, 0x067f, 0x057f, 0x007c, 0x0f7e, 0x8dff, - 0x0040, 0x8737, 0x6804, 0xa07d, 0x0040, 0x8735, 0x6807, 0x0000, - 0x1078, 0x4982, 0x2f68, 0x0078, 0x872a, 0x1078, 0x4982, 0x0f7f, - 0x007c, 0x157e, 0xa184, 0x0001, 0x0040, 0x873f, 0x8108, 0x810c, - 0x21a8, 0x2304, 0x8007, 0x2012, 0x8318, 0x8210, 0x00f0, 0x8741, - 0x157f, 0x007c, 0x067e, 0x127e, 0x2091, 0x8000, 0x2031, 0x0001, - 0x601c, 0xa084, 0x000f, 0x1079, 0x8766, 0x127f, 0x067f, 0x007c, - 0x127e, 0x2091, 0x8000, 0x067e, 0x2031, 0x0000, 0x601c, 0xa084, - 0x000f, 0x1079, 0x8766, 0x067f, 0x127f, 0x007c, 0x8780, 0x876e, - 0x877b, 0x879c, 0x876e, 0x877b, 0x879c, 0x877b, 0x1078, 0x1328, - 0x037e, 0x2019, 0x0010, 0x1078, 0x9a6a, 0x601f, 0x0006, 0x6003, - 0x0007, 0x037f, 0x007c, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, - 0x0d7e, 0x86ff, 0x00c0, 0x8797, 0x6010, 0x2068, 0x1078, 0x8a44, - 0x0040, 0x8799, 0xa00e, 0x2001, 0x0005, 0x1078, 0x4a60, 0x1078, - 0x8cc0, 0x1078, 0x4982, 0x1078, 0x753d, 0xa085, 0x0001, 0x0d7f, - 0x007c, 0xa006, 0x0078, 0x8797, 0x6000, 0xa08a, 0x0010, 0x10c8, - 0x1328, 0x1079, 0x87a4, 0x007c, 0x87b4, 0x87d4, 0x87b6, 0x87f7, - 0x87d0, 0x87b4, 0x877b, 0x8780, 0x8780, 0x877b, 0x877b, 0x877b, - 0x877b, 0x877b, 0x877b, 0x877b, 0x1078, 0x1328, 0x86ff, 0x00c0, - 0x87cd, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x87c2, - 0x1078, 0x8cc0, 0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, - 0x0002, 0x1078, 0x5bf8, 0x1078, 0x6109, 0xa085, 0x0001, 0x007c, - 0x1078, 0x1749, 0x0078, 0x87b6, 0x0e7e, 0x2071, 0xa5ab, 0x7024, - 0xac06, 0x00c0, 0x87dd, 0x1078, 0x6dda, 0x601c, 0xa084, 0x000f, - 0xa086, 0x0006, 0x00c0, 0x87ef, 0x087e, 0x097e, 0x2049, 0x0001, - 0x2c40, 0x1078, 0x7058, 0x097f, 0x087f, 0x0078, 0x87f1, 0x1078, - 0x6cd2, 0x0e7f, 0x00c0, 0x87b6, 0x1078, 0x877b, 0x007c, 0x037e, - 0x0e7e, 0x2071, 0xa5ab, 0x703c, 0xac06, 0x00c0, 0x8807, 0x2019, - 0x0000, 0x1078, 0x6e6c, 0x0e7f, 0x037f, 0x0078, 0x87b6, 0x1078, - 0x719a, 0x0e7f, 0x037f, 0x00c0, 0x87b6, 0x1078, 0x877b, 0x007c, - 0x0c7e, 0x601c, 0xa084, 0x000f, 0x1079, 0x8818, 0x0c7f, 0x007c, - 0x8827, 0x8895, 0x89cd, 0x8832, 0x8c01, 0x8827, 0x9a5b, 0x753d, - 0x8895, 0x1078, 0x8c3b, 0x00c0, 0x8827, 0x1078, 0x7a05, 0x007c, - 0x1078, 0x6010, 0x1078, 0x6109, 0x1078, 0x753d, 0x007c, 0x6017, - 0x0001, 0x007c, 0x6010, 0xa080, 0x0019, 0x2c02, 0x6000, 0xa08a, - 0x0010, 0x10c8, 0x1328, 0x1079, 0x883e, 0x007c, 0x884e, 0x8850, - 0x8872, 0x8884, 0x8891, 0x884e, 0x8827, 0x8827, 0x8827, 0x8884, - 0x8884, 0x884e, 0x884e, 0x884e, 0x884e, 0x888e, 0x1078, 0x1328, - 0x0e7e, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0xa5ab, - 0x7024, 0xac06, 0x0040, 0x886e, 0x1078, 0x6cd2, 0x6007, 0x0085, - 0x6003, 0x000b, 0x601f, 0x0002, 0x2001, 0xa5a1, 0x2004, 0x6016, - 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0e7f, 0x007c, 0x6017, 0x0001, - 0x0078, 0x886c, 0x0d7e, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, - 0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x1078, - 0x5bf8, 0x1078, 0x6109, 0x007c, 0x0d7e, 0x6017, 0x0001, 0x6010, - 0x2068, 0x6850, 0xc0b5, 0x6852, 0x0d7f, 0x007c, 0x1078, 0x753d, - 0x007c, 0x1078, 0x1749, 0x0078, 0x8872, 0x6000, 0xa08a, 0x0010, - 0x10c8, 0x1328, 0x1079, 0x889d, 0x007c, 0x88ad, 0x882f, 0x88af, - 0x88ad, 0x88af, 0x88af, 0x8828, 0x88ad, 0x8821, 0x8821, 0x88ad, - 0x88ad, 0x88ad, 0x88ad, 0x88ad, 0x88ad, 0x1078, 0x1328, 0x0d7e, - 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, 0xa08a, 0x000c, - 0x10c8, 0x1328, 0x1079, 0x88bd, 0x007c, 0x88c9, 0x8971, 0x88cb, - 0x890b, 0x88cb, 0x890b, 0x88cb, 0x88d8, 0x88c9, 0x890b, 0x88c9, - 0x88f5, 0x1078, 0x1328, 0x6004, 0xa08e, 0x0016, 0x0040, 0x8906, - 0xa08e, 0x0004, 0x0040, 0x8906, 0xa08e, 0x0002, 0x0040, 0x8906, - 0x6004, 0x1078, 0x8c3b, 0x0040, 0x898c, 0xa08e, 0x0021, 0x0040, - 0x8990, 0xa08e, 0x0022, 0x0040, 0x898c, 0xa08e, 0x003d, 0x0040, - 0x8990, 0xa08e, 0x0039, 0x0040, 0x8994, 0xa08e, 0x0035, 0x0040, - 0x8994, 0xa08e, 0x001e, 0x0040, 0x8908, 0xa08e, 0x0001, 0x00c0, - 0x8904, 0x0d7e, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, - 0xa086, 0x0006, 0x0040, 0x8906, 0x1078, 0x2813, 0x1078, 0x7a05, - 0x1078, 0x8c01, 0x007c, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, - 0x0040, 0x8961, 0xa186, 0x0002, 0x00c0, 0x8934, 0x6018, 0x2068, - 0x68a0, 0xd0bc, 0x00c0, 0x89b8, 0x6840, 0xa084, 0x00ff, 0xa005, - 0x0040, 0x8934, 0x8001, 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, - 0x6017, 0x0398, 0x1078, 0x74d7, 0x0040, 0x8934, 0x2d00, 0x601a, - 0x601f, 0x0001, 0x0078, 0x8961, 0x0d7f, 0x0c7f, 0x6004, 0xa08e, - 0x0002, 0x00c0, 0x8952, 0x6018, 0xa080, 0x0028, 0x2004, 0xa086, - 0x007e, 0x00c0, 0x8952, 0x2009, 0xa332, 0x2104, 0xc085, 0x200a, - 0x0e7e, 0x2071, 0xa300, 0x1078, 0x41f5, 0x0e7f, 0x1078, 0x7a05, - 0x0078, 0x8956, 0x1078, 0x7a05, 0x1078, 0x2813, 0x0e7e, 0x127e, - 0x2091, 0x8000, 0x1078, 0x2839, 0x127f, 0x0e7f, 0x1078, 0x8c01, - 0x007c, 0x2001, 0x0002, 0x1078, 0x443f, 0x6003, 0x0001, 0x6007, - 0x0002, 0x1078, 0x5c45, 0x1078, 0x6109, 0x0d7f, 0x0c7f, 0x0078, - 0x8960, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, 0x0040, 0x8961, - 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x8934, - 0x8001, 0x6842, 0x6003, 0x0001, 0x1078, 0x5c45, 0x1078, 0x6109, - 0x0d7f, 0x0c7f, 0x0078, 0x8960, 0x1078, 0x7a05, 0x0078, 0x8908, - 0x1078, 0x7a28, 0x0078, 0x8908, 0x0d7e, 0x2c68, 0x6104, 0x1078, - 0x8ef5, 0x0d7f, 0x0040, 0x89a0, 0x1078, 0x753d, 0x0078, 0x89b7, - 0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105, 0x6032, 0x6007, - 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038, 0x600a, 0x2001, - 0xa5a1, 0x2004, 0x6016, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x007c, - 0x0d7f, 0x0c7f, 0x1078, 0x7a05, 0x1078, 0x2813, 0x0e7e, 0x127e, - 0x2091, 0x8000, 0x1078, 0x2839, 0x6013, 0x0000, 0x601f, 0x0007, - 0x6017, 0x0398, 0x127f, 0x0e7f, 0x007c, 0x6000, 0xa08a, 0x0010, - 0x10c8, 0x1328, 0x1079, 0x89d5, 0x007c, 0x89e5, 0x89e5, 0x89e5, - 0x89e5, 0x89e5, 0x89e5, 0x89e5, 0x89e5, 0x89e5, 0x8827, 0x89e5, - 0x882f, 0x89e7, 0x882f, 0x89f5, 0x89e5, 0x1078, 0x1328, 0x6004, - 0xa086, 0x008b, 0x0040, 0x89f5, 0x6007, 0x008b, 0x6003, 0x000d, - 0x1078, 0x5bf8, 0x1078, 0x6109, 0x007c, 0x1078, 0x8bf4, 0x1078, - 0x8a44, 0x0040, 0x8a2d, 0x1078, 0x2813, 0x0d7e, 0x1078, 0x8a44, - 0x0040, 0x8a0f, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006, - 0x6847, 0x0000, 0x6850, 0xc0ed, 0x6852, 0x1078, 0x4982, 0x2c68, - 0x1078, 0x74d7, 0x0040, 0x8a1d, 0x6818, 0x601a, 0x0c7e, 0x2d60, - 0x1078, 0x8c01, 0x0c7f, 0x0078, 0x8a1e, 0x2d60, 0x0d7f, 0x6013, - 0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, - 0x5c45, 0x1078, 0x6109, 0x0078, 0x8a2f, 0x1078, 0x8c01, 0x007c, - 0xa284, 0x000f, 0x00c0, 0x8a41, 0xa282, 0xaa00, 0x0048, 0x8a41, - 0x2001, 0xa315, 0x2004, 0xa202, 0x00c8, 0x8a41, 0xa085, 0x0001, - 0x007c, 0xa006, 0x0078, 0x8a40, 0x027e, 0x0e7e, 0x2071, 0xa300, - 0x6210, 0x7058, 0xa202, 0x0048, 0x8a56, 0x705c, 0xa202, 0x00c8, - 0x8a56, 0xa085, 0x0001, 0x0e7f, 0x027f, 0x007c, 0xa006, 0x0078, - 0x8a53, 0x0e7e, 0x0c7e, 0x037e, 0x007e, 0x127e, 0x2091, 0x8000, - 0x2061, 0xaa00, 0x2071, 0xa300, 0x7344, 0x7060, 0xa302, 0x00c8, - 0x8a83, 0x601c, 0xa206, 0x00c0, 0x8a7b, 0x1078, 0x8d66, 0x0040, - 0x8a7b, 0x1078, 0x8c3b, 0x00c0, 0x8a77, 0x1078, 0x7a05, 0x0c7e, - 0x1078, 0x753d, 0x0c7f, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, - 0x8a83, 0x0078, 0x8a64, 0x127f, 0x007f, 0x037f, 0x0c7f, 0x0e7f, - 0x007c, 0x0e7e, 0x0c7e, 0x017e, 0xa188, 0xa434, 0x210c, 0x81ff, - 0x0040, 0x8aa1, 0x2061, 0xaa00, 0x2071, 0xa300, 0x017e, 0x1078, - 0x74d7, 0x017f, 0x0040, 0x8aa4, 0x611a, 0x1078, 0x2813, 0x1078, - 0x753d, 0xa006, 0x0078, 0x8aa6, 0xa085, 0x0001, 0x017f, 0x0c7f, - 0x0e7f, 0x007c, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x0c7e, - 0x1078, 0x74d7, 0x057f, 0x0040, 0x8ac3, 0x6612, 0x651a, 0x601f, - 0x0003, 0x2009, 0x004b, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, - 0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8abf, 0x0c7e, 0x057e, - 0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x74d7, 0x057f, - 0x0040, 0x8af1, 0x6013, 0x0000, 0x651a, 0x601f, 0x0003, 0x0c7e, - 0x2560, 0x1078, 0x471b, 0x0c7f, 0x1078, 0x5d53, 0x077e, 0x2039, - 0x0000, 0x1078, 0x5c78, 0x2c08, 0x1078, 0x9c38, 0x077f, 0x2009, - 0x004c, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f, - 0x007c, 0xa006, 0x0078, 0x8aed, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, - 0x1078, 0x74d7, 0x2c78, 0x0c7f, 0x0040, 0x8b0e, 0x7e12, 0x2c00, - 0x781a, 0x781f, 0x0003, 0x2021, 0x0005, 0x1078, 0x8b4e, 0x2f60, - 0x2009, 0x004d, 0x1078, 0x756c, 0xa085, 0x0001, 0x047f, 0x0c7f, - 0x0f7f, 0x007c, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x74d7, - 0x2c78, 0x0c7f, 0x0040, 0x8b2c, 0x7e12, 0x2c00, 0x781a, 0x781f, - 0x0003, 0x2021, 0x0005, 0x1078, 0x8b4e, 0x2f60, 0x2009, 0x004e, - 0x1078, 0x756c, 0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f, 0x007c, - 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x74d7, 0x2c78, 0x0c7f, - 0x0040, 0x8b4a, 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, - 0x0004, 0x1078, 0x8b4e, 0x2f60, 0x2009, 0x0052, 0x1078, 0x756c, - 0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f, 0x007c, 0x097e, 0x077e, - 0x127e, 0x2091, 0x8000, 0x1078, 0x46a7, 0x0040, 0x8b5b, 0x2001, - 0x8b53, 0x0078, 0x8b61, 0x1078, 0x466d, 0x0040, 0x8b6a, 0x2001, - 0x8b5b, 0x007e, 0xa00e, 0x2400, 0x1078, 0x4a60, 0x1078, 0x4982, - 0x007f, 0x007a, 0x2418, 0x1078, 0x5fa7, 0x62a0, 0x087e, 0x2041, - 0x0001, 0x2039, 0x0001, 0x2608, 0x1078, 0x5d6d, 0x087f, 0x1078, - 0x5c78, 0x2f08, 0x2648, 0x1078, 0x9c38, 0x613c, 0x81ff, 0x1040, - 0x5e21, 0x127f, 0x077f, 0x097f, 0x007c, 0x0c7e, 0x127e, 0x2091, - 0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8b9e, 0x660a, - 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x001f, 0x1078, - 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, - 0x8b9b, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x74d7, - 0x017f, 0x0040, 0x8bba, 0x660a, 0x611a, 0x601f, 0x0008, 0x2d00, - 0x6012, 0x2009, 0x0021, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, - 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8bb7, 0x0c7e, 0x127e, 0x2091, - 0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8bd6, 0x660a, - 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x003d, 0x1078, - 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, - 0x8bd3, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x74d7, - 0x017f, 0x0040, 0x8bf1, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, - 0x2009, 0x0000, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, - 0x007c, 0xa006, 0x0078, 0x8bee, 0x027e, 0x0d7e, 0x6218, 0x2268, - 0x6a3c, 0x82ff, 0x0040, 0x8bfe, 0x8211, 0x6a3e, 0x0d7f, 0x027f, - 0x007c, 0x007e, 0x6000, 0xa086, 0x0000, 0x0040, 0x8c13, 0x6013, - 0x0000, 0x601f, 0x0007, 0x2001, 0xa5a1, 0x2004, 0x6016, 0x1078, - 0xa134, 0x603f, 0x0000, 0x007f, 0x007c, 0x067e, 0x0c7e, 0x0d7e, - 0x2031, 0xa352, 0x2634, 0xd6e4, 0x0040, 0x8c23, 0x6618, 0x2660, - 0x6e48, 0x1078, 0x461b, 0x0d7f, 0x0c7f, 0x067f, 0x007c, 0x007e, - 0x017e, 0x6004, 0xa08e, 0x0002, 0x0040, 0x8c38, 0xa08e, 0x0003, - 0x0040, 0x8c38, 0xa08e, 0x0004, 0x0040, 0x8c38, 0xa085, 0x0001, - 0x017f, 0x007f, 0x007c, 0x007e, 0x0d7e, 0x6010, 0xa06d, 0x0040, - 0x8c48, 0x6838, 0xd0fc, 0x0040, 0x8c48, 0xa006, 0x0078, 0x8c4a, - 0xa085, 0x0001, 0x0d7f, 0x007f, 0x007c, 0x0c7e, 0x127e, 0x2091, - 0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8c67, 0x611a, - 0x601f, 0x0001, 0x2d00, 0x6012, 0x1078, 0x2813, 0x2009, 0x0028, - 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, - 0x0078, 0x8c64, 0xa186, 0x0015, 0x00c0, 0x8c7f, 0x2011, 0xa31f, - 0x2204, 0xa086, 0x0074, 0x00c0, 0x8c7f, 0x1078, 0x7d0d, 0x6003, - 0x0001, 0x6007, 0x0029, 0x1078, 0x5c45, 0x0078, 0x8c83, 0x1078, - 0x7a05, 0x1078, 0x753d, 0x007c, 0xa186, 0x0016, 0x00c0, 0x8c8e, - 0x2001, 0x0004, 0x1078, 0x443f, 0x0078, 0x8caf, 0xa186, 0x0015, - 0x00c0, 0x8cb3, 0x2011, 0xa31f, 0x2204, 0xa086, 0x0014, 0x00c0, - 0x8cb3, 0x0d7e, 0x6018, 0x2068, 0x1078, 0x457d, 0x0d7f, 0x1078, - 0x7dba, 0x00c0, 0x8cb3, 0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f, - 0xa005, 0x0040, 0x8cb3, 0x2001, 0x0006, 0x1078, 0x443f, 0x1078, - 0x7608, 0x0078, 0x8cb7, 0x1078, 0x7a05, 0x1078, 0x753d, 0x007c, - 0x6848, 0xa086, 0x0005, 0x00c0, 0x8cbf, 0x1078, 0x8cc0, 0x007c, - 0x6850, 0xc0ad, 0x6852, 0x007c, 0x0e7e, 0x2071, 0xa88c, 0x7014, - 0xd0e4, 0x0040, 0x8cd5, 0x6013, 0x0000, 0x6003, 0x0001, 0x6007, - 0x0050, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0e7f, 0x007c, 0x0c7e, - 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8ce4, 0x601c, - 0xa084, 0x000f, 0x1079, 0x8ce6, 0x0c7f, 0x007c, 0x8827, 0x8cf1, - 0x8cf4, 0x8cf7, 0x9f00, 0x9f1c, 0x9f1f, 0x8827, 0x8827, 0x1078, - 0x1328, 0x0005, 0x0005, 0x007c, 0x0005, 0x0005, 0x007c, 0x1078, - 0x8cfa, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0040, 0x8d29, - 0x1078, 0x74d7, 0x00c0, 0x8d0a, 0x2001, 0xa5a2, 0x2004, 0x783e, - 0x0078, 0x8d29, 0x7818, 0x601a, 0x781c, 0xa086, 0x0003, 0x0040, - 0x8d17, 0x7808, 0x6036, 0x2f00, 0x603a, 0x0078, 0x8d1b, 0x7808, - 0x603a, 0x2f00, 0x6036, 0x602a, 0x601f, 0x0001, 0x6007, 0x0035, - 0x6003, 0x0001, 0x7920, 0x6122, 0x1078, 0x5bf8, 0x1078, 0x6109, - 0x2f60, 0x0f7f, 0x007c, 0x017e, 0x0f7e, 0x682c, 0x6032, 0xa08e, - 0x0001, 0x0040, 0x8d3c, 0xa086, 0x0005, 0x0040, 0x8d40, 0xa006, - 0x602a, 0x602e, 0x0078, 0x8d51, 0x6824, 0xc0f4, 0xc0d5, 0x6826, - 0x6810, 0x2078, 0x787c, 0x6938, 0xa102, 0x7880, 0x6934, 0xa103, - 0x00c8, 0x8d37, 0x6834, 0x602a, 0x6838, 0xa084, 0xfffc, 0x683a, - 0x602e, 0x2d00, 0x6036, 0x6808, 0x603a, 0x6918, 0x611a, 0x6920, - 0x6122, 0x601f, 0x0001, 0x6007, 0x0039, 0x6003, 0x0001, 0x1078, - 0x5bf8, 0x6803, 0x0002, 0x0f7f, 0x017f, 0x007c, 0x007e, 0x017e, - 0x6004, 0xa08e, 0x0034, 0x0040, 0x8d8b, 0xa08e, 0x0035, 0x0040, - 0x8d8b, 0xa08e, 0x0036, 0x0040, 0x8d8b, 0xa08e, 0x0037, 0x0040, - 0x8d8b, 0xa08e, 0x0038, 0x0040, 0x8d8b, 0xa08e, 0x0039, 0x0040, - 0x8d8b, 0xa08e, 0x003a, 0x0040, 0x8d8b, 0xa08e, 0x003b, 0x0040, - 0x8d8b, 0xa085, 0x0001, 0x017f, 0x007f, 0x007c, 0x0f7e, 0x2c78, - 0x1078, 0x4893, 0x00c0, 0x8d98, 0xa085, 0x0001, 0x0078, 0x8da7, - 0x6024, 0xd0f4, 0x00c0, 0x8da6, 0xc0f5, 0x6026, 0x6010, 0x2078, - 0x7828, 0x603a, 0x782c, 0x6036, 0x1078, 0x1749, 0xa006, 0x0f7f, - 0x007c, 0x007e, 0x017e, 0x027e, 0x037e, 0x0e7e, 0x2001, 0xa59c, - 0x200c, 0x8000, 0x2014, 0x2001, 0x0032, 0x1078, 0x5a98, 0x2001, - 0xa5a0, 0x82ff, 0x00c0, 0x8dbe, 0x2011, 0x0002, 0x2202, 0x2001, - 0xa59e, 0x200c, 0x8000, 0x2014, 0x2071, 0xa58c, 0x711a, 0x721e, - 0x2001, 0x0064, 0x1078, 0x5a98, 0x2001, 0xa5a1, 0x82ff, 0x00c0, - 0x8dd3, 0x2011, 0x0002, 0x2202, 0x2009, 0xa5a2, 0xa280, 0x000a, - 0x200a, 0x0e7f, 0x037f, 0x027f, 0x017f, 0x007f, 0x007c, 0x007e, - 0x0e7e, 0x2001, 0xa5a0, 0x2003, 0x0028, 0x2001, 0xa5a1, 0x2003, - 0x0014, 0x2071, 0xa58c, 0x701b, 0x0000, 0x701f, 0x07d0, 0x2001, - 0xa5a2, 0x2003, 0x001e, 0x0e7f, 0x007f, 0x007c, 0x0c7e, 0x127e, - 0x2091, 0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8e0e, - 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0033, 0x1078, - 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, - 0x8e0b, 0x0d7e, 0x0e7e, 0x0f7e, 0x2071, 0xa300, 0xa186, 0x0015, - 0x00c0, 0x8e40, 0x707c, 0xa086, 0x0018, 0x00c0, 0x8e40, 0x6010, - 0x2068, 0x6a3c, 0xd2e4, 0x00c0, 0x8e34, 0x2c78, 0x1078, 0x62c6, - 0x0040, 0x8e48, 0x7068, 0x6a50, 0xa206, 0x00c0, 0x8e3c, 0x706c, - 0x6a54, 0xa206, 0x00c0, 0x8e3c, 0x6218, 0xa290, 0x0028, 0x2214, - 0x2009, 0x0000, 0x1078, 0x285b, 0x1078, 0x7608, 0x0078, 0x8e44, - 0x1078, 0x7a05, 0x1078, 0x753d, 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, - 0x704c, 0xa080, 0x293f, 0x2004, 0x6a54, 0xa206, 0x0040, 0x8e34, - 0x0078, 0x8e3c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, - 0x74d7, 0x017f, 0x0040, 0x8e6a, 0x611a, 0x601f, 0x0001, 0x2d00, - 0x6012, 0x2009, 0x0043, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, - 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8e67, 0x0d7e, 0x0e7e, 0x0f7e, - 0x2071, 0xa300, 0xa186, 0x0015, 0x00c0, 0x8e93, 0x707c, 0xa086, - 0x0004, 0x00c0, 0x8e93, 0x6010, 0xa0e8, 0x000f, 0x2c78, 0x1078, - 0x62c6, 0x0040, 0x8e9b, 0x7068, 0x6a08, 0xa206, 0x00c0, 0x8e8f, - 0x706c, 0x6a0c, 0xa206, 0x00c0, 0x8e8f, 0x1078, 0x2813, 0x1078, - 0x7608, 0x0078, 0x8e97, 0x1078, 0x7a05, 0x1078, 0x753d, 0x0f7f, - 0x0e7f, 0x0d7f, 0x007c, 0x704c, 0xa080, 0x293f, 0x2004, 0x6a0c, - 0xa206, 0x0040, 0x8e8d, 0x0078, 0x8e8f, 0x017e, 0x027e, 0x684c, - 0xd0ac, 0x0040, 0x8ebd, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0040, - 0x8ebd, 0x6860, 0xa106, 0x00c0, 0x8eb9, 0x685c, 0xa206, 0x0040, - 0x8ebd, 0x6962, 0x6a5e, 0xa085, 0x0001, 0x027f, 0x017f, 0x007c, - 0x0e7e, 0x127e, 0x2071, 0xa300, 0x2091, 0x8000, 0x7544, 0xa582, - 0x0001, 0x0048, 0x8ef2, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, - 0x0040, 0x8ede, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, 0x8eda, - 0x0078, 0x8ecd, 0x2061, 0xaa00, 0x0078, 0x8ecd, 0x6003, 0x0008, - 0x8529, 0x7546, 0xaca8, 0x0010, 0x7054, 0xa502, 0x00c8, 0x8eee, - 0x754a, 0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704b, 0xaa00, - 0x0078, 0x8ee9, 0xa006, 0x0078, 0x8eeb, 0x0c7e, 0x027e, 0x017e, - 0xa186, 0x0035, 0x0040, 0x8eff, 0x6a34, 0x0078, 0x8f00, 0x6a28, - 0x1078, 0x8a30, 0x0040, 0x8f29, 0x2260, 0x611c, 0xa186, 0x0003, - 0x0040, 0x8f0e, 0xa186, 0x0006, 0x00c0, 0x8f25, 0x6834, 0xa206, - 0x0040, 0x8f1d, 0x6838, 0xa206, 0x00c0, 0x8f25, 0x6108, 0x6834, - 0xa106, 0x00c0, 0x8f25, 0x0078, 0x8f22, 0x6008, 0x6938, 0xa106, - 0x00c0, 0x8f25, 0x6018, 0x6918, 0xa106, 0x017f, 0x027f, 0x0c7f, - 0x007c, 0xa085, 0x0001, 0x0078, 0x8f25, 0x067e, 0x6000, 0xa0b2, - 0x0010, 0x10c8, 0x1328, 0x1079, 0x8f37, 0x067f, 0x007c, 0x8f47, - 0x93bb, 0x94d3, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f81, - 0x955e, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x1078, - 0x1328, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1328, 0x1079, - 0x8f53, 0x067f, 0x007c, 0x8f63, 0x99f6, 0x8f63, 0x8f63, 0x8f63, - 0x8f63, 0x8f63, 0x8f63, 0x99b4, 0x9a44, 0x8f63, 0xa053, 0xa087, - 0xa053, 0xa087, 0x8f63, 0x1078, 0x1328, 0x067e, 0x6000, 0xa0b2, - 0x0010, 0x10c8, 0x1328, 0x1079, 0x8f6f, 0x067f, 0x007c, 0x8f7f, - 0x969f, 0x976a, 0x9798, 0x9813, 0x8f7f, 0x9919, 0x98c1, 0x956a, - 0x9988, 0x999e, 0x8f7f, 0x8f7f, 0x8f7f, 0x8f7f, 0x8f7f, 0x1078, - 0x1328, 0xa1b2, 0x0044, 0x10c8, 0x1328, 0x2100, 0x0079, 0x8f88, - 0x8fc8, 0x919a, 0x8fc8, 0x8fc8, 0x8fc8, 0x91a2, 0x8fc8, 0x8fc8, - 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, - 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fca, - 0x902d, 0x9038, 0x9081, 0x909c, 0x911b, 0x918b, 0x8fc8, 0x8fc8, - 0x91a6, 0x8fc8, 0x8fc8, 0x91b5, 0x91bc, 0x8fc8, 0x8fc8, 0x8fc8, - 0x8fc8, 0x8fc8, 0x91ea, 0x8fc8, 0x8fc8, 0x91f5, 0x8fc8, 0x8fc8, - 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x920a, 0x8fc8, 0x8fc8, 0x8fc8, - 0x9291, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x9305, - 0x1078, 0x1328, 0x1078, 0x4897, 0x00c0, 0x8fd7, 0x2001, 0xa332, - 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, 0x00c0, 0x8fdf, 0x6007, - 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0078, 0x9195, 0x1078, - 0x4887, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x6218, 0x2270, - 0x72a0, 0x027e, 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, - 0x0000, 0x1078, 0x5c78, 0x2c08, 0x1078, 0x9c38, 0x077f, 0x017f, - 0x2e60, 0x1078, 0x471b, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, - 0x6618, 0x0c7e, 0x2660, 0x1078, 0x4513, 0x0c7f, 0xa6b0, 0x0001, - 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x901f, 0x1078, - 0x9b6c, 0x00c0, 0x907b, 0x1078, 0x9afd, 0x00c0, 0x901b, 0x6007, - 0x0008, 0x0078, 0x9195, 0x6007, 0x0009, 0x0078, 0x9195, 0x1078, - 0x9d45, 0x0040, 0x9029, 0x1078, 0x9b6c, 0x0040, 0x9013, 0x0078, - 0x907b, 0x6013, 0x1900, 0x0078, 0x901b, 0x6106, 0x1078, 0x9aa8, - 0x6007, 0x0006, 0x0078, 0x9195, 0x6007, 0x0007, 0x0078, 0x9195, - 0x1078, 0xa0bf, 0x00c0, 0x9340, 0x0d7e, 0x6618, 0x2668, 0x6e04, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x905d, 0xa686, - 0x0004, 0x0040, 0x905d, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, - 0x0040, 0x905d, 0xa686, 0x0004, 0x0040, 0x905d, 0xa686, 0x0005, - 0x0040, 0x905d, 0x0d7f, 0x0078, 0x907b, 0x1078, 0x9bd2, 0x00c0, - 0x9076, 0xa686, 0x0006, 0x00c0, 0x906f, 0x027e, 0x6218, 0xa290, - 0x0028, 0x2214, 0x2009, 0x0000, 0x1078, 0x285b, 0x027f, 0x1078, - 0x457d, 0x6007, 0x000a, 0x0d7f, 0x0078, 0x9195, 0x6007, 0x000b, - 0x0d7f, 0x0078, 0x9195, 0x1078, 0x2813, 0x6007, 0x0001, 0x0078, - 0x9195, 0x1078, 0xa0bf, 0x00c0, 0x9340, 0x6618, 0x0d7e, 0x2668, - 0x6e04, 0x0d7f, 0xa686, 0x0707, 0x0040, 0x907b, 0x027e, 0x6218, - 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x1078, 0x285b, 0x027f, - 0x6007, 0x000c, 0x0078, 0x9195, 0x1078, 0x4897, 0x00c0, 0x90a9, - 0x2001, 0xa332, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, 0x00c0, - 0x90b1, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0078, - 0x9195, 0x1078, 0x4887, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, - 0x00ff, 0xa082, 0x0006, 0x0048, 0x90f5, 0xa6b4, 0xff00, 0x8637, - 0xa686, 0x0004, 0x0040, 0x90c8, 0xa686, 0x0006, 0x00c0, 0x907b, - 0x1078, 0x9be1, 0x00c0, 0x90d0, 0x6007, 0x000e, 0x0078, 0x9195, - 0x047e, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, 0x00ff, 0x8427, - 0x047e, 0x1078, 0x2813, 0x047f, 0x017e, 0xa006, 0x2009, 0xa352, - 0x210c, 0xd1a4, 0x0040, 0x90ef, 0x2009, 0x0029, 0x1078, 0x9ec0, - 0x6018, 0x0d7e, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x0d7f, 0x017f, - 0x047f, 0x6007, 0x0001, 0x0078, 0x9195, 0x2001, 0x0001, 0x1078, - 0x442b, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, 0x0004, 0x2019, - 0xa305, 0x2011, 0xa890, 0x1078, 0x7e55, 0x037f, 0x027f, 0x017f, - 0x157f, 0xa005, 0x0040, 0x9115, 0xa6b4, 0xff00, 0x8637, 0xa686, - 0x0006, 0x0040, 0x90c8, 0x0078, 0x907b, 0x6013, 0x1900, 0x6007, - 0x0009, 0x0078, 0x9195, 0x1078, 0x4897, 0x00c0, 0x9128, 0x2001, - 0xa332, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, 0x00c0, 0x9130, - 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0078, 0x9195, - 0x1078, 0x4887, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, - 0xa082, 0x0006, 0x0048, 0x9178, 0xa6b4, 0xff00, 0x8637, 0xa686, - 0x0004, 0x0040, 0x9147, 0xa686, 0x0006, 0x00c0, 0x907b, 0x1078, - 0x9c0c, 0x00c0, 0x9153, 0x1078, 0x9afd, 0x00c0, 0x9153, 0x6007, - 0x0010, 0x0078, 0x9195, 0x047e, 0x6418, 0xa4a0, 0x0028, 0x2424, - 0xa4a4, 0x00ff, 0x8427, 0x047e, 0x1078, 0x2813, 0x047f, 0x017e, - 0xa006, 0x2009, 0xa352, 0x210c, 0xd1a4, 0x0040, 0x9172, 0x2009, - 0x0029, 0x1078, 0x9ec0, 0x6018, 0x0d7e, 0x2068, 0x6800, 0xc0e5, - 0x6802, 0x0d7f, 0x017f, 0x047f, 0x6007, 0x0001, 0x0078, 0x9195, - 0x1078, 0x9d45, 0x0040, 0x9185, 0xa6b4, 0xff00, 0x8637, 0xa686, - 0x0006, 0x0040, 0x9147, 0x0078, 0x907b, 0x6013, 0x1900, 0x6007, - 0x0009, 0x0078, 0x9195, 0x1078, 0xa0bf, 0x00c0, 0x9340, 0x1078, - 0x9343, 0x00c0, 0x907b, 0x6007, 0x0012, 0x6003, 0x0001, 0x1078, - 0x5c45, 0x007c, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x5c45, - 0x0078, 0x9199, 0x6007, 0x0005, 0x0078, 0x919c, 0x1078, 0xa0bf, - 0x00c0, 0x9340, 0x1078, 0x9343, 0x00c0, 0x907b, 0x6007, 0x0020, - 0x6003, 0x0001, 0x1078, 0x5c45, 0x007c, 0x6007, 0x0023, 0x6003, - 0x0001, 0x1078, 0x5c45, 0x007c, 0x1078, 0xa0bf, 0x00c0, 0x9340, - 0x1078, 0x9343, 0x00c0, 0x907b, 0x017e, 0x027e, 0x2011, 0xa890, - 0x2214, 0x2c08, 0x1078, 0x9e8c, 0x00c0, 0x91de, 0x2160, 0x6007, - 0x0026, 0x6013, 0x1700, 0x2011, 0xa889, 0x2214, 0xa296, 0xffff, - 0x00c0, 0x91e3, 0x6007, 0x0025, 0x0078, 0x91e3, 0x1078, 0x753d, - 0x2160, 0x6007, 0x0025, 0x6003, 0x0001, 0x1078, 0x5c45, 0x027f, - 0x017f, 0x007c, 0x6106, 0x1078, 0x9363, 0x6007, 0x002b, 0x0078, - 0x9195, 0x6007, 0x002c, 0x0078, 0x9195, 0x1078, 0xa0bf, 0x00c0, - 0x9340, 0x1078, 0x9343, 0x00c0, 0x907b, 0x6106, 0x1078, 0x9368, - 0x00c0, 0x9206, 0x6007, 0x002e, 0x0078, 0x9195, 0x6007, 0x002f, - 0x0078, 0x9195, 0x0e7e, 0x0d7e, 0x0c7e, 0x6018, 0xa080, 0x0001, - 0x200c, 0xa184, 0x00ff, 0xa086, 0x0006, 0x0040, 0x9223, 0xa184, - 0xff00, 0x8007, 0xa086, 0x0006, 0x0040, 0x9223, 0x0c7f, 0x0d7f, - 0x0e7f, 0x0078, 0x919a, 0x2001, 0xa371, 0x2004, 0xd0e4, 0x0040, - 0x928d, 0x2071, 0xa88c, 0x7010, 0x6036, 0x7014, 0x603a, 0x7108, - 0x720c, 0x2001, 0xa352, 0x2004, 0xd0a4, 0x0040, 0x9241, 0x6018, - 0x2068, 0x6810, 0xa106, 0x00c0, 0x9241, 0x6814, 0xa206, 0x0040, - 0x9265, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x9281, 0x2069, - 0xa300, 0x686c, 0xa206, 0x00c0, 0x9281, 0x6868, 0xa106, 0x00c0, - 0x9281, 0x7210, 0x1078, 0x8a30, 0x0040, 0x9287, 0x1078, 0x9f31, - 0x0040, 0x9287, 0x622a, 0x6007, 0x0036, 0x6003, 0x0001, 0x1078, - 0x5bf8, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7214, 0xa286, 0xffff, - 0x0040, 0x9277, 0x1078, 0x8a30, 0x0040, 0x9287, 0xa280, 0x0002, - 0x2004, 0x7110, 0xa106, 0x00c0, 0x9287, 0x0078, 0x9252, 0x7210, - 0x2c08, 0x1078, 0x9e8c, 0x2c10, 0x2160, 0x0040, 0x9287, 0x0078, - 0x9252, 0x6007, 0x0037, 0x6013, 0x1500, 0x0078, 0x925d, 0x6007, - 0x0037, 0x6013, 0x1700, 0x0078, 0x925d, 0x6007, 0x0012, 0x0078, - 0x925d, 0x6018, 0xa080, 0x0001, 0x2004, 0xa084, 0xff00, 0x8007, - 0xa086, 0x0006, 0x00c0, 0x919a, 0x0e7e, 0x0d7e, 0x0c7e, 0x2001, - 0xa371, 0x2004, 0xd0e4, 0x0040, 0x92fd, 0x2069, 0xa300, 0x2071, - 0xa88c, 0x7008, 0x6036, 0x720c, 0x623a, 0xa286, 0xffff, 0x00c0, - 0x92ba, 0x7208, 0x0c7e, 0x2c08, 0x1078, 0x9e8c, 0x2c10, 0x0c7f, - 0x0040, 0x92f1, 0x1078, 0x8a30, 0x0040, 0x92f1, 0x0c7e, 0x027e, - 0x2260, 0x1078, 0x874a, 0x027f, 0x0c7f, 0x7118, 0xa18c, 0xff00, - 0x810f, 0xa186, 0x0001, 0x0040, 0x92db, 0xa186, 0x0005, 0x0040, - 0x92d5, 0xa186, 0x0007, 0x00c0, 0x92e5, 0xa280, 0x0004, 0x2004, - 0xa005, 0x0040, 0x92e5, 0x057e, 0x7510, 0x7614, 0x1078, 0x9f46, - 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x6007, 0x003b, 0x602b, - 0x0009, 0x6013, 0x2a00, 0x6003, 0x0001, 0x1078, 0x5bf8, 0x0078, - 0x92e1, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x1700, 0x6003, - 0x0001, 0x1078, 0x5bf8, 0x0078, 0x92e1, 0x6007, 0x003b, 0x602b, - 0x000b, 0x6013, 0x0000, 0x0078, 0x925d, 0x0e7e, 0x027e, 0x1078, - 0x4897, 0x0040, 0x933a, 0x1078, 0x4887, 0x1078, 0xa148, 0x00c0, - 0x9338, 0x2071, 0xa300, 0x70c8, 0xc085, 0x70ca, 0x0f7e, 0x2079, - 0x0100, 0x7294, 0xa284, 0x00ff, 0x706a, 0x78e6, 0xa284, 0xff00, - 0x726c, 0xa205, 0x706e, 0x78ea, 0x0f7f, 0x70d3, 0x0000, 0x2001, - 0xa352, 0x2004, 0xd0a4, 0x0040, 0x9331, 0x2011, 0xa5c4, 0x2013, - 0x07d0, 0xd0ac, 0x00c0, 0x933a, 0x1078, 0x260d, 0x0078, 0x933a, - 0x1078, 0xa178, 0x027f, 0x0e7f, 0x1078, 0x753d, 0x0078, 0x9199, - 0x1078, 0x753d, 0x007c, 0x0d7e, 0x067e, 0x6618, 0x2668, 0x6e04, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x9360, 0xa686, - 0x0004, 0x0040, 0x9360, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, - 0x0040, 0x9360, 0xa686, 0x0004, 0x0040, 0x9360, 0xa085, 0x0001, - 0x067f, 0x0d7f, 0x007c, 0x0d7e, 0x1078, 0x9397, 0x0d7f, 0x007c, - 0x0d7e, 0x1078, 0x93a6, 0x00c0, 0x9390, 0x680c, 0xa08c, 0xff00, - 0x6820, 0xa084, 0x00ff, 0xa115, 0x6212, 0x6824, 0x602a, 0xd1e4, - 0x0040, 0x937e, 0x2009, 0x0001, 0x0078, 0x938c, 0xd1ec, 0x0040, - 0x9390, 0x6920, 0xa18c, 0x00ff, 0x6824, 0x1078, 0x24e3, 0x00c0, - 0x9390, 0x2110, 0x2009, 0x0000, 0x1078, 0x285b, 0x0078, 0x9394, - 0xa085, 0x0001, 0x0078, 0x9395, 0xa006, 0x0d7f, 0x007c, 0x2069, - 0xa88d, 0x6800, 0xa082, 0x0010, 0x00c8, 0x93a4, 0x6013, 0x0000, - 0xa085, 0x0001, 0x0078, 0x93a5, 0xa006, 0x007c, 0x6013, 0x0000, - 0x2069, 0xa88c, 0x6808, 0xa084, 0xff00, 0xa086, 0x0800, 0x00c0, - 0x93ba, 0x6800, 0xa084, 0x00ff, 0xa08e, 0x0014, 0x0040, 0x93ba, - 0xa08e, 0x0010, 0x007c, 0x6004, 0xa0b2, 0x0044, 0x10c8, 0x1328, - 0xa1b6, 0x0013, 0x00c0, 0x93c7, 0x2008, 0x0079, 0x93da, 0xa1b6, - 0x0027, 0x0040, 0x93cf, 0xa1b6, 0x0014, 0x10c0, 0x1328, 0x2001, - 0x0007, 0x1078, 0x4472, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, - 0x6109, 0x007c, 0x941a, 0x941c, 0x941a, 0x941a, 0x941a, 0x941c, - 0x9424, 0x94ae, 0x9471, 0x94ae, 0x9485, 0x94ae, 0x9424, 0x94ae, - 0x94a6, 0x94ae, 0x94a6, 0x94ae, 0x94ae, 0x941a, 0x941a, 0x941a, - 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, - 0x941c, 0x941a, 0x94ae, 0x941a, 0x941a, 0x94ae, 0x941a, 0x94ae, - 0x94ae, 0x941a, 0x941a, 0x941a, 0x941a, 0x94ae, 0x94ae, 0x941a, - 0x94ae, 0x94ae, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941c, - 0x94ae, 0x94ae, 0x941a, 0x941a, 0x94ae, 0x94ae, 0x941a, 0x941a, - 0x941a, 0x941a, 0x1078, 0x1328, 0x1078, 0x6010, 0x6003, 0x0002, - 0x1078, 0x6109, 0x0078, 0x94b4, 0x0f7e, 0x2079, 0xa351, 0x7804, - 0x0f7f, 0xd0ac, 0x00c0, 0x94ae, 0x2001, 0x0000, 0x1078, 0x442b, - 0x6018, 0xa080, 0x0004, 0x2004, 0xa086, 0x00ff, 0x0040, 0x94ae, - 0x0c7e, 0x6018, 0x2060, 0x6000, 0xd0f4, 0x00c0, 0x9448, 0x6010, - 0xa005, 0x0040, 0x9448, 0x0c7f, 0x1078, 0x35f7, 0x0078, 0x94ae, - 0x0c7f, 0x2001, 0xa300, 0x2004, 0xa086, 0x0002, 0x00c0, 0x9457, - 0x0f7e, 0x2079, 0xa300, 0x788c, 0x8000, 0x788e, 0x0f7f, 0x2001, - 0x0002, 0x1078, 0x443f, 0x1078, 0x6010, 0x601f, 0x0001, 0x6003, - 0x0001, 0x6007, 0x0002, 0x1078, 0x5c45, 0x1078, 0x6109, 0x0c7e, - 0x6118, 0x2160, 0x2009, 0x0001, 0x1078, 0x58e1, 0x0c7f, 0x0078, - 0x94b4, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, 0xff00, - 0x8637, 0xa686, 0x0006, 0x0040, 0x94ae, 0xa686, 0x0004, 0x0040, - 0x94ae, 0x2001, 0x0004, 0x0078, 0x94ac, 0x2001, 0xa300, 0x2004, - 0xa086, 0x0003, 0x00c0, 0x948e, 0x1078, 0x35f7, 0x2001, 0x0006, - 0x1078, 0x94b5, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, - 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x94ae, 0x2001, 0x0006, - 0x0078, 0x94ac, 0x2001, 0x0004, 0x0078, 0x94ac, 0x2001, 0x0006, - 0x1078, 0x94b5, 0x0078, 0x94ae, 0x1078, 0x4472, 0x1078, 0x6010, - 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, 0x017e, 0x0d7e, 0x6118, - 0x2168, 0x6900, 0xd184, 0x0040, 0x94d0, 0x6104, 0xa18e, 0x000a, - 0x00c0, 0x94c8, 0x699c, 0xd1a4, 0x00c0, 0x94c8, 0x2001, 0x0007, - 0x1078, 0x443f, 0x2001, 0x0000, 0x1078, 0x442b, 0x1078, 0x2839, - 0x0d7f, 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, - 0xff00, 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1328, 0xa1b6, - 0x0015, 0x00c0, 0x94e7, 0x1079, 0x94ee, 0x0078, 0x94ed, 0xa1b6, - 0x0016, 0x10c0, 0x1328, 0x1079, 0x94fa, 0x007c, 0x7ad0, 0x7ad0, - 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x9547, 0x9506, 0x7ad0, 0x7ad0, - 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, - 0x9547, 0x954f, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x0f7e, 0x2079, - 0xa351, 0x7804, 0xd0ac, 0x00c0, 0x952d, 0x6018, 0xa07d, 0x0040, - 0x952d, 0x7800, 0xd0f4, 0x00c0, 0x9519, 0x7810, 0xa005, 0x00c0, - 0x952d, 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, - 0x443f, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, - 0x5c45, 0x1078, 0x6109, 0x0078, 0x9545, 0x2011, 0xa883, 0x2204, - 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, 0x9545, 0x0c7e, 0x1078, - 0x4501, 0x0040, 0x9540, 0x0c7f, 0x1078, 0x753d, 0x0078, 0x9545, - 0x1078, 0x4235, 0x0c7f, 0x1078, 0x753d, 0x0f7f, 0x007c, 0x6604, - 0xa6b6, 0x001e, 0x00c0, 0x954e, 0x1078, 0x753d, 0x007c, 0x1078, - 0x7d0a, 0x00c0, 0x955b, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, - 0x5c45, 0x0078, 0x955d, 0x1078, 0x753d, 0x007c, 0x6004, 0xa08a, - 0x0044, 0x10c8, 0x1328, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, - 0x6109, 0x007c, 0xa182, 0x0040, 0x0079, 0x956e, 0x9581, 0x9581, - 0x9581, 0x9581, 0x9583, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, - 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, - 0x9581, 0x1078, 0x1328, 0x0d7e, 0x0e7e, 0x0f7e, 0x157e, 0x047e, - 0x027e, 0x6218, 0xa280, 0x002b, 0x2004, 0xa005, 0x0040, 0x9594, - 0x2021, 0x0000, 0x1078, 0xa111, 0x6106, 0x2071, 0xa880, 0x7444, - 0xa4a4, 0xff00, 0x0040, 0x95eb, 0xa486, 0x2000, 0x00c0, 0x95a6, - 0x2009, 0x0001, 0x2011, 0x0200, 0x1078, 0x5a6d, 0x1078, 0x1381, - 0x1040, 0x1328, 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, - 0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2, - 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x694a, 0x017e, 0xa084, - 0xff00, 0x6846, 0x684f, 0x0000, 0x6857, 0x0036, 0x1078, 0x4982, - 0x017f, 0xa486, 0x2000, 0x00c0, 0x95d3, 0x2019, 0x0017, 0x1078, - 0x9e3b, 0x0078, 0x9645, 0xa486, 0x0400, 0x00c0, 0x95dd, 0x2019, - 0x0002, 0x1078, 0x9dec, 0x0078, 0x9645, 0xa486, 0x0200, 0x00c0, - 0x95e3, 0x1078, 0x9dd1, 0xa486, 0x1000, 0x00c0, 0x95e9, 0x1078, - 0x9e20, 0x0078, 0x9645, 0x2069, 0xa62d, 0x6a00, 0xd284, 0x0040, - 0x969b, 0xa284, 0x0300, 0x00c0, 0x9693, 0x6804, 0xa005, 0x0040, - 0x9683, 0x2d78, 0x6003, 0x0007, 0x1078, 0x1366, 0x0040, 0x964c, - 0x7800, 0xd08c, 0x00c0, 0x9607, 0x7804, 0x8001, 0x7806, 0x6013, - 0x0000, 0x6803, 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, 0x6008, - 0x68b2, 0x2c00, 0x684a, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, - 0x6986, 0x6846, 0x6853, 0x003d, 0x7244, 0xa294, 0x0003, 0xa286, - 0x0002, 0x00c0, 0x9627, 0x684f, 0x0040, 0x0078, 0x9631, 0xa286, - 0x0001, 0x00c0, 0x962f, 0x684f, 0x0080, 0x0078, 0x9631, 0x684f, - 0x0000, 0x20a9, 0x000a, 0x2001, 0xa890, 0xad90, 0x0015, 0x200c, - 0x810f, 0x2112, 0x8000, 0x8210, 0x00f0, 0x9637, 0x200c, 0x6982, - 0x8000, 0x200c, 0x697e, 0x1078, 0x4982, 0x027f, 0x047f, 0x157f, - 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, 0x6013, 0x0100, 0x6003, 0x0001, - 0x6007, 0x0041, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0078, 0x9645, - 0x2069, 0xa892, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x00c0, - 0x9677, 0x2069, 0xa880, 0x686c, 0xa084, 0x00ff, 0x017e, 0x6110, - 0xa18c, 0x0700, 0xa10d, 0x6112, 0x017f, 0x6003, 0x0001, 0x6007, - 0x0043, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0078, 0x9645, 0x6013, - 0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x5bf8, 0x1078, - 0x6109, 0x0078, 0x9645, 0x6013, 0x0300, 0x0078, 0x9689, 0x6013, - 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x5bf8, 0x1078, - 0x6109, 0x0078, 0x9645, 0x6013, 0x0500, 0x0078, 0x9689, 0x6013, - 0x0600, 0x0078, 0x9658, 0x6013, 0x0200, 0x0078, 0x9658, 0xa186, - 0x0013, 0x00c0, 0x96b1, 0x6004, 0xa08a, 0x0040, 0x1048, 0x1328, - 0xa08a, 0x0053, 0x10c8, 0x1328, 0xa082, 0x0040, 0x2008, 0x0079, - 0x9725, 0xa186, 0x0051, 0x0040, 0x96be, 0xa186, 0x0047, 0x00c0, - 0x96d7, 0x6004, 0xa086, 0x0041, 0x0040, 0x96e5, 0x2001, 0x0109, - 0x2004, 0xd084, 0x0040, 0x96e5, 0x127e, 0x2091, 0x2200, 0x007e, - 0x017e, 0x027e, 0x1078, 0x5ad2, 0x027f, 0x017f, 0x007f, 0x127f, - 0x6000, 0xa086, 0x0002, 0x00c0, 0x96e5, 0x0078, 0x976a, 0xa186, - 0x0027, 0x0040, 0x96df, 0xa186, 0x0014, 0x10c0, 0x1328, 0x6004, - 0xa082, 0x0040, 0x2008, 0x0079, 0x96e8, 0x1078, 0x7583, 0x007c, - 0x96fb, 0x96fd, 0x96fd, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, - 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, - 0x96fb, 0x96fb, 0x96fb, 0x1078, 0x1328, 0x1078, 0x6010, 0x1078, - 0x6109, 0x037e, 0x0d7e, 0x6010, 0xa06d, 0x0040, 0x9722, 0xad84, - 0xf000, 0x0040, 0x9722, 0x6003, 0x0002, 0x6018, 0x2004, 0xd0bc, - 0x00c0, 0x9722, 0x2019, 0x0004, 0x1078, 0x9e70, 0x6013, 0x0000, - 0x6014, 0xa005, 0x00c0, 0x9720, 0x2001, 0xa5a1, 0x2004, 0x6016, - 0x6003, 0x0007, 0x0d7f, 0x037f, 0x007c, 0x9738, 0x9757, 0x9741, - 0x9764, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, - 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, - 0x1078, 0x1328, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, - 0x200a, 0x1078, 0x6010, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, - 0x0040, 0x9752, 0x6003, 0x0007, 0x2009, 0x0043, 0x1078, 0x756c, - 0x0078, 0x9754, 0x6003, 0x0002, 0x1078, 0x6109, 0x007c, 0x1078, - 0x6010, 0x1078, 0xa0c6, 0x00c0, 0x9761, 0x1078, 0x5a41, 0x1078, - 0x753d, 0x1078, 0x6109, 0x007c, 0x1078, 0x6010, 0x2009, 0x0041, - 0x0078, 0x98c1, 0xa182, 0x0040, 0x0079, 0x976e, 0x9781, 0x9783, - 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x9784, 0x9781, 0x9781, - 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x978f, - 0x9781, 0x1078, 0x1328, 0x007c, 0x6003, 0x0004, 0x6110, 0x20e1, - 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15ec, 0x007c, 0x0d7e, - 0x1078, 0x5a41, 0x0d7f, 0x1078, 0xa134, 0x1078, 0x753d, 0x007c, - 0xa182, 0x0040, 0x0079, 0x979c, 0x97af, 0x97af, 0x97af, 0x97af, - 0x97af, 0x97af, 0x97af, 0x97b1, 0x97af, 0x97b4, 0x97df, 0x97af, - 0x97af, 0x97af, 0x97af, 0x97df, 0x97af, 0x97af, 0x97af, 0x1078, - 0x1328, 0x1078, 0x7583, 0x007c, 0x1078, 0x60b8, 0x1078, 0x61d3, - 0x6010, 0x0d7e, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x97ca, 0xa08c, - 0x0003, 0xa18e, 0x0002, 0x0040, 0x97d2, 0x2009, 0x0041, 0x0d7f, - 0x0078, 0x98c1, 0x6003, 0x0007, 0x6017, 0x0000, 0x1078, 0x5a41, - 0x0d7f, 0x007c, 0x1078, 0xa0c6, 0x0040, 0x97d8, 0x0d7f, 0x007c, - 0x1078, 0x5a41, 0x1078, 0x753d, 0x0d7f, 0x0078, 0x97d1, 0x037e, - 0x1078, 0x60b8, 0x1078, 0x61d3, 0x6010, 0x0d7e, 0x2068, 0x6018, - 0x2004, 0xd0bc, 0x0040, 0x97ff, 0x684c, 0xa084, 0x0003, 0xa086, - 0x0002, 0x0040, 0x97fb, 0x687c, 0x632c, 0xa31a, 0x632e, 0x6880, - 0x6328, 0xa31b, 0x632a, 0x6003, 0x0002, 0x0078, 0x9810, 0x2019, - 0x0004, 0x1078, 0x9e70, 0x6014, 0xa005, 0x00c0, 0x980c, 0x2001, - 0xa5a1, 0x2004, 0x8003, 0x6016, 0x6013, 0x0000, 0x6003, 0x0007, - 0x0d7f, 0x037f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x9821, 0x6004, - 0xa086, 0x0042, 0x10c0, 0x1328, 0x1078, 0x6010, 0x1078, 0x6109, - 0x007c, 0xa186, 0x0027, 0x0040, 0x9829, 0xa186, 0x0014, 0x00c0, - 0x9839, 0x6004, 0xa086, 0x0042, 0x10c0, 0x1328, 0x2001, 0x0007, - 0x1078, 0x4472, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, - 0x007c, 0xa182, 0x0040, 0x0079, 0x983d, 0x9850, 0x9850, 0x9850, - 0x9850, 0x9850, 0x9850, 0x9850, 0x9852, 0x985e, 0x9850, 0x9850, - 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, - 0x1078, 0x1328, 0x037e, 0x047e, 0x20e1, 0x0005, 0x3d18, 0x3e20, - 0x2c10, 0x1078, 0x15ec, 0x047f, 0x037f, 0x007c, 0x6010, 0x0d7e, - 0x2068, 0x6810, 0x6a14, 0x6118, 0x210c, 0xd1bc, 0x0040, 0x987d, - 0x6124, 0xd1f4, 0x00c0, 0x987d, 0x007e, 0x047e, 0x057e, 0x6c7c, - 0xa422, 0x6d80, 0x2200, 0xa52b, 0x602c, 0xa420, 0x642e, 0x6028, - 0xa529, 0x652a, 0x057f, 0x047f, 0x007f, 0xa20d, 0x00c0, 0x9891, - 0x684c, 0xd0fc, 0x0040, 0x9889, 0x2009, 0x0041, 0x0d7f, 0x0078, - 0x98c1, 0x6003, 0x0007, 0x6017, 0x0000, 0x1078, 0x5a41, 0x0d7f, - 0x007c, 0x007e, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x007f, - 0x0040, 0x989e, 0x6003, 0x0002, 0x0d7f, 0x007c, 0x2009, 0xa30d, - 0x210c, 0xd19c, 0x0040, 0x98a8, 0x6003, 0x0007, 0x0078, 0x98aa, - 0x6003, 0x0006, 0x1078, 0x98b0, 0x1078, 0x5a43, 0x0d7f, 0x007c, - 0xd2fc, 0x0040, 0x98bc, 0x8002, 0x8000, 0x8212, 0xa291, 0x0000, - 0x2009, 0x0009, 0x0078, 0x98be, 0x2009, 0x0015, 0x6a6a, 0x6866, - 0x007c, 0xa182, 0x0040, 0x0048, 0x98c7, 0x0079, 0x98d4, 0xa186, - 0x0013, 0x0040, 0x98cf, 0xa186, 0x0014, 0x10c0, 0x1328, 0x6024, - 0xd0dc, 0x1040, 0x1328, 0x007c, 0x98e7, 0x98ee, 0x98fa, 0x9906, - 0x98e7, 0x98e7, 0x98e7, 0x9915, 0x98e7, 0x98e9, 0x98e9, 0x98e7, - 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x1078, - 0x1328, 0x6024, 0xd0dc, 0x1040, 0x1328, 0x007c, 0x6003, 0x0001, - 0x6106, 0x1078, 0x5bf8, 0x127e, 0x2091, 0x8000, 0x1078, 0x6109, - 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x127e, - 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, 0x6003, 0x0003, - 0x6106, 0x2c10, 0x1078, 0x1cab, 0x127e, 0x2091, 0x8000, 0x1078, - 0x5c64, 0x1078, 0x61d3, 0x127f, 0x007c, 0xa016, 0x1078, 0x15ec, - 0x007c, 0x127e, 0x2091, 0x8000, 0x037e, 0x0d7e, 0xa182, 0x0040, - 0x1079, 0x9926, 0x0d7f, 0x037f, 0x127f, 0x007c, 0x9936, 0x9938, - 0x994d, 0x996c, 0x9936, 0x9936, 0x9936, 0x9984, 0x9936, 0x9936, - 0x9936, 0x9936, 0x9936, 0x9936, 0x9936, 0x9936, 0x1078, 0x1328, - 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x9962, 0xa09c, 0x0003, - 0xa39e, 0x0003, 0x0040, 0x9962, 0x6003, 0x0001, 0x6106, 0x1078, - 0x5bf8, 0x1078, 0x6109, 0x0078, 0x9987, 0x6010, 0x2068, 0x684c, - 0xd0fc, 0x0040, 0x9962, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040, - 0x9962, 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x1078, 0x6109, - 0x0078, 0x9987, 0x6013, 0x0000, 0x6017, 0x0000, 0x2019, 0x0004, - 0x1078, 0x9e70, 0x0078, 0x9987, 0x6010, 0x2068, 0x684c, 0xd0fc, - 0x0040, 0x9962, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040, 0x9962, - 0x6003, 0x0003, 0x6106, 0x2c10, 0x1078, 0x1cab, 0x1078, 0x5c64, - 0x1078, 0x61d3, 0x0078, 0x9987, 0xa016, 0x1078, 0x15ec, 0x007c, - 0x1078, 0x6010, 0x6110, 0x81ff, 0x0040, 0x9999, 0x0d7e, 0x2168, - 0x1078, 0xa181, 0x037e, 0x2019, 0x0029, 0x1078, 0x9e70, 0x037f, - 0x0d7f, 0x1078, 0x8c01, 0x1078, 0x6109, 0x007c, 0x1078, 0x60b8, - 0x6110, 0x81ff, 0x0040, 0x99af, 0x0d7e, 0x2168, 0x1078, 0xa181, - 0x037e, 0x2019, 0x0029, 0x1078, 0x9e70, 0x037f, 0x0d7f, 0x1078, - 0x8c01, 0x1078, 0x61d3, 0x007c, 0xa182, 0x0085, 0x0079, 0x99b8, - 0x99c1, 0x99bf, 0x99bf, 0x99cd, 0x99bf, 0x99bf, 0x99bf, 0x1078, - 0x1328, 0x6003, 0x000b, 0x6106, 0x1078, 0x5bf8, 0x127e, 0x2091, - 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, 0x027e, 0x0e7e, 0x1078, - 0xa0bf, 0x0040, 0x99d7, 0x1078, 0x753d, 0x0078, 0x99f3, 0x2071, - 0xa880, 0x7224, 0x6212, 0x7220, 0x1078, 0x9d10, 0x0040, 0x99e4, - 0x6007, 0x0086, 0x0078, 0x99ed, 0x6007, 0x0087, 0x7224, 0xa296, - 0xffff, 0x00c0, 0x99ed, 0x6007, 0x0086, 0x6003, 0x0001, 0x1078, - 0x5bf8, 0x1078, 0x6109, 0x0e7f, 0x027f, 0x007c, 0xa186, 0x0013, - 0x00c0, 0x9a07, 0x6004, 0xa08a, 0x0085, 0x1048, 0x1328, 0xa08a, - 0x008c, 0x10c8, 0x1328, 0xa082, 0x0085, 0x0079, 0x9a1e, 0xa186, - 0x0027, 0x0040, 0x9a13, 0xa186, 0x0014, 0x0040, 0x9a13, 0x1078, - 0x7583, 0x0078, 0x9a1d, 0x2001, 0x0007, 0x1078, 0x4472, 0x1078, - 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, 0x007c, 0x9a25, 0x9a27, - 0x9a27, 0x9a25, 0x9a25, 0x9a25, 0x9a25, 0x1078, 0x1328, 0x1078, - 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, 0x007c, 0xa182, 0x0085, - 0x1048, 0x1328, 0xa182, 0x008c, 0x10c8, 0x1328, 0xa182, 0x0085, - 0x0079, 0x9a3a, 0x9a41, 0x9a41, 0x9a41, 0x9a43, 0x9a41, 0x9a41, - 0x9a41, 0x1078, 0x1328, 0x007c, 0xa186, 0x0013, 0x0040, 0x9a54, - 0xa186, 0x0014, 0x0040, 0x9a54, 0xa186, 0x0027, 0x0040, 0x9a54, - 0x1078, 0x7583, 0x0078, 0x9a5a, 0x1078, 0x6010, 0x1078, 0x8c01, - 0x1078, 0x6109, 0x007c, 0x037e, 0x1078, 0xa134, 0x603f, 0x0000, - 0x2019, 0x000b, 0x1078, 0x9a6a, 0x601f, 0x0006, 0x6003, 0x0007, - 0x037f, 0x007c, 0x127e, 0x037e, 0x2091, 0x8000, 0x087e, 0x2c40, - 0x097e, 0x2049, 0x0000, 0x1078, 0x7058, 0x097f, 0x087f, 0x00c0, - 0x9aa5, 0x077e, 0x2c38, 0x1078, 0x7105, 0x077f, 0x00c0, 0x9aa5, - 0x6000, 0xa086, 0x0000, 0x0040, 0x9aa5, 0x601c, 0xa086, 0x0007, - 0x0040, 0x9aa5, 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x9a96, - 0x1078, 0xa134, 0x601f, 0x0007, 0x1078, 0x1749, 0x6010, 0x2068, - 0x1078, 0x8a44, 0x0040, 0x9a9e, 0x1078, 0x9e70, 0x0d7f, 0x6013, - 0x0000, 0x1078, 0xa134, 0x601f, 0x0007, 0x037f, 0x127f, 0x007c, - 0x0f7e, 0x0c7e, 0x037e, 0x157e, 0x2079, 0xa880, 0x7938, 0x783c, - 0x1078, 0x24e3, 0x00c0, 0x9af6, 0x017e, 0x0c7e, 0x1078, 0x4501, - 0x00c0, 0x9af6, 0x2011, 0xa890, 0xac98, 0x000a, 0x20a9, 0x0004, - 0x1078, 0x7e55, 0x00c0, 0x9af6, 0x017f, 0x027f, 0x027e, 0x017e, - 0x2019, 0x0029, 0x1078, 0x71e0, 0x1078, 0x5d53, 0x077e, 0x2039, - 0x0000, 0x1078, 0x5c78, 0x077f, 0x017f, 0x077e, 0x2039, 0x0000, - 0x1078, 0x9c38, 0x077f, 0x1078, 0x471b, 0x027e, 0x6204, 0xa294, - 0xff00, 0x8217, 0xa286, 0x0006, 0x0040, 0x9aea, 0xa286, 0x0004, - 0x00c0, 0x9aed, 0x62a0, 0x1078, 0x28d5, 0x027f, 0x017f, 0x1078, - 0x4235, 0x6612, 0x6516, 0xa006, 0x0078, 0x9af8, 0x0c7f, 0x017f, - 0x157f, 0x037f, 0x0c7f, 0x0f7f, 0x007c, 0x0c7e, 0x0d7e, 0x0e7e, - 0x017e, 0x2009, 0xa31f, 0x2104, 0xa086, 0x0074, 0x00c0, 0x9b60, - 0x2069, 0xa88e, 0x690c, 0xa182, 0x0100, 0x0048, 0x9b50, 0x6908, - 0xa184, 0x8000, 0x0040, 0x9b5c, 0x6018, 0x2070, 0x7010, 0xa084, - 0x00ff, 0x0040, 0x9b1f, 0x7000, 0xd0f4, 0x0040, 0x9b23, 0xa184, - 0x0800, 0x0040, 0x9b5c, 0x6910, 0xa18a, 0x0001, 0x0048, 0x9b54, - 0x6914, 0x2069, 0xa8ae, 0x6904, 0x81ff, 0x00c0, 0x9b48, 0x690c, - 0xa182, 0x0100, 0x0048, 0x9b50, 0x6908, 0x81ff, 0x00c0, 0x9b4c, - 0x6910, 0xa18a, 0x0001, 0x0048, 0x9b54, 0x6918, 0xa18a, 0x0001, - 0x0048, 0x9b5c, 0x0078, 0x9b66, 0x6013, 0x0100, 0x0078, 0x9b62, - 0x6013, 0x0300, 0x0078, 0x9b62, 0x6013, 0x0500, 0x0078, 0x9b62, - 0x6013, 0x0700, 0x0078, 0x9b62, 0x6013, 0x0900, 0x0078, 0x9b62, - 0x6013, 0x0b00, 0x0078, 0x9b62, 0x6013, 0x0f00, 0x0078, 0x9b62, - 0x6013, 0x2d00, 0xa085, 0x0001, 0x0078, 0x9b67, 0xa006, 0x017f, - 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x027e, 0x037e, - 0x157e, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff, 0xa286, 0x0006, - 0x0040, 0x9b90, 0xa286, 0x0004, 0x0040, 0x9b90, 0xa394, 0xff00, - 0x8217, 0xa286, 0x0006, 0x0040, 0x9b90, 0xa286, 0x0004, 0x0040, - 0x9b90, 0x0c7e, 0x2d60, 0x1078, 0x4513, 0x0c7f, 0x0078, 0x9bcb, - 0x2011, 0xa896, 0xad98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x7e55, - 0x00c0, 0x9bcc, 0x2011, 0xa89a, 0xad98, 0x0006, 0x20a9, 0x0004, - 0x1078, 0x7e55, 0x00c0, 0x9bcc, 0x047e, 0x017e, 0x6aa0, 0xa294, - 0x00ff, 0x8227, 0xa006, 0x2009, 0xa352, 0x210c, 0xd1a4, 0x0040, - 0x9bb8, 0x2009, 0x0029, 0x1078, 0x9ec0, 0x6800, 0xc0e5, 0x6802, - 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, 0x0000, 0x1078, - 0x5c78, 0x2c08, 0x1078, 0x9c38, 0x077f, 0x2001, 0x0007, 0x1078, - 0x4472, 0x017f, 0x047f, 0xa006, 0x157f, 0x037f, 0x027f, 0x0d7f, - 0x0c7f, 0x007c, 0x0d7e, 0x2069, 0xa88e, 0x6800, 0xa086, 0x0800, - 0x0040, 0x9bde, 0x6013, 0x0000, 0x0078, 0x9bdf, 0xa006, 0x0d7f, - 0x007c, 0x0c7e, 0x0f7e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2079, - 0xa88c, 0x7930, 0x7834, 0x1078, 0x24e3, 0x00c0, 0x9c05, 0x1078, - 0x4501, 0x00c0, 0x9c05, 0x2011, 0xa890, 0xac98, 0x000a, 0x20a9, - 0x0004, 0x1078, 0x7e55, 0x00c0, 0x9c05, 0x2011, 0xa894, 0xac98, - 0x0006, 0x20a9, 0x0004, 0x1078, 0x7e55, 0x157f, 0x037f, 0x027f, - 0x017f, 0x0f7f, 0x0c7f, 0x007c, 0x0c7e, 0x007e, 0x017e, 0x027e, - 0x037e, 0x157e, 0x2011, 0xa883, 0x2204, 0x8211, 0x220c, 0x1078, - 0x24e3, 0x00c0, 0x9c31, 0x1078, 0x4501, 0x00c0, 0x9c31, 0x2011, - 0xa896, 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x7e55, 0x00c0, - 0x9c31, 0x2011, 0xa89a, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078, - 0x7e55, 0x157f, 0x037f, 0x027f, 0x017f, 0x007f, 0x0c7f, 0x007c, - 0x0e7e, 0x0c7e, 0x087e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e, - 0x127e, 0x2091, 0x8000, 0x2740, 0x2029, 0xa5b4, 0x252c, 0x2021, - 0xa5ba, 0x2424, 0x2061, 0xaa00, 0x2071, 0xa300, 0x7644, 0x7060, - 0x81ff, 0x0040, 0x9c59, 0x8001, 0xa602, 0x00c8, 0x9cc3, 0x0078, - 0x9c5c, 0xa606, 0x0040, 0x9cc3, 0x2100, 0xac06, 0x0040, 0x9cb9, - 0x1078, 0x9ee5, 0x0040, 0x9cb9, 0x671c, 0xa786, 0x0001, 0x0040, - 0x9cde, 0xa786, 0x0004, 0x0040, 0x9cde, 0xa786, 0x0007, 0x0040, - 0x9cb9, 0x2500, 0xac06, 0x0040, 0x9cb9, 0x2400, 0xac06, 0x0040, - 0x9cb9, 0x1078, 0x9ef9, 0x00c0, 0x9cb9, 0x88ff, 0x0040, 0x9c84, - 0x6020, 0xa906, 0x00c0, 0x9cb9, 0x0d7e, 0x6000, 0xa086, 0x0004, - 0x00c0, 0x9c8e, 0x017e, 0x1078, 0x1749, 0x017f, 0xa786, 0x0008, - 0x00c0, 0x9c9d, 0x1078, 0x8c3b, 0x00c0, 0x9c9d, 0x1078, 0x7a05, - 0x0d7f, 0x1078, 0x8c01, 0x0078, 0x9cb9, 0x6010, 0x2068, 0x1078, - 0x8a44, 0x0040, 0x9cb6, 0xa786, 0x0003, 0x00c0, 0x9ccd, 0x6837, - 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0xa181, 0x017e, 0x1078, - 0x8cb8, 0x1078, 0x4982, 0x017f, 0x1078, 0x8bf4, 0x0d7f, 0x1078, - 0x8c01, 0xace0, 0x0010, 0x2001, 0xa315, 0x2004, 0xac02, 0x00c8, - 0x9cc3, 0x0078, 0x9c4c, 0x127f, 0x027f, 0x047f, 0x057f, 0x067f, - 0x077f, 0x087f, 0x0c7f, 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0, - 0x9ca7, 0xa386, 0x0005, 0x0040, 0x9cdb, 0x1078, 0xa181, 0x1078, - 0x9e70, 0x0078, 0x9cb6, 0x0d7f, 0x0078, 0x9cb9, 0x1078, 0x9ef9, - 0x00c0, 0x9cb9, 0x81ff, 0x0040, 0x9cb9, 0xa180, 0x0001, 0x2004, - 0xa086, 0x0018, 0x0040, 0x9cf3, 0xa180, 0x0001, 0x2004, 0xa086, - 0x002d, 0x00c0, 0x9cb9, 0x6000, 0xa086, 0x0002, 0x00c0, 0x9cb9, - 0x1078, 0x8c27, 0x0040, 0x9d04, 0x1078, 0x8c3b, 0x00c0, 0x9cb9, - 0x1078, 0x7a05, 0x0078, 0x9d0c, 0x1078, 0x2839, 0x1078, 0x8c3b, - 0x00c0, 0x9d0c, 0x1078, 0x7a05, 0x1078, 0x8c01, 0x0078, 0x9cb9, - 0x0c7e, 0x0e7e, 0x017e, 0x2c08, 0x2170, 0x1078, 0x9e8c, 0x017f, - 0x0040, 0x9d1f, 0x601c, 0xa084, 0x000f, 0x1079, 0x9d22, 0x0e7f, - 0x0c7f, 0x007c, 0x9d2a, 0x9d2a, 0x9d2a, 0x9d2a, 0x9d2a, 0x9d2a, - 0x9d2c, 0x9d2a, 0xa006, 0x007c, 0x047e, 0x017e, 0x7018, 0xa080, - 0x0028, 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, 0x0020, - 0x1078, 0x9ec0, 0x017f, 0x047f, 0x037e, 0x2019, 0x0002, 0x1078, - 0x9a6a, 0x037f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0001, 0x1078, - 0x442b, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, 0x0004, 0x2019, - 0xa305, 0x2011, 0xa896, 0x1078, 0x7e55, 0x037f, 0x027f, 0x017f, - 0x157f, 0xa005, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x087e, 0x077e, - 0x067e, 0x027e, 0x127e, 0x2091, 0x8000, 0x2740, 0x2061, 0xaa00, - 0x2079, 0x0001, 0x8fff, 0x0040, 0x9dc3, 0x2071, 0xa300, 0x7644, - 0x7060, 0x8001, 0xa602, 0x00c8, 0x9dc3, 0x88ff, 0x0040, 0x9d7e, - 0x2800, 0xac06, 0x00c0, 0x9db9, 0x2079, 0x0000, 0x1078, 0x9ee5, - 0x0040, 0x9db9, 0x2400, 0xac06, 0x0040, 0x9db9, 0x671c, 0xa786, - 0x0006, 0x00c0, 0x9db9, 0xa786, 0x0007, 0x0040, 0x9db9, 0x88ff, - 0x00c0, 0x9d9d, 0x6018, 0xa206, 0x00c0, 0x9db9, 0x85ff, 0x0040, - 0x9d9d, 0x6020, 0xa106, 0x00c0, 0x9db9, 0x0d7e, 0x6000, 0xa086, - 0x0004, 0x00c0, 0x9da9, 0x1078, 0xa134, 0x601f, 0x0007, 0x1078, - 0x1749, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x9db3, 0x047e, - 0x1078, 0x9e70, 0x047f, 0x0d7f, 0x1078, 0x8c01, 0x88ff, 0x00c0, - 0x9dcd, 0xace0, 0x0010, 0x2001, 0xa315, 0x2004, 0xac02, 0x00c8, - 0x9dc3, 0x0078, 0x9d6a, 0xa006, 0x127f, 0x027f, 0x067f, 0x077f, - 0x087f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0xa8c5, 0x0001, 0x0078, - 0x9dc4, 0x077e, 0x057e, 0x087e, 0x2041, 0x0000, 0x2029, 0x0001, - 0x2c20, 0x2019, 0x0002, 0x6218, 0x097e, 0x2049, 0x0000, 0x1078, - 0x7058, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078, 0x7105, 0x1078, - 0x9d5b, 0x057f, 0x077f, 0x007c, 0x027e, 0x047e, 0x057e, 0x077e, - 0x0c7e, 0x157e, 0x2c20, 0x2128, 0x20a9, 0x007f, 0x2009, 0x0000, - 0x017e, 0x037e, 0x1078, 0x4501, 0x00c0, 0x9e14, 0x2c10, 0x057e, - 0x087e, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001, 0x097e, 0x2049, - 0x0000, 0x1078, 0x7058, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078, - 0x7105, 0x1078, 0x9d5b, 0x057f, 0x037f, 0x017f, 0x8108, 0x00f0, - 0x9df8, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f, 0x027f, 0x007c, - 0x077e, 0x057e, 0x6218, 0x087e, 0x2041, 0x0000, 0x2029, 0x0001, - 0x2019, 0x0048, 0x097e, 0x2049, 0x0000, 0x1078, 0x7058, 0x097f, - 0x087f, 0x2039, 0x0000, 0x1078, 0x7105, 0x2c20, 0x1078, 0x9d5b, - 0x057f, 0x077f, 0x007c, 0x027e, 0x047e, 0x057e, 0x077e, 0x0c7e, - 0x157e, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x037e, - 0x1078, 0x4501, 0x00c0, 0x9e64, 0x2c10, 0x087e, 0x2041, 0x0000, - 0x2828, 0x047e, 0x2021, 0x0001, 0x1078, 0xa111, 0x047f, 0x097e, - 0x2049, 0x0000, 0x1078, 0x7058, 0x097f, 0x087f, 0x2039, 0x0000, - 0x1078, 0x7105, 0x1078, 0x9d5b, 0x037f, 0x017f, 0x8108, 0x00f0, - 0x9e46, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f, 0x027f, 0x007c, - 0x017e, 0x0f7e, 0xad82, 0xca00, 0x0048, 0x9e89, 0xad82, 0xffff, - 0x00c8, 0x9e89, 0x6800, 0xa07d, 0x0040, 0x9e86, 0x6803, 0x0000, - 0x6b52, 0x1078, 0x4982, 0x2f68, 0x0078, 0x9e7a, 0x6b52, 0x1078, - 0x4982, 0x0f7f, 0x017f, 0x007c, 0x0e7e, 0x047e, 0x037e, 0x2061, - 0xaa00, 0x2071, 0xa300, 0x7444, 0x7060, 0x8001, 0xa402, 0x00c8, - 0x9ebb, 0x2100, 0xac06, 0x0040, 0x9ead, 0x6000, 0xa086, 0x0000, - 0x0040, 0x9ead, 0x6008, 0xa206, 0x00c0, 0x9ead, 0x6018, 0xa1a0, - 0x0006, 0x2424, 0xa406, 0x0040, 0x9eb7, 0xace0, 0x0010, 0x2001, - 0xa315, 0x2004, 0xac02, 0x00c8, 0x9ebb, 0x0078, 0x9e91, 0xa085, - 0x0001, 0x0078, 0x9ebc, 0xa006, 0x037f, 0x047f, 0x0e7f, 0x007c, - 0x0d7e, 0x007e, 0x1078, 0x1381, 0x007f, 0x1040, 0x1328, 0x6837, - 0x010d, 0x685e, 0x027e, 0x2010, 0x1078, 0x8a30, 0x2001, 0x0000, - 0x0040, 0x9ed6, 0x2200, 0xa080, 0x0008, 0x2004, 0x027f, 0x684a, - 0x6956, 0x6c46, 0x684f, 0x0000, 0xa006, 0x68b2, 0x6802, 0x683a, - 0x685a, 0x1078, 0x4982, 0x0d7f, 0x007c, 0x6700, 0xa786, 0x0000, - 0x0040, 0x9ef8, 0xa786, 0x0001, 0x0040, 0x9ef8, 0xa786, 0x000a, - 0x0040, 0x9ef8, 0xa786, 0x0009, 0x0040, 0x9ef8, 0xa085, 0x0001, - 0x007c, 0x0e7e, 0x6018, 0x2070, 0x70a0, 0xa206, 0x0e7f, 0x007c, - 0x017e, 0x6004, 0xa08e, 0x001e, 0x00c0, 0x9f1a, 0x8007, 0x6130, - 0xa18c, 0x00ff, 0xa105, 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, - 0x601f, 0x0005, 0x2001, 0xa5a1, 0x2004, 0x6016, 0x1078, 0x5bf8, - 0x1078, 0x6109, 0x017f, 0x007c, 0x0005, 0x0005, 0x007c, 0x6024, - 0xd0e4, 0x0040, 0x9f30, 0xd0cc, 0x0040, 0x9f2a, 0x1078, 0x8cfa, - 0x0078, 0x9f30, 0x1078, 0xa134, 0x1078, 0x5a41, 0x1078, 0x753d, - 0x007c, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f, 0x0079, 0x9f38, - 0x9f41, 0x9f41, 0x9f41, 0x9f43, 0x9f41, 0x9f43, 0x9f43, 0x9f41, - 0x9f43, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa280, 0x0007, - 0x2004, 0xa084, 0x000f, 0x0079, 0x9f4d, 0x9f56, 0x9f56, 0x9f56, - 0x9f56, 0x9f56, 0x9f56, 0x9f61, 0x9f56, 0x9f56, 0x6007, 0x003b, - 0x602b, 0x0009, 0x6013, 0x2a00, 0x6003, 0x0001, 0x1078, 0x5bf8, - 0x007c, 0x0c7e, 0x2260, 0x1078, 0xa134, 0x603f, 0x0000, 0x6024, - 0xc0f4, 0xc0cc, 0x6026, 0x0c7f, 0x0d7e, 0x2268, 0xa186, 0x0007, - 0x00c0, 0x9fc2, 0x6810, 0xa005, 0x0040, 0x9f7f, 0xa080, 0x0013, - 0x2004, 0xd0fc, 0x00c0, 0x9f7f, 0x0d7f, 0x0078, 0x9f56, 0x6007, - 0x003a, 0x6003, 0x0001, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7e, - 0x2d60, 0x6100, 0xa186, 0x0002, 0x00c0, 0xa050, 0x6010, 0xa005, - 0x00c0, 0x9f99, 0x6000, 0xa086, 0x0007, 0x10c0, 0x1328, 0x0078, - 0xa050, 0xa08c, 0xf000, 0x00c0, 0x9fa5, 0x0078, 0x9fa5, 0x2068, - 0x6800, 0xa005, 0x00c0, 0x9f9f, 0x2d00, 0xa080, 0x0013, 0x2004, - 0xa084, 0x0003, 0xa086, 0x0002, 0x00c0, 0x9fbe, 0x6010, 0x2068, - 0x684c, 0xc0dc, 0xc0f4, 0x684e, 0x6850, 0xc0f4, 0xc0fc, 0x6852, - 0x2009, 0x0043, 0x1078, 0x98c1, 0x0078, 0xa050, 0x2009, 0x0041, - 0x0078, 0xa04a, 0xa186, 0x0005, 0x00c0, 0xa009, 0x6810, 0xa080, - 0x0013, 0x2004, 0xd0bc, 0x00c0, 0x9fd0, 0x0d7f, 0x0078, 0x9f56, - 0xd0b4, 0x0040, 0x9fd8, 0xd0fc, 0x1040, 0x1328, 0x0078, 0x9f72, - 0x6007, 0x003a, 0x6003, 0x0001, 0x1078, 0x5bf8, 0x1078, 0x6109, - 0x0c7e, 0x2d60, 0x6100, 0xa186, 0x0002, 0x0040, 0x9feb, 0xa186, - 0x0004, 0x00c0, 0xa050, 0x2071, 0xa5e1, 0x7000, 0xa086, 0x0003, - 0x00c0, 0x9ff8, 0x7004, 0xac06, 0x00c0, 0x9ff8, 0x7003, 0x0000, - 0x6810, 0xa080, 0x0013, 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000, - 0x200c, 0xc1f4, 0xc1fc, 0xc1bc, 0x2102, 0x2009, 0x0042, 0x0078, - 0xa04a, 0x037e, 0x0d7e, 0x0d7e, 0x1078, 0x1381, 0x037f, 0x1040, - 0x1328, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b, - 0x0000, 0x6b5e, 0x6857, 0x0045, 0x2c00, 0x6862, 0x6034, 0x6872, - 0x2360, 0x6024, 0xc0dd, 0x6026, 0x6018, 0xa080, 0x0028, 0x2004, - 0xa084, 0x00ff, 0x8007, 0x6320, 0x6b4a, 0x6846, 0x684f, 0x0000, - 0x6d6a, 0x6e66, 0x686f, 0x0001, 0x1078, 0x4982, 0x2019, 0x0045, - 0x6008, 0x2068, 0x1078, 0x9a6a, 0x2d00, 0x600a, 0x601f, 0x0006, - 0x6003, 0x0007, 0x6017, 0x0000, 0x603f, 0x0000, 0x0d7f, 0x037f, - 0x0078, 0xa051, 0x603f, 0x0000, 0x6003, 0x0007, 0x1078, 0x98c1, - 0x0c7f, 0x0d7f, 0x007c, 0xa186, 0x0013, 0x00c0, 0xa05d, 0x6004, - 0xa082, 0x0085, 0x2008, 0x0079, 0xa077, 0xa186, 0x0027, 0x00c0, - 0xa070, 0x1078, 0x6010, 0x037e, 0x0d7e, 0x6010, 0x2068, 0x2019, - 0x0004, 0x1078, 0x9e70, 0x0d7f, 0x037f, 0x1078, 0x6109, 0x007c, - 0xa186, 0x0014, 0x0040, 0xa061, 0x1078, 0x7583, 0x007c, 0xa080, - 0xa07e, 0xa07e, 0xa07e, 0xa07e, 0xa07e, 0xa080, 0x1078, 0x1328, - 0x1078, 0x6010, 0x6003, 0x000c, 0x1078, 0x6109, 0x007c, 0xa182, - 0x008c, 0x00c8, 0xa091, 0xa182, 0x0085, 0x0048, 0xa091, 0x0079, - 0xa094, 0x1078, 0x7583, 0x007c, 0xa09b, 0xa09b, 0xa09b, 0xa09b, - 0xa09d, 0xa0bc, 0xa09b, 0x1078, 0x1328, 0x0d7e, 0x2c68, 0x1078, - 0x74d7, 0x0040, 0xa0b7, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, - 0xa88e, 0x210c, 0x6136, 0x2009, 0xa88f, 0x210c, 0x613a, 0x600b, - 0xffff, 0x6918, 0x611a, 0x601f, 0x0004, 0x1078, 0x5bf8, 0x2d60, - 0x1078, 0x753d, 0x0d7f, 0x007c, 0x1078, 0x753d, 0x007c, 0x0e7e, - 0x6018, 0x2070, 0x7000, 0xd0ec, 0x0e7f, 0x007c, 0x6010, 0xa080, - 0x0013, 0x200c, 0xd1ec, 0x0040, 0xa110, 0x2001, 0xa371, 0x2004, - 0xd0ec, 0x0040, 0xa110, 0x6003, 0x0002, 0x6024, 0xc0e5, 0x6026, - 0xd1ac, 0x0040, 0xa0ee, 0x0f7e, 0x2c78, 0x1078, 0x488f, 0x0f7f, - 0x0040, 0xa0ee, 0x2001, 0xa5a2, 0x2004, 0x603e, 0x2009, 0xa371, - 0x210c, 0xd1f4, 0x00c0, 0xa10e, 0x0078, 0xa100, 0x2009, 0xa371, - 0x210c, 0xd1f4, 0x0040, 0xa0fa, 0x6024, 0xc0e4, 0x6026, 0xa006, - 0x0078, 0xa110, 0x2001, 0xa5a2, 0x200c, 0x8103, 0xa100, 0x603e, - 0x6018, 0xa088, 0x002b, 0x2104, 0xa005, 0x0040, 0xa10b, 0xa088, - 0x0003, 0x0078, 0xa103, 0x2c0a, 0x600f, 0x0000, 0xa085, 0x0001, - 0x007c, 0x017e, 0x0c7e, 0x0e7e, 0x6120, 0xa2f0, 0x002b, 0x2e04, - 0x2060, 0x8cff, 0x0040, 0xa130, 0x84ff, 0x00c0, 0xa123, 0x6020, - 0xa106, 0x00c0, 0xa12b, 0x600c, 0x2072, 0x1078, 0x5a41, 0x1078, - 0x753d, 0x0078, 0xa12d, 0xacf0, 0x0003, 0x2e64, 0x0078, 0xa119, - 0x0e7f, 0x0c7f, 0x017f, 0x007c, 0x0d7e, 0x6018, 0xa0e8, 0x002b, - 0x2d04, 0xa005, 0x0040, 0xa146, 0xac06, 0x0040, 0xa144, 0x2d04, - 0xa0e8, 0x0003, 0x0078, 0xa138, 0x600c, 0x206a, 0x0d7f, 0x007c, - 0x027e, 0x037e, 0x157e, 0x2011, 0xa325, 0x2204, 0xa084, 0x00ff, - 0x2019, 0xa88e, 0x2334, 0xa636, 0x00c0, 0xa174, 0x8318, 0x2334, - 0x2204, 0xa084, 0xff00, 0xa636, 0x00c0, 0xa174, 0x2011, 0xa890, - 0x6018, 0xa098, 0x000a, 0x20a9, 0x0004, 0x1078, 0x7e55, 0x00c0, - 0xa174, 0x2011, 0xa894, 0x6018, 0xa098, 0x0006, 0x20a9, 0x0004, - 0x1078, 0x7e55, 0x00c0, 0xa174, 0x157f, 0x037f, 0x027f, 0x007c, - 0x0e7e, 0x2071, 0xa300, 0x1078, 0x41f5, 0x1078, 0x260d, 0x0e7f, - 0x007c, 0x0e7e, 0x6018, 0x2070, 0x7000, 0xd0fc, 0x0040, 0xa18a, - 0x1078, 0xa18c, 0x0e7f, 0x007c, 0x6850, 0xc0e5, 0x6852, 0x007c, - 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e, 0x017e, - 0x127e, 0x2091, 0x8000, 0x2029, 0xa5b4, 0x252c, 0x2021, 0xa5ba, - 0x2424, 0x2061, 0xaa00, 0x2071, 0xa300, 0x7644, 0x7060, 0xa606, - 0x0040, 0xa1e4, 0x671c, 0xa786, 0x0001, 0x0040, 0xa1b3, 0xa786, - 0x0008, 0x00c0, 0xa1da, 0x2500, 0xac06, 0x0040, 0xa1da, 0x2400, - 0xac06, 0x0040, 0xa1da, 0x1078, 0x9ee5, 0x0040, 0xa1da, 0x1078, - 0x9ef9, 0x00c0, 0xa1da, 0x6000, 0xa086, 0x0004, 0x00c0, 0xa1cc, - 0x017e, 0x1078, 0x1749, 0x017f, 0x1078, 0x8c27, 0x00c0, 0xa1d2, - 0x1078, 0x2839, 0x1078, 0x8c3b, 0x00c0, 0xa1d8, 0x1078, 0x7a05, - 0x1078, 0x8c01, 0xace0, 0x0010, 0x2001, 0xa315, 0x2004, 0xac02, - 0x00c8, 0xa1e4, 0x0078, 0xa1a3, 0x127f, 0x017f, 0x027f, 0x047f, - 0x057f, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x007c, 0x127e, 0x007e, - 0x0e7e, 0x2091, 0x8000, 0x2071, 0xa340, 0xd5a4, 0x0040, 0xa1fb, - 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, 0xa201, 0x7030, 0x8000, - 0x7032, 0xd5ac, 0x0040, 0xa208, 0x2071, 0xa34a, 0x1078, 0xa237, - 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, - 0x8000, 0x2071, 0xa340, 0xd5a4, 0x0040, 0xa219, 0x7034, 0x8000, - 0x7036, 0xd5b4, 0x0040, 0xa21f, 0x7030, 0x8000, 0x7032, 0xd5ac, - 0x0040, 0xa226, 0x2071, 0xa34a, 0x1078, 0xa237, 0x0e7f, 0x007f, - 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071, - 0xa342, 0x1078, 0xa237, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x2e04, - 0x8000, 0x2072, 0x00c8, 0xa240, 0x8e70, 0x2e04, 0x8000, 0x2072, - 0x007c, 0x0e7e, 0x2071, 0xa340, 0x1078, 0xa237, 0x0e7f, 0x007c, - 0x0e7e, 0x2071, 0xa344, 0x1078, 0xa237, 0x0e7f, 0x007c, 0x0001, - 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, - 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x6286 -}; - -/************************************************************************ - * * - * --- ISP2200 Initiator/Target Firmware --- * - * with Fabric (Public Loop), Point-point, and * - * expanded LUN addressing for FCTAPE * - * * - ************************************************************************ - Copyright (C) 2000 and 2100 Qlogic Corporation - (www.qlogic.com) - - 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. -************************************************************************/ - -/* - * Firmware Version 2.01.27 (11:07 Dec 18, 2000) - */ - -static unsigned short risc_code_length2200 = 0x9cbf; -static unsigned short risc_code2200[] = { - 0x0470, 0x0000, 0x0000, 0x9cbf, 0x0000, 0x0002, 0x0001, 0x001b, - 0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939, - 0x3920, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241, - 0x5449, 0x4f4e, 0x2049, 0x5350, 0x3232, 0x3030, 0x2046, 0x6972, - 0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, - 0x322e, 0x3031, 0x2e32, 0x3720, 0x2020, 0x2020, 0x2400, 0x20c1, - 0x0005, 0x2001, 0x017f, 0x2003, 0x0000, 0x20c9, 0xb1ff, 0x2091, - 0x2000, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x27b5, - 0x2051, 0xad00, 0x2a70, 0x2029, 0xe400, 0x2031, 0xffff, 0x2039, - 0xe3e9, 0x2021, 0x0200, 0x0804, 0x1449, 0x20a1, 0xacbf, 0xa00e, - 0x20a9, 0x0741, 0x41a4, 0x3400, 0x755e, 0x7662, 0x775a, 0x7466, - 0x746a, 0x20a1, 0xb400, 0x7160, 0x810d, 0x810d, 0x810d, 0x810d, - 0xa18c, 0x000f, 0x2001, 0x000b, 0xa112, 0xa00e, 0x21a8, 0x41a4, - 0x3400, 0x8211, 0x1dd8, 0x7160, 0x3400, 0xa102, 0x0120, 0x0218, - 0x20a8, 0xa00e, 0x41a4, 0x3800, 0xd08c, 0x01d8, 0x2009, 0xad00, - 0x810d, 0x810d, 0x810d, 0x810d, 0xa18c, 0x000f, 0x2001, 0x0001, - 0xa112, 0x20a1, 0x1000, 0xa00e, 0x21a8, 0x41a4, 0x8211, 0x1de0, - 0x2009, 0xad00, 0x3400, 0xa102, 0x0120, 0x0218, 0x20a8, 0xa00e, - 0x41a4, 0x080c, 0x13fc, 0x080c, 0x1613, 0x080c, 0x17ac, 0x080c, - 0x1e67, 0x080c, 0x492e, 0x080c, 0x801a, 0x080c, 0x159c, 0x080c, - 0x2ce6, 0x080c, 0x5a01, 0x080c, 0x5045, 0x080c, 0x6487, 0x080c, - 0x236a, 0x080c, 0x6686, 0x080c, 0x5fae, 0x080c, 0x226b, 0x080c, - 0x2338, 0x2091, 0x3009, 0x7823, 0x0000, 0x1004, 0x10c5, 0x7820, - 0xa086, 0x0002, 0x1150, 0x7823, 0x4000, 0x0e04, 0x10bd, 0x781b, - 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, 0x7003, 0x0000, - 0x2a70, 0x7000, 0xa08e, 0x0003, 0x1158, 0x080c, 0x3c98, 0x080c, - 0x2d0d, 0x080c, 0x5a4f, 0x080c, 0x51f4, 0x080c, 0x64a2, 0x0c80, - 0x000b, 0x0c98, 0x10e4, 0x10e5, 0x1203, 0x10e2, 0x12cc, 0x13f9, - 0x13fa, 0x13fb, 0x080c, 0x14f6, 0x0005, 0x0126, 0x00f6, 0x2091, - 0x8000, 0x7000, 0xa086, 0x0001, 0x1904, 0x11d1, 0x080c, 0x1569, - 0x080c, 0x574f, 0x0150, 0x080c, 0x5775, 0x1580, 0x2079, 0x0100, - 0x7828, 0xa085, 0x1800, 0x782a, 0x0448, 0x080c, 0x569a, 0x7000, - 0xa086, 0x0001, 0x1904, 0x11d1, 0x7088, 0xa086, 0x0028, 0x1904, - 0x11d1, 0x2079, 0x0100, 0x7827, 0xffff, 0x7a28, 0xa295, 0x1e2f, - 0x7a2a, 0x2011, 0x566e, 0x080c, 0x650d, 0x2011, 0x567b, 0x080c, - 0x650d, 0x2011, 0x481b, 0x080c, 0x650d, 0x2011, 0x8030, 0x2019, - 0x0000, 0x7087, 0x0000, 0x080c, 0x1d0f, 0x00e8, 0x080c, 0x41d1, - 0x2079, 0x0100, 0x7844, 0xa005, 0x1904, 0x11d1, 0x2011, 0x481b, - 0x080c, 0x650d, 0x2011, 0x567b, 0x080c, 0x650d, 0x080c, 0x1d0f, - 0x2001, 0xaf8c, 0x2004, 0x780e, 0x7840, 0xa084, 0xfffb, 0x7842, - 0x2011, 0x8010, 0x73c8, 0x080c, 0x3c5c, 0x7238, 0xc284, 0x723a, - 0x2001, 0xad0c, 0x200c, 0xc1ac, 0x2102, 0x080c, 0x79bd, 0x2011, - 0x0004, 0x080c, 0x959c, 0x080c, 0x4f71, 0x080c, 0x574f, 0x0158, - 0x080c, 0x4917, 0x0140, 0x7087, 0x0001, 0x70c3, 0x0000, 0x080c, - 0x436e, 0x0804, 0x11d1, 0x080c, 0x502d, 0x0120, 0x7a0c, 0xc2b4, - 0x7a0e, 0x0050, 0x080c, 0x9937, 0x70d0, 0xd09c, 0x1128, 0x709c, - 0xa005, 0x0110, 0x080c, 0x48f5, 0x70db, 0x0000, 0x70d7, 0x0000, - 0x72d0, 0x080c, 0x574f, 0x1178, 0x2011, 0x0000, 0x0016, 0x080c, - 0x2744, 0x2019, 0xaf8e, 0x211a, 0x001e, 0x704f, 0xffff, 0x7053, - 0x00ef, 0x7073, 0x0000, 0x2079, 0xad51, 0x7804, 0xd0ac, 0x0108, - 0xc295, 0x72d2, 0x080c, 0x574f, 0x0118, 0xa296, 0x0004, 0x0508, - 0x2011, 0x0001, 0x080c, 0x959c, 0x7097, 0x0000, 0x709b, 0xffff, - 0x7003, 0x0002, 0x00fe, 0x080c, 0x28fa, 0x2011, 0x0005, 0x080c, - 0x7adf, 0x080c, 0x6c50, 0x080c, 0x574f, 0x0148, 0x00c6, 0x2061, - 0x0100, 0x0016, 0x080c, 0x2744, 0x61e2, 0x001e, 0x00ce, 0x012e, - 0x00d0, 0x7097, 0x0000, 0x709b, 0xffff, 0x7003, 0x0002, 0x2011, - 0x0005, 0x080c, 0x7adf, 0x080c, 0x6c50, 0x080c, 0x574f, 0x0148, - 0x00c6, 0x2061, 0x0100, 0x0016, 0x080c, 0x2744, 0x61e2, 0x001e, - 0x00ce, 0x00fe, 0x012e, 0x0005, 0x00c6, 0x080c, 0x574f, 0x1118, - 0x20a9, 0x0100, 0x0010, 0x20a9, 0x0082, 0x080c, 0x574f, 0x1118, - 0x2009, 0x0000, 0x0010, 0x2009, 0x007e, 0x0016, 0x0026, 0x0036, - 0x2110, 0x0026, 0x2019, 0x0029, 0x080c, 0x7cf4, 0x002e, 0x080c, - 0xac07, 0x003e, 0x002e, 0x001e, 0x080c, 0x2bc9, 0x8108, 0x1f04, - 0x11e5, 0x00ce, 0x706f, 0x0000, 0x7070, 0xa084, 0x00ff, 0x7072, - 0x709f, 0x0000, 0x0005, 0x0126, 0x2091, 0x8000, 0x7000, 0xa086, - 0x0002, 0x1904, 0x12ca, 0x7098, 0xa086, 0xffff, 0x0130, 0x080c, - 0x28fa, 0x080c, 0x6c50, 0x0804, 0x12ca, 0x70d0, 0xd0ac, 0x1110, - 0xd09c, 0x0540, 0xd084, 0x0530, 0x0006, 0x0016, 0x2001, 0x0103, - 0x2009, 0xaf8c, 0x210c, 0x2102, 0x001e, 0x000e, 0xd08c, 0x01d0, - 0x70d4, 0xa086, 0xffff, 0x0190, 0x080c, 0x2a56, 0x080c, 0x6c50, - 0x70d0, 0xd094, 0x1904, 0x12ca, 0x2011, 0x0001, 0x2019, 0x0000, - 0x080c, 0x2a8c, 0x080c, 0x6c50, 0x0804, 0x12ca, 0x70d8, 0xa005, - 0x1904, 0x12ca, 0x7094, 0xa005, 0x1904, 0x12ca, 0x70d0, 0xd0a4, - 0x0118, 0xd0b4, 0x0904, 0x12ca, 0x080c, 0x502d, 0x1904, 0x12ca, - 0x2001, 0xad52, 0x2004, 0xd0ac, 0x01c8, 0x0156, 0x00c6, 0x20a9, - 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4cdc, 0x1118, 0x6000, - 0xd0ec, 0x1138, 0x001e, 0x8108, 0x1f04, 0x125b, 0x00ce, 0x015e, - 0x0028, 0x001e, 0x00ce, 0x015e, 0x0804, 0x12ca, 0x0006, 0x0016, - 0x2001, 0x0103, 0x2009, 0xaf8c, 0x210c, 0x2102, 0x001e, 0x000e, - 0xa006, 0x2009, 0x0700, 0x20a9, 0x0002, 0x20a1, 0xafb5, 0x40a1, - 0x706c, 0x8007, 0x7170, 0x810f, 0x20a9, 0x0002, 0x40a1, 0x2009, - 0x0000, 0x080c, 0x14dc, 0x2001, 0x0000, 0x810f, 0x20a9, 0x0002, - 0x40a1, 0xa006, 0x2009, 0x0200, 0x20a9, 0x0002, 0x20a1, 0xafc5, - 0x40a1, 0x7030, 0xc08c, 0x7032, 0x7003, 0x0003, 0x709b, 0xffff, - 0x080c, 0x1562, 0xa006, 0x080c, 0x261e, 0x080c, 0x3cce, 0x00f6, - 0x2079, 0x0100, 0x080c, 0x5775, 0x0150, 0x080c, 0x574f, 0x7828, - 0x0118, 0xa084, 0xe1ff, 0x0010, 0xa084, 0xffdf, 0x782a, 0x00fe, - 0x2001, 0xafc8, 0x2004, 0xa086, 0x0005, 0x1120, 0x2011, 0x0000, - 0x080c, 0x7adf, 0x2011, 0x0000, 0x080c, 0x7ae9, 0x080c, 0x6c50, - 0x080c, 0x6d0d, 0x012e, 0x0005, 0x0016, 0x0046, 0x00f6, 0x0126, - 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0xad33, 0x2104, 0xa005, - 0x1110, 0x080c, 0x2770, 0x2009, 0x00f7, 0x080c, 0x48de, 0x7940, - 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0110, 0x7827, 0x0040, - 0xd19c, 0x0110, 0x7827, 0x0008, 0x0006, 0x0036, 0x0156, 0x7954, - 0xd1ac, 0x1904, 0x133a, 0x080c, 0x5761, 0x0158, 0x080c, 0x5775, - 0x1128, 0x2001, 0xaf9d, 0x2003, 0x0000, 0x0070, 0x080c, 0x5757, - 0x0dc0, 0x2001, 0xaf9d, 0x2003, 0xaaaa, 0x2001, 0xaf9e, 0x2003, - 0x0001, 0x080c, 0x569a, 0x0058, 0x080c, 0x574f, 0x0140, 0x2009, - 0x00f8, 0x080c, 0x48de, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, - 0x09c4, 0x7820, 0xd09c, 0x1138, 0x080c, 0x574f, 0x0138, 0x7824, - 0xd0ac, 0x1904, 0x13e0, 0x1f04, 0x1319, 0x0070, 0x7824, 0x080c, - 0x576b, 0x0118, 0xd0ac, 0x1904, 0x13e0, 0xa084, 0x1800, 0x0d98, - 0x7003, 0x0001, 0x0804, 0x13e0, 0x2001, 0x0001, 0x080c, 0x261e, - 0x0804, 0x13ef, 0x7850, 0xa084, 0x0180, 0x7852, 0x782f, 0x0020, - 0x20a9, 0x0046, 0x1d04, 0x1342, 0x2091, 0x6000, 0x1f04, 0x1342, - 0x7850, 0xa084, 0x0180, 0xa085, 0x0400, 0x7852, 0x782f, 0x0000, - 0x080c, 0x5761, 0x0158, 0x080c, 0x5775, 0x1128, 0x2001, 0xaf9d, - 0x2003, 0x0000, 0x0070, 0x080c, 0x5757, 0x0dc0, 0x2001, 0xaf9d, - 0x2003, 0xaaaa, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x080c, 0x569a, - 0x0020, 0x2009, 0x00f8, 0x080c, 0x48de, 0x20a9, 0x000e, 0xe000, - 0x1f04, 0x136f, 0x7850, 0xa084, 0x0180, 0xa085, 0x1400, 0x7852, - 0x080c, 0x574f, 0x0120, 0x7843, 0x0090, 0x7843, 0x0010, 0x2021, - 0xe678, 0x2019, 0xea60, 0x7820, 0xd09c, 0x1558, 0x080c, 0x574f, - 0x05b8, 0x7824, 0xd0ac, 0x1904, 0x13e0, 0x080c, 0x5775, 0x1508, - 0x0046, 0x2021, 0x0190, 0x8421, 0x1df0, 0x004e, 0x8421, 0x11c8, - 0x7827, 0x0048, 0x20a9, 0x01f4, 0x1d04, 0x139c, 0x2091, 0x6000, - 0x1f04, 0x139c, 0x7824, 0xa084, 0x0068, 0x15a8, 0x2001, 0xaf9d, - 0x2003, 0xaaaa, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x7003, 0x0001, - 0x0478, 0x8319, 0x1980, 0x2009, 0xad33, 0x2104, 0x8000, 0x200a, - 0xa084, 0xfff0, 0x0120, 0x200b, 0x0000, 0x080c, 0x2770, 0x00d8, - 0x080c, 0x5761, 0x1140, 0xa4a2, 0x0064, 0x1128, 0x080c, 0x5726, - 0x7003, 0x0001, 0x00a8, 0x7827, 0x1800, 0xe000, 0xe000, 0x7824, - 0x080c, 0x576b, 0x0110, 0xd0ac, 0x1158, 0xa084, 0x1800, 0x09c8, - 0x7003, 0x0001, 0x0028, 0x2001, 0x0001, 0x080c, 0x261e, 0x0048, - 0x2001, 0xad33, 0x2003, 0x0000, 0x7827, 0x0048, 0x7828, 0xc09d, - 0x782a, 0x7850, 0xa084, 0x0180, 0xa085, 0x0400, 0x7852, 0x015e, - 0x003e, 0x000e, 0x080c, 0x1539, 0x012e, 0x00fe, 0x004e, 0x001e, - 0x0005, 0x0005, 0x0005, 0x0005, 0x2a70, 0x2001, 0xaf9d, 0x2003, - 0x0000, 0x7087, 0x0000, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, - 0x0218, 0x704f, 0xffff, 0x0010, 0x704f, 0x0000, 0x7057, 0xffff, - 0x706f, 0x0000, 0x7073, 0x0000, 0x080c, 0x9937, 0x2061, 0xaf8d, - 0x6003, 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, - 0x6013, 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0, - 0x2061, 0xaf95, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000, - 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, - 0x601f, 0x0000, 0x2061, 0xafa6, 0x6003, 0x514c, 0x6007, 0x4f47, - 0x600b, 0x4943, 0x600f, 0x2020, 0x2001, 0xad27, 0x2003, 0x0000, - 0x0005, 0x04a0, 0x2011, 0x0000, 0x81ff, 0x0570, 0xa186, 0x0001, - 0x1148, 0x2031, 0x8fff, 0x2039, 0xcc01, 0x2021, 0x0100, 0x2029, - 0xcc00, 0x00e8, 0xa186, 0x0002, 0x1118, 0x2011, 0x0000, 0x00b8, - 0xa186, 0x0005, 0x1118, 0x2011, 0x0001, 0x0088, 0xa186, 0x0009, - 0x1118, 0x2011, 0x0002, 0x0058, 0xa186, 0x000a, 0x1118, 0x2011, - 0x0002, 0x0028, 0xa186, 0x0055, 0x1110, 0x2011, 0x0003, 0x3800, - 0xa084, 0xfffc, 0xa205, 0x20c0, 0x0804, 0x104d, 0xa00e, 0x2011, - 0x0003, 0x2019, 0x1485, 0x0804, 0x14d6, 0x2019, 0xaaaa, 0x2061, - 0xffff, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c04, 0xa306, 0x2262, - 0x1110, 0xc1b5, 0xc1a5, 0x2011, 0x0000, 0x2019, 0x1498, 0x04f0, - 0x2019, 0xaaaa, 0x2061, 0xffff, 0x2c14, 0x2362, 0xe000, 0xe000, - 0x2c1c, 0x2061, 0x7fff, 0xe000, 0xe000, 0x2c04, 0x2061, 0xffff, - 0x2262, 0xa306, 0x0110, 0xc18d, 0x0008, 0xc185, 0x2011, 0x0002, - 0x2019, 0x14b3, 0x0418, 0x2061, 0xffff, 0x2019, 0xaaaa, 0x2c14, - 0x2362, 0xe000, 0xe000, 0x2c04, 0x2262, 0xa306, 0x1180, 0x2c14, - 0x2362, 0xe000, 0xe000, 0x2c1c, 0x2061, 0x7fff, 0x2c04, 0x2061, - 0xffff, 0x2262, 0xa306, 0x1110, 0xc195, 0x0008, 0xc19d, 0x2011, - 0x0001, 0x2019, 0x14d4, 0x0010, 0x0804, 0x144a, 0x3800, 0xa084, - 0xfffc, 0xa205, 0x20c0, 0x0837, 0x2011, 0x0000, 0x080c, 0x4cdc, - 0x1178, 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0128, 0xa0c4, - 0xff00, 0xa8c6, 0x0600, 0x1120, 0xa186, 0x0080, 0x0108, 0x8210, - 0x8108, 0xa186, 0x0100, 0x1d50, 0x2208, 0x0005, 0x2091, 0x8000, - 0x0e04, 0x14f8, 0x0006, 0x0016, 0x2079, 0x0000, 0x7818, 0xd084, - 0x1de8, 0x001e, 0x792e, 0x000e, 0x782a, 0x000e, 0x7826, 0x3900, - 0x783a, 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, 0x0126, - 0x0156, 0x0146, 0x20a9, 0x0010, 0x20a1, 0xb0c8, 0x2091, 0x2000, - 0x40a1, 0x20a9, 0x0010, 0x2091, 0x2200, 0x40a1, 0x20a9, 0x0010, - 0x2091, 0x2400, 0x40a1, 0x20a9, 0x0010, 0x2091, 0x2600, 0x40a1, - 0x20a9, 0x0010, 0x2091, 0x2800, 0x40a1, 0x014e, 0x015e, 0x012e, - 0x2079, 0xad00, 0x7803, 0x0005, 0x2091, 0x4080, 0x04c9, 0x0cf8, - 0x0005, 0x0006, 0x080c, 0x1584, 0x1518, 0x00f6, 0x2079, 0xad23, - 0x2f04, 0x8000, 0x207a, 0xa082, 0x000f, 0x0258, 0xa006, 0x207a, - 0x2079, 0xad25, 0x2f04, 0xa084, 0x0001, 0xa086, 0x0001, 0x207a, - 0x0070, 0x2079, 0xad25, 0x2f7c, 0x8fff, 0x1128, 0x2001, 0x0c03, - 0x2003, 0x0040, 0x0020, 0x2001, 0x0c03, 0x2003, 0x00c0, 0x00fe, - 0x000e, 0x0005, 0x0409, 0x1120, 0x2001, 0x0c03, 0x2003, 0x0080, - 0x0005, 0x00d1, 0x1120, 0x2001, 0x0c03, 0x2003, 0x0040, 0x0005, - 0x0006, 0x0091, 0x1178, 0x2001, 0x0c03, 0x2003, 0x0040, 0x2009, - 0x0fff, 0x00a1, 0x2001, 0x0c03, 0x2003, 0x0080, 0x2009, 0x0fff, - 0x0069, 0x0c88, 0x000e, 0x0005, 0x00c6, 0x2061, 0x0c00, 0x2c04, - 0xa084, 0x00ff, 0xa086, 0x00aa, 0x00ce, 0x0005, 0x0156, 0x0126, - 0xa18c, 0x0fff, 0x21a8, 0x1d04, 0x1593, 0x2091, 0x6000, 0x1f04, - 0x1593, 0x012e, 0x015e, 0x0005, 0x2071, 0xad00, 0x715c, 0x712e, - 0x2021, 0x0001, 0xa190, 0x0030, 0xa298, 0x0030, 0x0240, 0x7060, - 0xa302, 0x1228, 0x220a, 0x2208, 0x2310, 0x8420, 0x0ca8, 0x3800, - 0xd08c, 0x0148, 0x7060, 0xa086, 0xad00, 0x0128, 0x7063, 0xad00, - 0x2011, 0x1000, 0x0c48, 0x200b, 0x0000, 0x74ae, 0x74b2, 0x0005, - 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0xad00, 0x70b0, 0xa0ea, - 0x0010, 0x0268, 0x8001, 0x70b2, 0x702c, 0x2068, 0x2d04, 0x702e, - 0x206b, 0x0000, 0x6807, 0x0000, 0x012e, 0x00ee, 0x0005, 0xa06e, - 0x0cd8, 0x00e6, 0x2071, 0xad00, 0x0126, 0x2091, 0x8000, 0x70b0, - 0x8001, 0x0260, 0x70b2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, - 0x0000, 0x6807, 0x0000, 0x012e, 0x00ee, 0x0005, 0xa06e, 0x0cd8, - 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0xad00, 0x702c, 0x206a, - 0x2d00, 0x702e, 0x70b0, 0x8000, 0x70b2, 0x012e, 0x00ee, 0x0005, - 0x8dff, 0x0138, 0x6804, 0x6807, 0x0000, 0x0006, 0x0c49, 0x00de, - 0x0cb8, 0x0005, 0x00e6, 0x2071, 0xad00, 0x70b0, 0xa08a, 0x0010, - 0xa00d, 0x00ee, 0x0005, 0x00e6, 0x2071, 0xafec, 0x7007, 0x0000, - 0x701b, 0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, - 0x8004, 0x7012, 0x00ee, 0x0005, 0x00e6, 0x2270, 0x700b, 0x0000, - 0x2071, 0xafec, 0x7018, 0xa088, 0xaff5, 0x220a, 0x8000, 0xa084, - 0x0007, 0x701a, 0x7004, 0xa005, 0x1128, 0x00f6, 0x2079, 0x0010, - 0x0081, 0x00fe, 0x00ee, 0x0005, 0x00e6, 0x2071, 0xafec, 0x7004, - 0xa005, 0x1128, 0x00f6, 0x2079, 0x0010, 0x0019, 0x00fe, 0x00ee, - 0x0005, 0x7000, 0x0002, 0x164f, 0x16b3, 0x16d0, 0x16d0, 0x7018, - 0x711c, 0xa106, 0x1118, 0x7007, 0x0000, 0x0005, 0x00d6, 0xa180, - 0xaff5, 0x2004, 0x700a, 0x2068, 0x8108, 0xa18c, 0x0007, 0x711e, - 0x7803, 0x0026, 0x6824, 0x7832, 0x6828, 0x7836, 0x682c, 0x783a, - 0x6830, 0x783e, 0x6810, 0x700e, 0x680c, 0x7016, 0x6804, 0x00de, - 0xd084, 0x0120, 0x7007, 0x0001, 0x0029, 0x0005, 0x7007, 0x0002, - 0x00b1, 0x0005, 0x0016, 0x0026, 0x710c, 0x2011, 0x0040, 0xa182, - 0x0040, 0x1210, 0x2110, 0xa006, 0x700e, 0x7212, 0x8203, 0x7822, - 0x7803, 0x0020, 0x7803, 0x0041, 0x002e, 0x001e, 0x0005, 0x0016, - 0x0026, 0x0136, 0x0146, 0x0156, 0x7014, 0x2098, 0x20a1, 0x0014, - 0x7803, 0x0026, 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x1210, - 0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, - 0x0020, 0x3300, 0x7016, 0x7803, 0x0001, 0x015e, 0x014e, 0x013e, - 0x002e, 0x001e, 0x0005, 0x0136, 0x0146, 0x0156, 0x2099, 0xadf9, - 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x0126, - 0x2091, 0x8000, 0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084, - 0x7002, 0x700b, 0xadf4, 0x012e, 0x015e, 0x014e, 0x013e, 0x0005, - 0x0136, 0x0146, 0x0156, 0x2001, 0xae28, 0x209c, 0x20a1, 0x0014, - 0x7803, 0x0026, 0x2001, 0xae29, 0x20ac, 0x53a6, 0x2099, 0xae2a, - 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x0126, - 0x2091, 0x8000, 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c, - 0x7002, 0x700b, 0xae25, 0x012e, 0x015e, 0x014e, 0x013e, 0x0005, - 0x0016, 0x00e6, 0x2071, 0xafec, 0x00f6, 0x2079, 0x0010, 0x7904, - 0x7803, 0x0002, 0xd1fc, 0x0120, 0xa18c, 0x0700, 0x7004, 0x0023, - 0x00fe, 0x00ee, 0x001e, 0x0005, 0x1649, 0x1713, 0x1741, 0x176b, - 0x179b, 0x1712, 0x0cf8, 0xa18c, 0x0700, 0x1528, 0x0136, 0x0146, - 0x0156, 0x7014, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x7010, - 0x20a8, 0x53a5, 0x3400, 0x7016, 0x015e, 0x014e, 0x013e, 0x700c, - 0xa005, 0x0570, 0x7830, 0x7832, 0x7834, 0x7836, 0x080c, 0x167a, - 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007, 0x0000, - 0x080c, 0x1649, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200, - 0x0ca8, 0xa18c, 0x0700, 0x1150, 0x700c, 0xa005, 0x0188, 0x7830, - 0x7832, 0x7834, 0x7836, 0x080c, 0x168f, 0x0005, 0x7008, 0xa080, - 0x0002, 0x2003, 0x0200, 0x7007, 0x0000, 0x080c, 0x1649, 0x0005, - 0x00d6, 0x7008, 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, - 0x682e, 0x783c, 0x6832, 0x680b, 0x0100, 0x00de, 0x7007, 0x0000, - 0x080c, 0x1649, 0x0005, 0xa18c, 0x0700, 0x1540, 0x0136, 0x0146, - 0x0156, 0x2001, 0xadf7, 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099, - 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, 0x53a5, 0x2001, 0xadf9, - 0x2004, 0xd0bc, 0x0148, 0x2001, 0xae02, 0x2004, 0xa080, 0x000d, - 0x20a0, 0x20a9, 0x0020, 0x53a5, 0x015e, 0x014e, 0x013e, 0x7007, - 0x0000, 0x080c, 0x5ae6, 0x080c, 0x1649, 0x0005, 0x2011, 0x8003, - 0x080c, 0x3c5c, 0x0cf8, 0xa18c, 0x0700, 0x1148, 0x2001, 0xae27, - 0x2003, 0x0100, 0x7007, 0x0000, 0x080c, 0x1649, 0x0005, 0x2011, - 0x8004, 0x080c, 0x3c5c, 0x0cf8, 0x0126, 0x2091, 0x2200, 0x2079, - 0x0030, 0x2071, 0xaffd, 0x7003, 0x0000, 0x700f, 0xb003, 0x7013, - 0xb003, 0x780f, 0x00f6, 0x7803, 0x0004, 0x012e, 0x0005, 0x6934, - 0xa184, 0x0007, 0x0002, 0x17cb, 0x1809, 0x17cb, 0x17cb, 0x17cb, - 0x17f1, 0x17d8, 0x17cf, 0xa085, 0x0001, 0x0804, 0x1823, 0x684c, - 0xd0bc, 0x0dc8, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x04c8, - 0xa18c, 0x00ff, 0xa186, 0x001e, 0x1d70, 0x684c, 0xd0bc, 0x0d58, - 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, 0xa080, 0x000d, - 0x2004, 0xa084, 0x000f, 0xa080, 0x2186, 0x2005, 0x6832, 0x6858, - 0x0440, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x19a8, 0x684c, 0xd0ac, - 0x0990, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, - 0xa080, 0x2186, 0x2005, 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, - 0x0080, 0x684c, 0xd0ac, 0x0904, 0x17cb, 0xa006, 0x682e, 0x682a, - 0x6858, 0xa18c, 0x000f, 0xa188, 0x2186, 0x210d, 0x6932, 0x2d08, - 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c, - 0x6912, 0x6980, 0x6916, 0x0005, 0x20e1, 0x0007, 0x20e1, 0x2000, - 0x2001, 0x020a, 0x2004, 0x82ff, 0x01a8, 0xa280, 0x0004, 0x00d6, - 0x206c, 0x684c, 0xd0dc, 0x1150, 0x080c, 0x17bf, 0x0138, 0x00de, - 0xa280, 0x0000, 0x2003, 0x0002, 0xa016, 0x0020, 0x6808, 0x8000, - 0x680a, 0x00de, 0x0126, 0x0046, 0x0036, 0x0026, 0x2091, 0x2200, - 0x002e, 0x003e, 0x004e, 0x7000, 0xa005, 0x01d0, 0x710c, 0x220a, - 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182, 0xb01e, 0x0210, - 0x2009, 0xb003, 0x710e, 0x7010, 0xa102, 0xa082, 0x0009, 0x0118, - 0xa080, 0x001b, 0x1118, 0x2009, 0x0138, 0x200a, 0x012e, 0x0005, - 0x7206, 0x2001, 0x1866, 0x0006, 0x2260, 0x0804, 0x197a, 0x0126, - 0x0026, 0x0036, 0x00c6, 0x0006, 0x2091, 0x2200, 0x000e, 0x004e, - 0x003e, 0x002e, 0x00d6, 0x00c6, 0x2460, 0x6110, 0x2168, 0x6a62, - 0x6b5e, 0xa005, 0x0904, 0x18c8, 0x6808, 0xa005, 0x0904, 0x18ff, - 0x7000, 0xa005, 0x1108, 0x0488, 0x700c, 0x7110, 0xa106, 0x1904, - 0x1907, 0x7004, 0xa406, 0x1548, 0x2001, 0x0005, 0x2004, 0xd08c, - 0x0168, 0x0046, 0x080c, 0x1a6c, 0x004e, 0x2460, 0x6010, 0xa080, - 0x0002, 0x2004, 0xa005, 0x0904, 0x18ff, 0x0c10, 0x2001, 0x0207, - 0x2004, 0xd09c, 0x1d48, 0x7804, 0xa084, 0x6000, 0x0120, 0xa086, - 0x6000, 0x0108, 0x0c08, 0x7818, 0x6812, 0x781c, 0x6816, 0x7803, - 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x6100, 0xa18e, 0x0004, - 0x1904, 0x1907, 0x2009, 0x0048, 0x080c, 0x80a7, 0x0804, 0x1907, - 0x6808, 0xa005, 0x05a0, 0x7000, 0xa005, 0x0588, 0x700c, 0x7110, - 0xa106, 0x1118, 0x7004, 0xa406, 0x1550, 0x2001, 0x0005, 0x2004, - 0xd08c, 0x0160, 0x0046, 0x080c, 0x1a6c, 0x004e, 0x2460, 0x6010, - 0xa080, 0x0002, 0x2004, 0xa005, 0x01d0, 0x0c28, 0x2001, 0x0207, - 0x2004, 0xd09c, 0x1d50, 0x2001, 0x0005, 0x2004, 0xd08c, 0x1d50, - 0x7804, 0xa084, 0x6000, 0x0118, 0xa086, 0x6000, 0x19f0, 0x7818, - 0x6812, 0x781c, 0x6816, 0x7803, 0x0004, 0x7003, 0x0000, 0x6100, - 0xa18e, 0x0004, 0x1120, 0x2009, 0x0048, 0x080c, 0x80a7, 0x00ce, - 0x00de, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x0026, 0x0036, 0x0046, - 0x0056, 0x080c, 0x1d86, 0x0026, 0x0056, 0x2071, 0xaffd, 0x7000, - 0xa086, 0x0000, 0x0580, 0x7004, 0xac06, 0x11f8, 0x2079, 0x0030, - 0x7000, 0xa086, 0x0003, 0x01c8, 0x7804, 0xd0fc, 0x1198, 0x2001, - 0x0207, 0x2004, 0xd09c, 0x1dc0, 0x7803, 0x0004, 0x7804, 0xd0ac, - 0x1de8, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, 0x0003, 0x7007, - 0x0000, 0x0018, 0x080c, 0x1a6c, 0x08d0, 0x0156, 0x20a9, 0x0009, - 0x2009, 0xb003, 0x2104, 0xac06, 0x1108, 0x200a, 0xa188, 0x0003, - 0x1f04, 0x1942, 0x015e, 0x005e, 0x002e, 0x2001, 0x015d, 0x201c, - 0x831a, 0x2302, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, - 0x005e, 0x004e, 0x003e, 0x002e, 0x00ee, 0x00fe, 0x0005, 0x700c, - 0x7110, 0xa106, 0x0904, 0x19dd, 0x2104, 0x7006, 0x2060, 0x8108, - 0x211c, 0x8108, 0x2124, 0x8108, 0xa182, 0xb01e, 0x0210, 0x2009, - 0xb003, 0x7112, 0x700c, 0xa106, 0x1128, 0x080c, 0x2744, 0x2001, - 0x0138, 0x2102, 0x8cff, 0x0588, 0x6010, 0x2068, 0x2d58, 0x6828, - 0xa406, 0x1580, 0x682c, 0xa306, 0x1568, 0x7004, 0x2060, 0x6020, - 0xc0d4, 0x6022, 0x684c, 0xd0f4, 0x0128, 0x6817, 0xffff, 0x6813, - 0xffff, 0x00d8, 0x6850, 0xd0f4, 0x1130, 0x7803, 0x0004, 0x6810, - 0x781a, 0x6814, 0x781e, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, - 0x2040, 0x6034, 0xa0cc, 0x000f, 0x2009, 0x0011, 0x04c9, 0x0118, - 0x2009, 0x0001, 0x04a9, 0x2d58, 0x0005, 0x080c, 0x1ced, 0x0904, - 0x195f, 0x0cd0, 0x6020, 0xd0d4, 0x01b8, 0x6038, 0xa402, 0x6034, - 0xa303, 0x0108, 0x1288, 0x643a, 0x6336, 0x6c2a, 0x6b2e, 0x0046, - 0x0036, 0x2400, 0x6c7c, 0xa402, 0x6812, 0x2300, 0x6b80, 0xa303, - 0x6816, 0x003e, 0x004e, 0x0018, 0x080c, 0x98cb, 0x09f0, 0x601c, - 0xa08e, 0x0008, 0x0904, 0x1985, 0xa08e, 0x000a, 0x0904, 0x1985, - 0x080c, 0x21a6, 0x1990, 0x0804, 0x1985, 0x7003, 0x0000, 0x0005, - 0x8aff, 0x0904, 0x1a46, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x11b8, - 0xd0f4, 0x1528, 0x00d6, 0x2805, 0xac68, 0x2900, 0x0002, 0x1a30, - 0x1a15, 0x1a15, 0x1a30, 0x1a30, 0x1a29, 0x1a30, 0x1a15, 0x1a30, - 0x1a1a, 0x1a1a, 0x1a30, 0x1a30, 0x1a30, 0x1a21, 0x1a1a, 0x7803, - 0x0004, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x00d6, - 0xd99c, 0x0548, 0x2805, 0xac68, 0x6f08, 0x6e0c, 0x0420, 0xc0f4, - 0x6852, 0x6b6c, 0x6a70, 0x00d6, 0x0428, 0x6b08, 0x6a0c, 0x6d00, - 0x6c04, 0x00c8, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, - 0x0090, 0x00de, 0x00d6, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, - 0x1138, 0x00de, 0x080c, 0x2148, 0x1904, 0x19e0, 0xa00e, 0x00b0, - 0x00de, 0x080c, 0x14f6, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, - 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x00de, 0x6828, 0xa300, - 0x682a, 0x682c, 0xa201, 0x682e, 0x080c, 0x2148, 0x0005, 0x080c, - 0x14f6, 0x080c, 0x1e1a, 0x7004, 0x2060, 0x00d6, 0x6010, 0x2068, - 0x7003, 0x0000, 0x080c, 0x1d22, 0x080c, 0x9596, 0x0170, 0x6808, - 0x8001, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff, - 0x682f, 0xffff, 0x6850, 0xc0bd, 0x6852, 0x00de, 0x080c, 0x929c, - 0x0804, 0x1c5e, 0x080c, 0x14f6, 0x0126, 0x2091, 0x2200, 0x0006, - 0x0016, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, - 0x0700, 0x1978, 0xa184, 0x0003, 0xa086, 0x0003, 0x0d58, 0x7000, - 0x0002, 0x1a89, 0x1a8f, 0x1b92, 0x1c39, 0x1c4d, 0x1a89, 0x1a89, - 0x1a89, 0x7804, 0xd09c, 0x1904, 0x1c5e, 0x080c, 0x14f6, 0x8001, - 0x7002, 0xa184, 0x0880, 0x1190, 0xd19c, 0x1904, 0x1b20, 0x8aff, - 0x0904, 0x1b20, 0x2009, 0x0001, 0x080c, 0x19e0, 0x0904, 0x1c5e, - 0x2009, 0x0001, 0x080c, 0x19e0, 0x0804, 0x1c5e, 0x7803, 0x0004, - 0x7003, 0x0000, 0xd1bc, 0x1904, 0x1b00, 0x0026, 0x0036, 0x7c20, - 0x7d24, 0x7e30, 0x7f34, 0x7818, 0x6812, 0x781c, 0x6816, 0x2001, - 0x0201, 0x2004, 0xa005, 0x0140, 0x7808, 0xd0ec, 0x1128, 0x7803, - 0x0009, 0x7003, 0x0004, 0x0010, 0x080c, 0x1c62, 0x6b28, 0x6a2c, - 0x2400, 0x686e, 0xa31a, 0x2500, 0x6872, 0xa213, 0x6b2a, 0x6a2e, - 0x00c6, 0x7004, 0x2060, 0x6020, 0xd0f4, 0x1110, 0x633a, 0x6236, - 0x00ce, 0x003e, 0x002e, 0x6e1e, 0x6f22, 0x080c, 0x215e, 0x2a00, - 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852, - 0x6808, 0x8001, 0x680a, 0x1148, 0x684c, 0xd0e4, 0x0130, 0x7004, - 0x2060, 0x2009, 0x0048, 0x080c, 0x80a7, 0x7000, 0xa086, 0x0004, - 0x0904, 0x1c5e, 0x7003, 0x0000, 0x080c, 0x195f, 0x0804, 0x1c5e, - 0x0056, 0x7d0c, 0xd5bc, 0x1110, 0x080c, 0xac73, 0x005e, 0x080c, - 0x1d22, 0x00f6, 0x7004, 0x2078, 0x080c, 0x5029, 0x0118, 0x7820, - 0xc0f5, 0x7822, 0x00fe, 0x682b, 0xffff, 0x682f, 0xffff, 0x6808, - 0x8001, 0x680a, 0x697c, 0x791a, 0x6980, 0x791e, 0x0804, 0x1c5e, - 0x7004, 0x00c6, 0x2060, 0x6020, 0x00ce, 0xd0f4, 0x0128, 0x6808, - 0x8001, 0x680a, 0x0804, 0x1c5e, 0x7818, 0x6812, 0x7a1c, 0x6a16, - 0xd19c, 0x0160, 0xa205, 0x0150, 0x7004, 0xa080, 0x0007, 0x2004, - 0xa084, 0xfffd, 0xa086, 0x0008, 0x1904, 0x1aa6, 0x684c, 0xc0f5, - 0x684e, 0x7814, 0xa005, 0x1180, 0x7003, 0x0000, 0x6808, 0x8001, - 0x680a, 0x1130, 0x7004, 0x2060, 0x2009, 0x0048, 0x080c, 0x80a7, - 0x080c, 0x195f, 0x0804, 0x1c5e, 0x7818, 0x6812, 0x781c, 0x6816, - 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa188, 0x0007, 0x8114, 0x8214, - 0x8214, 0xa10a, 0x8104, 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, - 0x810b, 0x080c, 0x1da5, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803, - 0x0001, 0x7804, 0xd0fc, 0x0de8, 0x7803, 0x0002, 0x7803, 0x0004, - 0x780f, 0x00f6, 0x7004, 0x7007, 0x0000, 0x2060, 0x2009, 0x0048, - 0x080c, 0x80a7, 0x080c, 0x1dd7, 0x0958, 0x7908, 0xd1ec, 0x1118, - 0x2009, 0x0009, 0x0010, 0x2009, 0x0019, 0x7902, 0x7003, 0x0003, - 0x0804, 0x1c5e, 0x8001, 0x7002, 0xd194, 0x01a8, 0x7804, 0xd0fc, - 0x1904, 0x1c2c, 0xd09c, 0x0130, 0x7804, 0xd0fc, 0x1904, 0x1a74, - 0xd09c, 0x11a8, 0x8aff, 0x0904, 0x1c5e, 0x2009, 0x0001, 0x080c, - 0x19e0, 0x0804, 0x1c5e, 0xa184, 0x0888, 0x1148, 0x8aff, 0x0904, - 0x1c5e, 0x2009, 0x0001, 0x080c, 0x19e0, 0x0804, 0x1c5e, 0x7818, - 0x6812, 0x7a1c, 0x6a16, 0xa205, 0x0904, 0x1b3e, 0x7803, 0x0004, - 0x7003, 0x0000, 0xd1bc, 0x1904, 0x1c0f, 0x6834, 0xa084, 0x00ff, - 0xa086, 0x0029, 0x1118, 0xd19c, 0x1904, 0x1b3e, 0x0026, 0x0036, - 0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7818, 0x6812, 0x781c, 0x6816, - 0x2001, 0x0201, 0x2004, 0xa005, 0x0140, 0x7808, 0xd0ec, 0x1128, - 0x7803, 0x0009, 0x7003, 0x0004, 0x0020, 0x0016, 0x080c, 0x1c62, - 0x001e, 0x6b28, 0x6a2c, 0x080c, 0x215e, 0x00d6, 0x2805, 0xac68, - 0x6034, 0xd09c, 0x1128, 0x6808, 0xa31a, 0x680c, 0xa213, 0x0020, - 0x6810, 0xa31a, 0x6814, 0xa213, 0x00de, 0xd194, 0x0904, 0x1ac8, - 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6808, 0x8001, - 0x680a, 0x6b2a, 0x6a2e, 0x003e, 0x002e, 0x0804, 0x1b50, 0x0056, - 0x7d0c, 0x080c, 0xac73, 0x005e, 0x080c, 0x1d22, 0x00f6, 0x7004, - 0x2078, 0x080c, 0x5029, 0x0118, 0x7820, 0xc0f5, 0x7822, 0x00fe, - 0x682b, 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, - 0x791a, 0x6980, 0x791e, 0x0490, 0x7804, 0xd09c, 0x0904, 0x1a74, - 0x7c20, 0x7824, 0xa405, 0x1904, 0x1a74, 0x7803, 0x0002, 0x0804, - 0x1bb7, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, 0x0150, - 0x6808, 0x8001, 0x680a, 0x1130, 0x7004, 0x2060, 0x2009, 0x0048, - 0x080c, 0x80a7, 0x080c, 0x195f, 0x0088, 0x7803, 0x0004, 0x7003, - 0x0000, 0x7004, 0x2060, 0x6010, 0xa005, 0x0da0, 0x2068, 0x6808, - 0x8000, 0x680a, 0x6c28, 0x6b2c, 0x080c, 0x197a, 0x001e, 0x000e, - 0x012e, 0x0005, 0x700c, 0x7110, 0xa106, 0x0904, 0x1ce1, 0x7004, - 0x0016, 0x210c, 0xa106, 0x001e, 0x0904, 0x1ce1, 0x00d6, 0x00c6, - 0x216c, 0x2d00, 0xa005, 0x0904, 0x1cdf, 0x6820, 0xd0d4, 0x1904, - 0x1cdf, 0x6810, 0x2068, 0x6850, 0xd0fc, 0x0558, 0x8108, 0x2104, - 0x6b2c, 0xa306, 0x1904, 0x1cdf, 0x8108, 0x2104, 0x6a28, 0xa206, - 0x1904, 0x1cdf, 0x6850, 0xc0fc, 0xc0f5, 0x6852, 0x686c, 0x7822, - 0x6870, 0x7826, 0x681c, 0x7832, 0x6820, 0x7836, 0x6818, 0x2060, - 0x6034, 0xd09c, 0x0150, 0x6830, 0x2005, 0x00d6, 0xac68, 0x6808, - 0x783a, 0x680c, 0x783e, 0x00de, 0x04a0, 0xa006, 0x783a, 0x783e, - 0x0480, 0x8108, 0x2104, 0xa005, 0x1590, 0x8108, 0x2104, 0xa005, - 0x1570, 0x6850, 0xc0f5, 0x6852, 0x6830, 0x2005, 0x6918, 0xa160, - 0xa180, 0x000d, 0x2004, 0xd09c, 0x1170, 0x6008, 0x7822, 0x686e, - 0x600c, 0x7826, 0x6872, 0x6000, 0x7832, 0x6004, 0x7836, 0xa006, - 0x783a, 0x783e, 0x0070, 0x6010, 0x7822, 0x686e, 0x6014, 0x7826, - 0x6872, 0x6000, 0x7832, 0x6004, 0x7836, 0x6008, 0x783a, 0x600c, - 0x783e, 0x6810, 0x781a, 0x6814, 0x781e, 0x7803, 0x0011, 0x00ce, - 0x00de, 0x0005, 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, 0xa005, - 0x1118, 0x8109, 0x1dd8, 0x0005, 0x0005, 0x0ca1, 0x01e0, 0x7908, - 0xd1ec, 0x1160, 0x080c, 0x1dd7, 0x0148, 0x7803, 0x0009, 0x7904, - 0xd1fc, 0x0de8, 0x7803, 0x0006, 0x0c29, 0x0168, 0x780c, 0xd0a4, - 0x1150, 0x7007, 0x0000, 0x080c, 0x1dd7, 0x0140, 0x7803, 0x0019, - 0x7003, 0x0003, 0x0018, 0x00b1, 0xa085, 0x0001, 0x0005, 0x0126, - 0x2091, 0x2200, 0x7000, 0xa086, 0x0003, 0x1150, 0x700c, 0x7110, - 0xa106, 0x0130, 0x20e1, 0x9028, 0x700f, 0xb003, 0x7013, 0xb003, - 0x012e, 0x0005, 0x00c6, 0x080c, 0x574f, 0x1550, 0x2001, 0x0160, - 0x2003, 0x0000, 0x2001, 0x0138, 0x2003, 0x0000, 0x2011, 0x00c8, - 0xe000, 0xe000, 0x8211, 0x1de0, 0x080c, 0x1d7e, 0x700c, 0x7110, - 0xa106, 0x0190, 0x2104, 0xa005, 0x0130, 0x2060, 0x6010, 0x2060, - 0x6008, 0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0xb01e, 0x0210, - 0x2009, 0xb003, 0x7112, 0x0c50, 0x080c, 0x57d1, 0x00ce, 0x0005, - 0x04a9, 0x20e1, 0x9028, 0x700c, 0x7110, 0xa106, 0x01d0, 0x2104, - 0xa005, 0x0130, 0x2060, 0x6010, 0x2060, 0x6008, 0x8001, 0x600a, - 0xa188, 0x0003, 0xa182, 0xb01e, 0x0210, 0x2009, 0xb003, 0x7112, - 0x700c, 0xa106, 0x1d40, 0x080c, 0x2744, 0x2001, 0x0138, 0x2102, - 0x0c10, 0x2001, 0x015d, 0x200c, 0x810a, 0x2102, 0x2001, 0x0160, - 0x2502, 0x2001, 0x0138, 0x2202, 0x00ce, 0x0005, 0x20e1, 0x9028, - 0x2001, 0x015d, 0x200c, 0x810a, 0x2102, 0x0005, 0x2001, 0x0138, - 0x2014, 0x2003, 0x0000, 0x2001, 0x0160, 0x202c, 0x2003, 0x0000, - 0x2021, 0xb015, 0x2001, 0x0141, 0x201c, 0xd3dc, 0x1168, 0x2001, - 0x0109, 0x201c, 0xa39c, 0x0048, 0x1138, 0x2001, 0x0111, 0x201c, - 0x83ff, 0x1110, 0x8421, 0x1d70, 0x0005, 0x00e6, 0x2071, 0x0200, - 0x7808, 0xa084, 0xf000, 0xa10d, 0x08c9, 0x2019, 0x5000, 0x8319, - 0x0168, 0x2001, 0xb01e, 0x2004, 0xa086, 0x0000, 0x0138, 0x2001, - 0x0021, 0xd0fc, 0x0da0, 0x080c, 0x1ff4, 0x0c78, 0x20e1, 0x7000, - 0x7324, 0x7420, 0x7028, 0x7028, 0x7426, 0x7037, 0x0001, 0x810f, - 0x712e, 0x702f, 0x0100, 0x7037, 0x0008, 0x7326, 0x7422, 0x2001, - 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x00ee, 0x0005, 0x7908, - 0xa18c, 0x0fff, 0xa182, 0x0009, 0x0218, 0xa085, 0x0001, 0x0088, - 0x2001, 0x020a, 0x81ff, 0x0130, 0x20e1, 0x6000, 0x200c, 0x200c, - 0x200c, 0x200c, 0x20e1, 0x7000, 0x200c, 0x200c, 0x7003, 0x0000, - 0xa006, 0x0005, 0x00f6, 0x00e6, 0x0016, 0x0026, 0x2071, 0xaffd, - 0x2079, 0x0030, 0x2011, 0x0050, 0x7000, 0xa086, 0x0000, 0x01a8, - 0x8211, 0x0188, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0dc8, 0x7904, - 0xa18c, 0x0780, 0x0016, 0x080c, 0x1a6c, 0x001e, 0x81ff, 0x1118, - 0x2011, 0x0050, 0x0c48, 0xa085, 0x0001, 0x002e, 0x001e, 0x00ee, - 0x00fe, 0x0005, 0x7803, 0x0004, 0x2009, 0x0064, 0x7804, 0xd0ac, - 0x0904, 0x1e66, 0x8109, 0x1dd0, 0x2009, 0x0100, 0x210c, 0xa18a, - 0x0003, 0x0a0c, 0x14f6, 0x080c, 0x20f2, 0x00e6, 0x00f6, 0x2071, - 0xafec, 0x2079, 0x0010, 0x7004, 0xa086, 0x0000, 0x0538, 0x7800, - 0x0006, 0x7820, 0x0006, 0x7830, 0x0006, 0x7834, 0x0006, 0x7838, - 0x0006, 0x783c, 0x0006, 0x7803, 0x0004, 0xe000, 0xe000, 0x2079, - 0x0030, 0x7804, 0xd0ac, 0x190c, 0x14f6, 0x2079, 0x0010, 0x000e, - 0x783e, 0x000e, 0x783a, 0x000e, 0x7836, 0x000e, 0x7832, 0x000e, - 0x7822, 0x000e, 0x7802, 0x00fe, 0x00ee, 0x0030, 0x00fe, 0x00ee, - 0x7804, 0xd0ac, 0x190c, 0x14f6, 0x080c, 0x6d0d, 0x0005, 0x00e6, - 0x2071, 0xb01e, 0x7003, 0x0000, 0x00ee, 0x0005, 0x00d6, 0xa280, - 0x0004, 0x206c, 0x694c, 0xd1dc, 0x1904, 0x1ee4, 0x6934, 0xa184, - 0x0007, 0x0002, 0x1e82, 0x1ecf, 0x1e82, 0x1e82, 0x1e82, 0x1eb6, - 0x1e95, 0x1e84, 0x080c, 0x14f6, 0x684c, 0xd0b4, 0x0904, 0x1fcc, - 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, - 0x6880, 0x680e, 0x6958, 0x0804, 0x1ed7, 0x6834, 0xa084, 0x00ff, - 0xa086, 0x001e, 0x1d38, 0x684c, 0xd0b4, 0x0904, 0x1fcc, 0x6860, - 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, - 0x680e, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, - 0xa080, 0x2186, 0x2005, 0x6832, 0x6958, 0x0450, 0xa18c, 0x00ff, - 0xa186, 0x0015, 0x1548, 0x684c, 0xd0b4, 0x0904, 0x1fcc, 0x6804, - 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x2186, - 0x2005, 0x6832, 0x6958, 0xa006, 0x682e, 0x682a, 0x0088, 0x684c, - 0xd0b4, 0x0904, 0x1a47, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00, - 0x681a, 0x6834, 0xa084, 0x000f, 0xa080, 0x2186, 0x2005, 0x6832, - 0x6926, 0x684c, 0xc0dd, 0x684e, 0x00de, 0x0005, 0x00f6, 0x2079, - 0x0020, 0x7804, 0xd0fc, 0x190c, 0x1ff4, 0x00e6, 0x00d6, 0x2071, - 0xb01e, 0x7000, 0xa005, 0x1904, 0x1f4c, 0x00c6, 0x7206, 0xa280, - 0x0004, 0x205c, 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, 0x00d6, - 0x2068, 0x686c, 0x7812, 0x6890, 0x00f6, 0x20e1, 0x9040, 0x2079, - 0x0200, 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x00fe, 0x00de, - 0x2b68, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, - 0xa0cc, 0x000f, 0x6908, 0x791a, 0x7116, 0x680c, 0x781e, 0x701a, - 0xa006, 0x700e, 0x7012, 0x7004, 0x692c, 0x6814, 0xa106, 0x1120, - 0x6928, 0x6810, 0xa106, 0x0158, 0x0036, 0x0046, 0x6b14, 0x6c10, - 0x080c, 0x21a6, 0x004e, 0x003e, 0x0110, 0x00ce, 0x00a8, 0x8aff, - 0x1120, 0x00ce, 0xa085, 0x0001, 0x0078, 0x0126, 0x2091, 0x8000, - 0x2079, 0x0020, 0x2009, 0x0001, 0x0059, 0x0118, 0x2009, 0x0001, - 0x0039, 0x012e, 0x00ce, 0xa006, 0x00de, 0x00ee, 0x00fe, 0x0005, - 0x0076, 0x0066, 0x0056, 0x0046, 0x0036, 0x0026, 0x8aff, 0x0904, - 0x1fc5, 0x700c, 0x7214, 0xa23a, 0x7010, 0x7218, 0xa203, 0x0a04, - 0x1fc4, 0xa705, 0x0904, 0x1fc4, 0xa03e, 0x2730, 0x6850, 0xd0fc, - 0x11a8, 0x00d6, 0x2805, 0xac68, 0x2900, 0x0002, 0x1fa7, 0x1f8c, - 0x1f8c, 0x1fa7, 0x1fa7, 0x1fa0, 0x1fa7, 0x1f8c, 0x1fa7, 0x1f91, - 0x1f91, 0x1fa7, 0x1fa7, 0x1fa7, 0x1f98, 0x1f91, 0xc0fc, 0x6852, - 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, 0x0528, 0x00d6, 0x2805, - 0xac68, 0x6f08, 0x6e0c, 0x00f0, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, - 0x00c8, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0090, - 0x00de, 0x00d6, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x1138, - 0x00de, 0x080c, 0x2148, 0x1904, 0x1f56, 0xa00e, 0x00f0, 0x00de, - 0x080c, 0x14f6, 0x00de, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, - 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, 0x682a, - 0x682c, 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, 0xa201, - 0x7012, 0x080c, 0x2148, 0x0008, 0xa006, 0x002e, 0x003e, 0x004e, - 0x005e, 0x006e, 0x007e, 0x0005, 0x080c, 0x14f6, 0x0026, 0x2001, - 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, - 0x0000, 0x7004, 0x2060, 0x00d6, 0x6010, 0x2068, 0x080c, 0x9596, - 0x0118, 0x6850, 0xc0bd, 0x6852, 0x00de, 0x080c, 0x929c, 0x20e1, - 0x9040, 0x080c, 0x7cb8, 0x2011, 0x0000, 0x080c, 0x7ae9, 0x080c, - 0x6d0d, 0x002e, 0x0804, 0x20ad, 0x0126, 0x2091, 0x2400, 0x0006, - 0x0016, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x2079, 0x0020, 0x2071, - 0xb01e, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, - 0x0700, 0x1920, 0x7000, 0x0002, 0x20ad, 0x2010, 0x2080, 0x20ab, - 0x8001, 0x7002, 0xd19c, 0x1170, 0x8aff, 0x05d0, 0x2009, 0x0001, - 0x080c, 0x1f50, 0x0904, 0x20ad, 0x2009, 0x0001, 0x080c, 0x1f50, - 0x0804, 0x20ad, 0x7803, 0x0004, 0xd194, 0x0148, 0x6850, 0xc0fc, - 0x6852, 0x8aff, 0x11d8, 0x684c, 0xc0f5, 0x684e, 0x00b8, 0x0026, - 0x0036, 0x6b28, 0x6a2c, 0x7820, 0x686e, 0xa31a, 0x7824, 0x6872, - 0xa213, 0x7830, 0x681e, 0x7834, 0x6822, 0x6b2a, 0x6a2e, 0x003e, - 0x002e, 0x080c, 0x215e, 0x6850, 0xc0fd, 0x6852, 0x2a00, 0x6826, - 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, 0x0000, 0x0804, 0x20ad, - 0x00f6, 0x0026, 0x781c, 0x0006, 0x7818, 0x0006, 0x2079, 0x0100, - 0x7a14, 0xa284, 0x0184, 0xa085, 0x0012, 0x7816, 0x0036, 0x2019, - 0x1000, 0x8319, 0x090c, 0x14f6, 0x7820, 0xd0bc, 0x1dd0, 0x003e, - 0x79c8, 0x000e, 0xa102, 0x001e, 0x0006, 0x0016, 0x79c4, 0x000e, - 0xa103, 0x78c6, 0x000e, 0x78ca, 0xa284, 0x0184, 0xa085, 0x0012, - 0x7816, 0x002e, 0x00fe, 0x7803, 0x0008, 0x7003, 0x0000, 0x0468, - 0x8001, 0x7002, 0xd194, 0x0168, 0x7804, 0xd0fc, 0x1904, 0x2004, - 0xd19c, 0x11f8, 0x8aff, 0x0508, 0x2009, 0x0001, 0x080c, 0x1f50, - 0x00e0, 0x0026, 0x0036, 0x6b28, 0x6a2c, 0x080c, 0x215e, 0x00d6, - 0x2805, 0xac68, 0x6034, 0xd09c, 0x1128, 0x6808, 0xa31a, 0x680c, - 0xa213, 0x0020, 0x6810, 0xa31a, 0x6814, 0xa213, 0x00de, 0x0804, - 0x2033, 0x0804, 0x202f, 0x080c, 0x14f6, 0x00ce, 0x00de, 0x00ee, - 0x00fe, 0x001e, 0x000e, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x2071, - 0xb01e, 0x7000, 0xa086, 0x0000, 0x0590, 0x2079, 0x0020, 0x0016, - 0x2009, 0x0207, 0x210c, 0xd194, 0x0158, 0x2009, 0x020c, 0x210c, - 0xa184, 0x0003, 0x0128, 0x20e1, 0x9040, 0x2001, 0x020c, 0x2102, - 0x2009, 0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0xa106, 0x1110, - 0x20e1, 0x9040, 0x7804, 0xd0fc, 0x0d18, 0x080c, 0x1ff4, 0x7000, - 0xa086, 0x0000, 0x19e8, 0x001e, 0x7803, 0x0004, 0x7804, 0xd0ac, - 0x1de8, 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x00ee, - 0x00fe, 0x0005, 0x0026, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2071, - 0xb01e, 0x2079, 0x0020, 0x7000, 0xa086, 0x0000, 0x0540, 0x7004, - 0x2060, 0x6010, 0x2068, 0x080c, 0x9596, 0x0158, 0x6850, 0xc0b5, - 0x6852, 0x680c, 0x7a1c, 0xa206, 0x1120, 0x6808, 0x7a18, 0xa206, - 0x01e0, 0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, - 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x080c, 0x929c, 0x20e1, - 0x9040, 0x080c, 0x7cb8, 0x2011, 0x0000, 0x080c, 0x7ae9, 0x00fe, - 0x00ee, 0x00de, 0x00ce, 0x002e, 0x0005, 0x6810, 0x6a14, 0xa205, - 0x1d00, 0x684c, 0xc0dc, 0x684e, 0x2c10, 0x080c, 0x1e6e, 0x2001, - 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, - 0x0000, 0x2069, 0xafc7, 0x6833, 0x0000, 0x683f, 0x0000, 0x08f8, - 0x8840, 0x2805, 0xa005, 0x1170, 0x6004, 0xa005, 0x0168, 0x681a, - 0x2060, 0x6034, 0xa084, 0x000f, 0xa080, 0x2186, 0x2045, 0x88ff, - 0x090c, 0x14f6, 0x8a51, 0x0005, 0x2050, 0x0005, 0x8a50, 0x8841, - 0x2805, 0xa005, 0x1190, 0x2c00, 0xad06, 0x0120, 0x6000, 0xa005, - 0x1108, 0x2d00, 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, - 0x2196, 0x2045, 0x88ff, 0x090c, 0x14f6, 0x0005, 0x0000, 0x0011, - 0x0015, 0x0019, 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, - 0x0015, 0x001b, 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x217b, - 0x2177, 0x0000, 0x0000, 0x2185, 0x0000, 0x217b, 0x0000, 0x2182, - 0x217f, 0x0000, 0x0000, 0x0000, 0x2185, 0x2182, 0x0000, 0x217d, - 0x217d, 0x0000, 0x0000, 0x2185, 0x0000, 0x217d, 0x0000, 0x2183, - 0x2183, 0x0000, 0x0000, 0x0000, 0x2185, 0x2183, 0x00a6, 0x0096, - 0x0086, 0x6b2e, 0x6c2a, 0x6858, 0xa055, 0x0904, 0x2237, 0x2d60, - 0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x2186, 0xa986, 0x0007, 0x0130, - 0xa986, 0x000e, 0x0118, 0xa986, 0x000f, 0x1120, 0x605c, 0xa422, - 0x6060, 0xa31a, 0x2805, 0xa045, 0x1140, 0x0310, 0x0804, 0x2237, - 0x6004, 0xa065, 0x0904, 0x2237, 0x0c18, 0x2805, 0xa005, 0x01a8, - 0xac68, 0xd99c, 0x1128, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0020, - 0x6810, 0xa422, 0x6814, 0xa31b, 0x0620, 0x2300, 0xa405, 0x0150, - 0x8a51, 0x0904, 0x2237, 0x8840, 0x0c40, 0x6004, 0xa065, 0x0904, - 0x2237, 0x0830, 0x8a51, 0x0904, 0x2237, 0x8840, 0x2805, 0xa005, - 0x1158, 0x6004, 0xa065, 0x0904, 0x2237, 0x6034, 0xa0cc, 0x000f, - 0xa9c0, 0x2186, 0x2805, 0x2040, 0x2b68, 0x6850, 0xc0fc, 0x6852, - 0x0458, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x00d6, 0x2b68, - 0x6c6e, 0x6b72, 0x00de, 0xd99c, 0x1168, 0x6908, 0x2400, 0xa122, - 0x690c, 0x2300, 0xa11b, 0x0a0c, 0x14f6, 0x6800, 0xa420, 0x6804, - 0xa319, 0x0060, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, - 0x0a0c, 0x14f6, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, - 0x6b22, 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, - 0x2a00, 0x6826, 0x000e, 0x000e, 0x000e, 0xa006, 0x0028, 0x008e, - 0x009e, 0x00ae, 0xa085, 0x0001, 0x0005, 0x2001, 0x0005, 0x2004, - 0xa084, 0x0007, 0x0002, 0x224b, 0x224c, 0x224f, 0x2252, 0x2257, - 0x225a, 0x225f, 0x2264, 0x0005, 0x080c, 0x1ff4, 0x0005, 0x080c, - 0x1a6c, 0x0005, 0x080c, 0x1a6c, 0x080c, 0x1ff4, 0x0005, 0x080c, - 0x16f8, 0x0005, 0x080c, 0x1ff4, 0x080c, 0x16f8, 0x0005, 0x080c, - 0x1a6c, 0x080c, 0x16f8, 0x0005, 0x080c, 0x1a6c, 0x080c, 0x1ff4, - 0x080c, 0x16f8, 0x0005, 0x0126, 0x2091, 0x2600, 0x2079, 0x0200, - 0x2071, 0xb280, 0x2069, 0xad00, 0x2009, 0x0004, 0x7912, 0x7817, - 0x0004, 0x080c, 0x2651, 0x781b, 0x0002, 0x20e1, 0x9080, 0x20e1, - 0x4000, 0x20a9, 0x0080, 0x782f, 0x0000, 0x1f04, 0x2283, 0x20e1, - 0x9080, 0x783b, 0x001f, 0x20e1, 0x8700, 0x012e, 0x0005, 0x0126, - 0x2091, 0x2600, 0x781c, 0xd0a4, 0x190c, 0x2335, 0xa084, 0x0007, - 0x0002, 0x22b3, 0x22a1, 0x22a4, 0x22a7, 0x22ac, 0x22ae, 0x22b0, - 0x22b2, 0x080c, 0x5fb7, 0x0078, 0x080c, 0x5ff0, 0x0060, 0x080c, - 0x5fb7, 0x080c, 0x5ff0, 0x0038, 0x0041, 0x0028, 0x0031, 0x0018, - 0x0021, 0x0008, 0x0011, 0x012e, 0x0005, 0x0006, 0x0016, 0x0026, - 0x7930, 0xa184, 0x0003, 0x0118, 0x20e1, 0x9040, 0x04a0, 0xa184, - 0x0030, 0x01e0, 0x6a00, 0xa286, 0x0003, 0x1108, 0x00a0, 0x080c, - 0x574f, 0x1178, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00, - 0x2003, 0x0001, 0xa085, 0x0001, 0x080c, 0x5793, 0x080c, 0x569a, - 0x0010, 0x080c, 0x485e, 0x20e1, 0x9010, 0x00a8, 0xa184, 0x00c0, - 0x0168, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0xaffd, 0x080c, - 0x1d22, 0x005e, 0x004e, 0x003e, 0x00ee, 0x0028, 0xa184, 0x0300, - 0x0110, 0x20e1, 0x9020, 0x7932, 0x002e, 0x001e, 0x000e, 0x0005, - 0x0016, 0x00e6, 0x00f6, 0x2071, 0xad00, 0x7128, 0x2001, 0xaf90, - 0x2102, 0x2001, 0xaf98, 0x2102, 0xa182, 0x0211, 0x1218, 0x2009, - 0x0008, 0x0400, 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, - 0xa182, 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349, - 0x1218, 0x2009, 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009, - 0x0004, 0x0040, 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, - 0x2009, 0x0002, 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x080c, - 0x2651, 0x00fe, 0x00ee, 0x001e, 0x0005, 0x7938, 0x080c, 0x14f6, - 0x0126, 0x2091, 0x2800, 0x2061, 0x0100, 0x2071, 0xad00, 0x6024, - 0x6026, 0x6053, 0x0030, 0x080c, 0x2690, 0x6050, 0xa084, 0xfe7f, - 0x6052, 0x2009, 0x00ef, 0x6132, 0x6136, 0x080c, 0x26a0, 0x60e7, - 0x0000, 0x61ea, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, - 0x602f, 0x0080, 0x602f, 0x0000, 0x6007, 0x0e9f, 0x601b, 0x001e, - 0x600f, 0x00ff, 0x2001, 0xaf8c, 0x2003, 0x00ff, 0x602b, 0x002f, - 0x012e, 0x0005, 0x2001, 0xad31, 0x2003, 0x0000, 0x2001, 0xad30, - 0x2003, 0x0001, 0x0005, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, - 0x0026, 0x6124, 0xa184, 0x1e2c, 0x1118, 0xa184, 0x0007, 0x002a, - 0xa195, 0x0004, 0xa284, 0x0007, 0x0002, 0x23a7, 0x238d, 0x2390, - 0x2393, 0x2398, 0x239a, 0x239e, 0x23a2, 0x080c, 0x6699, 0x00b8, - 0x080c, 0x6774, 0x00a0, 0x080c, 0x6774, 0x080c, 0x6699, 0x0078, - 0x0099, 0x0068, 0x080c, 0x6699, 0x0079, 0x0048, 0x080c, 0x6774, - 0x0059, 0x0028, 0x080c, 0x6774, 0x080c, 0x6699, 0x0029, 0x002e, - 0x001e, 0x000e, 0x012e, 0x0005, 0x6124, 0xd19c, 0x1904, 0x25bf, - 0x080c, 0x574f, 0x0578, 0x7000, 0xa086, 0x0003, 0x0198, 0x6024, - 0xa084, 0x1800, 0x0178, 0x080c, 0x5775, 0x0118, 0x080c, 0x5761, - 0x1148, 0x6027, 0x0020, 0x6043, 0x0000, 0x2001, 0xaf9d, 0x2003, - 0xaaaa, 0x0458, 0x080c, 0x5775, 0x15d0, 0x6024, 0xa084, 0x1800, - 0x1108, 0x04a8, 0x2001, 0xaf9d, 0x2003, 0xaaaa, 0x2001, 0xaf9e, - 0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0x080c, 0x569a, - 0x0804, 0x25bf, 0xd1ac, 0x1518, 0x6024, 0xd0dc, 0x1170, 0xd0e4, - 0x1188, 0xd0d4, 0x11a0, 0xd0cc, 0x0130, 0x7088, 0xa086, 0x0028, - 0x1110, 0x080c, 0x58da, 0x0804, 0x25bf, 0x2001, 0xaf9e, 0x2003, - 0x0000, 0x0048, 0x2001, 0xaf9e, 0x2003, 0x0002, 0x0020, 0x080c, - 0x584d, 0x0804, 0x25bf, 0x080c, 0x597a, 0x0804, 0x25bf, 0xd1ac, - 0x0904, 0x2507, 0x080c, 0x574f, 0x11d8, 0x6027, 0x0020, 0x0006, - 0x0026, 0x0036, 0x080c, 0x576b, 0x1170, 0x2001, 0xaf9e, 0x2003, - 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0x080c, 0x569a, 0x003e, - 0x002e, 0x000e, 0x0005, 0x003e, 0x002e, 0x000e, 0x080c, 0x5726, - 0x0016, 0x0046, 0x00c6, 0x644c, 0xa486, 0xf0f0, 0x1138, 0x2061, - 0x0100, 0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74ca, 0xa48c, - 0xff00, 0x7034, 0xd084, 0x0178, 0xa186, 0xf800, 0x1160, 0x7038, - 0xd084, 0x1148, 0xc085, 0x703a, 0x0036, 0x2418, 0x2011, 0x8016, - 0x080c, 0x3c5c, 0x003e, 0xa196, 0xff00, 0x05b8, 0x7050, 0xa084, - 0x00ff, 0x810f, 0xa116, 0x0588, 0x7130, 0xd184, 0x1570, 0x2011, - 0xad52, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132, 0x2011, 0xad52, - 0x2214, 0xd2ac, 0x1510, 0x6240, 0xa294, 0x0010, 0x0130, 0x6248, - 0xa294, 0xff00, 0xa296, 0xff00, 0x01c0, 0x7030, 0xd08c, 0x0904, - 0x24d2, 0x7034, 0xd08c, 0x1140, 0x2001, 0xad0c, 0x200c, 0xd1ac, - 0x1904, 0x24d2, 0xc1ad, 0x2102, 0x0036, 0x73c8, 0x2011, 0x8013, - 0x080c, 0x3c5c, 0x003e, 0x0804, 0x24d2, 0x7034, 0xd08c, 0x1140, - 0x2001, 0xad0c, 0x200c, 0xd1ac, 0x1904, 0x24d2, 0xc1ad, 0x2102, - 0x0036, 0x73c8, 0x2011, 0x8013, 0x080c, 0x3c5c, 0x003e, 0x7130, - 0xc185, 0x7132, 0x2011, 0xad52, 0x220c, 0xd1a4, 0x01d0, 0x0016, - 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x663f, 0x2019, 0x000e, - 0x080c, 0xa8eb, 0xa484, 0x00ff, 0xa080, 0x2be6, 0x200d, 0xa18c, - 0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x080c, 0xa96c, - 0x001e, 0xd1ac, 0x1148, 0x0016, 0x2009, 0x0000, 0x2019, 0x0004, - 0x080c, 0x2aac, 0x001e, 0x0070, 0x0156, 0x20a9, 0x007f, 0x2009, - 0x0000, 0x080c, 0x4cdc, 0x1110, 0x080c, 0x493a, 0x8108, 0x1f04, - 0x24c9, 0x015e, 0x00ce, 0x004e, 0x2011, 0x0003, 0x080c, 0x7adf, - 0x2011, 0x0002, 0x080c, 0x7ae9, 0x080c, 0x79e1, 0x080c, 0x6581, - 0x0036, 0x2019, 0x0000, 0x080c, 0x7a64, 0x003e, 0x60e3, 0x0000, - 0x001e, 0x2001, 0xad00, 0x2014, 0xa296, 0x0004, 0x1128, 0xd19c, - 0x1118, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xad22, - 0x2003, 0x0000, 0x6027, 0x0020, 0x080c, 0x5775, 0x1140, 0x0016, - 0x2009, 0x07d0, 0x2011, 0x567b, 0x080c, 0x6593, 0x001e, 0xd194, - 0x0904, 0x25bf, 0x0016, 0x6220, 0xd2b4, 0x0904, 0x2570, 0x080c, - 0x6581, 0x080c, 0x7834, 0x6027, 0x0004, 0x00f6, 0x2019, 0xafd0, - 0x2304, 0xa07d, 0x0570, 0x7804, 0xa086, 0x0032, 0x1550, 0x00d6, - 0x00c6, 0x00e6, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e, - 0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x1df0, - 0x6043, 0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e, 0x628a, - 0x080c, 0x6b73, 0x080c, 0x6c50, 0x7810, 0x2070, 0x7037, 0x0103, - 0x2f60, 0x080c, 0x8078, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e, - 0x0005, 0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, - 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, 0x2061, - 0xafc7, 0x6028, 0xa09a, 0x00c8, 0x1238, 0x8000, 0x602a, 0x00ce, - 0x080c, 0x7827, 0x0804, 0x25be, 0x2019, 0xafd0, 0x2304, 0xa065, - 0x0120, 0x2009, 0x0027, 0x080c, 0x80a7, 0x00ce, 0x0804, 0x25be, - 0xd2bc, 0x0904, 0x25be, 0x080c, 0x658e, 0x6014, 0xa084, 0x0184, - 0xa085, 0x0010, 0x6016, 0x6027, 0x0004, 0x00d6, 0x2069, 0x0140, - 0x6804, 0xa084, 0x4000, 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, - 0x00de, 0x00c6, 0x2061, 0xafc7, 0x6044, 0xa09a, 0x00c8, 0x12f0, - 0x8000, 0x6046, 0x603c, 0x00ce, 0xa005, 0x0540, 0x2009, 0x07d0, - 0x080c, 0x6586, 0xa080, 0x0007, 0x2004, 0xa086, 0x0006, 0x1138, - 0x6114, 0xa18c, 0x0184, 0xa18d, 0x0012, 0x6116, 0x00b8, 0x6114, - 0xa18c, 0x0184, 0xa18d, 0x0016, 0x6116, 0x0080, 0x0036, 0x2019, - 0x0001, 0x080c, 0x7a64, 0x003e, 0x2019, 0xafd6, 0x2304, 0xa065, - 0x0120, 0x2009, 0x004f, 0x080c, 0x80a7, 0x00ce, 0x001e, 0xd19c, - 0x0904, 0x261a, 0x7034, 0xd0ac, 0x1560, 0x0016, 0x0156, 0x6027, - 0x0008, 0x602f, 0x0020, 0x20a9, 0x0006, 0x1d04, 0x25cd, 0x2091, - 0x6000, 0x1f04, 0x25cd, 0x602f, 0x0000, 0x6150, 0xa185, 0x1400, - 0x6052, 0x20a9, 0x0366, 0x1d04, 0x25db, 0x2091, 0x6000, 0x6020, - 0xd09c, 0x1130, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x0490, - 0x080c, 0x2760, 0x1f04, 0x25db, 0x015e, 0x6152, 0x001e, 0x6027, - 0x0008, 0x0016, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c, - 0x7adf, 0x2011, 0x0002, 0x080c, 0x7ae9, 0x080c, 0x79e1, 0x080c, - 0x6581, 0x0036, 0x2019, 0x0000, 0x080c, 0x7a64, 0x003e, 0x60e3, - 0x0000, 0x080c, 0xac8d, 0x080c, 0xaca8, 0xa085, 0x0001, 0x080c, - 0x5793, 0x2001, 0xad00, 0x2003, 0x0004, 0x6027, 0x0008, 0x080c, - 0x12cc, 0x001e, 0xa18c, 0xffd0, 0x6126, 0x0005, 0x0006, 0x0016, - 0x0026, 0x00e6, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2071, 0xad00, - 0x71c0, 0x70c2, 0xa116, 0x01f0, 0x81ff, 0x0128, 0x2011, 0x8011, - 0x080c, 0x3c5c, 0x00b8, 0x2011, 0x8012, 0x080c, 0x3c5c, 0x2001, - 0xad71, 0x2004, 0xd0fc, 0x1170, 0x0036, 0x00c6, 0x080c, 0x26eb, - 0x2061, 0x0100, 0x2019, 0x0028, 0x2009, 0x0000, 0x080c, 0x2aac, - 0x00ce, 0x003e, 0x012e, 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e, - 0x0005, 0x00c6, 0x00f6, 0x0006, 0x0026, 0x2061, 0x0100, 0xa190, - 0x2664, 0x2205, 0x60f2, 0x2011, 0x2671, 0x2205, 0x60ee, 0x002e, - 0x000e, 0x00fe, 0x00ce, 0x0005, 0x0840, 0x0840, 0x0840, 0x0580, - 0x0420, 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, - 0x01a8, 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, - 0x00ff, 0x2130, 0xa094, 0xff00, 0x1110, 0x81ff, 0x0118, 0x080c, - 0x6278, 0x0038, 0xa080, 0x2be6, 0x200d, 0xa18c, 0xff00, 0x810f, - 0xa006, 0x0005, 0xa080, 0x2be6, 0x200d, 0xa18c, 0x00ff, 0x0005, - 0x00d6, 0x2069, 0x0140, 0x2001, 0xad14, 0x2003, 0x00ef, 0x20a9, - 0x0010, 0xa006, 0x6852, 0x6856, 0x1f04, 0x269b, 0x00de, 0x0005, - 0x0006, 0x00d6, 0x0026, 0x2069, 0x0140, 0x2001, 0xad14, 0x2102, - 0x8114, 0x8214, 0x8214, 0x8214, 0x20a9, 0x0010, 0x6853, 0x0000, - 0xa006, 0x82ff, 0x1128, 0xa184, 0x000f, 0xa080, 0xacae, 0x2005, - 0x6856, 0x8211, 0x1f04, 0x26b0, 0x002e, 0x00de, 0x000e, 0x0005, - 0x00c6, 0x2061, 0xad00, 0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c, - 0x6032, 0x00ce, 0x0005, 0x0156, 0x00d6, 0x0026, 0x0016, 0x0006, - 0x2069, 0x0140, 0x6980, 0xa116, 0x0180, 0xa112, 0x1230, 0x8212, - 0x8210, 0x22a8, 0x2001, 0x0402, 0x0018, 0x22a8, 0x2001, 0x0404, - 0x680e, 0x1f04, 0x26e0, 0x680f, 0x0000, 0x000e, 0x001e, 0x002e, - 0x00de, 0x015e, 0x0005, 0x2001, 0xad52, 0x2004, 0xd0c4, 0x0150, - 0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020, 0x2009, 0x002e, 0x080c, - 0xa96c, 0x004e, 0x0005, 0x00f6, 0x0016, 0x0026, 0x2079, 0x0140, - 0x78c4, 0xd0dc, 0x0548, 0xa084, 0x0700, 0xa08e, 0x0300, 0x1520, - 0x2011, 0x0000, 0x2009, 0x0002, 0x2300, 0xa080, 0x0020, 0x2018, - 0x2300, 0x080c, 0x6665, 0x2011, 0x0030, 0x2200, 0x8007, 0xa085, - 0x004c, 0x78c2, 0x2009, 0x0204, 0x210c, 0x2200, 0xa100, 0x2009, - 0x0138, 0x200a, 0x080c, 0x574f, 0x1118, 0x2009, 0xaf8e, 0x200a, - 0x002e, 0x001e, 0x00fe, 0x0005, 0x78c3, 0x0000, 0x0cc8, 0x0126, - 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x2001, 0x0170, 0x200c, - 0x8000, 0x2014, 0xa184, 0x0003, 0x0110, 0x0804, 0x1a6a, 0x002e, - 0x001e, 0x000e, 0x012e, 0x0005, 0x0006, 0x2001, 0x0100, 0x2004, - 0xa082, 0x0005, 0x000e, 0x0268, 0x2001, 0x0170, 0x200c, 0xa18c, - 0x00ff, 0xa18e, 0x004c, 0x1128, 0x200c, 0xa18c, 0xff00, 0x810f, - 0x0010, 0x2009, 0x0000, 0x2001, 0x0204, 0x2004, 0xa108, 0x0005, - 0x0006, 0x0156, 0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, - 0xd08c, 0x1110, 0x1f04, 0x2767, 0x00fe, 0x015e, 0x000e, 0x0005, - 0x0016, 0x00c6, 0x0006, 0x2061, 0x0100, 0x6030, 0x0006, 0x6048, - 0x0006, 0x60e4, 0x0006, 0x60e8, 0x0006, 0x6050, 0x0006, 0x60f0, - 0x0006, 0x60ec, 0x0006, 0x600c, 0x0006, 0x6004, 0x0006, 0x6028, - 0x0006, 0x60e0, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000, 0xe000, - 0xe000, 0xe000, 0xe000, 0x602f, 0x0040, 0x602f, 0x0000, 0x000e, - 0x60e2, 0x000e, 0x602a, 0x000e, 0x6006, 0x000e, 0x600e, 0x000e, - 0x60ee, 0x000e, 0x60f2, 0x000e, 0x6052, 0x000e, 0x60ea, 0x000e, - 0x60e6, 0x000e, 0x604a, 0x000e, 0x6032, 0x6036, 0x2008, 0x080c, - 0x26a0, 0x000e, 0x00ce, 0x001e, 0x0005, 0x2845, 0x2849, 0x284d, - 0x2853, 0x2859, 0x285f, 0x2865, 0x286d, 0x2875, 0x287b, 0x2881, - 0x2889, 0x2891, 0x2899, 0x28a1, 0x28ab, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b7, 0x28b7, 0x28bc, - 0x28bc, 0x28c3, 0x28c3, 0x28ca, 0x28ca, 0x28d3, 0x28d3, 0x28da, - 0x28da, 0x28e3, 0x28e3, 0x28ec, 0x28ec, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, - 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x0106, 0x0006, 0x0804, - 0x28f7, 0x0106, 0x0006, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, - 0x2373, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x0804, - 0x28f7, 0x0106, 0x0006, 0x080c, 0x223d, 0x0804, 0x28f7, 0x0106, - 0x0006, 0x080c, 0x223d, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, - 0x2373, 0x080c, 0x223d, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, - 0x2373, 0x080c, 0x223d, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, - 0x228f, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, 0x228f, 0x0804, - 0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x080c, 0x228f, 0x0804, - 0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x080c, 0x228f, 0x0804, - 0x28f7, 0x0106, 0x0006, 0x080c, 0x223d, 0x080c, 0x228f, 0x0804, - 0x28f7, 0x0106, 0x0006, 0x080c, 0x223d, 0x080c, 0x228f, 0x0804, - 0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x080c, 0x223d, 0x080c, - 0x228f, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x080c, - 0x223d, 0x080c, 0x228f, 0x0804, 0x28f7, 0xe000, 0x0cf0, 0x0106, - 0x0006, 0x080c, 0x272f, 0x04d8, 0x0106, 0x0006, 0x080c, 0x272f, - 0x080c, 0x2373, 0x04a0, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c, - 0x223d, 0x0468, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c, 0x2373, - 0x080c, 0x223d, 0x0420, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c, - 0x228f, 0x00e8, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c, 0x2373, - 0x080c, 0x228f, 0x00a0, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c, - 0x223d, 0x080c, 0x228f, 0x0058, 0x0106, 0x0006, 0x080c, 0x272f, - 0x080c, 0x2373, 0x080c, 0x223d, 0x080c, 0x228f, 0x0000, 0x000e, - 0x010e, 0x000d, 0x00c6, 0x0026, 0x0046, 0x2021, 0x0000, 0x080c, - 0x502d, 0x1904, 0x29d4, 0x72d0, 0x2001, 0xaf9d, 0x2004, 0xa005, - 0x1110, 0xd29c, 0x0148, 0xd284, 0x1138, 0xd2bc, 0x1904, 0x29d4, - 0x080c, 0x29d8, 0x0804, 0x29d4, 0x080c, 0x574f, 0x1120, 0x709b, - 0xffff, 0x0804, 0x29d4, 0xd294, 0x0120, 0x709b, 0xffff, 0x0804, - 0x29d4, 0x2001, 0xad14, 0x203c, 0x7284, 0xd284, 0x0904, 0x2976, - 0xd28c, 0x1904, 0x2976, 0x0036, 0x7398, 0xa38e, 0xffff, 0x1110, - 0x2019, 0x0001, 0x8314, 0xa2e0, 0xb3c0, 0x2c04, 0xa38c, 0x0001, - 0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084, 0x00ff, 0xa70e, - 0x0560, 0xa08e, 0x0000, 0x0548, 0xa08e, 0x00ff, 0x1150, 0x7230, - 0xd284, 0x1538, 0x7284, 0xc28d, 0x7286, 0x709b, 0xffff, 0x003e, - 0x0428, 0x2009, 0x0000, 0x080c, 0x2676, 0x080c, 0x4c80, 0x11b8, - 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1150, 0x7030, 0xd08c, - 0x0118, 0x6000, 0xd0bc, 0x0120, 0x080c, 0x29eb, 0x0140, 0x0028, - 0x080c, 0x2b1a, 0x080c, 0x2a19, 0x0110, 0x8318, 0x0818, 0x739a, - 0x0010, 0x709b, 0xffff, 0x003e, 0x0804, 0x29d4, 0xa780, 0x2be6, - 0x203d, 0xa7bc, 0xff00, 0x873f, 0x2041, 0x007e, 0x7098, 0xa096, - 0xffff, 0x1120, 0x2009, 0x0000, 0x28a8, 0x0050, 0xa812, 0x0220, - 0x2008, 0xa802, 0x20a8, 0x0020, 0x709b, 0xffff, 0x0804, 0x29d4, - 0x2700, 0x0156, 0x0016, 0xa106, 0x05a0, 0xc484, 0x080c, 0x4cdc, - 0x0120, 0x080c, 0x4c80, 0x15a8, 0x0008, 0xc485, 0x6004, 0xa084, - 0x00ff, 0xa086, 0x0006, 0x1130, 0x7030, 0xd08c, 0x01e8, 0x6000, - 0xd0bc, 0x11d0, 0x7284, 0xd28c, 0x0188, 0x6004, 0xa084, 0x00ff, - 0xa082, 0x0006, 0x02b0, 0xd484, 0x1118, 0x080c, 0x4c9f, 0x0028, - 0x080c, 0x2b9c, 0x0170, 0x080c, 0x2bc9, 0x0058, 0x080c, 0x2b1a, - 0x080c, 0x2a19, 0x0170, 0x0028, 0x080c, 0x2b9c, 0x0110, 0x0419, - 0x0140, 0x001e, 0x8108, 0x015e, 0x1f04, 0x2990, 0x709b, 0xffff, - 0x0018, 0x001e, 0x015e, 0x719a, 0x004e, 0x002e, 0x00ce, 0x0005, - 0x00c6, 0x0016, 0x709b, 0x0000, 0x2009, 0x007e, 0x080c, 0x4c80, - 0x1138, 0x080c, 0x2b1a, 0x04a9, 0x0118, 0x70d0, 0xc0bd, 0x70d2, - 0x001e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, - 0x2001, 0xad56, 0x2004, 0xa084, 0x00ff, 0x6842, 0x080c, 0x9807, - 0x01d8, 0x2d00, 0x601a, 0x080c, 0x9956, 0x601f, 0x0001, 0x2001, - 0x0000, 0x080c, 0x4c1e, 0x2001, 0x0000, 0x080c, 0x4c30, 0x0126, - 0x2091, 0x8000, 0x7094, 0x8000, 0x7096, 0x012e, 0x2009, 0x0004, - 0x080c, 0x80a7, 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, - 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x2001, 0xad56, - 0x2004, 0xa084, 0x00ff, 0x6842, 0x080c, 0x9807, 0x0550, 0x2d00, - 0x601a, 0x6800, 0xc0c4, 0x6802, 0x68a0, 0xa086, 0x007e, 0x0140, - 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1110, 0x080c, 0x2ad9, - 0x080c, 0x9956, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4c1e, - 0x2001, 0x0002, 0x080c, 0x4c30, 0x0126, 0x2091, 0x8000, 0x7094, - 0x8000, 0x7096, 0x012e, 0x2009, 0x0002, 0x080c, 0x80a7, 0xa085, - 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x0026, - 0x2009, 0x0080, 0x080c, 0x4c80, 0x1120, 0x0031, 0x0110, 0x70d7, - 0xffff, 0x002e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, - 0x2c68, 0x080c, 0x8022, 0x01d8, 0x2d00, 0x601a, 0x080c, 0x9956, - 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x2001, 0x0002, - 0x080c, 0x4c30, 0x0126, 0x2091, 0x8000, 0x70d8, 0x8000, 0x70da, - 0x012e, 0x2009, 0x0002, 0x080c, 0x80a7, 0xa085, 0x0001, 0x00ce, - 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x00d6, 0x0126, 0x2091, - 0x8000, 0x2009, 0x007f, 0x080c, 0x4c80, 0x1190, 0x2c68, 0x080c, - 0x8022, 0x0170, 0x2d00, 0x601a, 0x6312, 0x601f, 0x0001, 0x620a, - 0x080c, 0x9956, 0x2009, 0x0022, 0x080c, 0x80a7, 0xa085, 0x0001, - 0x012e, 0x00de, 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0066, 0x0036, - 0x0026, 0x080c, 0x68f3, 0x080c, 0x689d, 0x080c, 0x8a15, 0x2130, - 0x81ff, 0x0128, 0x20a9, 0x007e, 0x2009, 0x0000, 0x0020, 0x20a9, - 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4cdc, 0x1120, 0x080c, - 0x4ecf, 0x080c, 0x493a, 0x001e, 0x8108, 0x1f04, 0x2ac3, 0x86ff, - 0x1110, 0x080c, 0x11d4, 0x002e, 0x003e, 0x006e, 0x00ce, 0x00ee, - 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x6218, 0x2270, - 0x72a0, 0x0026, 0x2019, 0x0029, 0x080c, 0x68e7, 0x0076, 0x2039, - 0x0000, 0x080c, 0x681d, 0x2c08, 0x080c, 0xa712, 0x007e, 0x001e, - 0x2e60, 0x080c, 0x4ecf, 0x6210, 0x6314, 0x080c, 0x493a, 0x6212, - 0x6316, 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x0005, 0x00e6, - 0x0006, 0x6018, 0xa080, 0x0028, 0x2004, 0xa086, 0x0080, 0x0150, - 0x2071, 0xad00, 0x7094, 0xa005, 0x0110, 0x8001, 0x7096, 0x000e, - 0x00ee, 0x0005, 0x2071, 0xad00, 0x70d8, 0xa005, 0x0dc0, 0x8001, - 0x70da, 0x0ca8, 0x6000, 0xc08c, 0x6002, 0x0005, 0x00f6, 0x00e6, - 0x00c6, 0x0036, 0x0026, 0x0016, 0x0156, 0x2178, 0x81ff, 0x1118, - 0x20a9, 0x0001, 0x0098, 0x2001, 0xad52, 0x2004, 0xd0c4, 0x0150, - 0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020, 0x2009, 0x002d, 0x080c, - 0xa96c, 0x004e, 0x20a9, 0x00ff, 0x2011, 0x0000, 0x0026, 0xa28e, - 0x007e, 0x05c8, 0xa28e, 0x007f, 0x05b0, 0xa28e, 0x0080, 0x0598, - 0xa288, 0xae34, 0x210c, 0x81ff, 0x0570, 0x8fff, 0x05c1, 0x00c6, - 0x2160, 0x2001, 0x0001, 0x080c, 0x5037, 0x00ce, 0x2019, 0x0029, - 0x080c, 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x00c6, - 0x0026, 0x2160, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, 0x1118, - 0x6007, 0x0404, 0x0028, 0x2001, 0x0004, 0x8007, 0xa215, 0x6206, - 0x002e, 0x00ce, 0x0016, 0x2c08, 0x080c, 0xa712, 0x001e, 0x007e, - 0x2160, 0x080c, 0x4ecf, 0x002e, 0x8210, 0x1f04, 0x2b3e, 0x015e, - 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0046, - 0x0026, 0x0016, 0x2001, 0xad52, 0x2004, 0xd0c4, 0x0148, 0xd0a4, - 0x0138, 0xa006, 0x2220, 0x8427, 0x2009, 0x0029, 0x080c, 0xa96c, - 0x001e, 0x002e, 0x004e, 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, - 0x7284, 0x82ff, 0x01f8, 0x2011, 0xad52, 0x2214, 0xd2ac, 0x11d0, - 0x2100, 0x080c, 0x268a, 0x81ff, 0x01b8, 0x2019, 0x0001, 0x8314, - 0xa2e0, 0xb3c0, 0x2c04, 0xd384, 0x0120, 0xa084, 0xff00, 0x8007, - 0x0010, 0xa084, 0x00ff, 0xa116, 0x0138, 0xa096, 0x00ff, 0x0110, - 0x8318, 0x0c68, 0xa085, 0x0001, 0x00ce, 0x003e, 0x002e, 0x001e, - 0x0005, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0xa180, 0xae34, - 0x2004, 0xa065, 0x0178, 0x0016, 0x00c6, 0x080c, 0x9807, 0x001e, - 0x090c, 0x14f6, 0x611a, 0x080c, 0x2ad9, 0x080c, 0x8078, 0x001e, - 0x080c, 0x4c9f, 0x012e, 0x00ce, 0x001e, 0x0005, 0x7eef, 0x7de8, - 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, 0x80d6, - 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, 0x80cc, - 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, 0x80bc, - 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, 0x80b1, - 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, 0x6da6, - 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, 0x6797, - 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, 0x8081, 0x8080, 0x617c, - 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, 0x8071, - 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, 0x5a66, - 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, 0x8056, 0x8055, 0x5454, - 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, 0x4e4a, - 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, 0x8039, - 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, 0x472d, - 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, 0x8026, 0x8025, 0x4123, - 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, 0x3b0f, - 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, 0x8000, 0x3800, 0x3700, - 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, 0x8000, 0x3400, 0x8000, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3300, 0x3200, 0x8000, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3100, 0x3000, 0x8000, - 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, 0x8000, - 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, 0x2700, - 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, 0x8000, 0x8000, 0x2100, - 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, 0x1b00, - 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, - 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, 0x1500, 0x8000, 0x1400, - 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, 0x0e00, - 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, 0x0800, - 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, 0x8000, 0x0500, 0x0400, - 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, 0x8000, 0x0100, 0x8000, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x8000, 0x8000, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, - 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x2071, 0xad81, - 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, 0x703a, 0x703e, 0x7033, - 0xad91, 0x7037, 0xad91, 0x7007, 0x0001, 0x2061, 0xadd1, 0x6003, - 0x0002, 0x0005, 0x1004, 0x2d0c, 0x0e04, 0x2d0c, 0x2071, 0xad81, - 0x2b78, 0x7818, 0xd084, 0x1140, 0x2a60, 0x7820, 0xa08e, 0x0069, - 0x1904, 0x2df1, 0x0804, 0x2d8a, 0x0005, 0x2071, 0xad81, 0x7004, - 0x0002, 0x2d15, 0x2d16, 0x2d1f, 0x2d30, 0x0005, 0x1004, 0x2d1e, - 0x0e04, 0x2d1e, 0x2b78, 0x7818, 0xd084, 0x01e8, 0x0005, 0x2b78, - 0x2061, 0xadd1, 0x6008, 0xa08e, 0x0100, 0x0128, 0xa086, 0x0200, - 0x0904, 0x2deb, 0x0005, 0x7014, 0x2068, 0x2a60, 0x7018, 0x0807, - 0x7010, 0x2068, 0x6834, 0xa086, 0x0103, 0x0108, 0x0005, 0x2a60, - 0x2b78, 0x7018, 0x0807, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x1210, - 0x61c0, 0x0042, 0x2100, 0xa08a, 0x003f, 0x1a04, 0x2de8, 0x61c0, - 0x0804, 0x2d8a, 0x2dcc, 0x2df7, 0x2dff, 0x2e03, 0x2e0b, 0x2e11, - 0x2e15, 0x2e21, 0x2e24, 0x2e2e, 0x2e31, 0x2de8, 0x2de8, 0x2de8, - 0x2e34, 0x2de8, 0x2e43, 0x2e5a, 0x2e71, 0x2ee8, 0x2eed, 0x2f16, - 0x2f67, 0x2f78, 0x2f96, 0x2fcd, 0x2fd7, 0x2fe4, 0x2ff7, 0x3018, - 0x3021, 0x3057, 0x305d, 0x2de8, 0x3086, 0x2de8, 0x2de8, 0x2de8, - 0x2de8, 0x2de8, 0x308d, 0x3097, 0x2de8, 0x2de8, 0x2de8, 0x2de8, - 0x2de8, 0x2de8, 0x2de8, 0x2de8, 0x309f, 0x2de8, 0x2de8, 0x2de8, - 0x2de8, 0x2de8, 0x30b1, 0x30b9, 0x2de8, 0x2de8, 0x2de8, 0x2de8, - 0x2de8, 0x2de8, 0x0002, 0x30cb, 0x311f, 0x317a, 0x318a, 0x2de8, - 0x31a4, 0x35cb, 0x3fbb, 0x2de8, 0x2de8, 0x2de8, 0x2de8, 0x2de8, - 0x2de8, 0x2de8, 0x2de8, 0x2e2e, 0x2e31, 0x35cd, 0x2de8, 0x35da, - 0x403c, 0x4097, 0x40fb, 0x2de8, 0x415a, 0x4180, 0x419f, 0x2de8, - 0x2de8, 0x2de8, 0x2de8, 0x35de, 0x376b, 0x3785, 0x37a3, 0x3804, - 0x3858, 0x3863, 0x389a, 0x38a9, 0x38b8, 0x38bb, 0x38de, 0x3928, - 0x398e, 0x399b, 0x3a9c, 0x3bb3, 0x3bdc, 0x3cda, 0x3cfc, 0x3d08, - 0x3d41, 0x3e05, 0x2de8, 0x2de8, 0x2de8, 0x2de8, 0x3e6d, 0x3e88, - 0x3efa, 0x3fac, 0x713c, 0x0000, 0x2021, 0x4000, 0x080c, 0x3c39, - 0x0126, 0x2091, 0x8000, 0x0e04, 0x2dd8, 0x7818, 0xd084, 0x0110, - 0x012e, 0x0cb0, 0x7c22, 0x7926, 0x7a2a, 0x7b2e, 0x781b, 0x0001, - 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, 0x5000, 0x012e, 0x0005, - 0x2021, 0x4001, 0x0c18, 0x2021, 0x4002, 0x0c00, 0x2021, 0x4003, - 0x08e8, 0x2021, 0x4005, 0x08d0, 0x2021, 0x4006, 0x08b8, 0xa02e, - 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0804, 0x3c46, 0x7823, - 0x0004, 0x7824, 0x0807, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, - 0x7930, 0x0804, 0x3c49, 0x7924, 0x7828, 0x2114, 0x200a, 0x0804, - 0x2dcc, 0x7924, 0x2114, 0x0804, 0x2dcc, 0x2099, 0x0009, 0x20a1, - 0x0009, 0x20a9, 0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0804, - 0x2dcc, 0x7824, 0x2060, 0x0090, 0x2009, 0x0002, 0x2011, 0x0001, - 0x2019, 0x001b, 0x783b, 0x0017, 0x0804, 0x2dcc, 0x7d38, 0x7c3c, - 0x0840, 0x7d38, 0x7c3c, 0x0888, 0x2061, 0x1000, 0xe10c, 0xa006, - 0x2c15, 0xa200, 0x8c60, 0x8109, 0x1dd8, 0x2010, 0xa005, 0x0904, - 0x2dcc, 0x0804, 0x2dee, 0x2069, 0xad51, 0x7824, 0x7930, 0xa11a, - 0x1a04, 0x2df4, 0x8019, 0x0904, 0x2df4, 0x684a, 0x6942, 0x782c, - 0x6852, 0x7828, 0x6856, 0xa006, 0x685a, 0x685e, 0x080c, 0x5a1c, - 0x0804, 0x2dcc, 0x2069, 0xad51, 0x7824, 0x7934, 0xa11a, 0x1a04, - 0x2df4, 0x8019, 0x0904, 0x2df4, 0x684e, 0x6946, 0x782c, 0x6862, - 0x7828, 0x6866, 0xa006, 0x686a, 0x686e, 0x080c, 0x50d9, 0x0804, - 0x2dcc, 0xa02e, 0x2520, 0x81ff, 0x1904, 0x2df1, 0x7924, 0x7b28, - 0x7a2c, 0x20a9, 0x0005, 0x20a1, 0xad88, 0x41a1, 0x080c, 0x3c05, - 0x0904, 0x2df1, 0x2009, 0x0020, 0x080c, 0x3c46, 0x701b, 0x2e89, - 0x0005, 0x6834, 0x2008, 0xa084, 0x00ff, 0xa096, 0x0011, 0x0120, - 0xa096, 0x0019, 0x1904, 0x2df1, 0x810f, 0xa18c, 0x00ff, 0x0904, - 0x2df1, 0x710e, 0x700c, 0x8001, 0x0528, 0x700e, 0x080c, 0x3c05, - 0x0904, 0x2df1, 0x2009, 0x0020, 0x2061, 0xadd1, 0x6224, 0x6328, - 0x642c, 0x6530, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, - 0xa5a9, 0x0000, 0x080c, 0x3c46, 0x701b, 0x2eb7, 0x0005, 0x6834, - 0xa084, 0x00ff, 0xa096, 0x0002, 0x0120, 0xa096, 0x000a, 0x1904, - 0x2df1, 0x08c0, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, 0x080c, - 0x4b7c, 0x1128, 0x7007, 0x0003, 0x701b, 0x2ed1, 0x0005, 0x080c, - 0x51df, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, 0xad88, - 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, - 0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x012e, 0x0804, 0x3c49, - 0x61a8, 0x7824, 0x60aa, 0x0804, 0x2dcc, 0x2091, 0x8000, 0x7823, - 0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, 0x2020, 0x2009, - 0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100, 0x6200, - 0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, 0x2009, 0x04fd, - 0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, - 0x2071, 0x0010, 0x20c1, 0x00f0, 0x0804, 0x0427, 0x81ff, 0x1904, - 0x2df1, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4cdc, 0x1904, - 0x2df4, 0x7e38, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0210, 0x0804, - 0x2df4, 0x7c28, 0x7d2c, 0x080c, 0x4e96, 0xd28c, 0x1118, 0x080c, - 0x4e41, 0x0010, 0x080c, 0x4e6f, 0x1518, 0x2061, 0xb400, 0x0126, - 0x2091, 0x8000, 0x6000, 0xa086, 0x0000, 0x0148, 0x6010, 0xa06d, - 0x0130, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, 0x0150, 0x012e, - 0xace0, 0x0018, 0x2001, 0xad16, 0x2004, 0xac02, 0x1a04, 0x2df1, - 0x0c30, 0x080c, 0x929c, 0x012e, 0x0904, 0x2df1, 0x0804, 0x2dcc, - 0xa00e, 0x2001, 0x0005, 0x080c, 0x51df, 0x0126, 0x2091, 0x8000, - 0x080c, 0x9803, 0x080c, 0x510c, 0x012e, 0x0804, 0x2dcc, 0x81ff, - 0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4d96, - 0x0904, 0x2df1, 0x080c, 0x4ea2, 0x0904, 0x2df1, 0x0804, 0x2dcc, - 0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x080c, - 0x4f0d, 0x0904, 0x2df1, 0x2019, 0x0005, 0x080c, 0x4ebd, 0x0904, - 0x2df1, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2df4, 0x8003, 0x800b, - 0x810b, 0xa108, 0x080c, 0x6519, 0x0804, 0x2dcc, 0x0126, 0x2091, - 0x8000, 0x81ff, 0x0118, 0x2009, 0x0001, 0x0448, 0x2029, 0x00ff, - 0x644c, 0x2400, 0xa506, 0x01f0, 0x2508, 0x080c, 0x4cdc, 0x11d0, - 0x080c, 0x4f0d, 0x1128, 0x2009, 0x0002, 0x62b0, 0x2518, 0x00b8, - 0x2019, 0x0004, 0x080c, 0x4ebd, 0x1118, 0x2009, 0x0006, 0x0078, - 0x7824, 0xa08a, 0x1000, 0x1270, 0x8003, 0x800b, 0x810b, 0xa108, - 0x080c, 0x6519, 0x8529, 0x1ae8, 0x012e, 0x0804, 0x2dcc, 0x012e, - 0x0804, 0x2df1, 0x012e, 0x0804, 0x2df4, 0x080c, 0x3c1a, 0x0904, - 0x2df4, 0x080c, 0x4dfc, 0x080c, 0x4e96, 0x0804, 0x2dcc, 0x81ff, - 0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4ded, - 0x080c, 0x4e96, 0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x080c, - 0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4e71, 0x0904, 0x2df1, 0x080c, - 0x4bc0, 0x080c, 0x4e3a, 0x080c, 0x4e96, 0x0804, 0x2dcc, 0x080c, - 0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4d96, 0x0904, 0x2df1, 0x62a0, - 0x2019, 0x0005, 0x00c6, 0x080c, 0x4ecf, 0x2061, 0x0000, 0x080c, - 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x2009, 0x0000, - 0x080c, 0xa712, 0x007e, 0x00ce, 0x080c, 0x4e96, 0x0804, 0x2dcc, - 0x080c, 0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4e96, 0x2208, 0x0804, - 0x2dcc, 0x0156, 0x00d6, 0x00e6, 0x2069, 0xae13, 0x6810, 0x6914, - 0xa10a, 0x1210, 0x2009, 0x0000, 0x6816, 0x2011, 0x0000, 0x2019, - 0x0000, 0x20a9, 0x007e, 0x2069, 0xae34, 0x2d04, 0xa075, 0x0130, - 0x704c, 0x0071, 0xa210, 0x7080, 0x0059, 0xa318, 0x8d68, 0x1f04, - 0x3035, 0x2300, 0xa218, 0x00ee, 0x00de, 0x015e, 0x0804, 0x2dcc, - 0x00f6, 0x0016, 0xa07d, 0x0140, 0x2001, 0x0000, 0x8000, 0x2f0c, - 0x81ff, 0x0110, 0x2178, 0x0cd0, 0x001e, 0x00fe, 0x0005, 0x2069, - 0xae13, 0x6910, 0x62ac, 0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1, - 0x614c, 0xa190, 0x2be6, 0x2215, 0xa294, 0x00ff, 0x636c, 0x83ff, - 0x0108, 0x6270, 0x67d0, 0xd79c, 0x0118, 0x2031, 0x0001, 0x0090, - 0xd7ac, 0x0118, 0x2031, 0x0003, 0x0068, 0xd7a4, 0x0118, 0x2031, - 0x0002, 0x0040, 0x080c, 0x574f, 0x1118, 0x2031, 0x0004, 0x0010, - 0x2031, 0x0000, 0x7e3a, 0x7f3e, 0x0804, 0x2dcc, 0x613c, 0x6240, - 0x2019, 0xafa3, 0x231c, 0x0804, 0x2dcc, 0x0126, 0x2091, 0x8000, - 0x6134, 0xa006, 0x2010, 0x2018, 0x012e, 0x0804, 0x2dcc, 0x080c, - 0x3c2a, 0x0904, 0x2df4, 0x6244, 0x6338, 0x0804, 0x2dcc, 0x613c, - 0x6240, 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0xad51, 0x831f, - 0xa305, 0x6816, 0x782c, 0x2069, 0xafa3, 0x2d1c, 0x206a, 0x0804, - 0x2dcc, 0x0126, 0x2091, 0x8000, 0x7824, 0x6036, 0x012e, 0x0804, - 0x2dcc, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x7828, 0xa00d, 0x0904, - 0x2df4, 0x782c, 0xa005, 0x0904, 0x2df4, 0x6244, 0x6146, 0x6338, - 0x603a, 0x0804, 0x2dcc, 0x2001, 0xad00, 0x2004, 0xa086, 0x0003, - 0x1904, 0x2df1, 0x00c6, 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, - 0x00ff, 0xa196, 0x00ff, 0x1130, 0x2001, 0xad14, 0x2004, 0xa085, - 0xff00, 0x0078, 0xa182, 0x007f, 0x16a0, 0xa188, 0x2be6, 0x210d, - 0xa18c, 0x00ff, 0x2001, 0xad14, 0x2004, 0xa116, 0x0550, 0x810f, - 0xa105, 0x0126, 0x2091, 0x8000, 0x0006, 0x080c, 0x8022, 0x000e, - 0x01e0, 0x601a, 0x600b, 0xbc09, 0x601f, 0x0001, 0x080c, 0x3c05, - 0x01d8, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, - 0xc0fd, 0x683a, 0x701b, 0x3173, 0x2d00, 0x6012, 0x2009, 0x0032, - 0x080c, 0x80a7, 0x012e, 0x00ce, 0x0005, 0x012e, 0x00ce, 0x0804, - 0x2df1, 0x00ce, 0x0804, 0x2df4, 0x080c, 0x8078, 0x0cb0, 0x2001, - 0xad00, 0x2004, 0xa086, 0x0003, 0x1904, 0x2df1, 0x00c6, 0x2061, - 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, 0x1130, - 0x2001, 0xad14, 0x2004, 0xa085, 0xff00, 0x0078, 0xa182, 0x007f, - 0x16a0, 0xa188, 0x2be6, 0x210d, 0xa18c, 0x00ff, 0x2001, 0xad14, - 0x2004, 0xa116, 0x0550, 0x810f, 0xa105, 0x0126, 0x2091, 0x8000, - 0x0006, 0x080c, 0x8022, 0x000e, 0x01e0, 0x601a, 0x600b, 0xbc05, - 0x601f, 0x0001, 0x080c, 0x3c05, 0x01d8, 0x6837, 0x0000, 0x7007, - 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x701b, 0x3173, - 0x2d00, 0x6012, 0x2009, 0x0032, 0x080c, 0x80a7, 0x012e, 0x00ce, - 0x0005, 0x012e, 0x00ce, 0x0804, 0x2df1, 0x00ce, 0x0804, 0x2df4, - 0x080c, 0x8078, 0x0cb0, 0x6830, 0xa086, 0x0100, 0x0904, 0x2df1, - 0x0804, 0x2dcc, 0x2061, 0xb048, 0x0126, 0x2091, 0x8000, 0x6000, - 0xd084, 0x0128, 0x6104, 0x6208, 0x012e, 0x0804, 0x2dcc, 0x012e, - 0x0804, 0x2df4, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x574f, 0x0904, - 0x2df1, 0x0126, 0x2091, 0x8000, 0x6244, 0x6064, 0xa202, 0x0248, - 0xa085, 0x0001, 0x080c, 0x26c0, 0x080c, 0x436e, 0x012e, 0x0804, - 0x2dcc, 0x012e, 0x0804, 0x2df4, 0x0126, 0x2091, 0x8000, 0x7824, - 0xa084, 0x0007, 0x0002, 0x31b6, 0x31bf, 0x31c6, 0x31b3, 0x31b3, - 0x31b3, 0x31b3, 0x31b3, 0x012e, 0x0804, 0x2df4, 0x2009, 0x0114, - 0x2104, 0xa085, 0x0800, 0x200a, 0x080c, 0x332f, 0x0070, 0x2009, - 0x010b, 0x200b, 0x0010, 0x080c, 0x332f, 0x0038, 0x81ff, 0x0128, - 0x012e, 0x2021, 0x400b, 0x0804, 0x2dce, 0x0086, 0x0096, 0x00a6, - 0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2009, 0x0101, 0x210c, - 0x0016, 0x2001, 0x0138, 0x200c, 0x2003, 0x0001, 0x0016, 0x2001, - 0x007a, 0x2034, 0x2001, 0x007b, 0x202c, 0xa006, 0x2048, 0x2050, - 0x2058, 0x080c, 0x3570, 0x080c, 0x34da, 0xa03e, 0x2720, 0x00f6, - 0x00e6, 0x00c6, 0x2d60, 0x2071, 0xb01e, 0x2079, 0x0020, 0x00d6, - 0x2069, 0x0000, 0x6824, 0xd0b4, 0x0140, 0x2001, 0x007d, 0x2004, - 0x783e, 0x2001, 0x007c, 0x2004, 0x783a, 0x00de, 0x2011, 0x0001, - 0x080c, 0x3486, 0x080c, 0x3486, 0x00ce, 0x00ee, 0x00fe, 0x080c, - 0x33d5, 0x080c, 0x34ae, 0x080c, 0x342b, 0x080c, 0x3394, 0x080c, - 0x33c5, 0x00f6, 0x2079, 0x0100, 0x7824, 0xd094, 0x0530, 0x7814, - 0xa084, 0x0184, 0xa085, 0x0010, 0x7816, 0x2079, 0x0140, 0x080c, - 0x330d, 0x1110, 0x00fe, 0x0430, 0x7804, 0xd0dc, 0x0dc0, 0x2079, - 0x0100, 0x7827, 0x0086, 0x7814, 0xa084, 0x0184, 0xa085, 0x0032, - 0x7816, 0x080c, 0x330d, 0x1110, 0x00fe, 0x00a0, 0x7824, 0xd0bc, - 0x0dc0, 0x7827, 0x0080, 0xa026, 0x7c16, 0x7824, 0xd0ac, 0x0130, - 0x8b58, 0x080c, 0x3317, 0x00fe, 0x0804, 0x32d7, 0x00fe, 0x080c, - 0x330d, 0x1150, 0x8948, 0x2001, 0x007a, 0x2602, 0x2001, 0x007b, - 0x2502, 0x080c, 0x3317, 0x0088, 0x87ff, 0x0140, 0x2001, 0x0201, - 0x2004, 0xa005, 0x1904, 0x3211, 0x8739, 0x0038, 0x2001, 0xaffd, - 0x2004, 0xa086, 0x0000, 0x1904, 0x3211, 0x2001, 0x0033, 0x2003, - 0x00f6, 0x8631, 0x1208, 0x8529, 0x2500, 0xa605, 0x0904, 0x32d7, - 0x7824, 0xd0bc, 0x0128, 0x2900, 0xaa05, 0xab05, 0x1904, 0x32d7, - 0x6033, 0x000d, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824, 0xd0ac, - 0x1148, 0x2001, 0xaffd, 0x2003, 0x0003, 0x2001, 0x0030, 0x2003, - 0x0009, 0x0040, 0x6027, 0x0001, 0x2001, 0x0075, 0x2004, 0xa005, - 0x0108, 0x6026, 0x2c00, 0x601a, 0x20e1, 0x9040, 0x2d00, 0x681a, - 0x6833, 0x000d, 0x7824, 0xd0a4, 0x1180, 0x6827, 0x0000, 0x00c6, - 0x20a9, 0x0004, 0x2061, 0x0020, 0x6003, 0x0008, 0x2001, 0x0203, - 0x2004, 0x1f04, 0x32ac, 0x00ce, 0x0040, 0x6827, 0x0001, 0x2001, - 0x0074, 0x2004, 0xa005, 0x0108, 0x6826, 0x00f6, 0x00c6, 0x2079, - 0x0100, 0x2061, 0x0020, 0x7827, 0x0002, 0x2001, 0x0072, 0x2004, - 0xa084, 0xfff8, 0x601a, 0x0006, 0x2001, 0x0073, 0x2004, 0x601e, - 0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, 0x0804, 0x31ef, 0x2061, - 0x0100, 0x6027, 0x0002, 0x001e, 0x61e2, 0x001e, 0x6106, 0x7824, - 0xa084, 0x0003, 0xa086, 0x0002, 0x0188, 0x20e1, 0x9028, 0x6050, - 0xa084, 0xf7ef, 0x6052, 0x602f, 0x0000, 0x602c, 0xc0ac, 0x602e, - 0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, 0x0010, 0x2908, 0x2a10, - 0x2b18, 0x2b00, 0xaa05, 0xa905, 0x00fe, 0x00ee, 0x00de, 0x00ce, - 0x00be, 0x00ae, 0x009e, 0x008e, 0x1118, 0x012e, 0x0804, 0x2dcc, - 0x012e, 0x2021, 0x400c, 0x0804, 0x2dce, 0xa085, 0x0001, 0x1d04, - 0x3316, 0x2091, 0x6000, 0x8420, 0xa486, 0x0064, 0x0005, 0x2001, - 0x0105, 0x2003, 0x0010, 0x2001, 0x0030, 0x2003, 0x0004, 0x2001, - 0x0020, 0x2003, 0x0004, 0x2001, 0xaffd, 0x2003, 0x0000, 0x2001, - 0xb01e, 0x2003, 0x0000, 0x20e1, 0xf000, 0xa026, 0x0005, 0x00f6, - 0x2079, 0x0100, 0x2001, 0xad14, 0x200c, 0x7932, 0x7936, 0x080c, - 0x26a0, 0x7850, 0xa084, 0x0980, 0xa085, 0x0030, 0x7852, 0x2019, - 0x01f4, 0x8319, 0x1df0, 0xa084, 0x0980, 0x7852, 0x782c, 0xc0ad, - 0x782e, 0x20a9, 0x0046, 0x1d04, 0x334b, 0x2091, 0x6000, 0x1f04, - 0x334b, 0x7850, 0xa085, 0x0400, 0x7852, 0x2001, 0x0009, 0x2004, - 0xa084, 0x0003, 0xa086, 0x0001, 0x1118, 0x782c, 0xc0ac, 0x782e, - 0x784b, 0xf7f7, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, 0x000e, - 0xe000, 0x1f04, 0x3368, 0x7850, 0xa085, 0x1400, 0x7852, 0x2019, - 0x61a8, 0x7854, 0xe000, 0xe000, 0xd08c, 0x1110, 0x8319, 0x1dc8, - 0x7827, 0x0048, 0x7850, 0xa085, 0x0400, 0x7852, 0x7843, 0x0040, - 0x2019, 0x01f4, 0xe000, 0xe000, 0x8319, 0x1de0, 0x2001, 0x0140, - 0x2003, 0x0100, 0x7827, 0x0020, 0x7843, 0x0000, 0x2003, 0x0000, - 0x7827, 0x0048, 0x00fe, 0x0005, 0x7824, 0xd0ac, 0x11c8, 0x00f6, - 0x00e6, 0x2071, 0xaffd, 0x2079, 0x0030, 0x2001, 0x0201, 0x2004, - 0xa005, 0x0160, 0x7000, 0xa086, 0x0000, 0x1140, 0x0051, 0xd0bc, - 0x0108, 0x8738, 0x7003, 0x0003, 0x7803, 0x0019, 0x00ee, 0x00fe, - 0x0005, 0x780c, 0xa08c, 0x0070, 0x0178, 0x2009, 0x007a, 0x260a, - 0x2009, 0x007b, 0x250a, 0xd0b4, 0x0108, 0x8a50, 0xd0ac, 0x0108, - 0x8948, 0xd0a4, 0x0108, 0x8b58, 0x0005, 0x00f6, 0x2079, 0x0200, - 0x781c, 0xd084, 0x0140, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001, - 0x020a, 0x2004, 0x0ca8, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0100, - 0x2009, 0xad14, 0x210c, 0x716e, 0x7063, 0x0100, 0x7166, 0x719e, - 0x706b, 0x0000, 0x7073, 0x0809, 0x7077, 0x0008, 0x7078, 0xa080, - 0x0100, 0x707a, 0x7080, 0x8000, 0x7082, 0x7087, 0xaaaa, 0xa006, - 0x708a, 0x708e, 0x707e, 0x70d6, 0x70ab, 0x0036, 0x70af, 0x95d5, - 0x7027, 0x0080, 0x7014, 0xa084, 0x0184, 0xa085, 0x0032, 0x7016, - 0x080c, 0x34ae, 0x080c, 0x330d, 0x1110, 0x8421, 0x0028, 0x7024, - 0xd0bc, 0x0db0, 0x7027, 0x0080, 0x00f6, 0x00e6, 0x2071, 0xaffd, - 0x2079, 0x0030, 0x00d6, 0x2069, 0x0000, 0x6824, 0xd0b4, 0x0120, - 0x683c, 0x783e, 0x6838, 0x783a, 0x00de, 0x2011, 0x0011, 0x080c, - 0x3486, 0x2011, 0x0001, 0x080c, 0x3486, 0x00ee, 0x00fe, 0x7017, - 0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x2071, 0xaffd, 0x2079, - 0x0030, 0x7904, 0xd1fc, 0x0904, 0x3483, 0x7803, 0x0002, 0xa026, - 0xd19c, 0x1904, 0x347f, 0x7000, 0x0002, 0x3483, 0x3441, 0x3465, - 0x347f, 0xd1bc, 0x1150, 0xd1dc, 0x1150, 0x8001, 0x7002, 0x2011, - 0x0001, 0x04e1, 0x05c0, 0x04d1, 0x04b0, 0x780f, 0x0000, 0x7820, - 0x7924, 0x7803, 0x0004, 0x7822, 0x7926, 0x2001, 0x0201, 0x200c, - 0x81ff, 0x0de8, 0x080c, 0x33b1, 0x2009, 0x0001, 0x7808, 0xd0ec, - 0x0110, 0x2009, 0x0011, 0x7902, 0x00f0, 0x8001, 0x7002, 0xa184, - 0x0880, 0x1138, 0x7804, 0xd0fc, 0x1940, 0x2011, 0x0001, 0x00b1, - 0x0090, 0x6030, 0xa092, 0x0004, 0xa086, 0x0009, 0x1120, 0x6000, - 0x601a, 0x2011, 0x0025, 0x6232, 0xd1dc, 0x1988, 0x0870, 0x7803, - 0x0004, 0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x6024, 0xa005, - 0x0520, 0x8001, 0x6026, 0x6018, 0x6130, 0xa140, 0x2804, 0x7832, - 0x8840, 0x2804, 0x7836, 0x8840, 0x2804, 0x7822, 0x8840, 0x2804, - 0x7826, 0x8840, 0x7a02, 0x7000, 0x8000, 0x7002, 0x6018, 0xa802, - 0xa08a, 0x0029, 0x1138, 0x6018, 0xa080, 0x0001, 0x2004, 0x601a, - 0x2001, 0x000d, 0x6032, 0xa085, 0x0001, 0x0005, 0x00f6, 0x00e6, - 0x00c6, 0x2071, 0xb01e, 0x2079, 0x0020, 0x7904, 0xd1fc, 0x01f0, - 0x7803, 0x0002, 0x2d60, 0xa026, 0x7000, 0x0002, 0x34d6, 0x34c1, - 0x34cd, 0x8001, 0x7002, 0xd19c, 0x1188, 0x2011, 0x0001, 0x080c, - 0x3486, 0x0160, 0x080c, 0x3486, 0x0048, 0x8001, 0x7002, 0x7804, - 0xd0fc, 0x1d30, 0x2011, 0x0001, 0x080c, 0x3486, 0x00ce, 0x00ee, - 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x2061, 0x0200, 0x601b, - 0x0004, 0x2061, 0x0100, 0x60cf, 0x0400, 0x6004, 0xc0ac, 0xa085, - 0x0200, 0x6006, 0x2001, 0x0074, 0x2004, 0xa005, 0x01f8, 0x2038, - 0x2001, 0x0076, 0x2024, 0x2001, 0x0077, 0x201c, 0x080c, 0x3c05, - 0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220, - 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080, - 0x000d, 0x04a1, 0x1d90, 0x2d00, 0x681a, 0x0088, 0x080c, 0x3c05, - 0x6833, 0x000d, 0x2070, 0x6827, 0x0001, 0x2d00, 0x681a, 0x2001, - 0x0076, 0x2004, 0x2072, 0x2001, 0x0077, 0x2004, 0x7006, 0x2061, - 0x0020, 0x2079, 0x0100, 0x6013, 0x0400, 0x20e1, 0x9040, 0x2001, - 0x0072, 0x2004, 0xa084, 0xfff8, 0x700a, 0x601a, 0x0006, 0x2001, - 0x0073, 0x2004, 0x700e, 0x601e, 0x78c6, 0x000e, 0x78ca, 0xa006, - 0x603a, 0x603e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00e6, 0x2071, - 0x0010, 0x20a0, 0x2099, 0x0014, 0x7003, 0x0026, 0x7432, 0x7336, - 0xa006, 0x703a, 0x703e, 0x810b, 0x810b, 0x21a8, 0x810b, 0x7122, - 0x7003, 0x0041, 0x7004, 0xd0fc, 0x0de8, 0x7003, 0x0002, 0x7003, - 0x0040, 0x53a5, 0x7430, 0x7334, 0x87ff, 0x0180, 0x00c6, 0x00d6, - 0x2d60, 0x00c6, 0x080c, 0x3c05, 0x00ce, 0x6018, 0x2070, 0x2d00, - 0x7006, 0x601a, 0x00de, 0x00ce, 0xa085, 0x0001, 0x00ee, 0x0005, - 0x00e6, 0x2001, 0x0075, 0x2004, 0xa005, 0x0508, 0x2038, 0x2001, - 0x0078, 0x2024, 0x2001, 0x0079, 0x201c, 0x080c, 0x3c05, 0x2d60, - 0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220, - 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080, - 0x000d, 0x080c, 0x353e, 0x1d88, 0x2d00, 0x681a, 0x00e0, 0x080c, - 0x3c05, 0x2d60, 0x6033, 0x000d, 0x2070, 0x6027, 0x0001, 0x2c00, - 0x601a, 0x2001, 0x0078, 0x2004, 0x2072, 0x2001, 0x0079, 0x2004, - 0x7006, 0x2001, 0x0072, 0x2004, 0xa084, 0xfff8, 0x700a, 0x2001, - 0x0073, 0x2004, 0x700e, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824, - 0xd0ac, 0x1178, 0x2001, 0x0101, 0x200c, 0xc1ed, 0x2102, 0x6027, - 0x0000, 0x2001, 0xaffd, 0x2003, 0x0003, 0x2001, 0x0030, 0x2003, - 0x0009, 0x00ee, 0x0005, 0x0804, 0x2dcc, 0x0126, 0x2091, 0x8000, - 0x20a9, 0x0011, 0x2001, 0xad40, 0x20a0, 0xa006, 0x40a4, 0x012e, - 0x0804, 0x2dcc, 0x7d38, 0x7c3c, 0x0804, 0x2e73, 0x080c, 0x3c05, - 0x0904, 0x2df1, 0x080c, 0x574f, 0x0110, 0x080c, 0x491f, 0x2009, - 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3c46, 0x701b, - 0x35f2, 0x0005, 0xade8, 0x000d, 0x6800, 0xa005, 0x0904, 0x2df4, - 0x6804, 0xd0ac, 0x0118, 0xd0a4, 0x0904, 0x2df4, 0xd094, 0x00c6, - 0x2061, 0x0100, 0x6104, 0x0138, 0x6200, 0xa292, 0x0005, 0x0218, - 0xa18c, 0xffdf, 0x0010, 0xa18d, 0x0020, 0x6106, 0x00ce, 0xd08c, - 0x00c6, 0x2061, 0x0100, 0x6104, 0x0118, 0xa18d, 0x0010, 0x0010, - 0xa18c, 0xffef, 0x6106, 0x00ce, 0x2009, 0x0100, 0x210c, 0xa18a, - 0x0002, 0x0268, 0xd084, 0x0158, 0x6a28, 0xa28a, 0x007f, 0x1a04, - 0x2df4, 0xa288, 0x2be6, 0x210d, 0xa18c, 0x00ff, 0x6156, 0xd0dc, - 0x0130, 0x6828, 0xa08a, 0x007f, 0x1a04, 0x2df4, 0x604e, 0x6808, - 0xa08a, 0x0100, 0x0a04, 0x2df4, 0xa08a, 0x0841, 0x1a04, 0x2df4, - 0xa084, 0x0007, 0x1904, 0x2df4, 0x680c, 0xa005, 0x0904, 0x2df4, - 0x6810, 0xa005, 0x0904, 0x2df4, 0x6848, 0x6940, 0xa10a, 0x1a04, - 0x2df4, 0x8001, 0x0904, 0x2df4, 0x684c, 0x6944, 0xa10a, 0x1a04, - 0x2df4, 0x8001, 0x0904, 0x2df4, 0x6804, 0xd0fc, 0x0560, 0x080c, - 0x3c05, 0x0904, 0x2df1, 0x2009, 0x0014, 0x7a2c, 0x7b28, 0x7c3c, - 0x7d38, 0xa290, 0x0038, 0xa399, 0x0000, 0x080c, 0x3c46, 0x701b, - 0x3672, 0x0005, 0xade8, 0x000d, 0x20a9, 0x0014, 0x2d98, 0x2069, - 0xad6d, 0x2da0, 0x53a3, 0x7010, 0xa0e8, 0x000d, 0x2001, 0xad71, - 0x200c, 0xd1e4, 0x0140, 0x00c6, 0x2061, 0x0100, 0x6004, 0xa085, - 0x0b00, 0x6006, 0x00ce, 0x20a9, 0x001c, 0x2d98, 0x2069, 0xad51, - 0x2da0, 0x53a3, 0x6814, 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, - 0x00ff, 0x6042, 0x080c, 0x5a1c, 0x080c, 0x5070, 0x080c, 0x50d9, - 0x6000, 0xa086, 0x0000, 0x1904, 0x3755, 0x6808, 0x602a, 0x080c, - 0x22f8, 0x0006, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x000e, - 0x0268, 0x2009, 0x0170, 0x200b, 0x0080, 0xe000, 0xe000, 0x200b, - 0x0000, 0x0036, 0x6b08, 0x080c, 0x26fb, 0x003e, 0x6818, 0x691c, - 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a, - 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0148, 0x6830, 0x6934, 0x6a38, - 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f, 0x0010, 0xa084, 0xf0ff, - 0x6006, 0x610a, 0x620e, 0x6312, 0x8007, 0x810f, 0x8217, 0x831f, - 0x20a9, 0x0004, 0x20a1, 0xafad, 0x40a1, 0x080c, 0x659c, 0x6904, - 0xd1fc, 0x0520, 0x00c6, 0x2009, 0x0000, 0x20a9, 0x0001, 0x6b70, - 0xd384, 0x01c8, 0x0020, 0x839d, 0x12b0, 0x3508, 0x8109, 0x080c, - 0x5fa9, 0x6878, 0x6016, 0x6874, 0x2008, 0xa084, 0xff00, 0x8007, - 0x600a, 0xa184, 0x00ff, 0x6006, 0x8108, 0x1118, 0x6003, 0x0003, - 0x0010, 0x6003, 0x0001, 0x1f04, 0x36f3, 0x00ce, 0x2069, 0xad51, - 0x2001, 0xaf9d, 0x6a80, 0xa294, 0x0030, 0xa28e, 0x0000, 0x0170, - 0xa28e, 0x0010, 0x0118, 0xa28e, 0x0020, 0x0140, 0x2003, 0xaaaa, - 0x080c, 0x2744, 0x2001, 0xaf8e, 0x2102, 0x0008, 0x2102, 0x00c6, - 0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, 0x00ce, 0x080c, - 0x574f, 0x0128, 0x080c, 0x3e5f, 0x0110, 0x080c, 0x26c0, 0x60c4, - 0xa005, 0x01b0, 0x6003, 0x0001, 0x2009, 0x373f, 0x00c0, 0x080c, - 0x574f, 0x1158, 0x2011, 0x566e, 0x080c, 0x650d, 0x2001, 0xaf9e, - 0x2003, 0x0000, 0x080c, 0x569a, 0x0040, 0x080c, 0x485e, 0x0028, - 0x6003, 0x0004, 0x2009, 0x3755, 0x0010, 0x0804, 0x2dcc, 0x2001, - 0x0100, 0x2004, 0xa082, 0x0005, 0x0258, 0x2001, 0x0170, 0x2004, - 0xa084, 0x00ff, 0xa086, 0x004c, 0x1118, 0x2091, 0x309d, 0x0817, - 0x2091, 0x301d, 0x0817, 0x6000, 0xa086, 0x0000, 0x0904, 0x2df1, - 0x2069, 0xad51, 0x7830, 0x6842, 0x7834, 0x6846, 0x6804, 0xd0fc, - 0x0118, 0x2009, 0x0030, 0x0010, 0x2009, 0x001c, 0x2d00, 0x7a2c, - 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49, 0xa006, 0x080c, 0x26c0, - 0x81ff, 0x1904, 0x2df1, 0x080c, 0x574f, 0x1178, 0x2001, 0xaf9e, - 0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0xa085, 0x0001, - 0x080c, 0x5793, 0x080c, 0x569a, 0x0020, 0x080c, 0x491f, 0x080c, - 0x485e, 0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x574f, - 0x1110, 0x0804, 0x2df1, 0x6184, 0x81ff, 0x0198, 0x703f, 0x0000, - 0x2001, 0xb3c0, 0x2009, 0x0040, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, - 0x0126, 0x2091, 0x8000, 0x080c, 0x3c49, 0x701b, 0x2dca, 0x012e, - 0x0005, 0x703f, 0x0001, 0x00d6, 0x2069, 0xb3c0, 0x20a9, 0x0040, - 0x20a1, 0xb3c0, 0x2019, 0xffff, 0x43a4, 0x654c, 0xa588, 0x2be6, - 0x210d, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, 0x0002, 0x2100, - 0xa506, 0x01a8, 0x080c, 0x4cdc, 0x1190, 0x6014, 0x821c, 0x0238, - 0xa398, 0xb3c0, 0xa085, 0xff00, 0x8007, 0x201a, 0x0038, 0xa398, - 0xb3c0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, 0x8210, 0x8108, - 0xa182, 0x0080, 0x1208, 0x0c18, 0x8201, 0x8007, 0x2d0c, 0xa105, - 0x206a, 0x00de, 0x20a9, 0x0040, 0x20a1, 0xb3c0, 0x2099, 0xb3c0, - 0x080c, 0x48be, 0x0804, 0x37b0, 0x080c, 0x3c2a, 0x0904, 0x2df4, - 0x00c6, 0x080c, 0x3c05, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804, - 0x2df1, 0x2001, 0xad52, 0x2004, 0xd0b4, 0x01f0, 0x6000, 0xd08c, - 0x11d8, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x11a8, 0x6837, - 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x970b, 0x1120, 0x2009, - 0x0003, 0x0804, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3830, 0x0005, - 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x20a9, 0x002b, 0x2c98, 0xade8, - 0x0002, 0x2da0, 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, - 0xad80, 0x0006, 0x20a0, 0x080c, 0x48be, 0x20a9, 0x0004, 0xac80, - 0x000a, 0x2098, 0xad80, 0x000a, 0x20a0, 0x080c, 0x48be, 0x2d00, - 0x2009, 0x002b, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49, - 0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904, 0x2df4, 0x080c, - 0x4eab, 0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x7828, 0xa08a, - 0x1000, 0x1a04, 0x2df4, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x080c, - 0x4f0d, 0x0904, 0x2df1, 0x2019, 0x0004, 0x080c, 0x4ebd, 0x7924, - 0x810f, 0x7a28, 0x0011, 0x0804, 0x2dcc, 0xa186, 0x00ff, 0x0110, - 0x0071, 0x0060, 0x2029, 0x007e, 0x2061, 0xad00, 0x644c, 0x2400, - 0xa506, 0x0110, 0x2508, 0x0019, 0x8529, 0x1ec8, 0x0005, 0x080c, - 0x4cdc, 0x1138, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108, 0x080c, - 0x6519, 0x0005, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904, - 0x2df4, 0x080c, 0x4d96, 0x0904, 0x2df1, 0x080c, 0x4eb4, 0x0804, - 0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904, 0x2df4, - 0x080c, 0x4d96, 0x0904, 0x2df1, 0x080c, 0x4ea2, 0x0804, 0x2dcc, - 0x6100, 0x0804, 0x2dcc, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x2001, - 0xad00, 0x2004, 0xa086, 0x0003, 0x1904, 0x2df1, 0x00d6, 0xace8, - 0x000a, 0x7924, 0xd184, 0x0110, 0xace8, 0x0006, 0x680c, 0x8007, - 0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, 0x6a00, 0x8217, - 0x00de, 0x6100, 0xa18c, 0x0200, 0x0804, 0x2dcc, 0x7824, 0xa09c, - 0x00ff, 0xa39a, 0x0003, 0x1a04, 0x2df1, 0x624c, 0xa294, 0x00ff, - 0xa084, 0xff00, 0x8007, 0xa206, 0x1150, 0x2001, 0xad40, 0x2009, - 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49, 0x81ff, - 0x1904, 0x2df1, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x6004, 0xa084, - 0x00ff, 0xa086, 0x0006, 0x1904, 0x2df1, 0x00c6, 0x080c, 0x3c05, - 0x00ce, 0x0904, 0x2df1, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, - 0x080c, 0x96b7, 0x0904, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3919, - 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2df1, 0xad80, 0x000e, - 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49, - 0xa006, 0x080c, 0x26c0, 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff, - 0x0118, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x574f, 0x0110, 0x080c, - 0x491f, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2df4, 0x7924, 0xa18c, - 0xff00, 0x810f, 0xa186, 0x00ff, 0x0138, 0xa182, 0x007f, 0x1a04, - 0x2df4, 0x2100, 0x080c, 0x268a, 0x0026, 0x00c6, 0x0126, 0x2091, - 0x8000, 0x2061, 0xafda, 0x601b, 0x0000, 0x601f, 0x0000, 0x080c, - 0x574f, 0x1178, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00, - 0x2003, 0x0001, 0xa085, 0x0001, 0x080c, 0x5793, 0x080c, 0x569a, - 0x00a0, 0x2061, 0x0100, 0x2001, 0xad14, 0x2004, 0xa084, 0x00ff, - 0x810f, 0xa105, 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, - 0x002d, 0x2011, 0x4883, 0x080c, 0x6593, 0x7924, 0xa18c, 0xff00, - 0x810f, 0x080c, 0x574f, 0x1110, 0x2009, 0x00ff, 0x7a28, 0x080c, - 0x387d, 0x012e, 0x00ce, 0x002e, 0x0804, 0x2dcc, 0x7924, 0xa18c, - 0xff00, 0x810f, 0x00c6, 0x080c, 0x4c80, 0x2c08, 0x00ce, 0x1904, - 0x2df4, 0x0804, 0x2dcc, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, - 0x2df1, 0x60d0, 0xd0ac, 0x1130, 0xd09c, 0x1120, 0x2009, 0x0005, - 0x0804, 0x2df1, 0x080c, 0x3c05, 0x1120, 0x2009, 0x0002, 0x0804, - 0x2df1, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3c46, - 0x701b, 0x39bb, 0x0005, 0x2009, 0x0080, 0x080c, 0x4cdc, 0x1130, - 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0120, 0x2021, 0x400a, - 0x0804, 0x2dce, 0x00d6, 0xade8, 0x000d, 0x6900, 0x6a08, 0x6b0c, - 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, 0x0100, 0x0904, 0x3a32, - 0xa0be, 0x0112, 0x0904, 0x3a32, 0xa0be, 0x0113, 0x0904, 0x3a32, - 0xa0be, 0x0114, 0x0904, 0x3a32, 0xa0be, 0x0117, 0x0904, 0x3a32, - 0xa0be, 0x011a, 0x0904, 0x3a32, 0xa0be, 0x011c, 0x0904, 0x3a32, - 0xa0be, 0x0121, 0x05b0, 0xa0be, 0x0131, 0x0598, 0xa0be, 0x0171, - 0x05c8, 0xa0be, 0x0173, 0x05b0, 0xa0be, 0x01a1, 0x1120, 0x6830, - 0x8007, 0x6832, 0x04a8, 0xa0be, 0x0212, 0x0540, 0xa0be, 0x0213, - 0x0528, 0xa0be, 0x0214, 0x01b0, 0xa0be, 0x0217, 0x0168, 0xa0be, - 0x021a, 0x1120, 0x6838, 0x8007, 0x683a, 0x00e0, 0xa0be, 0x0300, - 0x01c8, 0x00de, 0x0804, 0x2df4, 0xad80, 0x0010, 0x20a9, 0x0007, - 0x080c, 0x3a78, 0xad80, 0x000e, 0x20a9, 0x0001, 0x080c, 0x3a78, - 0x0048, 0xad80, 0x000c, 0x080c, 0x3a86, 0x0050, 0xad80, 0x000e, - 0x080c, 0x3a86, 0xad80, 0x000c, 0x20a9, 0x0001, 0x080c, 0x3a78, - 0x00c6, 0x080c, 0x3c05, 0x0568, 0x6838, 0xc0fd, 0x683a, 0x6837, - 0x0119, 0x6853, 0x0000, 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, - 0x697e, 0x6883, 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, - 0x689b, 0x0000, 0x00ce, 0x00de, 0x6837, 0x0000, 0x6838, 0xc0fd, - 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x080c, 0x96d3, 0x1120, - 0x2009, 0x0003, 0x0804, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3a6f, - 0x0005, 0x00ce, 0x00de, 0x2009, 0x0002, 0x0804, 0x2df1, 0x6820, - 0xa086, 0x8001, 0x1904, 0x2dcc, 0x2009, 0x0004, 0x0804, 0x2df1, - 0x0016, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, - 0x280a, 0x8108, 0x1f04, 0x3a7a, 0x001e, 0x0005, 0x0016, 0x00a6, - 0x00b6, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, - 0x205c, 0x2b0a, 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, - 0x00be, 0x00ae, 0x001e, 0x0005, 0x81ff, 0x0120, 0x2009, 0x0001, - 0x0804, 0x2df1, 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f, 0x60d0, - 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2df4, 0xa182, 0x00ff, - 0x1a04, 0x2df4, 0x7a2c, 0x7b28, 0x606c, 0xa306, 0x1140, 0x6070, - 0xa24e, 0x0904, 0x2df4, 0xa9cc, 0xff00, 0x0904, 0x2df4, 0x00c6, - 0x080c, 0x3b58, 0x2c68, 0x00ce, 0x0538, 0xa0c6, 0x4000, 0x1180, - 0x00c6, 0x0006, 0x2d60, 0x2009, 0x0000, 0x080c, 0x4f6e, 0x1108, - 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x00ce, 0x0088, - 0xa0c6, 0x4007, 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008, 0x1118, - 0x2708, 0x2610, 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010, 0x2001, - 0x4006, 0x2020, 0x0804, 0x2dce, 0x2d00, 0x7022, 0x0016, 0x00b6, - 0x00c6, 0x00e6, 0x2c70, 0x080c, 0x8022, 0x05d8, 0x2d00, 0x601a, - 0x080c, 0x9956, 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c, 0x3c05, - 0x00ce, 0x2b70, 0x1150, 0x080c, 0x8078, 0x00ee, 0x00ce, 0x00be, - 0x001e, 0x2009, 0x0002, 0x0804, 0x2df1, 0x6837, 0x0000, 0x683b, - 0x0000, 0x2d00, 0x6012, 0x6833, 0x0000, 0x6838, 0xc0fd, 0xd88c, - 0x0108, 0xc0f5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x2ad9, - 0x012e, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x2001, - 0x0002, 0x080c, 0x4c30, 0x2009, 0x0002, 0x080c, 0x80a7, 0xa085, - 0x0001, 0x00ee, 0x00ce, 0x00be, 0x001e, 0x1120, 0x2009, 0x0003, - 0x0804, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3b3f, 0x0005, 0x6830, - 0xa086, 0x0100, 0x7020, 0x2060, 0x1138, 0x2009, 0x0004, 0x6204, - 0xa294, 0x00ff, 0x0804, 0x2df1, 0x2009, 0x0000, 0x080c, 0x4f6e, - 0x1108, 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x0804, 0x2dcc, - 0x00e6, 0x00d6, 0x2029, 0x0000, 0x2001, 0xad34, 0x2004, 0xd0ac, - 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, 0x2071, 0xae34, 0x0030, - 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, 0xaeb4, 0x2e04, 0xa005, - 0x1130, 0x2100, 0xa406, 0x1548, 0x2428, 0xc5fd, 0x0430, 0x2068, - 0x6f10, 0x2700, 0xa306, 0x11b0, 0x6e14, 0x2600, 0xa206, 0x1190, - 0x2400, 0xa106, 0x1160, 0x2d60, 0xd884, 0x0540, 0x6004, 0xa084, - 0x00ff, 0xa086, 0x0006, 0x1510, 0x2001, 0x4000, 0x0400, 0x2001, - 0x4007, 0x00e8, 0x2400, 0xa106, 0x1140, 0x6e14, 0x87ff, 0x1110, - 0x86ff, 0x09d0, 0x2001, 0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04, - 0x3b6e, 0x85ff, 0x1130, 0x2001, 0x4009, 0x0048, 0x2001, 0x0001, - 0x0030, 0x080c, 0x4c80, 0x1dd0, 0x6312, 0x6216, 0xa006, 0xa005, - 0x00de, 0x00ee, 0x0005, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c05, - 0x0904, 0x2df1, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7824, - 0xa005, 0x0904, 0x2df4, 0xa096, 0x00ff, 0x0120, 0xa092, 0x0004, - 0x1a04, 0x2df4, 0x2010, 0x2d18, 0x080c, 0x2a8c, 0x0904, 0x2df1, - 0x7007, 0x0003, 0x701b, 0x3bd5, 0x0005, 0x6830, 0xa086, 0x0100, - 0x0904, 0x2df1, 0x0804, 0x2dcc, 0x7924, 0xa18c, 0xff00, 0x810f, - 0x60d0, 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2df4, 0xa182, - 0x00ff, 0x1a04, 0x2df4, 0x0126, 0x2091, 0x8000, 0x080c, 0x95c6, - 0x1188, 0xa190, 0xae34, 0x2204, 0xa065, 0x0160, 0x080c, 0x493a, - 0x2001, 0xad34, 0x2004, 0xd0ac, 0x0110, 0x6017, 0x0000, 0x012e, - 0x0804, 0x2dcc, 0x012e, 0x0804, 0x2df1, 0x080c, 0x15d9, 0x0188, - 0xa006, 0x6802, 0x7010, 0xa005, 0x1120, 0x2d00, 0x7012, 0x7016, - 0x0030, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80, - 0x000d, 0x0005, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4cdc, - 0x1130, 0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0208, 0xa066, - 0x8cff, 0x0005, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x080c, 0x4cdc, - 0x1128, 0xa6b4, 0x00ff, 0xa682, 0x4000, 0x0208, 0xa066, 0x8cff, - 0x0005, 0x0016, 0x7110, 0x81ff, 0x0128, 0x2168, 0x6904, 0x080c, - 0x15f0, 0x0cc8, 0x7112, 0x7116, 0x001e, 0x0005, 0x2031, 0x0001, - 0x0010, 0x2031, 0x0000, 0x2061, 0xadd1, 0x6606, 0x6112, 0x600e, - 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x080c, 0x1624, 0x7007, - 0x0002, 0x701b, 0x2dcc, 0x0005, 0x00f6, 0x0126, 0x2091, 0x8000, - 0x2079, 0x0000, 0x2001, 0xad8f, 0x2004, 0xa005, 0x1168, 0x0e04, - 0x3c74, 0x7818, 0xd084, 0x1140, 0x7a22, 0x7b26, 0x7c2a, 0x781b, - 0x0001, 0x2091, 0x4080, 0x0408, 0x0016, 0x00c6, 0x00e6, 0x2071, - 0xad81, 0x7138, 0xa182, 0x0010, 0x0218, 0x7030, 0x2060, 0x0078, - 0x7030, 0xa0e0, 0x0004, 0xac82, 0xadd1, 0x0210, 0x2061, 0xad91, - 0x2c00, 0x7032, 0x81ff, 0x1108, 0x7036, 0x8108, 0x713a, 0x2262, - 0x6306, 0x640a, 0x00ee, 0x00ce, 0x001e, 0x012e, 0x00fe, 0x0005, - 0x00e6, 0x2071, 0xad81, 0x7038, 0xa005, 0x0570, 0x0126, 0x2091, - 0x8000, 0x0e04, 0x3ccb, 0x00f6, 0x2079, 0x0000, 0x7818, 0xd084, - 0x1508, 0x00c6, 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826, - 0x6008, 0x782a, 0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001, - 0x703a, 0xa005, 0x1130, 0x7033, 0xad91, 0x7037, 0xad91, 0x00ce, - 0x0048, 0xac80, 0x0004, 0xa0fa, 0xadd1, 0x0210, 0x2001, 0xad91, - 0x7036, 0x00ce, 0x00fe, 0x012e, 0x00ee, 0x0005, 0x0026, 0x2001, - 0xad52, 0x2004, 0xd0c4, 0x0120, 0x2011, 0x8014, 0x080c, 0x3c5c, - 0x002e, 0x0005, 0x81ff, 0x1904, 0x2df1, 0x0126, 0x2091, 0x8000, - 0x6030, 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x080c, 0x574f, 0x1178, - 0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, - 0xa085, 0x0001, 0x080c, 0x5793, 0x080c, 0x569a, 0x0010, 0x080c, - 0x485e, 0x012e, 0x0804, 0x2dcc, 0x7824, 0x2008, 0xa18c, 0xfffd, - 0x1128, 0x61dc, 0xa10d, 0x61de, 0x0804, 0x2dcc, 0x0804, 0x2df4, - 0x81ff, 0x1904, 0x2df1, 0x6000, 0xa086, 0x0003, 0x1904, 0x2df1, - 0x2001, 0xad52, 0x2004, 0xd0ac, 0x1904, 0x2df1, 0x080c, 0x3c2a, - 0x0904, 0x2df4, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1120, - 0x7828, 0xa005, 0x0904, 0x2dcc, 0x00c6, 0x080c, 0x3c05, 0x00ce, - 0x0904, 0x2df1, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, - 0x683a, 0x080c, 0x979c, 0x0904, 0x2df1, 0x7007, 0x0003, 0x701b, - 0x3d3a, 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2df1, 0x0804, - 0x2dcc, 0x2001, 0xad00, 0x2004, 0xa086, 0x0003, 0x1904, 0x2df1, - 0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3c05, 0x0904, - 0x2df1, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, 0x702f, - 0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x080c, 0x4cdc, 0x1904, - 0x3db4, 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0130, 0xa0c4, - 0xff00, 0xa8c6, 0x0600, 0x1904, 0x3db4, 0x2001, 0xad52, 0x2004, - 0xd0ac, 0x1128, 0x080c, 0x4f6e, 0x1110, 0xd79c, 0x05e8, 0xd794, - 0x1110, 0xd784, 0x0158, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, - 0x0004, 0x53a3, 0x080c, 0x3a86, 0xd794, 0x0148, 0xac80, 0x000a, - 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x080c, 0x3a86, 0x21a2, - 0xd794, 0x01d8, 0xac80, 0x0000, 0x2098, 0x94a0, 0x20a9, 0x0002, - 0x53a3, 0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80, 0x0004, 0x2098, - 0x3400, 0x20a9, 0x0002, 0x53a3, 0x080c, 0x3a78, 0xac80, 0x0026, - 0x2098, 0x20a9, 0x0002, 0x53a3, 0x0008, 0x94a0, 0xd794, 0x0110, - 0xa6b0, 0x000b, 0xa6b0, 0x0005, 0x8108, 0x2001, 0xad34, 0x2004, - 0xd0ac, 0x0118, 0xa186, 0x0100, 0x0040, 0xd78c, 0x0120, 0xa186, - 0x0100, 0x0170, 0x0018, 0xa186, 0x007e, 0x0150, 0xd794, 0x0118, - 0xa686, 0x0020, 0x0010, 0xa686, 0x0028, 0x0150, 0x0804, 0x3d5d, - 0x86ff, 0x1120, 0x7120, 0x810b, 0x0804, 0x2dcc, 0x702f, 0x0001, - 0x711e, 0x7020, 0xa600, 0x7022, 0x772a, 0x2061, 0xadd1, 0x6007, - 0x0000, 0x6612, 0x7024, 0x600e, 0x6226, 0x632a, 0x642e, 0x6532, - 0x2c10, 0x080c, 0x1624, 0x7007, 0x0002, 0x701b, 0x3df0, 0x0005, - 0x702c, 0xa005, 0x1170, 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, - 0x0000, 0x2061, 0xadd1, 0x6224, 0x6328, 0x642c, 0x6530, 0x0804, - 0x3d5d, 0x7120, 0x810b, 0x0804, 0x2dcc, 0x2029, 0x007e, 0x7924, - 0x7a28, 0x7b2c, 0x7c38, 0xa184, 0xff00, 0x8007, 0xa0e2, 0x0020, - 0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4, 0xa184, 0x00ff, 0xa0e2, - 0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4, 0xa284, 0xff00, - 0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4, - 0xa284, 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04, - 0x2df4, 0xa384, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2df4, - 0xa502, 0x0a04, 0x2df4, 0xa384, 0x00ff, 0xa0e2, 0x0020, 0x0a04, - 0x2df4, 0xa502, 0x0a04, 0x2df4, 0xa484, 0xff00, 0x8007, 0xa0e2, - 0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4, 0xa484, 0x00ff, - 0xa0e2, 0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4, 0x2061, - 0xafa6, 0x6102, 0x6206, 0x630a, 0x640e, 0x0804, 0x2dcc, 0x0006, - 0x2001, 0xad52, 0x2004, 0xd0cc, 0x000e, 0x0005, 0x0006, 0x2001, - 0xad71, 0x2004, 0xd0bc, 0x000e, 0x0005, 0x6164, 0x7a24, 0x6300, - 0x82ff, 0x1118, 0x7926, 0x0804, 0x2dcc, 0x83ff, 0x1904, 0x2df4, - 0x2001, 0xfff0, 0xa200, 0x1a04, 0x2df4, 0x2019, 0xffff, 0x6068, - 0xa302, 0xa200, 0x0a04, 0x2df4, 0x7926, 0x6266, 0x0804, 0x2dcc, - 0x2001, 0xad00, 0x2004, 0xa086, 0x0003, 0x1904, 0x2df1, 0x7c28, - 0x7d24, 0x7e38, 0x7f2c, 0x080c, 0x3c05, 0x0904, 0x2df1, 0x2009, - 0x0000, 0x2019, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80, - 0x0003, 0x7026, 0x20a0, 0xa1e0, 0xae34, 0x2c64, 0x8cff, 0x01b8, - 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0130, 0x6004, 0xa084, - 0xff00, 0xa086, 0x0600, 0x1158, 0x6014, 0x20a2, 0x94a0, 0x6010, - 0x8007, 0xa105, 0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002, 0x8108, - 0xa182, 0x00ff, 0x0120, 0xa386, 0x002a, 0x0148, 0x08e0, 0x83ff, - 0x1120, 0x7120, 0x810c, 0x0804, 0x2dcc, 0x702f, 0x0001, 0x711e, - 0x7020, 0xa300, 0x7022, 0x2061, 0xadd1, 0x6007, 0x0000, 0x6312, - 0x7024, 0x600e, 0x6426, 0x652a, 0x662e, 0x6732, 0x2c10, 0x080c, - 0x1624, 0x7007, 0x0002, 0x701b, 0x3ee6, 0x0005, 0x702c, 0xa005, - 0x1168, 0x711c, 0x7024, 0x20a0, 0x2019, 0x0000, 0x2061, 0xadd1, - 0x6424, 0x6528, 0x662c, 0x6730, 0x0804, 0x3ea3, 0x7120, 0x810c, - 0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x60d0, 0xd0ac, 0x1118, - 0xd09c, 0x0904, 0x2df1, 0x080c, 0x3c05, 0x0904, 0x2df1, 0x7924, - 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3c46, 0x701b, 0x3f11, - 0x0005, 0x00d6, 0xade8, 0x000d, 0x6828, 0xa0be, 0x7000, 0x0148, - 0xa0be, 0x7100, 0x0130, 0xa0be, 0x7200, 0x0118, 0x00de, 0x0804, - 0x2df4, 0x6820, 0x6924, 0x080c, 0x2676, 0x1510, 0x080c, 0x4c80, - 0x11f8, 0x7122, 0x6612, 0x6516, 0x6e18, 0x00c6, 0x080c, 0x3c05, - 0x01b8, 0x080c, 0x3c05, 0x01a0, 0x00ce, 0x00de, 0x6837, 0x0000, - 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x080c, - 0x96ef, 0x0904, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3f4b, 0x0005, - 0x00de, 0x0804, 0x2df1, 0x7120, 0x080c, 0x2bc9, 0x6820, 0xa086, - 0x8001, 0x0904, 0x2df1, 0x2d00, 0x701e, 0x6804, 0xa080, 0x0002, - 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x48be, 0x000e, - 0xade8, 0x000d, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0xadd1, - 0x6007, 0x0000, 0x6e00, 0x6f28, 0xa7c6, 0x7000, 0x1108, 0x0018, - 0xa7c6, 0x7100, 0x1140, 0xa6c2, 0x0004, 0x0a04, 0x2df4, 0x2009, - 0x0004, 0x0804, 0x3c49, 0xa7c6, 0x7200, 0x1904, 0x2df4, 0xa6c2, - 0x0054, 0x0a04, 0x2df4, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a, - 0x642e, 0x6532, 0x2c10, 0x080c, 0x1624, 0x7007, 0x0002, 0x701b, - 0x3f92, 0x0005, 0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004, - 0xa080, 0x0002, 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, - 0x48be, 0x000e, 0x2009, 0x002a, 0x2061, 0xadd1, 0x6224, 0x6328, - 0x642c, 0x6530, 0x0804, 0x3c49, 0x81ff, 0x1904, 0x2df1, 0x080c, - 0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4d96, 0x0904, 0x2df1, 0x080c, - 0x4ec6, 0x0804, 0x2dcc, 0x7824, 0xd084, 0x0904, 0x3804, 0x080c, - 0x3c2a, 0x0904, 0x2df4, 0x00c6, 0x080c, 0x3c05, 0x00ce, 0x1120, - 0x2009, 0x0002, 0x0804, 0x2df1, 0x6004, 0xa084, 0x00ff, 0xa086, - 0x0006, 0x0128, 0xa08e, 0x0004, 0x0110, 0xa08e, 0x0005, 0x1508, - 0x2001, 0xad52, 0x2004, 0xd0b4, 0x0904, 0x3834, 0x6000, 0xd08c, - 0x1904, 0x3834, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, - 0x970b, 0x1120, 0x2009, 0x0003, 0x0804, 0x2df1, 0x7007, 0x0003, - 0x701b, 0x3ff3, 0x0005, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x0804, - 0x3834, 0x2009, 0xad30, 0x210c, 0x81ff, 0x0120, 0x2009, 0x0001, - 0x0804, 0x2df1, 0x2001, 0xad00, 0x2004, 0xa086, 0x0003, 0x0120, - 0x2009, 0x0007, 0x0804, 0x2df1, 0x2001, 0xad52, 0x2004, 0xd0ac, - 0x0120, 0x2009, 0x0008, 0x0804, 0x2df1, 0x609c, 0xd0a4, 0x1118, - 0xd0ac, 0x1904, 0x3834, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, - 0xc0fd, 0x683a, 0x080c, 0x979c, 0x1120, 0x2009, 0x0003, 0x0804, - 0x2df1, 0x7007, 0x0003, 0x701b, 0x402e, 0x0005, 0x6830, 0xa086, - 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x2df1, 0x080c, 0x3c2a, - 0x0904, 0x2df4, 0x0804, 0x3fd8, 0x81ff, 0x2009, 0x0001, 0x1904, - 0x2df1, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x1904, 0x2df1, - 0x2001, 0xad52, 0x2004, 0xd0ac, 0x2009, 0x0008, 0x1904, 0x2df1, - 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x6004, 0xa084, 0x00ff, 0xa086, - 0x0006, 0x2009, 0x0009, 0x1904, 0x2df1, 0x00c6, 0x080c, 0x3c05, - 0x00ce, 0x2009, 0x0002, 0x0904, 0x2df1, 0x6837, 0x0000, 0x6833, - 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7928, 0xa194, 0xff00, 0xa18c, - 0x00ff, 0xa006, 0x82ff, 0x1128, 0xc0ed, 0x6952, 0x792c, 0x6956, - 0x0048, 0xa28e, 0x0100, 0x1904, 0x2df4, 0xc0e5, 0x6853, 0x0000, - 0x6857, 0x0000, 0x683e, 0x080c, 0x9957, 0x2009, 0x0003, 0x0904, - 0x2df1, 0x7007, 0x0003, 0x701b, 0x408e, 0x0005, 0x6830, 0xa086, - 0x0100, 0x2009, 0x0004, 0x0904, 0x2df1, 0x0804, 0x2dcc, 0x81ff, - 0x2009, 0x0001, 0x1904, 0x2df1, 0x6000, 0xa086, 0x0003, 0x2009, - 0x0007, 0x1904, 0x2df1, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x6004, - 0xa084, 0x00ff, 0xa086, 0x0006, 0x2009, 0x0009, 0x1904, 0x2df1, - 0x00c6, 0x080c, 0x3c05, 0x00ce, 0x2009, 0x0002, 0x0904, 0x2df1, - 0xad80, 0x000f, 0x2009, 0x0008, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, - 0x080c, 0x3c46, 0x701b, 0x40c5, 0x0005, 0x00d6, 0xade8, 0x000f, - 0x6800, 0xa086, 0x0500, 0x1140, 0x6804, 0xa005, 0x1128, 0x6808, - 0xa084, 0xff00, 0x1108, 0x0018, 0x00de, 0x1904, 0x2df4, 0x00de, - 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x00c6, - 0x080c, 0x3c2a, 0x1118, 0x00ce, 0x0804, 0x2df4, 0x080c, 0x99a6, - 0x2009, 0x0003, 0x00ce, 0x0904, 0x2df1, 0x7007, 0x0003, 0x701b, - 0x40f2, 0x0005, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0904, - 0x2df1, 0x0804, 0x2dcc, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, - 0x2df1, 0x6000, 0xa086, 0x0003, 0x0120, 0x2009, 0x0007, 0x0804, - 0x2df1, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0xa6b4, 0x00ff, 0x080c, - 0x4cdc, 0x1904, 0x2df4, 0xa186, 0x007f, 0x0150, 0x6004, 0xa084, - 0x00ff, 0xa086, 0x0006, 0x0120, 0x2009, 0x0009, 0x0804, 0x2df1, - 0x00c6, 0x080c, 0x3c05, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804, - 0x2df1, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x9726, - 0x1120, 0x2009, 0x0003, 0x0804, 0x2df1, 0x7007, 0x0003, 0x701b, - 0x413a, 0x0005, 0x6808, 0x8007, 0xa086, 0x0100, 0x1120, 0x2009, - 0x0004, 0x0804, 0x2df1, 0x68b0, 0x6836, 0x6810, 0x8007, 0xa084, - 0x00ff, 0x808e, 0x6814, 0x8007, 0xa084, 0x00ff, 0x8086, 0xa080, - 0x0002, 0xa108, 0xad80, 0x0004, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, - 0x0804, 0x3c49, 0x080c, 0x3c05, 0x1120, 0x2009, 0x0002, 0x0804, - 0x2df1, 0x7924, 0xa194, 0xff00, 0xa18c, 0x00ff, 0x8217, 0x82ff, - 0x0110, 0x0804, 0x2df4, 0x2009, 0x001a, 0x7a2c, 0x7b28, 0x7c3c, - 0x7d38, 0x080c, 0x3c46, 0x701b, 0x4176, 0x0005, 0xad80, 0x000d, - 0x2098, 0x20a9, 0x001a, 0x20a1, 0xafad, 0x53a3, 0x0804, 0x2dcc, - 0x080c, 0x3c05, 0x1120, 0x2009, 0x0002, 0x0804, 0x2df1, 0x7924, - 0xa194, 0xff00, 0xa18c, 0x00ff, 0x8217, 0x82ff, 0x0110, 0x0804, - 0x2df4, 0x2099, 0xafad, 0x20a0, 0x20a9, 0x001a, 0x53a3, 0x2009, - 0x001a, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49, 0x7824, - 0xa08a, 0x1000, 0x1a04, 0x2df4, 0x0126, 0x2091, 0x8000, 0x8003, - 0x800b, 0x810b, 0xa108, 0x00c6, 0x2061, 0xafda, 0x6142, 0x00ce, - 0x012e, 0x0804, 0x2dcc, 0x00c6, 0x080c, 0x574f, 0x1188, 0x2001, - 0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0xa085, - 0x0001, 0x080c, 0x5793, 0x080c, 0x569a, 0x080c, 0x14f6, 0x0038, - 0x2061, 0xad00, 0x6030, 0xc09d, 0x6032, 0x080c, 0x485e, 0x00ce, - 0x0005, 0x0126, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xad00, - 0x6044, 0xd0a4, 0x11b0, 0xd084, 0x0118, 0x080c, 0x4348, 0x0068, - 0xd08c, 0x0118, 0x080c, 0x4269, 0x0040, 0xd094, 0x0118, 0x080c, - 0x423a, 0x0018, 0xd09c, 0x0108, 0x0061, 0x00ee, 0x00ce, 0x012e, - 0x0005, 0x0016, 0x6128, 0xd19c, 0x1110, 0xc19d, 0x612a, 0x001e, - 0x0ca0, 0x624c, 0xa286, 0xf0f0, 0x1150, 0x6048, 0xa086, 0xf0f0, - 0x0130, 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0490, 0xa294, - 0xff00, 0xa296, 0xf700, 0x0178, 0x7134, 0xd1a4, 0x1160, 0x6240, - 0xa295, 0x0100, 0x6242, 0xa294, 0x0010, 0x0128, 0x2009, 0x00f7, - 0x080c, 0x48de, 0x00f0, 0x6040, 0xa084, 0x0010, 0xa085, 0x0040, - 0x6042, 0x6043, 0x0000, 0x7077, 0x0000, 0x7093, 0x0001, 0x70b7, - 0x0000, 0x70d3, 0x0000, 0x2009, 0xb3c0, 0x200b, 0x0000, 0x7087, - 0x0000, 0x707b, 0x000a, 0x2009, 0x000a, 0x2011, 0x4814, 0x080c, - 0x6593, 0x0005, 0x0156, 0x2001, 0xad73, 0x2004, 0xd08c, 0x0110, - 0x704f, 0xffff, 0x7078, 0xa005, 0x1510, 0x2011, 0x4814, 0x080c, - 0x650d, 0x6040, 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9, - 0x00c8, 0x6044, 0xd08c, 0x1168, 0x1f04, 0x4251, 0x6242, 0x708b, - 0x0000, 0x6040, 0xa094, 0x0010, 0xa285, 0x0080, 0x6042, 0x6242, - 0x0030, 0x6242, 0x708b, 0x0000, 0x707f, 0x0000, 0x0000, 0x015e, - 0x0005, 0x707c, 0xa08a, 0x0003, 0x1210, 0x0023, 0x0010, 0x080c, - 0x14f6, 0x0005, 0x4275, 0x42c5, 0x4347, 0x00f6, 0x707f, 0x0001, - 0x20e1, 0xa000, 0xe000, 0x20e1, 0x8700, 0x080c, 0x22f8, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x2079, 0xb200, 0x207b, 0x2200, 0x7807, - 0x00ef, 0x780b, 0x0000, 0x780f, 0x00ef, 0x7813, 0x0138, 0x7817, - 0x0000, 0x781b, 0x0000, 0x781f, 0x0000, 0x7823, 0xffff, 0x7827, - 0xffff, 0x782b, 0x0000, 0x782f, 0x0000, 0x2079, 0xb20c, 0x207b, - 0x1101, 0x7807, 0x0000, 0x2099, 0xad05, 0x20a1, 0xb20e, 0x20a9, - 0x0004, 0x53a3, 0x2079, 0xb212, 0x207b, 0x0000, 0x7807, 0x0000, - 0x2099, 0xb200, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3, - 0x000c, 0x600f, 0x0000, 0x080c, 0x4845, 0x00fe, 0x7083, 0x0000, - 0x6043, 0x0008, 0x6043, 0x0000, 0x0005, 0x00d6, 0x7080, 0x7083, - 0x0000, 0xa025, 0x0904, 0x432f, 0x6020, 0xd0b4, 0x1904, 0x432d, - 0x7190, 0x81ff, 0x0904, 0x431d, 0xa486, 0x000c, 0x1904, 0x4328, - 0xa480, 0x0018, 0x8004, 0x20a8, 0x2011, 0xb280, 0x2019, 0xb200, - 0x220c, 0x2304, 0xa106, 0x11b8, 0x8210, 0x8318, 0x1f04, 0x42e0, - 0x6043, 0x0004, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, - 0x707f, 0x0002, 0x708b, 0x0002, 0x2009, 0x07d0, 0x2011, 0x481b, - 0x080c, 0x6593, 0x0490, 0x2069, 0xb280, 0x6930, 0xa18e, 0x1101, - 0x1538, 0x6834, 0xa005, 0x1520, 0x6900, 0xa18c, 0x00ff, 0x1118, - 0x6804, 0xa005, 0x0190, 0x2011, 0xb28e, 0x2019, 0xad05, 0x20a9, - 0x0004, 0x220c, 0x2304, 0xa102, 0x0230, 0x1190, 0x8210, 0x8318, - 0x1f04, 0x4311, 0x0068, 0x7093, 0x0000, 0x20e1, 0x9080, 0x20e1, - 0x4000, 0x2099, 0xb280, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, - 0x6043, 0x0008, 0x6043, 0x0000, 0x0010, 0x00de, 0x0005, 0x6040, - 0xa085, 0x0100, 0x6042, 0x6020, 0xd0b4, 0x1db8, 0x60c3, 0x000c, - 0x2011, 0xafd1, 0x2013, 0x0000, 0x7083, 0x0000, 0x20e1, 0x9080, - 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x782b, 0x0c30, 0x0005, - 0x7088, 0xa08a, 0x001d, 0x1210, 0x0023, 0x0010, 0x080c, 0x14f6, - 0x0005, 0x437b, 0x438a, 0x43b2, 0x43cb, 0x43ef, 0x4417, 0x443b, - 0x446c, 0x4490, 0x44b8, 0x44ef, 0x4517, 0x4533, 0x4549, 0x4569, - 0x457c, 0x4584, 0x45b1, 0x45d5, 0x45fd, 0x4621, 0x4652, 0x468f, - 0x46be, 0x46da, 0x4719, 0x4739, 0x4752, 0x4753, 0x00c6, 0x2061, - 0xad00, 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9, - 0x6006, 0x00ce, 0x0005, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, - 0x0002, 0x708b, 0x0001, 0x2009, 0x07d0, 0x2011, 0x481b, 0x080c, - 0x6593, 0x0005, 0x00f6, 0x7080, 0xa086, 0x0014, 0x1508, 0x6043, - 0x0000, 0x6020, 0xd0b4, 0x11e0, 0x2079, 0xb280, 0x7a30, 0xa296, - 0x1102, 0x11a0, 0x7834, 0xa005, 0x1188, 0x7a38, 0xd2fc, 0x0128, - 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x2011, 0x481b, 0x080c, - 0x650d, 0x708b, 0x0010, 0x080c, 0x4584, 0x0010, 0x080c, 0x485e, - 0x00fe, 0x0005, 0x708b, 0x0003, 0x6043, 0x0004, 0x2011, 0x481b, - 0x080c, 0x650d, 0x080c, 0x48c6, 0x20a3, 0x1102, 0x20a3, 0x0000, - 0x20a9, 0x000a, 0x20a3, 0x0000, 0x1f04, 0x43c2, 0x60c3, 0x0014, - 0x080c, 0x4845, 0x0005, 0x00f6, 0x7080, 0xa005, 0x01f0, 0x2011, - 0x481b, 0x080c, 0x650d, 0xa086, 0x0014, 0x11a8, 0x2079, 0xb280, - 0x7a30, 0xa296, 0x1102, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, - 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x708b, - 0x0004, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe, 0x0005, 0x708b, - 0x0005, 0x080c, 0x48c6, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, - 0x2011, 0xb28e, 0x080c, 0x4917, 0x1160, 0x7074, 0xa005, 0x1148, - 0x714c, 0xa186, 0xffff, 0x0128, 0x080c, 0x47df, 0x0110, 0x080c, - 0x48f5, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x4845, 0x0005, 0x00f6, - 0x7080, 0xa005, 0x01f0, 0x2011, 0x481b, 0x080c, 0x650d, 0xa086, - 0x0014, 0x11a8, 0x2079, 0xb280, 0x7a30, 0xa296, 0x1103, 0x1178, - 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, - 0x1110, 0x70b7, 0x0001, 0x708b, 0x0006, 0x0029, 0x0010, 0x080c, - 0x485e, 0x00fe, 0x0005, 0x708b, 0x0007, 0x080c, 0x48c6, 0x20a3, - 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0xb28e, 0x080c, 0x4917, - 0x11a8, 0x7074, 0xa005, 0x1190, 0x7154, 0xa186, 0xffff, 0x0170, - 0xa180, 0x2be6, 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x47df, - 0x0128, 0x080c, 0x3e66, 0x0110, 0x080c, 0x26c0, 0x20a9, 0x0008, - 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, - 0x0014, 0x080c, 0x4845, 0x0005, 0x00f6, 0x7080, 0xa005, 0x01f0, - 0x2011, 0x481b, 0x080c, 0x650d, 0xa086, 0x0014, 0x11a8, 0x2079, - 0xb280, 0x7a30, 0xa296, 0x1104, 0x1178, 0x7834, 0xa005, 0x1160, - 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, - 0x708b, 0x0008, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe, 0x0005, - 0x708b, 0x0009, 0x080c, 0x48c6, 0x20a3, 0x1105, 0x20a3, 0x0100, - 0x3430, 0x080c, 0x4917, 0x1150, 0x7074, 0xa005, 0x1138, 0x080c, - 0x4754, 0x1170, 0xa085, 0x0001, 0x080c, 0x26c0, 0x20a9, 0x0008, - 0x2099, 0xb28e, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x0014, 0x080c, 0x4845, 0x0010, 0x080c, 0x436e, 0x0005, - 0x00f6, 0x7080, 0xa005, 0x0588, 0x2011, 0x481b, 0x080c, 0x650d, - 0xa086, 0x0014, 0x1540, 0x2079, 0xb280, 0x7a30, 0xa296, 0x1105, - 0x1510, 0x7834, 0x2011, 0x0100, 0xa21e, 0x1160, 0x7a38, 0xd2fc, - 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x708b, 0x000a, - 0x00b1, 0x0098, 0xa005, 0x1178, 0x7a38, 0xd2fc, 0x0128, 0x70b4, - 0xa005, 0x1110, 0x70b7, 0x0001, 0x7087, 0x0000, 0x708b, 0x000e, - 0x080c, 0x4569, 0x0010, 0x080c, 0x485e, 0x00fe, 0x0005, 0x708b, - 0x000b, 0x2011, 0xb20e, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff, - 0x43a4, 0x20a9, 0x0002, 0x2009, 0x0000, 0x41a4, 0x080c, 0x48c6, - 0x20a3, 0x1106, 0x20a3, 0x0000, 0x080c, 0x4917, 0x0118, 0x2013, - 0x0000, 0x0020, 0x7050, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, - 0x0042, 0x53a6, 0x60c3, 0x0084, 0x080c, 0x4845, 0x0005, 0x00f6, - 0x7080, 0xa005, 0x01b0, 0x2011, 0x481b, 0x080c, 0x650d, 0xa086, - 0x0084, 0x1168, 0x2079, 0xb280, 0x7a30, 0xa296, 0x1106, 0x1138, - 0x7834, 0xa005, 0x1120, 0x708b, 0x000c, 0x0029, 0x0010, 0x080c, - 0x485e, 0x00fe, 0x0005, 0x708b, 0x000d, 0x080c, 0x48c6, 0x20a3, - 0x1107, 0x20a3, 0x0000, 0x2099, 0xb28e, 0x20a9, 0x0040, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x4845, - 0x0005, 0x00f6, 0x7080, 0xa005, 0x01d0, 0x2011, 0x481b, 0x080c, - 0x650d, 0xa086, 0x0084, 0x1188, 0x2079, 0xb280, 0x7a30, 0xa296, - 0x1107, 0x1158, 0x7834, 0xa005, 0x1140, 0x7087, 0x0001, 0x080c, - 0x48b8, 0x708b, 0x000e, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe, - 0x0005, 0x708b, 0x000f, 0x7083, 0x0000, 0x608b, 0xbc85, 0x608f, - 0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, - 0x481b, 0x080c, 0x6501, 0x0005, 0x7080, 0xa005, 0x0120, 0x2011, - 0x481b, 0x080c, 0x650d, 0x0005, 0x708b, 0x0011, 0x080c, 0x4917, - 0x1188, 0x716c, 0x81ff, 0x0170, 0x2009, 0x0000, 0x7070, 0xa084, - 0x00ff, 0x080c, 0x2676, 0xa186, 0x0080, 0x0120, 0x2011, 0xb28e, - 0x080c, 0x47df, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xb280, - 0x20a1, 0x020b, 0x7480, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, - 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0014, 0x080c, 0x4845, - 0x0005, 0x00f6, 0x7080, 0xa005, 0x01f0, 0x2011, 0x481b, 0x080c, - 0x650d, 0xa086, 0x0014, 0x11a8, 0x2079, 0xb280, 0x7a30, 0xa296, - 0x1103, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128, - 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x708b, 0x0012, 0x0029, - 0x0010, 0x080c, 0x485e, 0x00fe, 0x0005, 0x708b, 0x0013, 0x080c, - 0x48d2, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0xb28e, - 0x080c, 0x4917, 0x1160, 0x7074, 0xa005, 0x1148, 0x714c, 0xa186, - 0xffff, 0x0128, 0x080c, 0x47df, 0x0110, 0x080c, 0x48f5, 0x20a9, - 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x60c3, 0x0014, 0x080c, 0x4845, 0x0005, 0x00f6, 0x7080, 0xa005, - 0x01f0, 0x2011, 0x481b, 0x080c, 0x650d, 0xa086, 0x0014, 0x11a8, - 0x2079, 0xb280, 0x7a30, 0xa296, 0x1104, 0x1178, 0x7834, 0xa005, - 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, - 0x0001, 0x708b, 0x0014, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe, - 0x0005, 0x708b, 0x0015, 0x080c, 0x48d2, 0x20a3, 0x1104, 0x20a3, - 0x0000, 0x3430, 0x2011, 0xb28e, 0x080c, 0x4917, 0x11a8, 0x7074, - 0xa005, 0x1190, 0x7154, 0xa186, 0xffff, 0x0170, 0xa180, 0x2be6, - 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x47df, 0x0128, 0x080c, - 0x3e66, 0x0110, 0x080c, 0x26c0, 0x20a9, 0x0008, 0x2298, 0x26a0, - 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, - 0x4845, 0x0005, 0x00f6, 0x7080, 0xa005, 0x05b8, 0x2011, 0x481b, - 0x080c, 0x650d, 0xa086, 0x0014, 0x1570, 0x2079, 0xb280, 0x7a30, - 0xa296, 0x1105, 0x1540, 0x7834, 0x2011, 0x0100, 0xa21e, 0x1148, - 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, - 0x0060, 0xa005, 0x11c0, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, - 0x1110, 0x70b7, 0x0001, 0x7087, 0x0000, 0x7a38, 0xd2f4, 0x0138, - 0x2001, 0xad73, 0x2004, 0xd0a4, 0x1110, 0x70d3, 0x0008, 0x708b, - 0x0016, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe, 0x0005, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x2099, 0xb280, 0x20a1, 0x020b, 0x20a9, - 0x000e, 0x53a6, 0x3430, 0x2011, 0xb28e, 0x708b, 0x0017, 0x080c, - 0x4917, 0x1150, 0x7074, 0xa005, 0x1138, 0x080c, 0x4754, 0x1170, - 0xa085, 0x0001, 0x080c, 0x26c0, 0x20a9, 0x0008, 0x2099, 0xb28e, - 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, - 0x080c, 0x4845, 0x0010, 0x080c, 0x436e, 0x0005, 0x00f6, 0x7080, - 0xa005, 0x01b0, 0x2011, 0x481b, 0x080c, 0x650d, 0xa086, 0x0084, - 0x1168, 0x2079, 0xb280, 0x7a30, 0xa296, 0x1106, 0x1138, 0x7834, - 0xa005, 0x1120, 0x708b, 0x0018, 0x0029, 0x0010, 0x080c, 0x485e, - 0x00fe, 0x0005, 0x708b, 0x0019, 0x080c, 0x48d2, 0x20a3, 0x1106, - 0x20a3, 0x0000, 0x3430, 0x2099, 0xb28e, 0x2039, 0xb20e, 0x27a0, - 0x20a9, 0x0040, 0x53a3, 0x080c, 0x4917, 0x11e8, 0x2728, 0x2514, - 0x8207, 0xa084, 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, - 0xa205, 0x202a, 0x7050, 0x2310, 0x8214, 0xa2a0, 0xb20e, 0x2414, - 0xa38c, 0x0001, 0x0118, 0xa294, 0xff00, 0x0018, 0xa294, 0x00ff, - 0x8007, 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x4845, - 0x0005, 0x00f6, 0x7080, 0xa005, 0x01d0, 0x2011, 0x481b, 0x080c, - 0x650d, 0xa086, 0x0084, 0x1188, 0x2079, 0xb280, 0x7a30, 0xa296, - 0x1107, 0x1158, 0x7834, 0xa005, 0x1140, 0x7087, 0x0001, 0x080c, - 0x48b8, 0x708b, 0x001a, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe, - 0x0005, 0x708b, 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, - 0xb280, 0x20a1, 0x020b, 0x7480, 0xa480, 0x0018, 0xa080, 0x0007, - 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0084, 0x080c, - 0x4845, 0x0005, 0x0005, 0x0005, 0x0086, 0x0096, 0x2029, 0xad52, - 0x252c, 0x20a9, 0x0008, 0x2041, 0xb20e, 0x28a0, 0x2099, 0xb28e, - 0x53a3, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0110, 0x2011, - 0x0000, 0x2800, 0xa200, 0x200c, 0xa1a6, 0xffff, 0x1148, 0xd5d4, - 0x0110, 0x8210, 0x0008, 0x8211, 0x1f04, 0x4769, 0x0804, 0x47d7, - 0x82ff, 0x1160, 0xd5d4, 0x0120, 0xa1a6, 0x3fff, 0x0d90, 0x0020, - 0xa1a6, 0x3fff, 0x0904, 0x47d7, 0xa18d, 0xc000, 0x20a9, 0x0010, - 0x2019, 0x0001, 0xd5d4, 0x0110, 0x2019, 0x0010, 0x2120, 0xd5d4, - 0x0110, 0x8423, 0x0008, 0x8424, 0x1240, 0xd5d4, 0x0110, 0x8319, - 0x0008, 0x8318, 0x1f04, 0x478f, 0x04d0, 0x23a8, 0x2021, 0x0001, - 0x8426, 0x8425, 0x1f04, 0x47a1, 0x2328, 0x8529, 0xa2be, 0x0007, - 0x0158, 0x0006, 0x2039, 0x0007, 0x2200, 0xa73a, 0x000e, 0x27a8, - 0xa5a8, 0x0010, 0x1f04, 0x47b0, 0x754e, 0xa5c8, 0x2be6, 0x292d, - 0xa5ac, 0x00ff, 0x7572, 0x6532, 0x6536, 0x0016, 0x2508, 0x080c, - 0x26a0, 0x001e, 0x60e7, 0x0000, 0x65ea, 0x2018, 0x2304, 0xa405, - 0x201a, 0x7077, 0x0001, 0x26a0, 0x2898, 0x20a9, 0x0008, 0x53a6, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0xa085, 0x0001, 0x0028, 0xa006, - 0x0018, 0xa006, 0x080c, 0x14f6, 0x009e, 0x008e, 0x0005, 0x2118, - 0x2021, 0x0000, 0x2001, 0x0007, 0xa39a, 0x0010, 0x0218, 0x8420, - 0x8001, 0x0cd0, 0x2118, 0x84ff, 0x0120, 0xa39a, 0x0010, 0x8421, - 0x1de0, 0x2021, 0x0001, 0x83ff, 0x0118, 0x8423, 0x8319, 0x1de8, - 0xa238, 0x2704, 0xa42c, 0x11b8, 0xa405, 0x203a, 0x714e, 0xa1a0, - 0x2be6, 0x242d, 0xa5ac, 0x00ff, 0x7572, 0x6532, 0x6536, 0x0016, - 0x2508, 0x080c, 0x26a0, 0x001e, 0x60e7, 0x0000, 0x65ea, 0x7077, - 0x0001, 0xa084, 0x0000, 0x0005, 0x00e6, 0x2071, 0xad00, 0x707b, - 0x0000, 0x00ee, 0x0005, 0x00e6, 0x00f6, 0x2079, 0x0100, 0x2071, - 0x0140, 0x080c, 0x7834, 0x7004, 0xa084, 0x4000, 0x0120, 0x7003, - 0x1000, 0x7003, 0x0000, 0x0126, 0x2091, 0x8000, 0x2071, 0xad22, - 0x2073, 0x0000, 0x7840, 0x0026, 0x0016, 0x2009, 0x00f7, 0x080c, - 0x48de, 0x001e, 0xa094, 0x0010, 0xa285, 0x0080, 0x7842, 0x7a42, - 0x002e, 0x012e, 0x00fe, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, - 0x2011, 0xafd1, 0x2013, 0x0000, 0x7083, 0x0000, 0x012e, 0x20e1, - 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x782b, 0x2009, - 0x07d0, 0x2011, 0x481b, 0x080c, 0x6593, 0x0005, 0x0016, 0x0026, - 0x00c6, 0x0126, 0x2091, 0x8000, 0x2009, 0x00f7, 0x080c, 0x48de, - 0x2061, 0xafda, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0xad00, - 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, - 0x2009, 0x002d, 0x2011, 0x4883, 0x080c, 0x6501, 0x012e, 0x00ce, - 0x002e, 0x001e, 0x0005, 0x00e6, 0x0006, 0x0126, 0x2091, 0x8000, - 0x2071, 0x0100, 0x080c, 0x7834, 0x2071, 0x0140, 0x7004, 0xa084, - 0x4000, 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x080c, 0x5757, - 0x01a8, 0x080c, 0x5775, 0x1190, 0x2001, 0xaf9d, 0x2003, 0xaaaa, - 0x0016, 0x080c, 0x2744, 0x2001, 0xaf8e, 0x2102, 0x001e, 0x2001, - 0xaf9e, 0x2003, 0x0000, 0x080c, 0x569a, 0x0030, 0x2001, 0x0001, - 0x080c, 0x261e, 0x080c, 0x485e, 0x012e, 0x000e, 0x00ee, 0x0005, - 0x20a9, 0x0040, 0x20a1, 0xb3c0, 0x2099, 0xb28e, 0x3304, 0x8007, - 0x20a2, 0x9398, 0x94a0, 0x1f04, 0x48be, 0x0005, 0x20e1, 0x9080, - 0x20e1, 0x4000, 0x2099, 0xb200, 0x20a1, 0x020b, 0x20a9, 0x000c, - 0x53a6, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xb280, - 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x0005, 0x00c6, 0x0006, - 0x2061, 0x0100, 0x810f, 0x2001, 0xad30, 0x2004, 0xa005, 0x1138, - 0x2001, 0xad14, 0x2004, 0xa084, 0x00ff, 0xa105, 0x0010, 0xa185, - 0x00f7, 0x604a, 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046, 0x2001, - 0xad52, 0x2004, 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, 0x002a, - 0x080c, 0xa96c, 0x2001, 0xad0c, 0x200c, 0xc195, 0x2102, 0x2019, - 0x002a, 0x2009, 0x0000, 0x080c, 0x2aac, 0x004e, 0x001e, 0x0005, - 0x080c, 0x485e, 0x708b, 0x0000, 0x7083, 0x0000, 0x0005, 0x0006, - 0x2001, 0xad0c, 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005, 0x0006, - 0x0016, 0x0126, 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0xa18d, - 0x0006, 0x2102, 0x012e, 0x001e, 0x000e, 0x0005, 0x0156, 0x20a9, - 0x00ff, 0x2009, 0xae34, 0xa006, 0x200a, 0x8108, 0x1f04, 0x4934, - 0x015e, 0x0005, 0x00d6, 0x0036, 0x0156, 0x0136, 0x0146, 0x2069, - 0xad51, 0xa006, 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, - 0xa198, 0x2be6, 0x231d, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, - 0xac98, 0x0006, 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, 0x000a, - 0x23a0, 0x40a4, 0x603e, 0x6042, 0x604e, 0x6052, 0x6056, 0x605a, - 0x605e, 0x6062, 0x6066, 0x606a, 0x606e, 0x6072, 0x6076, 0x607a, - 0x607e, 0x6082, 0x6086, 0x608a, 0x608e, 0x6092, 0x6096, 0x609a, - 0x609e, 0x60ae, 0x61a2, 0x00d6, 0x60a4, 0xa06d, 0x0110, 0x080c, - 0x15f0, 0x60a7, 0x0000, 0x60a8, 0xa06d, 0x0110, 0x080c, 0x15f0, - 0x60ab, 0x0000, 0x00de, 0xa006, 0x604a, 0x6810, 0x603a, 0x680c, - 0x6046, 0x6814, 0xa084, 0x00ff, 0x6042, 0x014e, 0x013e, 0x015e, - 0x003e, 0x00de, 0x0005, 0x0126, 0x2091, 0x8000, 0x6944, 0x6e48, - 0xa684, 0x3fff, 0xa082, 0x4000, 0x1a04, 0x4a49, 0xa18c, 0xff00, - 0x810f, 0xa182, 0x00ff, 0x1a04, 0x4a4e, 0x2001, 0xad0c, 0x2004, - 0xa084, 0x0003, 0x01c0, 0x2001, 0xad0c, 0x2004, 0xd084, 0x1904, - 0x4a31, 0xa188, 0xae34, 0x2104, 0xa065, 0x0904, 0x4a31, 0x6004, - 0xa084, 0x00ff, 0xa08e, 0x0006, 0x1904, 0x4a31, 0x6000, 0xd0c4, - 0x0904, 0x4a31, 0x0068, 0xa188, 0xae34, 0x2104, 0xa065, 0x0904, - 0x4a15, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x1904, 0x4a1a, - 0x60a4, 0xa00d, 0x0118, 0x080c, 0x4ef9, 0x05d0, 0x60a8, 0xa00d, - 0x0188, 0x080c, 0x4f43, 0x1170, 0x694c, 0xd1fc, 0x1118, 0x080c, - 0x4c11, 0x0448, 0x080c, 0x4bd3, 0x694c, 0xd1ec, 0x1520, 0x080c, - 0x4ded, 0x0408, 0x694c, 0xa184, 0xa000, 0x0178, 0xd1ec, 0x0140, - 0xd1fc, 0x0118, 0x080c, 0x4dfc, 0x0028, 0x080c, 0x4dfc, 0x0028, - 0xd1fc, 0x0118, 0x080c, 0x4bd3, 0x0070, 0x6050, 0xa00d, 0x0130, - 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x0028, 0x2d00, 0x6052, - 0x604e, 0x6803, 0x0000, 0x080c, 0x67c5, 0xa006, 0x012e, 0x0005, - 0x2001, 0x0005, 0x2009, 0x0000, 0x04e8, 0x2001, 0x0028, 0x2009, - 0x0000, 0x04c0, 0xa082, 0x0006, 0x12a0, 0x2001, 0xad34, 0x2004, - 0xd0ac, 0x1160, 0x60a0, 0xd0bc, 0x1148, 0x6100, 0xd1fc, 0x0904, - 0x49d0, 0x2001, 0x0029, 0x2009, 0x1000, 0x0420, 0x2001, 0x0028, - 0x00a8, 0x2009, 0xad0c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, - 0x0068, 0xd184, 0x0118, 0x2001, 0x0004, 0x0040, 0x2001, 0x0029, - 0x6100, 0xd1fc, 0x0118, 0x2009, 0x1000, 0x0060, 0x2009, 0x0000, - 0x0048, 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, 0x0029, - 0x2009, 0x0000, 0xa005, 0x012e, 0x0005, 0x00e6, 0x0126, 0x2091, - 0x8000, 0x6844, 0x8007, 0xa084, 0x00ff, 0x2008, 0xa182, 0x00ff, - 0x1a04, 0x4aa8, 0xa188, 0xae34, 0x2104, 0xa065, 0x01c0, 0x6004, - 0xa084, 0x00ff, 0xa08e, 0x0006, 0x11a8, 0x2c70, 0x080c, 0x8022, - 0x05e8, 0x2e00, 0x601a, 0x2d00, 0x6012, 0x600b, 0xffff, 0x601f, - 0x000a, 0x2009, 0x0003, 0x080c, 0x80a7, 0xa006, 0x0460, 0x2001, - 0x0028, 0x0440, 0xa082, 0x0006, 0x1298, 0x2001, 0xad34, 0x2004, - 0xd0ac, 0x1158, 0x60a0, 0xd0bc, 0x1140, 0x6100, 0xd1fc, 0x09e8, - 0x2001, 0x0029, 0x2009, 0x1000, 0x00a8, 0x2001, 0x0028, 0x0090, - 0x2009, 0xad0c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0050, - 0xd184, 0x0118, 0x2001, 0x0004, 0x0028, 0x2001, 0x0029, 0x0010, - 0x2001, 0x0029, 0xa005, 0x012e, 0x00ee, 0x0005, 0x2001, 0x002c, - 0x0cc8, 0x00f6, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2011, 0x0000, - 0x2079, 0xad00, 0x6944, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, - 0x1a04, 0x4b77, 0x2001, 0xad0c, 0x2004, 0xa084, 0x0003, 0x1904, - 0x4b65, 0x080c, 0x4cdc, 0x1180, 0x6004, 0xa084, 0x00ff, 0xa082, - 0x0006, 0x1250, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x1904, 0x4b60, - 0x60a0, 0xd0bc, 0x1904, 0x4b60, 0x6864, 0xa0c6, 0x006f, 0x0118, - 0x2008, 0x0804, 0x4b28, 0x6968, 0x2140, 0xa18c, 0xff00, 0x810f, - 0x78d0, 0xd0ac, 0x1118, 0xa182, 0x0080, 0x06d0, 0xa182, 0x00ff, - 0x16b8, 0x6a70, 0x6b6c, 0x786c, 0xa306, 0x1160, 0x7870, 0xa24e, - 0x1118, 0x2208, 0x2310, 0x0460, 0xa9cc, 0xff00, 0x1118, 0x2208, - 0x2310, 0x0430, 0x080c, 0x3b58, 0x2c70, 0x0550, 0x2009, 0x0000, - 0x2011, 0x0000, 0xa0c6, 0x4000, 0x1160, 0x0006, 0x2e60, 0x080c, - 0x4f6e, 0x1108, 0xc185, 0x7000, 0xd0bc, 0x0108, 0xc18d, 0x000e, - 0x0088, 0xa0c6, 0x4007, 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008, - 0x1118, 0x2708, 0x2610, 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010, - 0x2001, 0x4006, 0x6866, 0x696a, 0x6a6e, 0x2001, 0x0030, 0x0458, - 0x080c, 0x8022, 0x1138, 0x2001, 0x4005, 0x2009, 0x0003, 0x2011, - 0x0000, 0x0c80, 0x2e00, 0x601a, 0x080c, 0x9956, 0x2d00, 0x6012, - 0x601f, 0x0001, 0xa006, 0xd88c, 0x0110, 0x2001, 0x4000, 0x683a, - 0x0126, 0x2091, 0x8000, 0x080c, 0x2ad9, 0x012e, 0x2001, 0x0000, - 0x080c, 0x4c1e, 0x2001, 0x0002, 0x080c, 0x4c30, 0x2009, 0x0002, - 0x080c, 0x80a7, 0xa006, 0xa005, 0x012e, 0x00ee, 0x00fe, 0x0005, - 0x2001, 0x0028, 0x2009, 0x0000, 0x0cb0, 0x2009, 0xad0c, 0x210c, - 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, 0x2001, - 0x0004, 0x0010, 0x2001, 0x0029, 0x2009, 0x0000, 0x0c20, 0x2001, - 0x0029, 0x2009, 0x0000, 0x08f8, 0x6944, 0x6e48, 0xa684, 0x3fff, - 0xa082, 0x4000, 0x16b8, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, - 0x12e0, 0xa188, 0xae34, 0x2104, 0xa065, 0x01b8, 0x6004, 0xa084, - 0x00ff, 0xa08e, 0x0006, 0x11b0, 0x684c, 0xd0ec, 0x0120, 0x080c, - 0x4dfc, 0x04c9, 0x0030, 0x04b9, 0x684c, 0xd0fc, 0x0110, 0x080c, - 0x4ded, 0x080c, 0x4e3a, 0xa006, 0x00c8, 0x2001, 0x0028, 0x2009, - 0x0000, 0x00a0, 0xa082, 0x0006, 0x1240, 0x6100, 0xd1fc, 0x0d20, - 0x2001, 0x0029, 0x2009, 0x1000, 0x0048, 0x2001, 0x0029, 0x2009, - 0x0000, 0x0020, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, 0x0005, - 0x0126, 0x2091, 0x8000, 0x6050, 0xa00d, 0x0138, 0x2d00, 0x200a, - 0x6803, 0x0000, 0x6052, 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, - 0x6803, 0x0000, 0x0cc0, 0x0126, 0x2091, 0x8000, 0x604c, 0xa005, - 0x0170, 0x00e6, 0x2071, 0xafc7, 0x7004, 0xa086, 0x0002, 0x0168, - 0x00ee, 0x604c, 0x6802, 0x2d00, 0x604e, 0x012e, 0x0005, 0x2d00, - 0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0, 0x701c, 0xac06, 0x1d80, - 0x604c, 0x2070, 0x7000, 0x6802, 0x2d00, 0x7002, 0x00ee, 0x012e, - 0x0005, 0x0126, 0x2091, 0x8000, 0x604c, 0xa06d, 0x0130, 0x6800, - 0xa005, 0x1108, 0x6052, 0x604e, 0xad05, 0x012e, 0x0005, 0x604c, - 0xa06d, 0x0130, 0x6800, 0xa005, 0x1108, 0x6052, 0x604e, 0xad05, - 0x0005, 0x6803, 0x0000, 0x6084, 0xa00d, 0x0120, 0x2d00, 0x200a, - 0x6086, 0x0005, 0x2d00, 0x6086, 0x6082, 0x0cd8, 0x0126, 0x00c6, - 0x0026, 0x2091, 0x8000, 0x6218, 0x2260, 0x6200, 0xa005, 0x0110, - 0xc285, 0x0008, 0xc284, 0x6202, 0x002e, 0x00ce, 0x012e, 0x0005, - 0x0126, 0x00c6, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, 0x0006, - 0xa086, 0x0006, 0x1180, 0x609c, 0xd0ac, 0x0168, 0x2001, 0xad52, - 0x2004, 0xd0a4, 0x0140, 0xa284, 0xff00, 0x8007, 0xa086, 0x0007, - 0x1110, 0x2011, 0x0600, 0x000e, 0xa294, 0xff00, 0xa215, 0x6206, - 0x0006, 0xa086, 0x0006, 0x1128, 0x6290, 0x82ff, 0x1110, 0x080c, - 0x14f6, 0x000e, 0x00ce, 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091, - 0x8000, 0x6218, 0x2260, 0x6204, 0x0006, 0xa086, 0x0006, 0x1178, - 0x609c, 0xd0a4, 0x0160, 0x2001, 0xad52, 0x2004, 0xd0ac, 0x1138, - 0xa284, 0x00ff, 0xa086, 0x0007, 0x1110, 0x2011, 0x0006, 0x000e, - 0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x00ce, 0x012e, 0x0005, - 0x0026, 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x00b0, 0xa190, - 0xae34, 0x2204, 0xa065, 0x1180, 0x0016, 0x00d6, 0x080c, 0x15c0, - 0x2d60, 0x00de, 0x001e, 0x0d80, 0x2c00, 0x2012, 0x60a7, 0x0000, - 0x60ab, 0x0000, 0x080c, 0x493a, 0xa006, 0x002e, 0x0005, 0x0126, - 0x2091, 0x8000, 0x0026, 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, - 0x0480, 0x00d6, 0xa190, 0xae34, 0x2204, 0xa06d, 0x0540, 0x2013, - 0x0000, 0x00d6, 0x00c6, 0x2d60, 0x60a4, 0xa06d, 0x0110, 0x080c, - 0x15f0, 0x60a8, 0xa06d, 0x0110, 0x080c, 0x15f0, 0x00ce, 0x00de, - 0x00d6, 0x00c6, 0x68ac, 0x2060, 0x8cff, 0x0168, 0x600c, 0x0006, - 0x6010, 0x2068, 0x080c, 0x9596, 0x0110, 0x080c, 0x1600, 0x080c, - 0x8078, 0x00ce, 0x0c88, 0x00ce, 0x00de, 0x080c, 0x15f0, 0x00de, - 0xa006, 0x002e, 0x012e, 0x0005, 0x0016, 0xa182, 0x00ff, 0x0218, - 0xa085, 0x0001, 0x0030, 0xa188, 0xae34, 0x2104, 0xa065, 0x0dc0, - 0xa006, 0x001e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x600b, - 0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, 0x6002, 0x080c, 0x574f, - 0x1538, 0x60a0, 0xa086, 0x007e, 0x2069, 0xb290, 0x0130, 0x2001, - 0xad34, 0x2004, 0xd0ac, 0x11e0, 0x0098, 0x2d04, 0xd0e4, 0x01c0, - 0x00d6, 0x2069, 0xb28e, 0x00c6, 0x2061, 0xaf9f, 0x6810, 0x2062, - 0x6814, 0x6006, 0x6818, 0x600a, 0x681c, 0x600e, 0x00ce, 0x00de, - 0x8d69, 0x2d04, 0x2069, 0x0140, 0x6886, 0x2069, 0xad00, 0x68a2, - 0x2069, 0xb28e, 0x6808, 0x605e, 0x6810, 0x6062, 0x6138, 0xa10a, - 0x0208, 0x603a, 0x6814, 0x6066, 0x2099, 0xb296, 0xac88, 0x000a, - 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2099, 0xb29a, 0xac88, 0x0006, - 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2069, 0xb2ae, 0x6808, 0x606a, - 0x690c, 0x616e, 0x6810, 0x6072, 0x6818, 0x6076, 0xa182, 0x0211, - 0x1218, 0x2009, 0x0008, 0x0400, 0xa182, 0x0259, 0x1218, 0x2009, - 0x0007, 0x00d0, 0xa182, 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, - 0xa182, 0x0349, 0x1218, 0x2009, 0x0005, 0x0070, 0xa182, 0x0421, - 0x1218, 0x2009, 0x0004, 0x0040, 0xa182, 0x0581, 0x1218, 0x2009, - 0x0003, 0x0010, 0x2009, 0x0002, 0x6192, 0x014e, 0x013e, 0x015e, - 0x00de, 0x0005, 0x0016, 0x0026, 0x00e6, 0x2071, 0xb28d, 0x2e04, - 0x6896, 0x2071, 0xb28e, 0x7004, 0x689a, 0x701c, 0x689e, 0x6a00, - 0x2009, 0xad71, 0x210c, 0xd0bc, 0x0120, 0xd1ec, 0x0110, 0xc2ad, - 0x0008, 0xc2ac, 0xd0c4, 0x0120, 0xd1e4, 0x0110, 0xc2bd, 0x0008, - 0xc2bc, 0x6a02, 0x00ee, 0x002e, 0x001e, 0x0005, 0x00d6, 0x0126, - 0x2091, 0x8000, 0x60a4, 0xa06d, 0x01c0, 0x6900, 0x81ff, 0x1540, - 0x6a04, 0xa282, 0x0010, 0x1648, 0xad88, 0x0004, 0x20a9, 0x0010, - 0x2104, 0xa086, 0xffff, 0x0128, 0x8108, 0x1f04, 0x4da8, 0x080c, - 0x14f6, 0x260a, 0x8210, 0x6a06, 0x0098, 0x080c, 0x15d9, 0x01a8, - 0x2d00, 0x60a6, 0x6803, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, - 0x200b, 0xffff, 0x8108, 0x1f04, 0x4dc0, 0x6807, 0x0001, 0x6e12, - 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, 0x0126, - 0x2091, 0x8000, 0x00d6, 0x60a4, 0xa00d, 0x01a0, 0x2168, 0x6800, - 0xa005, 0x1160, 0x080c, 0x4ef9, 0x1168, 0x200b, 0xffff, 0x6804, - 0xa08a, 0x0002, 0x0218, 0x8001, 0x6806, 0x0020, 0x080c, 0x15f0, - 0x60a7, 0x0000, 0x00de, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, - 0x080c, 0x4f56, 0x0010, 0x080c, 0x4bc0, 0x080c, 0x4e71, 0x1dd8, - 0x080c, 0x4e3a, 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, - 0x60a8, 0xa06d, 0x01c0, 0x6950, 0x81ff, 0x1540, 0x6a54, 0xa282, - 0x0010, 0x1670, 0xad88, 0x0018, 0x20a9, 0x0010, 0x2104, 0xa086, - 0xffff, 0x0128, 0x8108, 0x1f04, 0x4e0e, 0x080c, 0x14f6, 0x260a, - 0x8210, 0x6a56, 0x0098, 0x080c, 0x15d9, 0x01d0, 0x2d00, 0x60aa, - 0x6853, 0x0000, 0xad88, 0x0018, 0x20a9, 0x0010, 0x200b, 0xffff, - 0x8108, 0x1f04, 0x4e26, 0x6857, 0x0001, 0x6e62, 0x0010, 0x080c, - 0x4c11, 0x0089, 0x1de0, 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, - 0xa006, 0x0cd8, 0x0126, 0x2091, 0x8000, 0x080c, 0x67c5, 0x012e, - 0x0005, 0xa01e, 0x0010, 0x2019, 0x0001, 0xa00e, 0x0126, 0x2091, - 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x1170, 0x8dff, 0x01e8, - 0x83ff, 0x0120, 0x6848, 0xa606, 0x0158, 0x0030, 0x683c, 0xa406, - 0x1118, 0x6840, 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70, - 0x6a00, 0x604c, 0xad06, 0x1110, 0x624e, 0x0018, 0xa180, 0x0000, - 0x2202, 0x82ff, 0x1110, 0x6152, 0x8dff, 0x012e, 0x0005, 0xa01e, - 0x0010, 0x2019, 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x01e8, - 0x83ff, 0x0120, 0x6848, 0xa606, 0x0158, 0x0030, 0x683c, 0xa406, - 0x1118, 0x6840, 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70, - 0x6a00, 0x6080, 0xad06, 0x1110, 0x6282, 0x0018, 0xa180, 0x0000, - 0x2202, 0x82ff, 0x1110, 0x6186, 0x8dff, 0x0005, 0xa016, 0x080c, - 0x4ef3, 0x1110, 0x2011, 0x0001, 0x080c, 0x4f3d, 0x1110, 0xa295, - 0x0002, 0x0005, 0x080c, 0x4f6e, 0x0118, 0x080c, 0x964b, 0x0010, - 0xa085, 0x0001, 0x0005, 0x080c, 0x4f6e, 0x0118, 0x080c, 0x95e4, - 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x4f6e, 0x0118, 0x080c, - 0x962e, 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x4f6e, 0x0118, - 0x080c, 0x9600, 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x4f6e, - 0x0118, 0x080c, 0x9667, 0x0010, 0xa085, 0x0001, 0x0005, 0x0126, - 0x0006, 0x00d6, 0x2091, 0x8000, 0x6080, 0xa06d, 0x01a0, 0x6800, - 0x0006, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x97fd, - 0x0006, 0x6000, 0xd0fc, 0x0110, 0x080c, 0xac03, 0x000e, 0x080c, - 0x510c, 0x000e, 0x0c50, 0x6083, 0x0000, 0x6087, 0x0000, 0x00de, - 0x000e, 0x012e, 0x0005, 0x60a4, 0xa00d, 0x1118, 0xa085, 0x0001, - 0x0005, 0x00e6, 0x2170, 0x7000, 0xa005, 0x1160, 0x20a9, 0x0010, - 0xae88, 0x0004, 0x2104, 0xa606, 0x0128, 0x8108, 0x1f04, 0x4f02, - 0xa085, 0x0001, 0xa006, 0x00ee, 0x0005, 0x00d6, 0x0126, 0x2091, - 0x8000, 0x60a4, 0xa06d, 0x1128, 0x080c, 0x15d9, 0x01a0, 0x2d00, - 0x60a6, 0x6803, 0x0001, 0x6807, 0x0000, 0xad88, 0x0004, 0x20a9, - 0x0010, 0x200b, 0xffff, 0x8108, 0x1f04, 0x4f21, 0xa085, 0x0001, - 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, 0x00d6, 0x0126, 0x2091, - 0x8000, 0x60a4, 0xa06d, 0x0130, 0x60a7, 0x0000, 0x080c, 0x15f0, - 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0x60a8, 0xa00d, 0x1118, - 0xa085, 0x0001, 0x0005, 0x00e6, 0x2170, 0x7050, 0xa005, 0x1160, - 0x20a9, 0x0010, 0xae88, 0x0018, 0x2104, 0xa606, 0x0128, 0x8108, - 0x1f04, 0x4f4c, 0xa085, 0x0001, 0x00ee, 0x0005, 0x0126, 0x2091, - 0x8000, 0x0c19, 0x1188, 0x200b, 0xffff, 0x00d6, 0x60a8, 0x2068, - 0x6854, 0xa08a, 0x0002, 0x0218, 0x8001, 0x6856, 0x0020, 0x080c, - 0x15f0, 0x60ab, 0x0000, 0x00de, 0x012e, 0x0005, 0x609c, 0xd0a4, - 0x0005, 0x00f6, 0x080c, 0x574f, 0x01b0, 0x71b4, 0x81ff, 0x1198, - 0x71d0, 0xd19c, 0x0180, 0x2001, 0x007e, 0xa080, 0xae34, 0x2004, - 0xa07d, 0x0148, 0x7804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1118, - 0x7800, 0xc0ed, 0x7802, 0x2079, 0xad51, 0x7804, 0xd0a4, 0x01e8, - 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, - 0x4cdc, 0x1168, 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004, - 0x0118, 0xa086, 0x0006, 0x1118, 0x6000, 0xc0ed, 0x6002, 0x001e, - 0x8108, 0x1f04, 0x4f96, 0x00ce, 0x015e, 0x080c, 0x502d, 0x0120, - 0x2001, 0xafa2, 0x200c, 0x0038, 0x2079, 0xad51, 0x7804, 0xd0a4, - 0x0130, 0x2009, 0x07d0, 0x2011, 0x4fc1, 0x080c, 0x6593, 0x00fe, - 0x0005, 0x2011, 0x4fc1, 0x080c, 0x650d, 0x080c, 0x502d, 0x01f0, - 0x2001, 0xaeb2, 0x2004, 0xa080, 0x0000, 0x200c, 0xc1ec, 0x2102, - 0x2001, 0xad52, 0x2004, 0xd0a4, 0x0130, 0x2009, 0x07d0, 0x2011, - 0x4fc1, 0x080c, 0x6593, 0x00e6, 0x2071, 0xad00, 0x706f, 0x0000, - 0x7073, 0x0000, 0x080c, 0x28fa, 0x00ee, 0x04b0, 0x0156, 0x00c6, - 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4cdc, 0x1530, - 0x6000, 0xd0ec, 0x0518, 0x0046, 0x62a0, 0xa294, 0x00ff, 0x8227, - 0xa006, 0x2009, 0x0029, 0x080c, 0xa96c, 0x6000, 0xc0e5, 0xc0ec, - 0x6002, 0x6004, 0xa084, 0x00ff, 0xa085, 0x0700, 0x6006, 0x2019, - 0x0029, 0x080c, 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, - 0x2009, 0x0000, 0x080c, 0xa712, 0x007e, 0x004e, 0x001e, 0x8108, - 0x1f04, 0x4fec, 0x00ce, 0x015e, 0x0005, 0x00c6, 0x6018, 0x2060, - 0x6000, 0xc0ec, 0x6002, 0x00ce, 0x0005, 0x7818, 0x2004, 0xd0ac, - 0x0005, 0x7818, 0x2004, 0xd0bc, 0x0005, 0x00f6, 0x2001, 0xaeb2, - 0x2004, 0xa07d, 0x0110, 0x7800, 0xd0ec, 0x00fe, 0x0005, 0x0126, - 0x0026, 0x2091, 0x8000, 0x6200, 0xa005, 0x0110, 0xc2fd, 0x0008, - 0xc2fc, 0x6202, 0x002e, 0x012e, 0x0005, 0x2071, 0xae13, 0x7003, - 0x0001, 0x7007, 0x0000, 0x7013, 0x0000, 0x7017, 0x0000, 0x701b, - 0x0000, 0x701f, 0x0000, 0x700b, 0x0000, 0x704b, 0x0001, 0x704f, - 0x0000, 0x705b, 0x0020, 0x705f, 0x0040, 0x707f, 0x0000, 0x2071, - 0xaf7c, 0x7003, 0xae13, 0x7007, 0x0000, 0x700b, 0x0000, 0x700f, - 0xaf5c, 0x7013, 0x0020, 0x7017, 0x0040, 0x7037, 0x0000, 0x0005, - 0x0016, 0x00e6, 0x2071, 0xaf34, 0xa00e, 0x7186, 0x718a, 0x7097, - 0x0001, 0x2001, 0xad52, 0x2004, 0xd0fc, 0x1150, 0x2001, 0xad52, - 0x2004, 0xa00e, 0xd09c, 0x0108, 0x8108, 0x7102, 0x0804, 0x50d6, - 0x2001, 0xad71, 0x200c, 0xa184, 0x000f, 0x2009, 0xad72, 0x210c, - 0x0002, 0x507e, 0x50b1, 0x50b8, 0x50c2, 0x50c7, 0x507e, 0x507e, - 0x507e, 0x50a1, 0x507e, 0x507e, 0x507e, 0x507e, 0x507e, 0x507e, - 0x507e, 0x7003, 0x0004, 0x0136, 0x0146, 0x0156, 0x2099, 0xad75, - 0x20a1, 0xaf85, 0x20a9, 0x0004, 0x53a3, 0x015e, 0x014e, 0x013e, - 0x0428, 0x708f, 0x0005, 0x7007, 0x0122, 0x2001, 0x0002, 0x0030, - 0x708f, 0x0002, 0x7007, 0x0121, 0x2001, 0x0003, 0x7002, 0x7097, - 0x0001, 0x0088, 0x7007, 0x0122, 0x2001, 0x0002, 0x0020, 0x7007, - 0x0121, 0x2001, 0x0003, 0x7002, 0xa006, 0x7096, 0x708e, 0xa184, - 0xff00, 0x8007, 0x709a, 0xa184, 0x00ff, 0x7092, 0x00ee, 0x001e, - 0x0005, 0x00e6, 0x2071, 0xae13, 0x684c, 0xa005, 0x1130, 0x7028, - 0xc085, 0x702a, 0xa085, 0x0001, 0x0428, 0x6a60, 0x7236, 0x6b64, - 0x733a, 0x6868, 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, - 0x702e, 0x6844, 0x7032, 0x2009, 0x000d, 0x200a, 0x700b, 0x0000, - 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, - 0x2100, 0xa319, 0x726e, 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, - 0x0001, 0xa006, 0x00ee, 0x0005, 0x0156, 0x00e6, 0x0026, 0x6838, - 0xd0fc, 0x1904, 0x5165, 0x6804, 0xa00d, 0x0188, 0x00d6, 0x2071, - 0xad00, 0xa016, 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, - 0x81ff, 0x1dc8, 0x702e, 0x70b0, 0xa200, 0x70b2, 0x00de, 0x2071, - 0xae13, 0x701c, 0xa005, 0x1904, 0x5175, 0x20a9, 0x0032, 0x0f04, - 0x5173, 0x0e04, 0x512f, 0x2071, 0xaf34, 0x7200, 0x82ff, 0x05d8, - 0x6934, 0xa186, 0x0103, 0x1904, 0x5183, 0x6948, 0x6844, 0xa105, - 0x1540, 0x2009, 0x8020, 0x2200, 0x0002, 0x5173, 0x514a, 0x519b, - 0x51a7, 0x5173, 0x2071, 0x0000, 0x20a9, 0x0032, 0x0f04, 0x5173, - 0x7018, 0xd084, 0x1dd8, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, - 0x701b, 0x0001, 0x2091, 0x4080, 0x2071, 0xad00, 0x702c, 0x206a, - 0x2d00, 0x702e, 0x70b0, 0x8000, 0x70b2, 0x002e, 0x00ee, 0x015e, - 0x0005, 0x6844, 0xa086, 0x0100, 0x1130, 0x6868, 0xa005, 0x1118, - 0x2009, 0x8020, 0x0880, 0x2071, 0xae13, 0x2d08, 0x206b, 0x0000, - 0x7010, 0x8000, 0x7012, 0x7018, 0xa06d, 0x711a, 0x0110, 0x6902, - 0x0008, 0x711e, 0x0c10, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0130, - 0xa186, 0x001e, 0x0118, 0xa18e, 0x001f, 0x1d28, 0x684c, 0xd0cc, - 0x0d10, 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, 0x19e0, 0x2009, - 0x8021, 0x0804, 0x5143, 0x7084, 0x8008, 0xa092, 0x001e, 0x1a98, - 0x7186, 0xae90, 0x0003, 0xa210, 0x683c, 0x2012, 0x0078, 0x7084, - 0x8008, 0xa092, 0x000f, 0x1a38, 0x7186, 0xae90, 0x0003, 0x8003, - 0xa210, 0x683c, 0x2012, 0x8210, 0x6840, 0x2012, 0x7088, 0xa10a, - 0x0a04, 0x515c, 0x718c, 0x7084, 0xa10a, 0x0a04, 0x515c, 0x2071, - 0x0000, 0x7018, 0xd084, 0x1904, 0x515c, 0x2071, 0xaf34, 0x7000, - 0xa086, 0x0002, 0x1150, 0x080c, 0x5426, 0x2071, 0x0000, 0x701b, - 0x0001, 0x2091, 0x4080, 0x0804, 0x515c, 0x080c, 0x5450, 0x2071, - 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, 0x515c, 0x0006, - 0x684c, 0x0006, 0x6837, 0x0103, 0x20a9, 0x001c, 0xad80, 0x0011, - 0x20a0, 0x2001, 0x0000, 0x40a4, 0x000e, 0xa084, 0x00ff, 0x684e, - 0x000e, 0x684a, 0x6952, 0x0005, 0x2071, 0xae13, 0x7004, 0x0002, - 0x5202, 0x5213, 0x5411, 0x5412, 0x541f, 0x5425, 0x5203, 0x5402, - 0x5398, 0x53ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x0e04, 0x5212, - 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, 0x7007, 0x0001, - 0x700b, 0x0000, 0x012e, 0x2069, 0xafda, 0x683c, 0xa005, 0x03f8, - 0x11f0, 0x0126, 0x2091, 0x8000, 0x2069, 0x0000, 0x6934, 0x2001, - 0xae1f, 0x2004, 0xa10a, 0x0170, 0x0e04, 0x5236, 0x2069, 0x0000, - 0x6818, 0xd084, 0x1158, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, - 0x2091, 0x4080, 0x2069, 0xafda, 0x683f, 0xffff, 0x012e, 0x2069, - 0xad00, 0x6844, 0x6964, 0xa102, 0x2069, 0xaf34, 0x688a, 0x6984, - 0x701c, 0xa06d, 0x0120, 0x81ff, 0x0904, 0x528c, 0x00a0, 0x81ff, - 0x0904, 0x5352, 0x2071, 0xaf34, 0x7184, 0x7088, 0xa10a, 0x1258, - 0x7190, 0x2071, 0xafda, 0x7038, 0xa005, 0x0128, 0x1b04, 0x5352, - 0x713a, 0x0804, 0x5352, 0x2071, 0xaf34, 0x718c, 0x0126, 0x2091, - 0x8000, 0x7084, 0xa10a, 0x0a04, 0x536d, 0x0e04, 0x530e, 0x2071, - 0x0000, 0x7018, 0xd084, 0x1904, 0x530e, 0x2001, 0xffff, 0x2071, - 0xafda, 0x703a, 0x2071, 0xaf34, 0x7000, 0xa086, 0x0002, 0x1150, - 0x080c, 0x5426, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, - 0x0804, 0x530e, 0x080c, 0x5450, 0x2071, 0x0000, 0x701b, 0x0001, - 0x2091, 0x4080, 0x0804, 0x530e, 0x2071, 0xaf34, 0x7000, 0xa005, - 0x0904, 0x5334, 0x6934, 0xa186, 0x0103, 0x1904, 0x5311, 0x684c, - 0xd0bc, 0x1904, 0x5334, 0x6948, 0x6844, 0xa105, 0x1904, 0x5329, - 0x2009, 0x8020, 0x2071, 0xaf34, 0x7000, 0x0002, 0x5334, 0x52f4, - 0x52cc, 0x52de, 0x52ab, 0x0136, 0x0146, 0x0156, 0x2099, 0xad75, - 0x20a1, 0xaf85, 0x20a9, 0x0004, 0x53a3, 0x015e, 0x014e, 0x013e, - 0x2071, 0xaf7c, 0xad80, 0x000f, 0x700e, 0x7013, 0x0002, 0x7007, - 0x0002, 0x700b, 0x0000, 0x2e10, 0x080c, 0x1624, 0x2071, 0xae13, - 0x7007, 0x0009, 0x0804, 0x5352, 0x7084, 0x8008, 0xa092, 0x001e, - 0x1a04, 0x5352, 0xae90, 0x0003, 0xa210, 0x683c, 0x2012, 0x7186, - 0x2071, 0xae13, 0x080c, 0x54a7, 0x0804, 0x5352, 0x7084, 0x8008, - 0xa092, 0x000f, 0x1a04, 0x5352, 0xae90, 0x0003, 0x8003, 0xa210, - 0x683c, 0x2012, 0x8210, 0x6840, 0x2012, 0x7186, 0x2071, 0xae13, - 0x080c, 0x54a7, 0x0804, 0x5352, 0x0126, 0x2091, 0x8000, 0x0e04, - 0x530e, 0x2071, 0x0000, 0x7018, 0xd084, 0x1180, 0x7122, 0x683c, - 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x012e, - 0x2071, 0xae13, 0x080c, 0x54a7, 0x0804, 0x5352, 0x012e, 0x0804, - 0x5352, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0130, 0xa186, 0x001e, - 0x0118, 0xa18e, 0x001f, 0x11c0, 0x684c, 0xd0cc, 0x01a8, 0x6850, - 0xa084, 0x00ff, 0xa086, 0x0001, 0x1178, 0x2009, 0x8021, 0x0804, - 0x52a2, 0x6844, 0xa086, 0x0100, 0x1138, 0x6868, 0xa005, 0x1120, - 0x2009, 0x8020, 0x0804, 0x52a2, 0x2071, 0xae13, 0x080c, 0x54b9, - 0x01c8, 0x2071, 0xae13, 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, - 0xa086, 0x0003, 0x1130, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0108, - 0x710e, 0x7007, 0x0003, 0x080c, 0x54d2, 0x7050, 0xa086, 0x0100, - 0x0904, 0x5412, 0x0126, 0x2091, 0x8000, 0x2071, 0xae13, 0x7008, - 0xa086, 0x0001, 0x1180, 0x0e04, 0x536b, 0x2009, 0x000d, 0x7030, - 0x200a, 0x2091, 0x4080, 0x700b, 0x0000, 0x7004, 0xa086, 0x0006, - 0x1110, 0x7007, 0x0001, 0x012e, 0x0005, 0x2071, 0xae13, 0x080c, - 0x54b9, 0x0518, 0x2071, 0xaf34, 0x7084, 0x700a, 0x20a9, 0x0020, - 0x2099, 0xaf35, 0x20a1, 0xaf5c, 0x53a3, 0x7087, 0x0000, 0x2071, - 0xae13, 0x2069, 0xaf7c, 0x706c, 0x6826, 0x7070, 0x682a, 0x7074, - 0x682e, 0x7078, 0x6832, 0x2d10, 0x080c, 0x1624, 0x7007, 0x0008, - 0x2001, 0xffff, 0x2071, 0xafda, 0x703a, 0x012e, 0x0804, 0x5352, - 0x2069, 0xaf7c, 0x6808, 0xa08e, 0x0000, 0x0904, 0x53ed, 0xa08e, - 0x0200, 0x0904, 0x53eb, 0xa08e, 0x0100, 0x1904, 0x53ed, 0x0126, - 0x2091, 0x8000, 0x0e04, 0x53e9, 0x2069, 0x0000, 0x6818, 0xd084, - 0x15c0, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034, - 0x706e, 0x7038, 0x7072, 0x0048, 0x706c, 0xa080, 0x0040, 0x706e, - 0x1220, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x6936, 0x700b, - 0x0000, 0x2001, 0xaf59, 0x2004, 0xa005, 0x1190, 0x6934, 0x2069, - 0xaf34, 0x689c, 0x699e, 0x2069, 0xafda, 0xa102, 0x1118, 0x683c, - 0xa005, 0x1368, 0x2001, 0xaf5a, 0x200c, 0x810d, 0x693e, 0x0038, - 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, 0x7007, - 0x0001, 0x012e, 0x0010, 0x7007, 0x0005, 0x0005, 0x2001, 0xaf7e, - 0x2004, 0xa08e, 0x0100, 0x1128, 0x7007, 0x0001, 0x080c, 0x54a7, - 0x0005, 0xa08e, 0x0000, 0x0de0, 0xa08e, 0x0200, 0x1dc8, 0x7007, - 0x0005, 0x0005, 0x701c, 0xa06d, 0x0158, 0x080c, 0x54b9, 0x0140, - 0x7007, 0x0003, 0x080c, 0x54d2, 0x7050, 0xa086, 0x0100, 0x0110, - 0x0005, 0x0005, 0x7050, 0xa09e, 0x0100, 0x1118, 0x7007, 0x0004, - 0x0030, 0xa086, 0x0200, 0x1110, 0x7007, 0x0005, 0x0005, 0x080c, - 0x5475, 0x7006, 0x080c, 0x54a7, 0x0005, 0x0005, 0x00e6, 0x0156, - 0x2071, 0xaf34, 0x7184, 0x81ff, 0x0500, 0xa006, 0x7086, 0xae80, - 0x0003, 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x0f04, - 0x544a, 0x2014, 0x722a, 0x8000, 0x0f04, 0x544a, 0x2014, 0x722e, - 0x8000, 0x0f04, 0x544a, 0x2014, 0x723a, 0x8000, 0x0f04, 0x544a, - 0x2014, 0x723e, 0xa180, 0x8030, 0x7022, 0x015e, 0x00ee, 0x0005, - 0x00e6, 0x0156, 0x2071, 0xaf34, 0x7184, 0x81ff, 0x01d8, 0xa006, - 0x7086, 0xae80, 0x0003, 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226, - 0x8000, 0x2014, 0x722a, 0x8000, 0x0f04, 0x546c, 0x2014, 0x723a, - 0x8000, 0x2014, 0x723e, 0x0018, 0x2001, 0x8020, 0x0010, 0x2001, - 0x8042, 0x7022, 0x015e, 0x00ee, 0x0005, 0x702c, 0x7130, 0x8108, - 0xa102, 0x0230, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0048, - 0x706c, 0xa080, 0x0040, 0x706e, 0x1220, 0x7070, 0xa081, 0x0000, - 0x7072, 0x7132, 0x700c, 0x8001, 0x700e, 0x1180, 0x0126, 0x2091, - 0x8000, 0x0e04, 0x54a1, 0x2001, 0x000d, 0x2102, 0x2091, 0x4080, - 0x2001, 0x0001, 0x700b, 0x0000, 0x012e, 0x0005, 0x2001, 0x0007, - 0x0005, 0x2001, 0x0006, 0x700b, 0x0001, 0x012e, 0x0005, 0x701c, - 0xa06d, 0x0170, 0x0126, 0x2091, 0x8000, 0x7010, 0x8001, 0x7012, - 0x2d04, 0x701e, 0xa005, 0x1108, 0x701a, 0x012e, 0x080c, 0x15f0, - 0x0005, 0x2019, 0x000d, 0x2304, 0x230c, 0xa10e, 0x0130, 0x2304, - 0x230c, 0xa10e, 0x0110, 0xa006, 0x0060, 0x732c, 0x8319, 0x7130, - 0xa102, 0x1118, 0x2300, 0xa005, 0x0020, 0x0210, 0xa302, 0x0008, - 0x8002, 0x0005, 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, - 0x0000, 0x0126, 0x2091, 0x8000, 0x2009, 0xafec, 0x2104, 0xc08d, - 0x200a, 0x012e, 0x080c, 0x163c, 0x0005, 0x7088, 0xa08a, 0x0029, - 0x1220, 0xa082, 0x001d, 0x0033, 0x0010, 0x080c, 0x14f6, 0x6027, - 0x1e00, 0x0005, 0x55c1, 0x555b, 0x5571, 0x5595, 0x55b4, 0x55e6, - 0x55f8, 0x5571, 0x55d2, 0x54ff, 0x552d, 0x54fe, 0x0005, 0x00d6, - 0x2069, 0x0200, 0x6804, 0xa005, 0x1180, 0x6808, 0xa005, 0x1518, - 0x708b, 0x0028, 0x2069, 0xafac, 0x2d04, 0x7002, 0x080c, 0x584d, - 0x6028, 0xa085, 0x0600, 0x602a, 0x00b0, 0x708b, 0x0028, 0x2069, - 0xafac, 0x2d04, 0x7002, 0x6028, 0xa085, 0x0600, 0x602a, 0x00e6, - 0x0036, 0x0046, 0x0056, 0x2071, 0xaffd, 0x080c, 0x1d22, 0x005e, - 0x004e, 0x003e, 0x00ee, 0x00de, 0x0005, 0x00d6, 0x2069, 0x0200, - 0x6804, 0xa005, 0x1180, 0x6808, 0xa005, 0x1518, 0x708b, 0x0028, - 0x2069, 0xafac, 0x2d04, 0x7002, 0x080c, 0x58da, 0x6028, 0xa085, - 0x0600, 0x602a, 0x00b0, 0x708b, 0x0028, 0x2069, 0xafac, 0x2d04, - 0x7002, 0x6028, 0xa085, 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046, - 0x0056, 0x2071, 0xaffd, 0x080c, 0x1d22, 0x005e, 0x004e, 0x003e, - 0x00ee, 0x00de, 0x0005, 0x6803, 0x0090, 0x6124, 0xd1e4, 0x1180, - 0x080c, 0x5663, 0xd1d4, 0x1150, 0xd1dc, 0x1128, 0xd1cc, 0x0140, - 0x708b, 0x0020, 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, - 0x0005, 0x6803, 0x0088, 0x6124, 0xd1cc, 0x11c8, 0xd1dc, 0x11a0, - 0xd1e4, 0x1178, 0xa184, 0x1e00, 0x11b8, 0x60e3, 0x0001, 0x600c, - 0xc0b4, 0x600e, 0x080c, 0x577f, 0x6803, 0x0080, 0x708b, 0x0028, - 0x0058, 0x708b, 0x001e, 0x0040, 0x708b, 0x001d, 0x0028, 0x708b, - 0x0020, 0x0010, 0x708b, 0x001f, 0x0005, 0x60e3, 0x0001, 0x600c, - 0xc0b4, 0x600e, 0x080c, 0x577f, 0x6803, 0x0080, 0x6124, 0xd1d4, - 0x1180, 0xd1dc, 0x1158, 0xd1e4, 0x1130, 0xa184, 0x1e00, 0x1158, - 0x708b, 0x0028, 0x0040, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d, - 0x0010, 0x708b, 0x001f, 0x0005, 0x6803, 0x00a0, 0x6124, 0xd1dc, - 0x1128, 0xd1e4, 0x0128, 0x708b, 0x001e, 0x0010, 0x708b, 0x001d, - 0x0005, 0x080c, 0x568d, 0x6124, 0xd1dc, 0x1158, 0x080c, 0x5663, - 0xd1d4, 0x1128, 0xd1e4, 0x0128, 0x708b, 0x001e, 0x0010, 0x708b, - 0x001f, 0x0005, 0x6803, 0x00a0, 0x6124, 0xd1d4, 0x1160, 0xd1cc, - 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x708b, 0x001e, 0x0028, - 0x708b, 0x001d, 0x0010, 0x708b, 0x0021, 0x0005, 0x080c, 0x568d, - 0x6124, 0xd1d4, 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x708b, - 0x001e, 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005, - 0x6803, 0x0090, 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150, 0xd1dc, - 0x1128, 0xd1e4, 0x0158, 0x708b, 0x001e, 0x0040, 0x708b, 0x001d, - 0x0028, 0x708b, 0x0020, 0x0010, 0x708b, 0x001f, 0x0005, 0x0016, - 0x00c6, 0x00d6, 0x00e6, 0x0126, 0x2061, 0x0100, 0x2069, 0x0140, - 0x2071, 0xad00, 0x2091, 0x8000, 0x080c, 0x574f, 0x11e8, 0x2001, - 0xad0c, 0x200c, 0xd1b4, 0x01c0, 0xc1b4, 0x2102, 0x6027, 0x0200, - 0xe000, 0xe000, 0x6024, 0xd0cc, 0x0158, 0x6803, 0x00a0, 0x2001, - 0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0x0428, - 0x6028, 0xc0cd, 0x602a, 0x0408, 0x080c, 0x576b, 0x0150, 0x080c, - 0x5761, 0x1138, 0x2001, 0x0001, 0x080c, 0x261e, 0x080c, 0x5726, - 0x00a0, 0x080c, 0x568a, 0x0178, 0x2001, 0x0001, 0x080c, 0x261e, - 0x7088, 0xa086, 0x001e, 0x0120, 0x7088, 0xa086, 0x0022, 0x1118, - 0x708b, 0x0025, 0x0010, 0x708b, 0x0021, 0x012e, 0x00ee, 0x00de, - 0x00ce, 0x001e, 0x0005, 0x0016, 0x0026, 0x2009, 0x0064, 0x2011, - 0x566e, 0x080c, 0x6501, 0x002e, 0x001e, 0x0005, 0x00e6, 0x00f6, - 0x0016, 0x080c, 0x7834, 0x2071, 0xad00, 0x080c, 0x560f, 0x001e, - 0x00fe, 0x00ee, 0x0005, 0x2001, 0xad00, 0x2004, 0xa086, 0x0004, - 0x0140, 0x2001, 0xaf9d, 0x2003, 0xaaaa, 0x2001, 0xaf9e, 0x2003, - 0x0000, 0x0005, 0x6020, 0xd09c, 0x0005, 0x6803, 0x00c0, 0x0156, - 0x20a9, 0x002d, 0x1d04, 0x5692, 0x2091, 0x6000, 0x1f04, 0x5692, - 0x015e, 0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, - 0x0140, 0x2071, 0xad00, 0x2001, 0xaf9e, 0x200c, 0xa186, 0x0000, - 0x0158, 0xa186, 0x0001, 0x0158, 0xa186, 0x0002, 0x0158, 0xa186, - 0x0003, 0x0158, 0x0804, 0x5714, 0x708b, 0x0022, 0x0040, 0x708b, - 0x0021, 0x0028, 0x708b, 0x0023, 0x0020, 0x708b, 0x0024, 0x6043, - 0x0000, 0x60e3, 0x0000, 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, - 0x26cb, 0x0026, 0x2011, 0x0003, 0x080c, 0x7adf, 0x2011, 0x0002, - 0x080c, 0x7ae9, 0x002e, 0x7000, 0xa08e, 0x0004, 0x0118, 0x602b, - 0x0028, 0x0010, 0x602b, 0x0020, 0x0156, 0x0126, 0x2091, 0x8000, - 0x20a9, 0x0005, 0x6024, 0xd0ac, 0x0118, 0x012e, 0x015e, 0x04d0, - 0x6800, 0xa084, 0x00a0, 0xc0bd, 0x6802, 0x6904, 0xd1d4, 0x1130, - 0x6803, 0x0100, 0x1f04, 0x56e2, 0x080c, 0x57a0, 0x012e, 0x015e, - 0x080c, 0x5761, 0x01a8, 0x6044, 0xa005, 0x0168, 0x6050, 0x0006, - 0xa085, 0x0020, 0x6052, 0x080c, 0x57a0, 0xa006, 0x8001, 0x1df0, - 0x000e, 0x6052, 0x0028, 0x6804, 0xd0d4, 0x1110, 0x080c, 0x57a0, - 0x2001, 0xaf9e, 0x2003, 0x0004, 0x080c, 0x54e5, 0x080c, 0x5761, - 0x0148, 0x6804, 0xd0d4, 0x1130, 0xd0dc, 0x1100, 0x2001, 0xaf9e, - 0x2003, 0x0000, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6, - 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xad00, 0x2001, - 0xaf9d, 0x2003, 0x0000, 0x2001, 0xaf8e, 0x2003, 0x0000, 0x708b, - 0x0000, 0x60e3, 0x0000, 0x6887, 0x0000, 0x2001, 0x0000, 0x080c, - 0x26cb, 0x6803, 0x0000, 0x6043, 0x0090, 0x6043, 0x0010, 0x6027, - 0xffff, 0x602b, 0x182f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006, - 0x2001, 0xaf9d, 0x2004, 0xa086, 0xaaaa, 0x000e, 0x0005, 0x0006, - 0x2001, 0xad71, 0x2004, 0xa084, 0x0030, 0xa086, 0x0000, 0x000e, - 0x0005, 0x0006, 0x2001, 0xad71, 0x2004, 0xa084, 0x0030, 0xa086, - 0x0030, 0x000e, 0x0005, 0x0006, 0x2001, 0xad71, 0x2004, 0xa084, - 0x0030, 0xa086, 0x0010, 0x000e, 0x0005, 0x0006, 0x2001, 0xad71, - 0x2004, 0xa084, 0x0030, 0xa086, 0x0020, 0x000e, 0x0005, 0x2001, - 0xad0c, 0x2004, 0xd0a4, 0x0170, 0x080c, 0x26eb, 0x0036, 0x0016, - 0x2009, 0x0000, 0x2019, 0x0028, 0x080c, 0x2aac, 0x001e, 0x003e, - 0xa006, 0x0009, 0x0005, 0x00e6, 0x2071, 0xad0c, 0x2e04, 0x0118, - 0xa085, 0x0010, 0x0010, 0xa084, 0xffef, 0x2072, 0x00ee, 0x0005, - 0x6050, 0x0006, 0x60f0, 0x0006, 0x60ec, 0x0006, 0x600c, 0x0006, - 0x6004, 0x0006, 0x6028, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000, - 0x602f, 0x0040, 0x602f, 0x0000, 0x000e, 0x602a, 0x000e, 0x6006, - 0x000e, 0x600e, 0x000e, 0x60ee, 0x000e, 0x60f2, 0x60e3, 0x0000, - 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x26cb, 0x6800, 0xa084, - 0x00a0, 0xc0bd, 0x6802, 0x6803, 0x00a0, 0x000e, 0x6052, 0x6050, - 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, - 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xad00, 0x6020, 0xa084, - 0x0080, 0x0138, 0x2001, 0xad0c, 0x200c, 0xc1bd, 0x2102, 0x0804, - 0x5845, 0x2001, 0xad0c, 0x200c, 0xc1bc, 0x2102, 0x6028, 0xa084, - 0xe1ff, 0x602a, 0x6027, 0x0200, 0x6803, 0x0090, 0x20a9, 0x0384, - 0x6024, 0xd0cc, 0x1518, 0x1d04, 0x57f8, 0x2091, 0x6000, 0x1f04, - 0x57f8, 0x2011, 0x0003, 0x080c, 0x7adf, 0x2011, 0x0002, 0x080c, - 0x7ae9, 0x080c, 0x79e1, 0x080c, 0x6581, 0x2019, 0x0000, 0x080c, - 0x7a64, 0x6803, 0x00a0, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001, - 0xad00, 0x2003, 0x0001, 0xa085, 0x0001, 0x0438, 0x60e3, 0x0000, - 0x2001, 0xaf8e, 0x2004, 0x080c, 0x26cb, 0x60e2, 0x6803, 0x0080, - 0x20a9, 0x0384, 0x6027, 0x1e00, 0x2009, 0x1e00, 0xe000, 0x6024, - 0xa10c, 0x0138, 0x1d04, 0x582a, 0x2091, 0x6000, 0x1f04, 0x582a, - 0x0840, 0x6028, 0xa085, 0x1e00, 0x602a, 0x70a0, 0xa005, 0x1118, - 0x6887, 0x0001, 0x0008, 0x6886, 0xa006, 0x00ee, 0x00de, 0x00ce, - 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, - 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xad00, - 0x2069, 0x0140, 0x6020, 0xa084, 0x00c0, 0x0120, 0x6884, 0xa005, - 0x1904, 0x58a1, 0x6803, 0x0088, 0x60e3, 0x0000, 0x6887, 0x0000, - 0x2001, 0x0000, 0x080c, 0x26cb, 0x2069, 0x0200, 0x6804, 0xa005, - 0x1118, 0x6808, 0xa005, 0x01c0, 0x6028, 0xa084, 0xfbff, 0x602a, - 0x6027, 0x0400, 0x2069, 0xafac, 0x7000, 0x206a, 0x708b, 0x0026, - 0x7003, 0x0001, 0x20a9, 0x0002, 0x1d04, 0x5884, 0x2091, 0x6000, - 0x1f04, 0x5884, 0x0804, 0x58d2, 0x2069, 0x0140, 0x20a9, 0x0384, - 0x6027, 0x1e00, 0x2009, 0x1e00, 0xe000, 0x6024, 0xa10c, 0x0530, - 0xa084, 0x1a00, 0x1518, 0x1d04, 0x5890, 0x2091, 0x6000, 0x1f04, - 0x5890, 0x2011, 0x0003, 0x080c, 0x7adf, 0x2011, 0x0002, 0x080c, - 0x7ae9, 0x080c, 0x79e1, 0x080c, 0x6581, 0x2019, 0x0000, 0x080c, - 0x7a64, 0x6803, 0x00a0, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001, - 0xad00, 0x2003, 0x0001, 0xa085, 0x0001, 0x00a0, 0x6803, 0x0080, - 0x2069, 0x0140, 0x60e3, 0x0000, 0x70a0, 0xa005, 0x1118, 0x6887, - 0x0001, 0x0008, 0x6886, 0x2001, 0xaf8e, 0x2004, 0x080c, 0x26cb, - 0x60e2, 0xa006, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, - 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, - 0x00e6, 0x2061, 0x0100, 0x2071, 0xad00, 0x6020, 0xa084, 0x00c0, - 0x01f0, 0x2011, 0x0003, 0x080c, 0x7adf, 0x2011, 0x0002, 0x080c, - 0x7ae9, 0x080c, 0x79e1, 0x080c, 0x6581, 0x2019, 0x0000, 0x080c, - 0x7a64, 0x2069, 0x0140, 0x6803, 0x00a0, 0x2001, 0xaf9e, 0x2003, - 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0x0804, 0x5972, 0x2001, - 0xad0c, 0x200c, 0xd1b4, 0x1150, 0xc1b5, 0x2102, 0x080c, 0x5663, - 0x2069, 0x0140, 0x6803, 0x0080, 0x60e3, 0x0000, 0x2069, 0x0200, - 0x6804, 0xa005, 0x1118, 0x6808, 0xa005, 0x01b8, 0x6028, 0xa084, - 0xfdff, 0x602a, 0x6027, 0x0200, 0x2069, 0xafac, 0x7000, 0x206a, - 0x708b, 0x0027, 0x7003, 0x0001, 0x20a9, 0x0002, 0x1d04, 0x592e, - 0x2091, 0x6000, 0x1f04, 0x592e, 0x04e8, 0x6027, 0x1e00, 0x2009, - 0x1e00, 0xe000, 0x6024, 0xa10c, 0x01c8, 0xa084, 0x1c00, 0x11b0, - 0x1d04, 0x5935, 0x0006, 0x0016, 0x00c6, 0x00d6, 0x00e6, 0x080c, - 0x64a2, 0x00ee, 0x00de, 0x00ce, 0x001e, 0x000e, 0x00e6, 0x2071, - 0xafda, 0x7018, 0x00ee, 0xa005, 0x1d00, 0x01e0, 0x0026, 0x2011, - 0x566e, 0x080c, 0x650d, 0x002e, 0x2069, 0x0140, 0x60e3, 0x0000, - 0x70a0, 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x2001, - 0xaf8e, 0x2004, 0x080c, 0x26cb, 0x60e2, 0x2001, 0xad0c, 0x200c, - 0xc1b4, 0x2102, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, - 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x0046, 0x00c6, - 0x00e6, 0x2061, 0x0100, 0x2071, 0xad00, 0x7130, 0xd184, 0x1180, - 0x2011, 0xad52, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132, 0x2011, - 0xad52, 0x2214, 0xd2ac, 0x1120, 0x7030, 0xd08c, 0x0904, 0x59df, - 0x7130, 0xc185, 0x7132, 0x2011, 0xad52, 0x220c, 0xd1a4, 0x0530, - 0x0016, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x663f, 0x2019, - 0x000e, 0x080c, 0xa8eb, 0x0156, 0x20a9, 0x007f, 0x2009, 0x0000, - 0xa186, 0x007e, 0x0170, 0xa186, 0x0080, 0x0158, 0x080c, 0x4cdc, - 0x1140, 0x8127, 0xa006, 0x0016, 0x2009, 0x000e, 0x080c, 0xa96c, - 0x001e, 0x8108, 0x1f04, 0x59b0, 0x015e, 0x001e, 0xd1ac, 0x1148, - 0x0016, 0x2009, 0x0000, 0x2019, 0x0004, 0x080c, 0x2aac, 0x001e, - 0x0070, 0x0156, 0x20a9, 0x007f, 0x2009, 0x0000, 0x080c, 0x4cdc, - 0x1110, 0x080c, 0x493a, 0x8108, 0x1f04, 0x59d6, 0x015e, 0x2011, - 0x0003, 0x080c, 0x7adf, 0x2011, 0x0002, 0x080c, 0x7ae9, 0x080c, - 0x79e1, 0x080c, 0x6581, 0x0036, 0x2019, 0x0000, 0x080c, 0x7a64, - 0x003e, 0x60e3, 0x0000, 0x2001, 0xad00, 0x2003, 0x0001, 0x080c, - 0x569a, 0x00ee, 0x00ce, 0x004e, 0x003e, 0x002e, 0x001e, 0x015e, - 0x0005, 0x2071, 0xade1, 0x7003, 0x0000, 0x7007, 0x0000, 0x700f, - 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001, 0x705f, - 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000, 0x708f, - 0x0001, 0x70bf, 0x0000, 0x0005, 0x00e6, 0x2071, 0xade1, 0x6848, - 0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, 0x0428, - 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, 0x703e, 0x707a, 0x685c, - 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, 0x7032, 0x2009, 0x000c, - 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, - 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, 0x7028, 0xc084, 0x702a, - 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x00ee, 0x0005, 0x2b78, - 0x2071, 0xade1, 0x7004, 0x0043, 0x700c, 0x0002, 0x5a5b, 0x5a52, - 0x5a52, 0x5a52, 0x5a52, 0x0005, 0x5ab1, 0x5ab2, 0x5ae4, 0x5ae5, - 0x5aaf, 0x5b33, 0x5b38, 0x5b69, 0x5b6a, 0x5b85, 0x5b86, 0x5b87, - 0x5b88, 0x5b89, 0x5b8a, 0x5c40, 0x5c67, 0x700c, 0x0002, 0x5a74, - 0x5aaf, 0x5aaf, 0x5ab0, 0x5ab0, 0x7830, 0x7930, 0xa106, 0x0120, - 0x7830, 0x7930, 0xa106, 0x1510, 0x7030, 0xa10a, 0x01f8, 0x1210, - 0x712c, 0xa10a, 0xa18a, 0x0002, 0x12d0, 0x080c, 0x15c0, 0x01b0, - 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, 0x0003, 0x7057, 0x0000, - 0x0126, 0x0006, 0x2091, 0x8000, 0x2009, 0xafec, 0x2104, 0xc085, - 0x200a, 0x000e, 0x700e, 0x012e, 0x080c, 0x163c, 0x0005, 0x080c, - 0x15c0, 0x0de0, 0x2d00, 0x705a, 0x080c, 0x15c0, 0x1108, 0x0c10, - 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, 0x08f8, 0x0005, - 0x0005, 0x0005, 0x700c, 0x0002, 0x5ab9, 0x5abc, 0x5aca, 0x5ae3, - 0x5ae3, 0x080c, 0x5a6d, 0x0005, 0x0126, 0x8001, 0x700e, 0x7058, - 0x0006, 0x080c, 0x5f90, 0x0120, 0x2091, 0x8000, 0x080c, 0x5a6d, - 0x00de, 0x0048, 0x0126, 0x8001, 0x700e, 0x080c, 0x5f90, 0x7058, - 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, - 0xa084, 0x00ff, 0xa08a, 0x003a, 0x1218, 0x00db, 0x012e, 0x0005, - 0x012e, 0x080c, 0x5b8b, 0x0005, 0x0005, 0x0005, 0x00e6, 0x2071, - 0xade1, 0x700c, 0x0002, 0x5af0, 0x5af0, 0x5af0, 0x5af2, 0x5af5, - 0x00ee, 0x0005, 0x700f, 0x0001, 0x0010, 0x700f, 0x0002, 0x00ee, - 0x0005, 0x5b8b, 0x5b8b, 0x5ba7, 0x5b8b, 0x5d22, 0x5b8b, 0x5b8b, - 0x5b8b, 0x5b8b, 0x5b8b, 0x5ba7, 0x5d64, 0x5da7, 0x5df0, 0x5e04, - 0x5b8b, 0x5b8b, 0x5bc3, 0x5ba7, 0x5b8b, 0x5b8b, 0x5c1d, 0x5ead, - 0x5ec8, 0x5b8b, 0x5bc3, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5c13, - 0x5ec8, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, - 0x5b8b, 0x5b8b, 0x5bd7, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, - 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, - 0x5b8b, 0x5b8b, 0x5bec, 0x7020, 0x2068, 0x080c, 0x15f0, 0x0005, - 0x700c, 0x0002, 0x5b3f, 0x5b42, 0x5b50, 0x5b68, 0x5b68, 0x080c, - 0x5a6d, 0x0005, 0x0126, 0x8001, 0x700e, 0x7058, 0x0006, 0x080c, - 0x5f90, 0x0120, 0x2091, 0x8000, 0x080c, 0x5a6d, 0x00de, 0x0048, - 0x0126, 0x8001, 0x700e, 0x080c, 0x5f90, 0x7058, 0x2068, 0x7084, - 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, - 0xa08a, 0x001a, 0x1218, 0x003b, 0x012e, 0x0005, 0x012e, 0x0419, - 0x0005, 0x0005, 0x0005, 0x5b8b, 0x5ba7, 0x5d0e, 0x5b8b, 0x5ba7, - 0x5b8b, 0x5ba7, 0x5ba7, 0x5b8b, 0x5ba7, 0x5d0e, 0x5ba7, 0x5ba7, - 0x5ba7, 0x5ba7, 0x5ba7, 0x5b8b, 0x5ba7, 0x5d0e, 0x5b8b, 0x5b8b, - 0x5ba7, 0x5b8b, 0x5b8b, 0x5b8b, 0x5ba7, 0x0005, 0x0005, 0x0005, - 0x0005, 0x0005, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, - 0xc0d5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x510c, 0x012e, - 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, 0x683a, - 0x0126, 0x2091, 0x8000, 0x080c, 0x510c, 0x012e, 0x0005, 0x7007, - 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed, 0x683a, 0x0126, 0x2091, - 0x8000, 0x080c, 0x510c, 0x012e, 0x0005, 0x7007, 0x0001, 0x6838, - 0xa084, 0x00ff, 0xc0dd, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, - 0x510c, 0x012e, 0x0005, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0988, - 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x5cd0, 0x7007, 0x0006, - 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5cd0, 0x0005, 0x6834, - 0x8007, 0xa084, 0x00ff, 0x0904, 0x5b99, 0x8001, 0x1120, 0x7007, - 0x0001, 0x0804, 0x5ced, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, - 0x701a, 0x704b, 0x5ced, 0x0005, 0x6834, 0x8007, 0xa084, 0x00ff, - 0xa086, 0x0001, 0x1904, 0x5b99, 0x7007, 0x0001, 0x2009, 0xad30, - 0x210c, 0x81ff, 0x11a8, 0x6838, 0xa084, 0x00ff, 0x683a, 0x6853, - 0x0000, 0x080c, 0x4ab1, 0x1108, 0x0005, 0x0126, 0x2091, 0x8000, - 0x6837, 0x0139, 0x684a, 0x6952, 0x080c, 0x510c, 0x012e, 0x0ca0, - 0x2001, 0x0028, 0x0c90, 0x684c, 0xa084, 0x00c0, 0xa086, 0x00c0, - 0x1120, 0x7007, 0x0001, 0x0804, 0x5ee0, 0x2d00, 0x7016, 0x701a, - 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, 0xae0c, 0x53a3, - 0x6858, 0x7012, 0xa082, 0x0401, 0x1a04, 0x5bb5, 0x6a84, 0xa28a, - 0x0002, 0x1a04, 0x5bb5, 0x82ff, 0x1138, 0x6888, 0x698c, 0xa105, - 0x0118, 0x2001, 0x5ca3, 0x0018, 0xa280, 0x5c99, 0x2005, 0x70c6, - 0x7010, 0xa015, 0x0904, 0x5c85, 0x080c, 0x15c0, 0x1118, 0x7007, - 0x000f, 0x0005, 0x2d00, 0x7022, 0x70c4, 0x2060, 0x2c05, 0x6836, - 0xe004, 0xad00, 0x7096, 0xe008, 0xa20a, 0x1210, 0xa00e, 0x2200, - 0x7112, 0xe20c, 0x8003, 0x800b, 0xa296, 0x0004, 0x0108, 0xa108, - 0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x080c, 0x1624, 0x7090, - 0xa08e, 0x0100, 0x0170, 0xa086, 0x0200, 0x0118, 0x7007, 0x0010, - 0x0005, 0x7020, 0x2068, 0x080c, 0x15f0, 0x7014, 0x2068, 0x0804, - 0x5bb5, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, 0x0000, 0x2d08, - 0x2068, 0x6906, 0x711a, 0x0804, 0x5c40, 0x7014, 0x2068, 0x7007, - 0x0001, 0x6884, 0xa005, 0x1128, 0x6888, 0x698c, 0xa105, 0x0108, - 0x00b1, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x0904, 0x5ee0, - 0x04b8, 0x5c9b, 0x5c9f, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, - 0x000f, 0x0005, 0x0006, 0x000a, 0x0011, 0x0005, 0x0004, 0x00f6, - 0x00e6, 0x00c6, 0x0076, 0x0066, 0x6f88, 0x6e8c, 0x6804, 0x2060, - 0xacf0, 0x0021, 0xacf8, 0x0027, 0x2009, 0x0005, 0x700c, 0x7816, - 0x7008, 0x7812, 0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e, 0x7f0a, - 0x8109, 0x0128, 0xaef2, 0x0004, 0xaffa, 0x0006, 0x0c78, 0x6004, - 0xa065, 0x1d30, 0x006e, 0x007e, 0x00ce, 0x00ee, 0x00fe, 0x0005, - 0x2009, 0xad30, 0x210c, 0x81ff, 0x1198, 0x6838, 0xa084, 0x00ff, - 0x683a, 0x080c, 0x4993, 0x1108, 0x0005, 0x080c, 0x51df, 0x0126, - 0x2091, 0x8000, 0x080c, 0x97fd, 0x080c, 0x510c, 0x012e, 0x0ca0, - 0x2001, 0x0028, 0x2009, 0x0000, 0x0c80, 0x2009, 0xad30, 0x210c, - 0x81ff, 0x11b0, 0x6858, 0xa005, 0x01b0, 0x6838, 0xa084, 0x00ff, - 0x683a, 0x6853, 0x0000, 0x080c, 0x4a55, 0x1108, 0x0005, 0x0126, - 0x2091, 0x8000, 0x080c, 0x51df, 0x080c, 0x510c, 0x012e, 0x0cb0, - 0x2001, 0x0028, 0x0ca0, 0x2001, 0x0000, 0x0c88, 0x7018, 0x6802, - 0x2d08, 0x2068, 0x6906, 0x711a, 0x7010, 0x8001, 0x7012, 0x0118, - 0x7007, 0x0006, 0x0030, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, - 0x080f, 0x0005, 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, - 0x6848, 0xa084, 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x01b0, - 0x2009, 0x0000, 0x20a9, 0x00ff, 0xa096, 0x0002, 0x0178, 0xa005, - 0x11f0, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4cdc, 0x11b8, - 0x0066, 0x6e50, 0x080c, 0x4dcf, 0x006e, 0x0088, 0x0046, 0x2011, - 0xad0c, 0x2224, 0xc484, 0x2412, 0x004e, 0x00c6, 0x080c, 0x4cdc, - 0x1110, 0x080c, 0x4f2d, 0x8108, 0x1f04, 0x5d4e, 0x00ce, 0x684c, - 0xd084, 0x1118, 0x080c, 0x15f0, 0x0005, 0x0126, 0x2091, 0x8000, - 0x080c, 0x510c, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x7007, - 0x0001, 0x2001, 0xad52, 0x2004, 0xd0a4, 0x0580, 0x2061, 0xb048, - 0x6100, 0xd184, 0x0178, 0x6858, 0xa084, 0x00ff, 0x1550, 0x6000, - 0xd084, 0x0520, 0x6004, 0xa005, 0x1538, 0x6003, 0x0000, 0x600b, - 0x0000, 0x00c8, 0x2011, 0x0001, 0x6860, 0xa005, 0x1110, 0x2001, - 0x001e, 0x8000, 0x6016, 0x6858, 0xa084, 0x00ff, 0x0178, 0x6006, - 0x6858, 0x8007, 0xa084, 0x00ff, 0x0148, 0x600a, 0x6858, 0x8000, - 0x1108, 0xc28d, 0x6202, 0x012e, 0x0804, 0x5f7f, 0x012e, 0x0804, - 0x5f79, 0x012e, 0x0804, 0x5f73, 0x012e, 0x0804, 0x5f76, 0x0126, - 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xad52, 0x2004, 0xd0a4, - 0x05e0, 0x2061, 0xb048, 0x6000, 0xd084, 0x05b8, 0x6204, 0x6308, - 0xd08c, 0x1530, 0x6c48, 0xa484, 0x0003, 0x0170, 0x6958, 0xa18c, - 0x00ff, 0x8001, 0x1120, 0x2100, 0xa210, 0x0620, 0x0028, 0x8001, - 0x1508, 0x2100, 0xa212, 0x02f0, 0xa484, 0x000c, 0x0188, 0x6958, - 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x1120, 0x2100, 0xa318, - 0x0288, 0x0030, 0xa082, 0x0004, 0x1168, 0x2100, 0xa31a, 0x0250, - 0x6860, 0xa005, 0x0110, 0x8000, 0x6016, 0x6206, 0x630a, 0x012e, - 0x0804, 0x5f7f, 0x012e, 0x0804, 0x5f7c, 0x012e, 0x0804, 0x5f79, - 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, 0xb048, 0x6300, - 0xd38c, 0x1120, 0x6308, 0x8318, 0x0220, 0x630a, 0x012e, 0x0804, - 0x5f8d, 0x012e, 0x0804, 0x5f7c, 0x0126, 0x00c6, 0x2091, 0x8000, - 0x7007, 0x0001, 0x684c, 0xd0ac, 0x0148, 0x00c6, 0x2061, 0xb048, - 0x6000, 0xa084, 0xfcff, 0x6002, 0x00ce, 0x0448, 0x6858, 0xa005, - 0x05d0, 0x685c, 0xa065, 0x0598, 0x2001, 0xad30, 0x2004, 0xa005, - 0x0118, 0x080c, 0x974e, 0x0068, 0x6013, 0x0400, 0x6057, 0x0000, - 0x694c, 0xd1a4, 0x0110, 0x6950, 0x6156, 0x2009, 0x0041, 0x080c, - 0x80a7, 0x6958, 0xa18c, 0xff00, 0xa186, 0x2000, 0x1140, 0x0026, - 0x2009, 0x0000, 0x2011, 0xfdff, 0x080c, 0x663f, 0x002e, 0x684c, - 0xd0c4, 0x0148, 0x2061, 0xb048, 0x6000, 0xd08c, 0x1120, 0x6008, - 0x8000, 0x0208, 0x600a, 0x00ce, 0x012e, 0x0804, 0x5f7f, 0x00ce, - 0x012e, 0x0804, 0x5f79, 0x6954, 0xa186, 0x002e, 0x0d40, 0xa186, - 0x002d, 0x0d28, 0xa186, 0x0045, 0x0510, 0xa186, 0x002a, 0x1130, - 0x2001, 0xad0c, 0x200c, 0xc194, 0x2102, 0x08c8, 0xa186, 0x0020, - 0x0170, 0xa186, 0x0029, 0x1d18, 0x6944, 0xa18c, 0xff00, 0x810f, - 0x080c, 0x4cdc, 0x1960, 0x6000, 0xc0e4, 0x6002, 0x0840, 0x685c, - 0xa065, 0x09a8, 0x2001, 0xafa3, 0x2004, 0x6016, 0x0800, 0x685c, - 0xa065, 0x0968, 0x00e6, 0x6860, 0xa075, 0x2001, 0xad30, 0x2004, - 0xa005, 0x0150, 0x080c, 0x974e, 0x8eff, 0x0118, 0x2e60, 0x080c, - 0x974e, 0x00ee, 0x0804, 0x5e3f, 0x6020, 0xc0dc, 0xc0d5, 0x6022, - 0x2e60, 0x6007, 0x003a, 0x6870, 0xa005, 0x0130, 0x6007, 0x003b, - 0x6874, 0x602a, 0x6878, 0x6012, 0x6003, 0x0001, 0x080c, 0x67a8, - 0x080c, 0x6c50, 0x00ee, 0x0804, 0x5e3f, 0x2061, 0xb048, 0x6000, - 0xd084, 0x0190, 0xd08c, 0x1904, 0x5f8d, 0x0126, 0x2091, 0x8000, - 0x6204, 0x8210, 0x0220, 0x6206, 0x012e, 0x0804, 0x5f8d, 0x012e, - 0x6853, 0x0016, 0x0804, 0x5f86, 0x6853, 0x0007, 0x0804, 0x5f86, - 0x6834, 0x8007, 0xa084, 0x00ff, 0x1118, 0x080c, 0x5b99, 0x0078, - 0x2030, 0x8001, 0x1120, 0x7007, 0x0001, 0x0051, 0x0040, 0x7007, - 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5ee0, 0x0005, - 0x00e6, 0x0126, 0x2091, 0x8000, 0x2009, 0xad30, 0x210c, 0x81ff, - 0x1904, 0x5f5b, 0x2009, 0xad0c, 0x210c, 0xd194, 0x1904, 0x5f63, - 0x6848, 0x2070, 0xae82, 0xb400, 0x0a04, 0x5f4f, 0x2001, 0xad16, - 0x2004, 0xae02, 0x1a04, 0x5f4f, 0x2061, 0xb048, 0x6100, 0xa184, - 0x0301, 0xa086, 0x0001, 0x15a8, 0x711c, 0xa186, 0x0006, 0x15b0, - 0x7018, 0xa005, 0x0904, 0x5f5b, 0x2004, 0xd0e4, 0x1904, 0x5f5e, - 0x7020, 0xd0dc, 0x1904, 0x5f66, 0x6853, 0x0000, 0x6803, 0x0000, - 0x2d08, 0x7010, 0xa005, 0x1158, 0x7112, 0x684c, 0xd0f4, 0x1904, - 0x5f69, 0x2e60, 0x080c, 0x65aa, 0x012e, 0x00ee, 0x0005, 0x2068, - 0x6800, 0xa005, 0x1de0, 0x6902, 0x2168, 0x684c, 0xd0f4, 0x15c8, - 0x012e, 0x00ee, 0x0005, 0x012e, 0x00ee, 0x6853, 0x0006, 0x0804, - 0x5f86, 0xd184, 0x0dc0, 0xd1c4, 0x11a8, 0x00b8, 0x6944, 0xa18c, - 0xff00, 0x810f, 0x080c, 0x4cdc, 0x11c8, 0x6000, 0xd0e4, 0x11b0, - 0x711c, 0xa186, 0x0007, 0x1118, 0x6853, 0x0002, 0x0088, 0x6853, - 0x0008, 0x0070, 0x6853, 0x000e, 0x0058, 0x6853, 0x0017, 0x0040, - 0x6853, 0x0035, 0x0028, 0x6853, 0x0028, 0x0010, 0x6853, 0x0029, - 0x012e, 0x00ee, 0x0418, 0x6853, 0x002a, 0x0cd0, 0x6853, 0x0045, - 0x0cb8, 0x2e60, 0x2019, 0x0002, 0x6017, 0x0014, 0x080c, 0xa566, - 0x012e, 0x00ee, 0x0005, 0x2009, 0x003e, 0x0058, 0x2009, 0x0004, - 0x0040, 0x2009, 0x0006, 0x0028, 0x2009, 0x0016, 0x0010, 0x2009, - 0x0001, 0x6854, 0xa084, 0xff00, 0xa105, 0x6856, 0x0126, 0x2091, - 0x8000, 0x080c, 0x510c, 0x012e, 0x0005, 0x080c, 0x15f0, 0x0005, - 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034, 0x7072, - 0x7038, 0x7076, 0x0058, 0x7070, 0xa080, 0x0040, 0x7072, 0x1230, - 0x7074, 0xa081, 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, 0x7132, - 0x0005, 0x00d6, 0x080c, 0x65a1, 0x00de, 0x0005, 0x00d6, 0x2011, - 0x0004, 0x2204, 0xa085, 0x8002, 0x2012, 0x00de, 0x0005, 0x20e1, - 0x0002, 0x3d08, 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, 0x0118, - 0xa086, 0x1000, 0x1540, 0x20e1, 0x0000, 0x3d00, 0xa094, 0xff00, - 0x8217, 0xa084, 0xf000, 0xa086, 0x3000, 0x1118, 0x080c, 0x61c6, - 0x00b0, 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x1108, 0x3e60, 0xac84, - 0x0007, 0x1188, 0xac82, 0xb400, 0x0270, 0x6858, 0xac02, 0x1258, - 0x6120, 0xd1f4, 0x1160, 0x2009, 0x0047, 0x080c, 0x80a7, 0x7a1c, - 0xd284, 0x1968, 0x0005, 0xa016, 0x080c, 0x1824, 0x0cc0, 0x0cd8, - 0x781c, 0xd08c, 0x0500, 0x0156, 0x0136, 0x0146, 0x20e1, 0x3000, - 0x3d20, 0x3e28, 0xa584, 0x0076, 0x1530, 0xa484, 0x7000, 0xa086, - 0x1000, 0x11a8, 0x080c, 0x604e, 0x01f0, 0x20e1, 0x3000, 0x7828, - 0x7828, 0x080c, 0x606a, 0x014e, 0x013e, 0x015e, 0x2009, 0xafcf, - 0x2104, 0xa005, 0x1108, 0x0005, 0x080c, 0x6c50, 0x0ce0, 0xa484, - 0x7000, 0x1518, 0x0499, 0x01b8, 0x7000, 0xa084, 0xff00, 0xa086, - 0x8100, 0x0d18, 0x0080, 0xd5a4, 0x0158, 0x080c, 0x1d86, 0x20e1, - 0x9010, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x0048, - 0x00e9, 0x6883, 0x0000, 0x080c, 0xac59, 0x20e1, 0x3000, 0x7828, - 0x7828, 0x014e, 0x013e, 0x015e, 0x08b0, 0x0081, 0x1130, 0x7000, - 0xa084, 0xff00, 0xa086, 0x8100, 0x1d70, 0x080c, 0xac59, 0x20e1, - 0x3000, 0x7828, 0x7828, 0x080c, 0x642d, 0x0c58, 0xa484, 0x01ff, - 0x6882, 0xa005, 0x0160, 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac, - 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x0005, 0x20a9, - 0x000c, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, - 0x0001, 0x0ca0, 0x7000, 0xa084, 0xff00, 0xa08c, 0xf000, 0x8007, - 0xa196, 0x0000, 0x1118, 0x0804, 0x62cf, 0x0005, 0xa196, 0x2000, - 0x1148, 0x6900, 0xa18e, 0x0001, 0x1118, 0x080c, 0x41d1, 0x0ca8, - 0x0039, 0x0c98, 0xa196, 0x8000, 0x1d80, 0x080c, 0x6372, 0x0c68, - 0x00c6, 0x6a80, 0x82ff, 0x0904, 0x61c0, 0x7110, 0xa18c, 0xff00, - 0x810f, 0xa196, 0x0001, 0x0120, 0xa196, 0x0023, 0x1904, 0x61c0, - 0xa08e, 0x0023, 0x1570, 0x080c, 0x6408, 0x0904, 0x61c0, 0x7124, - 0x610a, 0x7030, 0xa08e, 0x0200, 0x1150, 0x7034, 0xa005, 0x1904, - 0x61c0, 0x2009, 0x0015, 0x080c, 0x80a7, 0x0804, 0x61c0, 0xa08e, - 0x0214, 0x0118, 0xa08e, 0x0210, 0x1130, 0x2009, 0x0015, 0x080c, - 0x80a7, 0x0804, 0x61c0, 0xa08e, 0x0100, 0x1904, 0x61c0, 0x7034, - 0xa005, 0x1904, 0x61c0, 0x2009, 0x0016, 0x080c, 0x80a7, 0x0804, - 0x61c0, 0xa08e, 0x0022, 0x1904, 0x61c0, 0x7030, 0xa08e, 0x0300, - 0x1580, 0x68d0, 0xd0a4, 0x0528, 0xc0b5, 0x68d2, 0x7100, 0xa18c, - 0x00ff, 0x696e, 0x7004, 0x6872, 0x00f6, 0x2079, 0x0100, 0x79e6, - 0x78ea, 0x0006, 0xa084, 0x00ff, 0x0016, 0x2008, 0x080c, 0x26a0, - 0x7932, 0x7936, 0x001e, 0x000e, 0x00fe, 0x080c, 0x2676, 0x694e, - 0x703c, 0x00e6, 0x2071, 0x0140, 0x7086, 0x2071, 0xad00, 0x70a2, - 0x00ee, 0x7034, 0xa005, 0x1904, 0x61c0, 0x2009, 0x0017, 0x0804, - 0x6193, 0xa08e, 0x0400, 0x1158, 0x7034, 0xa005, 0x1904, 0x61c0, - 0x68d0, 0xc0a5, 0x68d2, 0x2009, 0x0030, 0x0804, 0x6193, 0xa08e, - 0x0500, 0x1140, 0x7034, 0xa005, 0x1904, 0x61c0, 0x2009, 0x0018, - 0x0804, 0x6193, 0xa08e, 0x2010, 0x1120, 0x2009, 0x0019, 0x0804, - 0x6193, 0xa08e, 0x2110, 0x1120, 0x2009, 0x001a, 0x0804, 0x6193, - 0xa08e, 0x5200, 0x1140, 0x7034, 0xa005, 0x1904, 0x61c0, 0x2009, - 0x001b, 0x0804, 0x6193, 0xa08e, 0x5000, 0x1140, 0x7034, 0xa005, - 0x1904, 0x61c0, 0x2009, 0x001c, 0x0804, 0x6193, 0xa08e, 0x1300, - 0x1120, 0x2009, 0x0034, 0x0804, 0x6193, 0xa08e, 0x1200, 0x1140, - 0x7034, 0xa005, 0x1904, 0x61c0, 0x2009, 0x0024, 0x0804, 0x6193, - 0xa08c, 0xff00, 0xa18e, 0x2400, 0x1118, 0x2009, 0x002d, 0x04d8, - 0xa08c, 0xff00, 0xa18e, 0x5300, 0x1118, 0x2009, 0x002a, 0x0498, - 0xa08e, 0x0f00, 0x1118, 0x2009, 0x0020, 0x0468, 0xa08e, 0x5300, - 0x1108, 0x00d8, 0xa08e, 0x6104, 0x11c0, 0x2011, 0xb28d, 0x8208, - 0x2204, 0xa082, 0x0004, 0x20a8, 0x95ac, 0x95ac, 0x2011, 0x8015, - 0x211c, 0x8108, 0x0046, 0x2124, 0x080c, 0x3c5c, 0x004e, 0x8108, - 0x1f04, 0x6176, 0x2009, 0x0023, 0x0070, 0xa08e, 0x6000, 0x1118, - 0x2009, 0x003f, 0x0040, 0xa08e, 0x7800, 0x1118, 0x2009, 0x0045, - 0x0010, 0x2009, 0x001d, 0x0016, 0x2011, 0xb283, 0x2204, 0x8211, - 0x220c, 0x080c, 0x2676, 0x1530, 0x080c, 0x4c80, 0x1518, 0x6612, - 0x6516, 0x86ff, 0x0180, 0x001e, 0x0016, 0xa186, 0x0017, 0x1158, - 0x686c, 0xa606, 0x1140, 0x6870, 0xa506, 0xa084, 0xff00, 0x1118, - 0x6000, 0xc0f5, 0x6002, 0x00c6, 0x080c, 0x8022, 0x0168, 0x001e, - 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, 0x80a7, - 0x00ce, 0x0005, 0x001e, 0x0ce0, 0x00ce, 0x0ce0, 0x00c6, 0x0046, - 0x080c, 0x6221, 0x1904, 0x621e, 0xa184, 0xff00, 0x8007, 0xa086, - 0x0008, 0x1904, 0x621e, 0xa28e, 0x0033, 0x11e8, 0x080c, 0x6408, - 0x0904, 0x621e, 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, 0x1140, - 0x7034, 0xa005, 0x15d8, 0x2009, 0x0015, 0x080c, 0x80a7, 0x04b0, - 0xa08e, 0x0100, 0x1598, 0x7034, 0xa005, 0x1580, 0x2009, 0x0016, - 0x080c, 0x80a7, 0x0458, 0xa28e, 0x0032, 0x1540, 0x7030, 0xa08e, - 0x1400, 0x1520, 0x2009, 0x0038, 0x0016, 0x2011, 0xb283, 0x2204, - 0x8211, 0x220c, 0x080c, 0x2676, 0x11c0, 0x080c, 0x4c80, 0x11a8, - 0x6612, 0x6516, 0x00c6, 0x080c, 0x8022, 0x0170, 0x001e, 0x611a, - 0x080c, 0x9956, 0x601f, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, - 0x80a7, 0x080c, 0x6c50, 0x0010, 0x00ce, 0x001e, 0x004e, 0x00ce, - 0x0005, 0x00f6, 0x00d6, 0x0026, 0x0016, 0x0136, 0x0146, 0x0156, - 0x3c00, 0x0006, 0x2079, 0x0030, 0x2069, 0x0200, 0x080c, 0x1df2, - 0x1590, 0x080c, 0x1ce2, 0x05c8, 0x04d9, 0x1130, 0x7908, 0xa18c, - 0x1fff, 0xa182, 0x0011, 0x1688, 0x20a9, 0x000c, 0x20e1, 0x0000, - 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x20e1, 0x2000, 0x2001, 0x020a, - 0x2004, 0x7a0c, 0x7808, 0xa080, 0x0007, 0xa084, 0x1ff8, 0x0401, - 0x1120, 0xa08a, 0x0140, 0x1a0c, 0x14f6, 0x80ac, 0x20e1, 0x6000, - 0x2099, 0x020a, 0x53a5, 0x20e1, 0x7000, 0x6828, 0x6828, 0x7803, - 0x0004, 0xa294, 0x0070, 0x000e, 0x20e0, 0x015e, 0x014e, 0x013e, - 0x001e, 0x002e, 0x00de, 0x00fe, 0x0005, 0xa085, 0x0001, 0x0c98, - 0x0006, 0x2001, 0x0111, 0x2004, 0xa084, 0x0003, 0x000e, 0x0005, - 0x0046, 0x00e6, 0x00d6, 0x2028, 0x2130, 0xa696, 0x00ff, 0x1198, - 0xa596, 0xfffd, 0x1120, 0x2009, 0x007f, 0x0804, 0x62ca, 0xa596, - 0xfffe, 0x1118, 0x2009, 0x007e, 0x04e8, 0xa596, 0xfffc, 0x1118, - 0x2009, 0x0080, 0x04b8, 0x2011, 0x0000, 0x2019, 0xad34, 0x231c, - 0xd3ac, 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, 0x2071, 0xae34, - 0x0030, 0x2021, 0x0081, 0x20a9, 0x007e, 0x2071, 0xaeb5, 0x2e1c, - 0x83ff, 0x1128, 0x82ff, 0x1198, 0x2410, 0xc2fd, 0x0080, 0x2368, - 0x6f10, 0x0006, 0x2100, 0xa706, 0x000e, 0x6b14, 0x1120, 0xa346, - 0x1110, 0x2408, 0x0078, 0x87ff, 0x1110, 0x83ff, 0x0d58, 0x8420, - 0x8e70, 0x1f04, 0x62a7, 0x82ff, 0x1118, 0xa085, 0x0001, 0x0018, - 0xc2fc, 0x2208, 0xa006, 0x00de, 0x00ee, 0x004e, 0x0005, 0xa084, - 0x0007, 0x000a, 0x0005, 0x62db, 0x62db, 0x62db, 0x641a, 0x62db, - 0x62dc, 0x62f1, 0x635d, 0x0005, 0x7110, 0xd1bc, 0x0188, 0x7120, - 0x2160, 0xac8c, 0x0007, 0x1160, 0xac8a, 0xb400, 0x0248, 0x6858, - 0xac02, 0x1230, 0x7124, 0x610a, 0x2009, 0x0046, 0x080c, 0x80a7, - 0x0005, 0x00c6, 0x7110, 0xd1bc, 0x1904, 0x6344, 0x2011, 0xb283, - 0x2204, 0x8211, 0x220c, 0x080c, 0x2676, 0x1904, 0x6344, 0x080c, - 0x4c80, 0x1904, 0x6344, 0x6612, 0x6516, 0x6000, 0xd0ec, 0x15e0, - 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x0160, 0x080c, - 0x574f, 0x11d0, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, 0x11a0, - 0xa295, 0x0600, 0x6206, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0530, - 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6152, 0x2009, - 0x0044, 0x080c, 0x80a7, 0x00c0, 0x00c6, 0x080c, 0x8022, 0x001e, - 0x0198, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, 0x0004, - 0x1118, 0x6007, 0x0005, 0x0010, 0x6007, 0x0001, 0x6003, 0x0001, - 0x080c, 0x67ee, 0x080c, 0x6c50, 0x00ce, 0x0005, 0x00c6, 0x080c, - 0x9807, 0x001e, 0x0dc8, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, - 0x7130, 0x6152, 0x6013, 0x0300, 0x6003, 0x0001, 0x6007, 0x0041, - 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0c38, 0x7110, 0xd1bc, 0x0188, - 0x7020, 0x2060, 0xac84, 0x0007, 0x1160, 0xac82, 0xb400, 0x0248, - 0x6858, 0xac02, 0x1230, 0x7124, 0x610a, 0x2009, 0x0045, 0x080c, - 0x80a7, 0x0005, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, - 0x1130, 0xa084, 0x000f, 0xa08a, 0x0006, 0x1208, 0x000b, 0x0005, - 0x6386, 0x6387, 0x6386, 0x6386, 0x63f0, 0x63fc, 0x0005, 0x7110, - 0xd1bc, 0x0120, 0x702c, 0xd084, 0x0904, 0x63ef, 0x700c, 0x7108, - 0x080c, 0x2676, 0x1904, 0x63ef, 0x080c, 0x4c80, 0x1904, 0x63ef, - 0x6612, 0x6516, 0x6204, 0x7110, 0xd1bc, 0x01f8, 0xa28c, 0x00ff, - 0xa186, 0x0004, 0x0118, 0xa186, 0x0006, 0x15c8, 0x00c6, 0x080c, - 0x6408, 0x00ce, 0x0904, 0x63ef, 0x00c6, 0x080c, 0x8022, 0x001e, - 0x05f0, 0x611a, 0x080c, 0x9956, 0x601f, 0x0002, 0x7120, 0x610a, - 0x2009, 0x0088, 0x080c, 0x80a7, 0x0490, 0xa28c, 0x00ff, 0xa186, - 0x0006, 0x0160, 0xa186, 0x0004, 0x0148, 0xa294, 0xff00, 0x8217, - 0xa286, 0x0004, 0x0118, 0xa286, 0x0006, 0x1188, 0x00c6, 0x080c, - 0x8022, 0x001e, 0x01e0, 0x611a, 0x080c, 0x9956, 0x601f, 0x0005, - 0x7120, 0x610a, 0x2009, 0x0088, 0x080c, 0x80a7, 0x0080, 0x00c6, - 0x080c, 0x8022, 0x001e, 0x0158, 0x611a, 0x080c, 0x9956, 0x601f, - 0x0004, 0x7120, 0x610a, 0x2009, 0x0001, 0x080c, 0x80a7, 0x0005, - 0x7110, 0xd1bc, 0x0140, 0x00a1, 0x0130, 0x7124, 0x610a, 0x2009, - 0x0089, 0x080c, 0x80a7, 0x0005, 0x7110, 0xd1bc, 0x0140, 0x0041, - 0x0130, 0x7124, 0x610a, 0x2009, 0x008a, 0x080c, 0x80a7, 0x0005, - 0x7020, 0x2060, 0xac84, 0x0007, 0x1158, 0xac82, 0xb400, 0x0240, - 0x2001, 0xad16, 0x2004, 0xac02, 0x1218, 0xa085, 0x0001, 0x0005, - 0xa006, 0x0ce8, 0x7110, 0xd1bc, 0x1178, 0x7024, 0x2060, 0xac84, - 0x0007, 0x1150, 0xac82, 0xb400, 0x0238, 0x6858, 0xac02, 0x1220, - 0x2009, 0x0051, 0x080c, 0x80a7, 0x0005, 0x2031, 0x0105, 0x0069, - 0x0005, 0x2031, 0x0206, 0x0049, 0x0005, 0x2031, 0x0207, 0x0029, - 0x0005, 0x2031, 0x0213, 0x0009, 0x0005, 0x00c6, 0x00d6, 0x00f6, - 0x7000, 0xa084, 0xf000, 0xa086, 0xc000, 0x05b0, 0x080c, 0x8022, - 0x0598, 0x0066, 0x00c6, 0x0046, 0x2011, 0xb283, 0x2204, 0x8211, - 0x220c, 0x080c, 0x2676, 0x1580, 0x080c, 0x4c80, 0x1568, 0x6612, - 0x6516, 0x2c00, 0x004e, 0x00ce, 0x601a, 0x080c, 0x9956, 0x080c, - 0x15d9, 0x01f0, 0x2d00, 0x6056, 0x6803, 0x0000, 0x6837, 0x0000, - 0x6c3a, 0xadf8, 0x000f, 0x20a9, 0x000e, 0x2fa0, 0x2e98, 0x53a3, - 0x006e, 0x6612, 0x6007, 0x003e, 0x601f, 0x0001, 0x6003, 0x0001, - 0x080c, 0x67ee, 0x080c, 0x6c50, 0x00fe, 0x00de, 0x00ce, 0x0005, - 0x080c, 0x8078, 0x006e, 0x0cc0, 0x004e, 0x00ce, 0x0cc8, 0x2071, - 0xafda, 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, 0x7012, - 0x7017, 0xb400, 0x7007, 0x0000, 0x7026, 0x702b, 0x7841, 0x7032, - 0x7037, 0x789d, 0x703b, 0xffff, 0x703f, 0xffff, 0x7042, 0x7047, - 0x41b3, 0x0005, 0x2071, 0xafda, 0x1d04, 0x64fc, 0x2091, 0x6000, - 0x700c, 0x8001, 0x700e, 0x1180, 0x700f, 0x0361, 0x7007, 0x0001, - 0x0126, 0x2091, 0x8000, 0x7040, 0xa00d, 0x0148, 0x8109, 0x7142, - 0x1130, 0x7044, 0x080f, 0x0018, 0x0126, 0x2091, 0x8000, 0x7024, - 0xa00d, 0x0188, 0x7020, 0x8001, 0x7022, 0x1168, 0x7023, 0x0009, - 0x8109, 0x7126, 0xa186, 0x03e8, 0x1110, 0x7028, 0x080f, 0x81ff, - 0x1110, 0x7028, 0x080f, 0x7030, 0xa00d, 0x0158, 0x702c, 0x8001, - 0x702e, 0x1138, 0x702f, 0x0009, 0x8109, 0x7132, 0x1110, 0x7034, - 0x080f, 0x7038, 0xa005, 0x0118, 0x0310, 0x8001, 0x703a, 0x703c, - 0xa005, 0x0118, 0x0310, 0x8001, 0x703e, 0x7018, 0xa00d, 0x0158, - 0x7008, 0x8001, 0x700a, 0x1138, 0x700b, 0x0009, 0x8109, 0x711a, - 0x1110, 0x701c, 0x080f, 0x012e, 0x7004, 0x0002, 0x6522, 0x6523, - 0x653b, 0x00e6, 0x2071, 0xafda, 0x7018, 0xa005, 0x1120, 0x711a, - 0x721e, 0x700b, 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, - 0xafda, 0x701c, 0xa206, 0x1110, 0x701a, 0x701e, 0x000e, 0x00ee, - 0x0005, 0x00e6, 0x2071, 0xafda, 0x6088, 0xa102, 0x0208, 0x618a, - 0x00ee, 0x0005, 0x0005, 0x7110, 0x080c, 0x4cdc, 0x1158, 0x6088, - 0x8001, 0x0240, 0x608a, 0x1130, 0x0126, 0x2091, 0x8000, 0x080c, - 0x6c50, 0x012e, 0x8108, 0xa182, 0x00ff, 0x0218, 0xa00e, 0x7007, - 0x0002, 0x7112, 0x0005, 0x7014, 0x2060, 0x0126, 0x2091, 0x8000, - 0x603c, 0xa005, 0x0128, 0x8001, 0x603e, 0x1110, 0x080c, 0x9846, - 0x6014, 0xa005, 0x0500, 0x8001, 0x6016, 0x11e8, 0x611c, 0xa186, - 0x0003, 0x0118, 0xa186, 0x0006, 0x11a0, 0x6010, 0x2068, 0x6854, - 0xa08a, 0x199a, 0x0270, 0xa082, 0x1999, 0x6856, 0xa08a, 0x199a, - 0x0210, 0x2001, 0x1999, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, - 0x0010, 0x080c, 0x9350, 0x012e, 0xac88, 0x0018, 0x7116, 0x2001, - 0xe400, 0xa102, 0x0220, 0x7017, 0xb400, 0x7007, 0x0000, 0x0005, - 0x00e6, 0x2071, 0xafda, 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, - 0x0005, 0x2001, 0xafe3, 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, - 0xafda, 0x7132, 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011, 0xafe6, - 0x2013, 0x0000, 0x0005, 0x00e6, 0x2071, 0xafda, 0x711a, 0x721e, - 0x700b, 0x0009, 0x00ee, 0x0005, 0x00c6, 0x2061, 0xb048, 0x00ce, - 0x0005, 0xa184, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0xb048, - 0x2060, 0x0005, 0x6854, 0xa08a, 0x199a, 0x0210, 0x2001, 0x1999, - 0xa005, 0x1150, 0x00c6, 0x2061, 0xb048, 0x6014, 0x00ce, 0xa005, - 0x1138, 0x2001, 0x001e, 0x0020, 0xa08e, 0xffff, 0x1108, 0xa006, - 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c, 0x00c0, - 0xa18e, 0x00c0, 0x05b0, 0xd0b4, 0x1138, 0xd0bc, 0x1528, 0x2009, - 0x0006, 0x080c, 0x661a, 0x0005, 0xd0fc, 0x0130, 0xa084, 0x0003, - 0x0118, 0xa086, 0x0003, 0x15c0, 0x6020, 0xd0d4, 0x0130, 0xc0d4, - 0x6022, 0x6860, 0x602a, 0x685c, 0x602e, 0x2009, 0xad73, 0x2104, - 0xd084, 0x0128, 0x2009, 0x0042, 0x080c, 0x80a7, 0x0005, 0x2009, - 0x0043, 0x080c, 0x80a7, 0x0005, 0xd0fc, 0x0130, 0xa084, 0x0003, - 0x0118, 0xa086, 0x0003, 0x11c0, 0x2009, 0x0042, 0x080c, 0x80a7, - 0x0005, 0xd0fc, 0x0150, 0xa084, 0x0003, 0xa08e, 0x0002, 0x0138, - 0x2009, 0x0041, 0x080c, 0x80a7, 0x0005, 0x0051, 0x0ce8, 0x2009, - 0x0043, 0x080c, 0x80a7, 0x0cc0, 0x2009, 0x0004, 0x0019, 0x0005, - 0x2009, 0x0001, 0x00d6, 0x6010, 0xa0ec, 0xf000, 0x01f0, 0x2068, - 0x6952, 0x6800, 0x6012, 0xa186, 0x0001, 0x1188, 0x694c, 0xa18c, - 0x8100, 0xa18e, 0x8100, 0x1158, 0x00c6, 0x2061, 0xb048, 0x6200, - 0xd28c, 0x1120, 0x6204, 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, - 0x510c, 0x6010, 0xa06d, 0x190c, 0x65aa, 0x00de, 0x0005, 0x0156, - 0x00c6, 0x2061, 0xb048, 0x6000, 0x81ff, 0x0110, 0xa205, 0x0008, - 0xa204, 0x6002, 0x00ce, 0x015e, 0x0005, 0x6800, 0xd08c, 0x1138, - 0x6808, 0xa005, 0x0120, 0x8001, 0x680a, 0xa085, 0x0001, 0x0005, - 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, 0x1208, 0xa200, - 0x1f04, 0x665c, 0x8086, 0x818e, 0x0005, 0x0156, 0x20a9, 0x0010, - 0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213, 0x818d, 0x0228, 0xa11a, - 0x1220, 0x1f04, 0x666c, 0x0028, 0xa11a, 0x2308, 0x8210, 0x1f04, - 0x666c, 0x0006, 0x3200, 0xa084, 0xefff, 0x2080, 0x000e, 0x015e, - 0x0005, 0x0006, 0x3200, 0xa085, 0x1000, 0x0cb8, 0x0126, 0x2091, - 0x2800, 0x2079, 0xafc7, 0x012e, 0x00d6, 0x2069, 0xafc7, 0x6803, - 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, 0x8001, 0x206a, 0x00de, - 0x0005, 0x00c6, 0x6027, 0x0001, 0x7804, 0xa084, 0x0007, 0x0002, - 0x66aa, 0x66cb, 0x671e, 0x66b0, 0x66cb, 0x66aa, 0x66a8, 0x66a8, - 0x080c, 0x14f6, 0x080c, 0x6581, 0x080c, 0x6c50, 0x00ce, 0x0005, - 0x62c0, 0x82ff, 0x1110, 0x00ce, 0x0005, 0x2011, 0x481b, 0x080c, - 0x650d, 0x7828, 0xa092, 0x00c8, 0x1228, 0x8000, 0x782a, 0x080c, - 0x4855, 0x0c88, 0x080c, 0x481b, 0x7807, 0x0003, 0x7827, 0x0000, - 0x782b, 0x0000, 0x0c40, 0x080c, 0x6581, 0x3c00, 0x0006, 0x2011, - 0x0209, 0x20e1, 0x4000, 0x2214, 0x000e, 0x20e0, 0x82ff, 0x0178, - 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, 0x7824, 0xa065, 0x090c, - 0x14f6, 0x2009, 0x0013, 0x080c, 0x80a7, 0x00ce, 0x0005, 0x3900, - 0xa082, 0xb0e8, 0x1210, 0x080c, 0x7d8d, 0x00c6, 0x7824, 0xa065, - 0x090c, 0x14f6, 0x7804, 0xa086, 0x0004, 0x0904, 0x675e, 0x7828, - 0xa092, 0x2710, 0x1230, 0x8000, 0x782a, 0x00ce, 0x080c, 0x7827, - 0x0c20, 0x6104, 0xa186, 0x0003, 0x1188, 0x00e6, 0x2071, 0xad00, - 0x70dc, 0x00ee, 0xd08c, 0x0150, 0x00c6, 0x00e6, 0x2061, 0x0100, - 0x2071, 0xad00, 0x080c, 0x485e, 0x00ee, 0x00ce, 0x080c, 0xaca2, - 0x2009, 0x0014, 0x080c, 0x80a7, 0x00ce, 0x0838, 0x2001, 0xafe3, - 0x2003, 0x0000, 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, 0x7824, - 0xa065, 0x090c, 0x14f6, 0x2009, 0x0013, 0x080c, 0x80fb, 0x00ce, - 0x0005, 0x00c6, 0x00d6, 0x3900, 0xa082, 0xb0e8, 0x1210, 0x080c, - 0x7d8d, 0x7824, 0xa005, 0x090c, 0x14f6, 0x781c, 0xa06d, 0x090c, - 0x14f6, 0x6800, 0xc0dc, 0x6802, 0x7924, 0x2160, 0x080c, 0x8078, - 0x693c, 0x81ff, 0x090c, 0x14f6, 0x8109, 0x693e, 0x6854, 0xa015, - 0x0110, 0x7a1e, 0x0010, 0x7918, 0x791e, 0x7807, 0x0000, 0x7827, - 0x0000, 0x00de, 0x00ce, 0x080c, 0x6c50, 0x0888, 0x6104, 0xa186, - 0x0002, 0x0128, 0xa186, 0x0004, 0x0110, 0x0804, 0x66f7, 0x7808, - 0xac06, 0x0904, 0x66f7, 0x080c, 0x6b73, 0x080c, 0x67ee, 0x00ce, - 0x080c, 0x6c50, 0x0804, 0x66e5, 0x00c6, 0x6027, 0x0002, 0x62c8, - 0x60c4, 0xa205, 0x1178, 0x793c, 0xa1e5, 0x0000, 0x0130, 0x2009, - 0x0049, 0x080c, 0x80a7, 0x00ce, 0x0005, 0x2011, 0xafe6, 0x2013, - 0x0000, 0x0cc8, 0x3908, 0xa192, 0xb0e8, 0x1210, 0x080c, 0x7d8d, - 0x793c, 0x81ff, 0x0d90, 0x793c, 0xa188, 0x0007, 0x210c, 0xa18e, - 0x0006, 0x1138, 0x6014, 0xa084, 0x0184, 0xa085, 0x0012, 0x6016, - 0x0c10, 0x6014, 0xa084, 0x0184, 0xa085, 0x0016, 0x6016, 0x08d8, - 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, - 0x2c08, 0x2061, 0xafc7, 0x6020, 0x8000, 0x6022, 0x6010, 0xa005, - 0x0148, 0xa080, 0x0003, 0x2102, 0x6112, 0x012e, 0x00ce, 0x001e, - 0x000e, 0x0005, 0x6116, 0x6112, 0x0cc0, 0x00d6, 0x2069, 0xafc7, - 0x6000, 0xd0d4, 0x0168, 0x6820, 0x8000, 0x6822, 0xa086, 0x0001, - 0x1110, 0x2c00, 0x681e, 0x6804, 0xa084, 0x0007, 0x0804, 0x6c56, - 0xc0d5, 0x6002, 0x6818, 0xa005, 0x0158, 0x6056, 0x605b, 0x0000, - 0x0006, 0x2c00, 0x681a, 0x00de, 0x685a, 0x2069, 0xafc7, 0x0c18, - 0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, 0x08e8, 0x0006, 0x0016, - 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, - 0xafc7, 0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0148, 0xa080, - 0x0003, 0x2102, 0x610a, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, - 0x610e, 0x610a, 0x0cc0, 0x00c6, 0x600f, 0x0000, 0x2c08, 0x2061, - 0xafc7, 0x6034, 0xa005, 0x0130, 0xa080, 0x0003, 0x2102, 0x6136, - 0x00ce, 0x0005, 0x613a, 0x6136, 0x0cd8, 0x00f6, 0x00e6, 0x00d6, - 0x00c6, 0x0076, 0x0066, 0x0026, 0x0016, 0x0006, 0x0126, 0x2071, - 0xafc7, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0904, - 0x6889, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x6884, - 0x87ff, 0x0120, 0x6050, 0xa106, 0x1904, 0x6884, 0x703c, 0xac06, - 0x1170, 0x0036, 0x2019, 0x0001, 0x080c, 0x7a64, 0x7033, 0x0000, - 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x003e, 0x7038, - 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, 0xac36, 0x1140, 0x2c00, - 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, 0x660c, - 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, - 0x0000, 0x080c, 0x9596, 0x0198, 0x6010, 0x2068, 0x601c, 0xa086, - 0x0003, 0x1510, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, - 0x97fd, 0x080c, 0xabfa, 0x080c, 0x510c, 0x080c, 0x9742, 0x080c, - 0x974e, 0x00ce, 0x0804, 0x682e, 0x2c78, 0x600c, 0x2060, 0x0804, - 0x682e, 0x012e, 0x000e, 0x001e, 0x002e, 0x006e, 0x007e, 0x00ce, - 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x19d0, - 0x080c, 0xabfa, 0x080c, 0xa91f, 0x0c10, 0x0006, 0x0066, 0x00c6, - 0x00d6, 0x00f6, 0x2031, 0x0000, 0x0126, 0x2091, 0x8000, 0x2079, - 0xafc7, 0x7838, 0xa065, 0x0558, 0x600c, 0x0006, 0x600f, 0x0000, - 0x783c, 0xac06, 0x1170, 0x0036, 0x2019, 0x0001, 0x080c, 0x7a64, - 0x7833, 0x0000, 0x783f, 0x0000, 0x7843, 0x0000, 0x7847, 0x0000, - 0x003e, 0x080c, 0x9596, 0x0178, 0x6010, 0x2068, 0x601c, 0xa086, - 0x0003, 0x11b0, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, - 0x510c, 0x080c, 0x9742, 0x080c, 0x974e, 0x000e, 0x0898, 0x7e3a, - 0x7e36, 0x012e, 0x00fe, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, - 0x601c, 0xa086, 0x0006, 0x1d30, 0x080c, 0xa91f, 0x0c60, 0x0016, - 0x0026, 0x0086, 0x2041, 0x0000, 0x0099, 0x080c, 0x69a9, 0x008e, - 0x002e, 0x001e, 0x0005, 0x00f6, 0x0126, 0x2079, 0xafc7, 0x2091, - 0x8000, 0x080c, 0x6a36, 0x080c, 0x6aa8, 0x012e, 0x00fe, 0x0005, - 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0016, 0x0006, 0x0126, - 0x2091, 0x8000, 0x2071, 0xafc7, 0x7614, 0x2660, 0x2678, 0x8cff, - 0x0904, 0x6985, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, - 0x6980, 0x88ff, 0x0120, 0x6050, 0xa106, 0x1904, 0x6980, 0x7024, - 0xac06, 0x1538, 0x2069, 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, - 0x6581, 0x080c, 0x7834, 0x68c3, 0x0000, 0x080c, 0x7ca8, 0x7027, - 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, - 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, - 0x0110, 0x6827, 0x0001, 0x003e, 0x0020, 0x6003, 0x0009, 0x630a, - 0x04b8, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616, 0x7010, 0xac36, - 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, - 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, - 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, 0x9596, 0x0188, - 0x601c, 0xa086, 0x0003, 0x1510, 0x6837, 0x0103, 0x6b4a, 0x6847, - 0x0000, 0x080c, 0x97fd, 0x080c, 0xabfa, 0x080c, 0x510c, 0x080c, - 0x9742, 0x080c, 0x974e, 0x080c, 0x7b88, 0x00ce, 0x0804, 0x690f, - 0x2c78, 0x600c, 0x2060, 0x0804, 0x690f, 0x012e, 0x000e, 0x001e, - 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, - 0x0006, 0x1128, 0x080c, 0xabfa, 0x080c, 0xa91f, 0x0c10, 0x601c, - 0xa086, 0x0002, 0x1128, 0x6004, 0xa086, 0x0085, 0x0968, 0x08c8, - 0x601c, 0xa086, 0x0005, 0x19a8, 0x6004, 0xa086, 0x0085, 0x0d50, - 0x0880, 0x00c6, 0x0006, 0x0126, 0x2091, 0x8000, 0xa280, 0xae34, - 0x2004, 0xa065, 0x0904, 0x6a32, 0x00f6, 0x00e6, 0x00d6, 0x0066, - 0x2071, 0xafc7, 0x6654, 0x7018, 0xac06, 0x1108, 0x761a, 0x701c, - 0xac06, 0x1130, 0x86ff, 0x1118, 0x7018, 0x701e, 0x0008, 0x761e, - 0x6058, 0xa07d, 0x0108, 0x7e56, 0xa6ed, 0x0000, 0x0110, 0x2f00, - 0x685a, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, - 0x6002, 0x080c, 0x4c07, 0x0904, 0x6a2e, 0x7624, 0x86ff, 0x05e8, - 0xa680, 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, 0x2069, 0x0100, - 0x68c0, 0xa005, 0x0548, 0x080c, 0x6581, 0x080c, 0x7834, 0x68c3, - 0x0000, 0x080c, 0x7ca8, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, - 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, - 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, - 0x00de, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, 0x2660, - 0x080c, 0x974e, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, 0x6003, - 0x0009, 0x630a, 0x00ce, 0x0804, 0x69d9, 0x8dff, 0x0158, 0x6837, - 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x97fd, 0x080c, 0xabfa, - 0x080c, 0x510c, 0x080c, 0x7b88, 0x0804, 0x69d9, 0x006e, 0x00de, - 0x00ee, 0x00fe, 0x012e, 0x000e, 0x00ce, 0x0005, 0x0006, 0x0066, - 0x00c6, 0x00d6, 0x2031, 0x0000, 0x7814, 0xa065, 0x0904, 0x6a88, - 0x600c, 0x0006, 0x600f, 0x0000, 0x7824, 0xac06, 0x1540, 0x2069, - 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x6581, 0x080c, 0x7834, - 0x68c3, 0x0000, 0x080c, 0x7ca8, 0x7827, 0x0000, 0x0036, 0x2069, - 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, - 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, - 0x003e, 0x0028, 0x6003, 0x0009, 0x630a, 0x2c30, 0x00b0, 0x6010, - 0x2068, 0x080c, 0x9596, 0x0168, 0x601c, 0xa086, 0x0003, 0x11b8, - 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x510c, 0x080c, - 0x9742, 0x080c, 0x974e, 0x080c, 0x7b88, 0x000e, 0x0804, 0x6a3d, - 0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x601c, - 0xa086, 0x0006, 0x1118, 0x080c, 0xa91f, 0x0c58, 0x601c, 0xa086, - 0x0002, 0x1128, 0x6004, 0xa086, 0x0085, 0x09d0, 0x0c10, 0x601c, - 0xa086, 0x0005, 0x19f0, 0x6004, 0xa086, 0x0085, 0x0d60, 0x08c8, - 0x0006, 0x0066, 0x00c6, 0x00d6, 0x7818, 0xa065, 0x0904, 0x6b0e, - 0x6054, 0x0006, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, - 0xc0dc, 0x6002, 0x080c, 0x4c07, 0x0904, 0x6b0b, 0x7e24, 0x86ff, - 0x05e8, 0xa680, 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, 0x2069, - 0x0100, 0x68c0, 0xa005, 0x0548, 0x080c, 0x6581, 0x080c, 0x7834, - 0x68c3, 0x0000, 0x080c, 0x7ca8, 0x7827, 0x0000, 0x0036, 0x2069, - 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, - 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, - 0x003e, 0x00de, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, - 0x2660, 0x080c, 0x974e, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, - 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x6aba, 0x8dff, 0x0138, - 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x510c, 0x080c, - 0x7b88, 0x0804, 0x6aba, 0x000e, 0x0804, 0x6aad, 0x781e, 0x781a, - 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x00e6, 0x00d6, 0x0066, - 0x6000, 0xd0dc, 0x0188, 0x604c, 0xa06d, 0x0170, 0x6848, 0xa606, - 0x1158, 0x2071, 0xafc7, 0x7024, 0xa035, 0x0130, 0xa080, 0x0004, - 0x2004, 0xad06, 0x1108, 0x0021, 0x006e, 0x00de, 0x00ee, 0x0005, - 0x00f6, 0x2079, 0x0100, 0x78c0, 0xa005, 0x1138, 0x00c6, 0x2660, - 0x6003, 0x0009, 0x630a, 0x00ce, 0x04a0, 0x080c, 0x7834, 0x78c3, - 0x0000, 0x080c, 0x7ca8, 0x7027, 0x0000, 0x0036, 0x2079, 0x0140, - 0x7b04, 0xa384, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, - 0x2079, 0x0100, 0x7824, 0xd084, 0x0110, 0x7827, 0x0001, 0x080c, - 0x7ca8, 0x003e, 0x080c, 0x4c07, 0x00c6, 0x603c, 0xa005, 0x0110, - 0x8001, 0x603e, 0x2660, 0x080c, 0x8078, 0x00ce, 0x6837, 0x0103, - 0x6b4a, 0x6847, 0x0000, 0x080c, 0x97fd, 0x080c, 0x510c, 0x080c, - 0x7b88, 0x00fe, 0x0005, 0x00e6, 0x00c6, 0x2071, 0xafc7, 0x7004, - 0xa084, 0x0007, 0x0002, 0x6b85, 0x6b88, 0x6b9e, 0x6bb7, 0x6bf0, - 0x6b85, 0x6b83, 0x6b83, 0x080c, 0x14f6, 0x00ce, 0x00ee, 0x0005, - 0x7024, 0xa065, 0x0148, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, - 0x0150, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000, - 0x00ce, 0x00ee, 0x0005, 0x7216, 0x7212, 0x0cb0, 0x6018, 0x2060, - 0x080c, 0x4c07, 0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001, 0x7022, - 0x0120, 0x6054, 0xa015, 0x0140, 0x721e, 0x7007, 0x0000, 0x7027, - 0x0000, 0x00ce, 0x00ee, 0x0005, 0x7218, 0x721e, 0x0cb0, 0x7024, - 0xa065, 0x0598, 0x700c, 0xac06, 0x1160, 0x080c, 0x7b88, 0x600c, - 0xa015, 0x0120, 0x720e, 0x600f, 0x0000, 0x0428, 0x720e, 0x720a, - 0x0410, 0x7014, 0xac06, 0x1160, 0x080c, 0x7b88, 0x600c, 0xa015, - 0x0120, 0x7216, 0x600f, 0x0000, 0x00b0, 0x7216, 0x7212, 0x0098, - 0x6018, 0x2060, 0x080c, 0x4c07, 0x6000, 0xc0dc, 0x6002, 0x080c, - 0x7b88, 0x701c, 0xa065, 0x0138, 0x6054, 0xa015, 0x0110, 0x721e, - 0x0010, 0x7218, 0x721e, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005, - 0x7024, 0xa065, 0x0140, 0x080c, 0x7b88, 0x600c, 0xa015, 0x0150, - 0x720e, 0x600f, 0x0000, 0x080c, 0x7ca8, 0x7027, 0x0000, 0x00ce, - 0x00ee, 0x0005, 0x720e, 0x720a, 0x0cb0, 0x00d6, 0x2069, 0xafc7, - 0x6830, 0xa084, 0x0003, 0x0002, 0x6c12, 0x6c14, 0x6c38, 0x6c10, - 0x080c, 0x14f6, 0x00de, 0x0005, 0x00c6, 0x6840, 0xa086, 0x0001, - 0x01b8, 0x683c, 0xa065, 0x0130, 0x600c, 0xa015, 0x0170, 0x6a3a, - 0x600f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x2011, 0xafe6, - 0x2013, 0x0000, 0x00ce, 0x00de, 0x0005, 0x683a, 0x6836, 0x0c90, - 0x6843, 0x0000, 0x6838, 0xa065, 0x0d68, 0x6003, 0x0003, 0x0c50, - 0x00c6, 0x6843, 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0168, - 0x600c, 0xa015, 0x0130, 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000, - 0x0020, 0x683f, 0x0000, 0x683a, 0x6836, 0x00ce, 0x00de, 0x0005, - 0x00d6, 0x2069, 0xafc7, 0x6804, 0xa084, 0x0007, 0x0002, 0x6c61, - 0x6cfd, 0x6cfd, 0x6cfd, 0x6cfd, 0x6cff, 0x6c5f, 0x6c5f, 0x080c, - 0x14f6, 0x6820, 0xa005, 0x1110, 0x00de, 0x0005, 0x00c6, 0x680c, - 0xa065, 0x0150, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x080c, - 0x6d49, 0x00ce, 0x00de, 0x0005, 0x6814, 0xa065, 0x0150, 0x6807, - 0x0001, 0x6826, 0x682b, 0x0000, 0x080c, 0x6d49, 0x00ce, 0x00de, - 0x0005, 0x00e6, 0x0036, 0x6a1c, 0xa2f5, 0x0000, 0x0904, 0x6cf9, - 0x704c, 0xa00d, 0x0118, 0x7088, 0xa005, 0x01a0, 0x7054, 0xa075, - 0x0120, 0xa20e, 0x0904, 0x6cf9, 0x0028, 0x6818, 0xa20e, 0x0904, - 0x6cf9, 0x2070, 0x704c, 0xa00d, 0x0d88, 0x7088, 0xa005, 0x1d70, - 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302, 0x1e40, 0x080c, 0x804f, - 0x0904, 0x6cf9, 0x8318, 0x733e, 0x6112, 0x2e10, 0x621a, 0xa180, - 0x0014, 0x2004, 0xa084, 0x00ff, 0x605a, 0xa180, 0x0014, 0x2003, - 0x0000, 0xa180, 0x0015, 0x2004, 0xa08a, 0x199a, 0x0210, 0x2001, - 0x1999, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x003e, 0x00f6, - 0x2c78, 0x71a0, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x1110, 0xd1bc, - 0x0150, 0x7100, 0xd1f4, 0x0120, 0x7114, 0xa18c, 0x00ff, 0x0040, - 0x2009, 0x0000, 0x0028, 0xa1e0, 0x2be6, 0x2c0d, 0xa18c, 0x00ff, - 0x2061, 0x0100, 0x619a, 0x080c, 0x736f, 0x7300, 0xc3dd, 0x7302, - 0x6807, 0x0002, 0x2f18, 0x6b26, 0x682b, 0x0000, 0x781f, 0x0003, - 0x7803, 0x0001, 0x7807, 0x0040, 0x00fe, 0x00ee, 0x00ce, 0x00de, - 0x0005, 0x003e, 0x00ee, 0x00ce, 0x0cd0, 0x00de, 0x0005, 0x00c6, - 0x680c, 0xa065, 0x0138, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, - 0x080c, 0x6d49, 0x00ce, 0x00de, 0x0005, 0x00f6, 0x00d6, 0x2069, - 0xafc7, 0x6830, 0xa086, 0x0000, 0x11c0, 0x2001, 0xad0c, 0x200c, - 0xd1bc, 0x1550, 0x6838, 0xa07d, 0x0180, 0x6833, 0x0001, 0x683e, - 0x6847, 0x0000, 0x0126, 0x00f6, 0x2091, 0x2400, 0x002e, 0x080c, - 0x1ee6, 0x1130, 0x012e, 0x080c, 0x76a5, 0x00de, 0x00fe, 0x0005, - 0x012e, 0xe000, 0x6843, 0x0000, 0x7803, 0x0002, 0x780c, 0xa015, - 0x0140, 0x6a3a, 0x780f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, - 0x0c60, 0x683a, 0x6836, 0x0cc0, 0xc1bc, 0x2102, 0x080c, 0x57d1, - 0x0888, 0x601c, 0xa084, 0x000f, 0x000b, 0x0005, 0x6d57, 0x6d5c, - 0x7210, 0x732c, 0x6d5c, 0x7210, 0x732c, 0x6d57, 0x6d5c, 0x080c, - 0x6b73, 0x080c, 0x6c50, 0x0005, 0x0156, 0x0136, 0x0146, 0x00c6, - 0x00f6, 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x14f6, 0x6118, 0x2178, - 0x79a0, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, - 0x7900, 0xd1f4, 0x0120, 0x7914, 0xa18c, 0x00ff, 0x0040, 0x2009, - 0x0000, 0x0028, 0xa1f8, 0x2be6, 0x2f0d, 0xa18c, 0x00ff, 0x2c78, - 0x2061, 0x0100, 0x619a, 0xa08a, 0x0040, 0x1a04, 0x6dd0, 0x0033, - 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, 0x0005, 0x6e7c, 0x6ec7, - 0x6ef4, 0x6fc1, 0x6fef, 0x6ff7, 0x701d, 0x702e, 0x703f, 0x7047, - 0x705d, 0x7047, 0x70b7, 0x702e, 0x70d8, 0x70e0, 0x703f, 0x70e0, - 0x70f1, 0x6dce, 0x6dce, 0x6dce, 0x6dce, 0x6dce, 0x6dce, 0x6dce, - 0x6dce, 0x6dce, 0x6dce, 0x6dce, 0x790d, 0x7932, 0x7947, 0x796a, - 0x798b, 0x701d, 0x6dce, 0x701d, 0x7047, 0x6dce, 0x6ef4, 0x6fc1, - 0x6dce, 0x7daa, 0x7047, 0x6dce, 0x7dca, 0x7047, 0x6dce, 0x703f, - 0x6e75, 0x6de0, 0x6dce, 0x7def, 0x7e64, 0x7f3b, 0x6dce, 0x7f4c, - 0x7018, 0x7f68, 0x6dce, 0x79a0, 0x7fc3, 0x6dce, 0x080c, 0x14f6, - 0x2100, 0x0033, 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, 0x0005, - 0x6dde, 0x6dde, 0x6dde, 0x6e14, 0x6e32, 0x6e48, 0x080c, 0x14f6, - 0x00d6, 0x20a1, 0x020b, 0x080c, 0x710e, 0x7810, 0x2068, 0x20a3, - 0x2414, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x683c, 0x20a2, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x6850, - 0x20a2, 0x6854, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, - 0x0018, 0x080c, 0x7821, 0x00de, 0x0005, 0x00d6, 0x7818, 0x2068, - 0x68a0, 0x2069, 0xad00, 0x6ad0, 0xd2ac, 0x1110, 0xd0bc, 0x0110, - 0xa085, 0x0001, 0x00de, 0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c, - 0x710e, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x7810, 0xa0e8, 0x000f, - 0x6808, 0x20a2, 0x680c, 0x20a2, 0x6810, 0x20a2, 0x6814, 0x20a2, - 0x6818, 0x20a2, 0x681c, 0x20a2, 0x60c3, 0x0010, 0x080c, 0x7821, - 0x00de, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x710e, - 0x20a3, 0x7800, 0x20a3, 0x0000, 0x7808, 0x8007, 0x20a2, 0x20a3, - 0x0000, 0x60c3, 0x0008, 0x080c, 0x7821, 0x014e, 0x015e, 0x0005, - 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0200, - 0x20a3, 0x0000, 0x20a3, 0xdf10, 0x20a3, 0x0034, 0x2099, 0xad05, - 0x20a9, 0x0004, 0x53a6, 0x2099, 0xad01, 0x20a9, 0x0004, 0x53a6, - 0x2099, 0xafad, 0x20a9, 0x001a, 0x3304, 0x8007, 0x20a2, 0x9398, - 0x1f04, 0x6e64, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x004c, - 0x080c, 0x7821, 0x014e, 0x015e, 0x0005, 0x2001, 0xad14, 0x2004, - 0x609a, 0x080c, 0x7821, 0x0005, 0x20a1, 0x020b, 0x080c, 0x710e, - 0x20a3, 0x5200, 0x20a3, 0x0000, 0x00d6, 0x2069, 0xad51, 0x6804, - 0xd084, 0x0150, 0x6828, 0x20a3, 0x0000, 0x0016, 0x080c, 0x268a, - 0x21a2, 0x001e, 0x00de, 0x0028, 0x00de, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a9, 0x0004, 0x2099, 0xad05, 0x53a6, 0x20a9, 0x0004, - 0x2099, 0xad01, 0x53a6, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x1138, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0238, 0x2001, - 0xad1b, 0x20a6, 0x2001, 0xad1c, 0x20a6, 0x0040, 0x20a3, 0x0000, - 0x2001, 0xad14, 0x2004, 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x001c, 0x080c, 0x7821, 0x0005, 0x20a1, - 0x020b, 0x080c, 0x710e, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x2001, - 0xad34, 0x2004, 0xd0ac, 0x1138, 0x7818, 0xa080, 0x0028, 0x2004, - 0xa082, 0x007f, 0x0238, 0x2001, 0xad1b, 0x20a6, 0x2001, 0xad1c, - 0x20a6, 0x0040, 0x20a3, 0x0000, 0x2001, 0xad14, 0x2004, 0xa084, - 0x00ff, 0x20a2, 0x20a9, 0x0004, 0x2099, 0xad05, 0x53a6, 0x60c3, - 0x0010, 0x080c, 0x7821, 0x0005, 0x20a1, 0x020b, 0x080c, 0x710e, - 0x00c6, 0x7818, 0x2060, 0x2001, 0x0000, 0x080c, 0x5037, 0x00ce, - 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x1130, 0x20a3, - 0x0400, 0x620c, 0xc2b4, 0x620e, 0x0010, 0x20a3, 0x0300, 0x20a3, - 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x1904, - 0x6f83, 0x2001, 0xad34, 0x2004, 0xd0a4, 0x01c8, 0x2099, 0xaf8d, - 0x33a6, 0x9398, 0x20a3, 0x0000, 0x9398, 0x3304, 0xa084, 0x2000, - 0x20a2, 0x9398, 0x33a6, 0x9398, 0x20a3, 0x0000, 0x9398, 0x2001, - 0x2710, 0x20a2, 0x9398, 0x33a6, 0x9398, 0x33a6, 0x00d0, 0x2099, - 0xaf8d, 0x33a6, 0x9398, 0x33a6, 0x9398, 0x3304, 0x080c, 0x574f, - 0x1118, 0xa084, 0x37ff, 0x0010, 0xa084, 0x3fff, 0x20a2, 0x9398, - 0x33a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a9, 0x0004, 0x2099, 0xad05, 0x53a6, 0x20a9, 0x0004, - 0x2099, 0xad01, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, - 0x6f5d, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x6f63, 0x2099, - 0xaf95, 0x3304, 0xc0dd, 0x20a2, 0x2001, 0xad71, 0x2004, 0xd0e4, - 0x0158, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x9398, 0x9398, 0x9398, - 0x33a6, 0x20a9, 0x0004, 0x0010, 0x20a9, 0x0007, 0x20a3, 0x0000, - 0x1f04, 0x6f7e, 0x0468, 0x2001, 0xad34, 0x2004, 0xd0a4, 0x0140, - 0x2001, 0xaf8e, 0x2004, 0x60e3, 0x0000, 0x080c, 0x26cb, 0x60e2, - 0x2099, 0xaf8d, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0004, 0x2099, - 0xad05, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xad01, 0x53a6, 0x20a9, - 0x0008, 0x20a3, 0x0000, 0x1f04, 0x6fa1, 0x20a9, 0x0008, 0x20a3, - 0x0000, 0x1f04, 0x6fa7, 0x2099, 0xaf95, 0x20a9, 0x0008, 0x53a6, - 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x6fb2, 0x20a9, 0x000a, - 0x20a3, 0x0000, 0x1f04, 0x6fb8, 0x60c3, 0x0074, 0x080c, 0x7821, - 0x0005, 0x20a1, 0x020b, 0x080c, 0x710e, 0x20a3, 0x2010, 0x20a3, - 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006, 0x20a2, 0x20a2, - 0x20a2, 0x20a2, 0x20a2, 0x00f6, 0x2079, 0xad51, 0x7904, 0x00fe, - 0xd1ac, 0x1110, 0xa085, 0x0020, 0xd1a4, 0x0110, 0xa085, 0x0010, - 0xa085, 0x0002, 0x00d6, 0x0804, 0x7099, 0x20a2, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x7821, 0x0005, 0x20a1, - 0x020b, 0x080c, 0x710e, 0x20a3, 0x5000, 0x0804, 0x6f0f, 0x20a1, - 0x020b, 0x080c, 0x710e, 0x20a3, 0x2110, 0x20a3, 0x0014, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x7821, 0x0005, - 0x20a1, 0x020b, 0x080c, 0x71a2, 0x0020, 0x20a1, 0x020b, 0x080c, - 0x71aa, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x0004, 0x080c, 0x7821, 0x0005, 0x20a1, 0x020b, - 0x080c, 0x71aa, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, - 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x080c, 0x7821, 0x0005, 0x20a1, - 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0200, 0x0804, 0x6f0f, 0x20a1, - 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, - 0xa005, 0x0110, 0x20a2, 0x0010, 0x20a3, 0x0003, 0x7810, 0x20a2, - 0x60c3, 0x0008, 0x080c, 0x7821, 0x0005, 0x00d6, 0x20a1, 0x020b, - 0x080c, 0x71aa, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, - 0x7818, 0x2068, 0x6894, 0xa086, 0x0014, 0x1178, 0x6998, 0xa184, - 0xc000, 0x1140, 0xd1ec, 0x0118, 0x20a3, 0x2100, 0x0040, 0x20a3, - 0x0100, 0x0028, 0x20a3, 0x0400, 0x0010, 0x20a3, 0x0700, 0xa006, - 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x00f6, 0x2079, 0xad51, - 0x7904, 0x00fe, 0xd1ac, 0x1110, 0xa085, 0x0020, 0xd1a4, 0x0110, - 0xa085, 0x0010, 0x2009, 0xad73, 0x210c, 0xd184, 0x1110, 0xa085, - 0x0002, 0x0026, 0x2009, 0xad71, 0x210c, 0xd1e4, 0x0130, 0xc0c5, - 0xa094, 0x0030, 0xa296, 0x0010, 0x0140, 0xd1ec, 0x0130, 0xa094, - 0x0030, 0xa296, 0x0010, 0x0108, 0xc0bd, 0x002e, 0x20a2, 0x20a2, - 0x20a2, 0x60c3, 0x0014, 0x080c, 0x7821, 0x00de, 0x0005, 0x20a1, - 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, - 0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x7821, 0x0005, - 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0200, 0x0804, 0x6e82, - 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0100, 0x20a3, 0x0000, - 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x080c, 0x7821, - 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x080c, - 0x71aa, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3, - 0x0000, 0x60c3, 0x0008, 0x080c, 0x7821, 0x0005, 0x0026, 0x0036, - 0x0046, 0x2019, 0x3200, 0x2021, 0x0800, 0x0038, 0x0026, 0x0036, - 0x0046, 0x2019, 0x2200, 0x2021, 0x0100, 0x20e1, 0x9080, 0x20e1, - 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x11a0, - 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffe, 0x20a3, 0x0000, 0x2011, - 0xad14, 0x2214, 0x2001, 0xaf9d, 0x2004, 0xa005, 0x0118, 0x2011, - 0xad1c, 0x2214, 0x22a2, 0x04d0, 0xa286, 0x007f, 0x1138, 0x00d6, - 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffd, 0x00c8, 0x2001, 0xad34, - 0x2004, 0xd0ac, 0x1110, 0xd2bc, 0x01c8, 0xa286, 0x0080, 0x00d6, - 0x1130, 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffc, 0x0040, 0xa2e8, - 0xae34, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, - 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0080, 0x00d6, 0xa2e8, - 0xae34, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x00de, - 0x20a3, 0x0000, 0x2011, 0xad14, 0x2214, 0x22a2, 0xa485, 0x0029, - 0x20a2, 0x004e, 0x003e, 0x20a3, 0x0000, 0x080c, 0x7810, 0x22a2, - 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x002e, 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, - 0x20a3, 0x02ff, 0x2011, 0xfffc, 0x22a2, 0x00d6, 0x2069, 0xad1b, - 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x20a3, 0x2029, 0x20a3, 0x0000, - 0x08e0, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, - 0x0000, 0x0005, 0x0026, 0x0036, 0x0046, 0x2019, 0x3300, 0x2021, - 0x0800, 0x0038, 0x0026, 0x0036, 0x0046, 0x2019, 0x2300, 0x2021, - 0x0100, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, - 0x02d8, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa305, 0x20a2, - 0x6814, 0x20a2, 0x6810, 0xa005, 0x1140, 0x6814, 0xa005, 0x1128, - 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0028, 0x2069, 0xad1b, 0x2da6, - 0x8d68, 0x2da6, 0x00de, 0x0080, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, - 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, - 0x2011, 0xad14, 0x2214, 0x22a2, 0xa485, 0x0098, 0x20a2, 0x20a3, - 0x0000, 0x004e, 0x003e, 0x080c, 0x7810, 0x22a2, 0x20a3, 0x0000, - 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, - 0x0005, 0x080c, 0x7810, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, - 0x7810, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, - 0x00c6, 0x00f6, 0x6004, 0xa08a, 0x0085, 0x0a0c, 0x14f6, 0xa08a, - 0x008c, 0x1a0c, 0x14f6, 0x6118, 0x2178, 0x79a0, 0x2011, 0xad34, - 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x7900, 0xd1f4, 0x0120, - 0x7914, 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1f8, - 0x2be6, 0x2f0d, 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, - 0xa082, 0x0085, 0x001b, 0x00fe, 0x00ce, 0x0005, 0x7247, 0x7251, - 0x726c, 0x7245, 0x7245, 0x7245, 0x7247, 0x080c, 0x14f6, 0x0146, - 0x20a1, 0x020b, 0x04a1, 0x60c3, 0x0000, 0x080c, 0x7821, 0x014e, - 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c, 0x72b8, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, 0x20a2, 0x20a3, 0x0000, - 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c, - 0x080c, 0x7821, 0x014e, 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c, - 0x72f2, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x60c3, 0x0004, 0x080c, 0x7821, 0x014e, 0x0005, 0x0026, - 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, - 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0288, - 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, - 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, - 0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x8100, - 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14, - 0x2214, 0x22a2, 0x20a3, 0x0009, 0x20a3, 0x0000, 0x0804, 0x7175, - 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, - 0x0288, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x8400, - 0x20a2, 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, - 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, - 0x8400, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, - 0xad14, 0x2214, 0x22a2, 0x2001, 0x0099, 0x20a2, 0x20a3, 0x0000, - 0x0804, 0x7201, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, - 0xa080, 0x0028, 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118, - 0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, - 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, - 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, - 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, - 0x0000, 0x2011, 0xad14, 0x2214, 0x22a2, 0x2001, 0x0099, 0x20a2, - 0x20a3, 0x0000, 0x0804, 0x7201, 0x00c6, 0x00f6, 0x2c78, 0x7804, - 0xa08a, 0x0040, 0x0a0c, 0x14f6, 0xa08a, 0x0053, 0x1a0c, 0x14f6, - 0x7918, 0x2160, 0x61a0, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, - 0xd1bc, 0x0150, 0x6100, 0xd1f4, 0x0120, 0x6114, 0xa18c, 0x00ff, - 0x0040, 0x2009, 0x0000, 0x0028, 0xa1e0, 0x2be6, 0x2c0d, 0xa18c, - 0x00ff, 0x2061, 0x0100, 0x619a, 0xa082, 0x0040, 0x001b, 0x00fe, - 0x00ce, 0x0005, 0x736f, 0x747b, 0x7418, 0x761a, 0x736d, 0x736d, - 0x736d, 0x736d, 0x736d, 0x736d, 0x736d, 0x7b41, 0x7b51, 0x7b61, - 0x7b71, 0x736d, 0x7f79, 0x736d, 0x7b30, 0x080c, 0x14f6, 0x00d6, - 0x0156, 0x0146, 0x780b, 0xffff, 0x20a1, 0x020b, 0x080c, 0x73cf, - 0x7910, 0x2168, 0x6948, 0x7952, 0x21a2, 0xa016, 0x22a2, 0x22a2, - 0x22a2, 0x694c, 0xa184, 0x000f, 0x1118, 0x2001, 0x0005, 0x0040, - 0xd184, 0x0118, 0x2001, 0x0004, 0x0018, 0xa084, 0x0006, 0x8004, - 0x0016, 0x2008, 0x7858, 0xa084, 0x00ff, 0x8007, 0xa105, 0x001e, - 0x20a2, 0xd1ac, 0x0118, 0x20a3, 0x0002, 0x0048, 0xd1b4, 0x0118, - 0x20a3, 0x0001, 0x0020, 0x20a3, 0x0000, 0x2230, 0x0010, 0x6a80, - 0x6e7c, 0x20a9, 0x0008, 0x0136, 0xad88, 0x0017, 0x2198, 0x20a1, - 0x021b, 0x53a6, 0x013e, 0x20a1, 0x020b, 0x22a2, 0x26a2, 0x60c3, - 0x0020, 0x20e1, 0x9080, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, - 0x6016, 0x2001, 0xafe3, 0x2003, 0x07d0, 0x2001, 0xafe2, 0x2003, - 0x0009, 0x080c, 0x17bf, 0x014e, 0x015e, 0x00de, 0x0005, 0x20e1, - 0x9080, 0x20e1, 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, - 0xa294, 0x00ff, 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, - 0x2019, 0xad34, 0x231c, 0xd3ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, - 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, - 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, - 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2, - 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2009, 0xad14, 0x210c, - 0x21a2, 0x20a3, 0x0829, 0x20a3, 0x0000, 0x22a2, 0x20a3, 0x0000, - 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x0005, - 0x00d6, 0x0156, 0x0136, 0x0146, 0x20a1, 0x020b, 0x00c1, 0x7810, - 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, 0x6880, 0x20a2, 0x687c, - 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x000c, - 0x080c, 0x7821, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x0026, - 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, - 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, - 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, - 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, - 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, - 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14, 0x2214, - 0x22a2, 0x20a3, 0x0889, 0x20a3, 0x0000, 0x080c, 0x7810, 0x22a2, - 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x002e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x7810, - 0xa06d, 0x080c, 0x5025, 0x0148, 0x684c, 0xa084, 0x2020, 0xa086, - 0x2020, 0x1118, 0x7820, 0xc0cd, 0x7822, 0x20a1, 0x020b, 0x080c, - 0x75d0, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810, - 0xa084, 0xf000, 0x1130, 0x7810, 0xa084, 0x0700, 0x8007, 0x0043, - 0x0010, 0xa006, 0x002b, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, - 0x74b2, 0x7547, 0x7550, 0x7579, 0x758c, 0x75a7, 0x75b0, 0x74b0, - 0x080c, 0x14f6, 0x0016, 0x0036, 0x694c, 0xa18c, 0x0003, 0x0118, - 0xa186, 0x0003, 0x1170, 0x6b78, 0x7820, 0xd0cc, 0x0108, 0xc3e5, - 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x003e, 0x001e, 0x0804, - 0x7583, 0xa186, 0x0001, 0x190c, 0x14f6, 0x6b78, 0x7820, 0xd0cc, - 0x0108, 0xc3e5, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, - 0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, - 0x0300, 0x0904, 0x7541, 0xd3c4, 0x0110, 0x687c, 0xa108, 0xd3cc, - 0x0110, 0x6874, 0xa108, 0x0156, 0x20a9, 0x000d, 0xad80, 0x0020, - 0x201c, 0x831f, 0x23a2, 0x8000, 0x1f04, 0x74f0, 0x015e, 0x22a2, - 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0904, 0x7541, 0x20a1, 0x020b, - 0x20e1, 0x9080, 0x20e1, 0x4000, 0x0006, 0x7818, 0xa080, 0x0028, - 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, - 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, - 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, - 0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0700, - 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14, - 0x2214, 0x22a2, 0x000e, 0x7b20, 0xd3cc, 0x0118, 0x20a3, 0x0889, - 0x0010, 0x20a3, 0x0898, 0x20a2, 0x080c, 0x7810, 0x22a2, 0x20a3, - 0x0000, 0x61c2, 0x003e, 0x001e, 0x080c, 0x7821, 0x0005, 0x2011, - 0x0008, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x0488, - 0x2011, 0x0302, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, - 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2, 0x20a3, 0x0008, - 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000, 0x20a3, 0x0500, - 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3, 0x2500, 0x22a2, - 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032, 0x080c, 0x7821, - 0x0005, 0x2011, 0x0028, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, - 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, - 0x0018, 0x080c, 0x7821, 0x0005, 0x2011, 0x0100, 0x7820, 0xd0cc, - 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, - 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x7854, 0xa084, 0x00ff, 0x20a2, - 0x22a2, 0x22a2, 0x60c3, 0x0020, 0x080c, 0x7821, 0x0005, 0x2011, - 0x0008, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x0888, - 0x0036, 0x7b10, 0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, - 0x1138, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0x003e, 0x0808, - 0x0046, 0x2021, 0x0800, 0x0006, 0x7820, 0xd0cc, 0x000e, 0x0108, - 0xc4e5, 0x24a2, 0x004e, 0x22a2, 0x20a2, 0x003e, 0x0804, 0x7583, - 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, - 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, - 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, - 0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0700, - 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14, - 0x2214, 0x22a2, 0x7820, 0xd0cc, 0x0118, 0x20a3, 0x0889, 0x0010, - 0x20a3, 0x0898, 0x20a3, 0x0000, 0x080c, 0x7810, 0x22a2, 0x20a3, - 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x002e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x0016, 0x0036, - 0x7810, 0xa084, 0x0700, 0x8007, 0x003b, 0x003e, 0x001e, 0x014e, - 0x013e, 0x015e, 0x00de, 0x0005, 0x7634, 0x7634, 0x7636, 0x7634, - 0x7634, 0x7634, 0x7658, 0x7634, 0x080c, 0x14f6, 0x7910, 0xa18c, - 0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003, - 0x00f9, 0x00d6, 0x2069, 0xad51, 0x6804, 0xd0bc, 0x0130, 0x682c, - 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0010, 0x20a3, 0x3f00, 0x00de, - 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, 0x080c, 0x7821, 0x0005, - 0x20a1, 0x020b, 0x2009, 0x0003, 0x0019, 0x20a3, 0x7f00, 0x0c80, - 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, - 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, - 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, - 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, - 0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0100, - 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14, - 0x2214, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x080c, - 0x7810, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x00e6, 0x00d6, 0x00c6, - 0x0056, 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0xad00, 0x7150, - 0x7818, 0x2068, 0x68a0, 0x2028, 0x76d0, 0xd6ac, 0x1130, 0xd0bc, - 0x1120, 0x6910, 0x6a14, 0x7450, 0x0020, 0x6910, 0x6a14, 0x736c, - 0x7470, 0x781c, 0xa0be, 0x0006, 0x0904, 0x775b, 0xa0be, 0x000a, - 0x15e8, 0xa185, 0x0200, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, - 0x2029, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, - 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, - 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, - 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, - 0x609f, 0x0000, 0x080c, 0x8014, 0x2009, 0x07d0, 0x60c4, 0xa084, - 0xfff0, 0xa005, 0x0110, 0x2009, 0x1b58, 0x080c, 0x6586, 0x003e, - 0x004e, 0x005e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x70d0, 0xd0ac, - 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, - 0x646e, 0x0038, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, - 0x646e, 0x6073, 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, - 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, - 0x7808, 0x6086, 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, - 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, - 0x60d7, 0x0000, 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, - 0x6a14, 0xa294, 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x080c, - 0x8014, 0x2009, 0x07d0, 0x60c4, 0xa084, 0xfff0, 0xa005, 0x0110, - 0x2009, 0x1b58, 0x080c, 0x6586, 0x003e, 0x004e, 0x005e, 0x00ce, - 0x00de, 0x00ee, 0x0005, 0x7810, 0x2070, 0x704c, 0xa084, 0x0003, - 0xa086, 0x0002, 0x0904, 0x77b1, 0x2001, 0xad34, 0x2004, 0xd0ac, - 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, - 0x646e, 0x0038, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, - 0x646e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, - 0x00ff, 0x688e, 0x8007, 0x607a, 0x7834, 0x607e, 0x2f00, 0x6086, - 0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, 0x60c6, - 0x707c, 0x60ca, 0x707c, 0x792c, 0xa108, 0x792e, 0x7080, 0x7928, - 0xa109, 0x792a, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, - 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294, - 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x080c, 0x8011, 0x0804, - 0x7749, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x1110, 0xd5bc, 0x0138, - 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, 0x0038, 0xa185, - 0x0700, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x080c, 0x5025, - 0x0180, 0x00d6, 0x7810, 0xa06d, 0x684c, 0x00de, 0xa084, 0x2020, - 0xa086, 0x2020, 0x1130, 0x7820, 0xc0cd, 0x7822, 0x6073, 0x0889, - 0x0010, 0x6073, 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, - 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, - 0x7808, 0x6082, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, - 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, - 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294, - 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x7820, 0xd0cc, 0x0120, - 0x080c, 0x8014, 0x0804, 0x7749, 0x080c, 0x8011, 0x0804, 0x7749, - 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, - 0x8217, 0x0005, 0x00d6, 0x2069, 0xafc7, 0x6843, 0x0001, 0x00de, - 0x0005, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x0019, - 0x080c, 0x6578, 0x0005, 0x0006, 0x6014, 0xa084, 0x0004, 0xa085, - 0x0009, 0x6016, 0x000e, 0x0005, 0x0006, 0x00c6, 0x2061, 0x0100, - 0x6014, 0xa084, 0x0004, 0xa085, 0x0008, 0x6016, 0x00ce, 0x000e, - 0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026, 0x2061, 0x0100, 0x2069, - 0x0140, 0x080c, 0x574f, 0x1178, 0x2001, 0xafe3, 0x2004, 0xa005, - 0x1598, 0x080c, 0x57d1, 0x1118, 0x080c, 0x6578, 0x0468, 0x00c6, - 0x2061, 0xafc7, 0x00d8, 0x6904, 0xa194, 0x4000, 0x0550, 0x08a1, - 0x6803, 0x1000, 0x6803, 0x0000, 0x00c6, 0x2061, 0xafc7, 0x6128, - 0xa192, 0x00c8, 0x1258, 0x8108, 0x612a, 0x6124, 0x00ce, 0x81ff, - 0x0198, 0x080c, 0x6578, 0x080c, 0x782b, 0x0070, 0x6124, 0xa1e5, - 0x0000, 0x0140, 0x080c, 0xaca2, 0x2009, 0x0014, 0x080c, 0x80a7, - 0x080c, 0x6581, 0x00ce, 0x0000, 0x002e, 0x001e, 0x00de, 0x00ce, - 0x0005, 0x2001, 0xafe3, 0x2004, 0xa005, 0x1db0, 0x00c6, 0x2061, - 0xafc7, 0x6128, 0xa192, 0x0003, 0x1e08, 0x8108, 0x612a, 0x00ce, - 0x080c, 0x6578, 0x080c, 0x485e, 0x0c38, 0x00c6, 0x00d6, 0x00e6, - 0x0016, 0x0026, 0x080c, 0x658e, 0x2071, 0xafc7, 0x713c, 0x81ff, - 0x0570, 0x2061, 0x0100, 0x2069, 0x0140, 0x080c, 0x574f, 0x1188, - 0x0036, 0x2019, 0x0001, 0x080c, 0x7a64, 0x003e, 0x713c, 0x2160, - 0x080c, 0xaca2, 0x2009, 0x004a, 0x080c, 0x80a7, 0x080c, 0x57d1, - 0x00b0, 0x6904, 0xa194, 0x4000, 0x01c0, 0x6803, 0x1000, 0x6803, - 0x0000, 0x0036, 0x2019, 0x0001, 0x080c, 0x7a64, 0x003e, 0x713c, - 0x2160, 0x080c, 0xaca2, 0x2009, 0x004a, 0x080c, 0x80a7, 0x002e, - 0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0c58, 0x00e6, 0x00d6, - 0x00c6, 0x0066, 0x0056, 0x0046, 0x0006, 0x0126, 0x2091, 0x8000, - 0x6018, 0x2068, 0x6ca0, 0x2071, 0xafc7, 0x7018, 0x2068, 0x8dff, - 0x0198, 0x68a0, 0xa406, 0x0118, 0x6854, 0x2068, 0x0cc0, 0x6010, - 0x2060, 0x643c, 0x6540, 0x6e48, 0x2d60, 0x080c, 0x4e41, 0x0120, - 0x080c, 0x7b88, 0xa085, 0x0001, 0x012e, 0x000e, 0x004e, 0x005e, - 0x006e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x20a1, 0x020b, 0x080c, - 0x710e, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x781c, - 0xa086, 0x0004, 0x1110, 0x6098, 0x0018, 0x2001, 0xad14, 0x2004, - 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9, 0x0010, 0xa006, - 0x20a2, 0x1f04, 0x7928, 0x20a2, 0x20a2, 0x60c3, 0x002c, 0x080c, - 0x7821, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x710e, - 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, - 0x60c3, 0x0008, 0x080c, 0x7821, 0x014e, 0x015e, 0x0005, 0x0156, - 0x0146, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0200, 0x20a3, - 0x0000, 0x20a9, 0x0006, 0x2011, 0xad40, 0x2019, 0xad41, 0x23a6, - 0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x1f04, 0x7957, 0x20a3, - 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x080c, 0x7821, 0x014e, - 0x015e, 0x0005, 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, - 0x080c, 0x7183, 0x080c, 0x7199, 0x7810, 0xa080, 0x0000, 0x2004, - 0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, - 0xa080, 0x0004, 0x8003, 0x60c2, 0x080c, 0x7821, 0x002e, 0x001e, - 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, - 0x710e, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, - 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7821, 0x014e, 0x015e, 0x0005, - 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, 0x080c, 0x710e, - 0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017, 0x2098, 0x7808, - 0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x080c, 0x7821, - 0x002e, 0x001e, 0x014e, 0x015e, 0x0005, 0x00e6, 0x00c6, 0x0006, - 0x0126, 0x2091, 0x8000, 0x2071, 0xafc7, 0x700c, 0x2060, 0x8cff, - 0x0178, 0x080c, 0x9789, 0x1110, 0x080c, 0x85f3, 0x600c, 0x0006, - 0x080c, 0x994e, 0x080c, 0x8078, 0x080c, 0x7b88, 0x00ce, 0x0c78, - 0x700f, 0x0000, 0x700b, 0x0000, 0x012e, 0x000e, 0x00ce, 0x00ee, - 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0026, - 0x0016, 0x0006, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, - 0x2071, 0xafc7, 0x7024, 0x2060, 0x8cff, 0x05a0, 0x080c, 0x7834, - 0x68c3, 0x0000, 0x080c, 0x6581, 0x2009, 0x0013, 0x080c, 0x80a7, - 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, - 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, - 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, 0x7a02, 0x7804, - 0xa084, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, - 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, - 0x012e, 0x0005, 0x2001, 0xad00, 0x2004, 0xa096, 0x0001, 0x0550, - 0xa096, 0x0004, 0x0538, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, - 0x481b, 0x080c, 0x650d, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158, - 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, - 0x7803, 0x0000, 0x0078, 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, - 0x1f04, 0x7a3d, 0x7804, 0xa084, 0x1000, 0x0120, 0x7803, 0x0100, - 0x7803, 0x0000, 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, - 0x00fe, 0x015e, 0x012e, 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, - 0x00d6, 0x00c6, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000, 0x2069, - 0x0100, 0x2079, 0x0140, 0x2071, 0xafc7, 0x703c, 0x2060, 0x8cff, - 0x0904, 0x7ad5, 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, 0x1df0, - 0x68c7, 0x0000, 0x68cb, 0x0008, 0x080c, 0x658e, 0x080c, 0x20b5, - 0x0046, 0x2009, 0x017f, 0x200b, 0x00a5, 0x2021, 0x0169, 0x2404, - 0xa084, 0x000f, 0xa086, 0x0004, 0x11b0, 0x68c7, 0x0000, 0x68cb, - 0x0008, 0x00e6, 0x00f6, 0x2079, 0x0020, 0x2071, 0xb01e, 0x6814, - 0xa084, 0x0184, 0xa085, 0x0012, 0x6816, 0x7803, 0x0008, 0x7003, - 0x0000, 0x00fe, 0x00ee, 0x200b, 0x0000, 0x004e, 0xa39d, 0x0000, - 0x1120, 0x2009, 0x0049, 0x080c, 0x80a7, 0x20a9, 0x03e8, 0x6824, - 0xd094, 0x0158, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, - 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0xd08c, 0x0118, 0x6827, - 0x0002, 0x0010, 0x1f04, 0x7ab7, 0x7804, 0xa084, 0x1000, 0x0120, - 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x000e, 0x001e, 0x002e, - 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x00d6, - 0x0126, 0x2091, 0x8000, 0x2069, 0xafc7, 0x6a06, 0x012e, 0x00de, - 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2069, 0xafc7, 0x6a32, - 0x012e, 0x00de, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0006, - 0x0126, 0x2071, 0xafc7, 0x7614, 0x2660, 0x2678, 0x2091, 0x8000, - 0x8cff, 0x0538, 0x601c, 0xa206, 0x1500, 0x7014, 0xac36, 0x1110, - 0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, - 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, - 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, - 0x974e, 0x080c, 0x7b88, 0x00ce, 0x08d8, 0x2c78, 0x600c, 0x2060, - 0x08b8, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00ee, 0x00fe, 0x0005, - 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810, 0x20a2, - 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x1000, 0x0804, - 0x7b80, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810, - 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x4000, - 0x0478, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810, - 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000, - 0x00f8, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810, - 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, - 0x0078, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810, - 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, - 0x0089, 0x60c3, 0x0020, 0x080c, 0x7821, 0x014e, 0x015e, 0x0005, - 0x00e6, 0x2071, 0xafc7, 0x7020, 0xa005, 0x0110, 0x8001, 0x7022, - 0x00ee, 0x0005, 0x20a9, 0x0008, 0x20a2, 0x1f04, 0x7b94, 0x20a2, - 0x20a2, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, - 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0xafc7, 0x7614, 0x2660, - 0x2678, 0x2039, 0x0001, 0x87ff, 0x0904, 0x7c24, 0x8cff, 0x0904, - 0x7c24, 0x601c, 0xa086, 0x0006, 0x1904, 0x7c1f, 0x88ff, 0x0138, - 0x2800, 0xac06, 0x1904, 0x7c1f, 0x2039, 0x0000, 0x0050, 0x6018, - 0xa206, 0x1904, 0x7c1f, 0x85ff, 0x0120, 0x6050, 0xa106, 0x1904, - 0x7c1f, 0x7024, 0xac06, 0x1538, 0x2069, 0x0100, 0x68c0, 0xa005, - 0x01f0, 0x080c, 0x6581, 0x6817, 0x0008, 0x68c3, 0x0000, 0x080c, - 0x7ca8, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, - 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, - 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x0020, 0x6003, - 0x0009, 0x630a, 0x0460, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616, - 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012, - 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, - 0x7e0e, 0x0008, 0x2678, 0x89ff, 0x1158, 0x600f, 0x0000, 0x6010, - 0x2068, 0x080c, 0x9596, 0x0110, 0x080c, 0xa91f, 0x080c, 0x974e, - 0x080c, 0x7b88, 0x88ff, 0x1190, 0x00ce, 0x0804, 0x7bab, 0x2c78, - 0x600c, 0x2060, 0x0804, 0x7bab, 0xa006, 0x012e, 0x000e, 0x006e, - 0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6017, 0x0000, - 0x00ce, 0xa8c5, 0x0001, 0x0c88, 0x00f6, 0x00e6, 0x00d6, 0x00c6, - 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0xafc7, - 0x7638, 0x2660, 0x2678, 0x8cff, 0x0904, 0x7c98, 0x601c, 0xa086, - 0x0006, 0x1904, 0x7c93, 0x87ff, 0x0128, 0x2700, 0xac06, 0x1904, - 0x7c93, 0x0040, 0x6018, 0xa206, 0x15f0, 0x85ff, 0x0118, 0x6050, - 0xa106, 0x15c8, 0x703c, 0xac06, 0x1170, 0x0036, 0x2019, 0x0001, - 0x080c, 0x7a64, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, - 0x7047, 0x0000, 0x003e, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, - 0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, - 0x0010, 0x7037, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, - 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, - 0x9596, 0x0110, 0x080c, 0xa91f, 0x080c, 0x974e, 0x87ff, 0x1190, - 0x00ce, 0x0804, 0x7c43, 0x2c78, 0x600c, 0x2060, 0x0804, 0x7c43, - 0xa006, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, - 0x00fe, 0x0005, 0x6017, 0x0000, 0x00ce, 0xa7bd, 0x0001, 0x0c88, - 0x00e6, 0x2071, 0xafc7, 0x2001, 0xad00, 0x2004, 0xa086, 0x0002, - 0x1118, 0x7007, 0x0005, 0x0010, 0x7007, 0x0000, 0x00ee, 0x0005, - 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, - 0x8000, 0x2071, 0xafc7, 0x2c10, 0x7638, 0x2660, 0x2678, 0x8cff, - 0x0518, 0x2200, 0xac06, 0x11e0, 0x7038, 0xac36, 0x1110, 0x660c, - 0x763a, 0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, - 0x7036, 0x0010, 0x7037, 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0110, - 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0xa085, 0x0001, 0x0020, - 0x2c78, 0x600c, 0x2060, 0x08d8, 0x012e, 0x000e, 0x002e, 0x006e, - 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, - 0x0066, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0xafc7, 0x760c, - 0x2660, 0x2678, 0x8cff, 0x0904, 0x7d7e, 0x6018, 0xa080, 0x0028, - 0x2004, 0xa206, 0x1904, 0x7d79, 0x7024, 0xac06, 0x1508, 0x2069, - 0x0100, 0x68c0, 0xa005, 0x0904, 0x7d55, 0x080c, 0x7834, 0x68c3, - 0x0000, 0x080c, 0x7ca8, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, - 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, - 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, - 0x700c, 0xac36, 0x1110, 0x660c, 0x760e, 0x7008, 0xac36, 0x1140, - 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x700a, 0x0010, 0x700b, 0x0000, - 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, - 0x600f, 0x0000, 0x080c, 0x9778, 0x1158, 0x080c, 0x2aff, 0x080c, - 0x9789, 0x11f0, 0x080c, 0x85f3, 0x00d8, 0x080c, 0x7ca8, 0x08c0, - 0x080c, 0x9789, 0x1118, 0x080c, 0x85f3, 0x0090, 0x6010, 0x2068, - 0x080c, 0x9596, 0x0168, 0x601c, 0xa086, 0x0003, 0x11f8, 0x6837, - 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x510c, 0x080c, 0x9742, - 0x080c, 0x994e, 0x080c, 0x974e, 0x080c, 0x7b88, 0x00ce, 0x0804, - 0x7d02, 0x2c78, 0x600c, 0x2060, 0x0804, 0x7d02, 0x012e, 0x000e, - 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, - 0x0006, 0x1d30, 0x080c, 0xa91f, 0x0c18, 0x0036, 0x0156, 0x0136, - 0x0146, 0x3908, 0xa006, 0xa190, 0x0020, 0x221c, 0xa39e, 0x28f9, - 0x1118, 0x8210, 0x8000, 0x0cc8, 0xa005, 0x0138, 0x20a9, 0x0020, - 0x2198, 0xa110, 0x22a0, 0x22c8, 0x53a3, 0x014e, 0x013e, 0x015e, - 0x003e, 0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, - 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x2099, 0xafa6, 0x20a9, 0x0004, 0x53a6, 0x20a3, 0x0004, - 0x20a3, 0x7878, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x080c, 0x7821, - 0x00de, 0x0005, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0214, - 0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, 0xa084, 0xff00, 0x20a2, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, - 0x7810, 0xa084, 0x00ff, 0x20a2, 0x7828, 0x20a2, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x60c3, 0x0018, 0x080c, 0x7821, 0x0005, 0x00d6, - 0x0016, 0x2f68, 0x2009, 0x0035, 0x080c, 0x9a34, 0x1904, 0x7e5d, - 0x20a1, 0x020b, 0x080c, 0x710e, 0x20a3, 0x1300, 0x20a3, 0x0000, - 0x7828, 0x2068, 0x681c, 0xa086, 0x0003, 0x0580, 0x7818, 0xa080, - 0x0028, 0x2014, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x11d0, 0xa286, - 0x007e, 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x04b8, 0xa286, - 0x007f, 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffd, 0x0478, 0xd2bc, - 0x0180, 0xa286, 0x0080, 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffc, - 0x0428, 0xa2e8, 0xae34, 0x2d6c, 0x6810, 0x20a2, 0x6814, 0x20a2, - 0x00e8, 0x20a3, 0x0000, 0x6098, 0x20a2, 0x00c0, 0x2001, 0xad34, - 0x2004, 0xd0ac, 0x1138, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, - 0x007e, 0x0240, 0x00d6, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, - 0x00de, 0x0020, 0x20a3, 0x0000, 0x6034, 0x20a2, 0x7834, 0x20a2, - 0x7838, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c, - 0x080c, 0x7821, 0x001e, 0x00de, 0x0005, 0x7817, 0x0001, 0x7803, - 0x0006, 0x001e, 0x00de, 0x0005, 0x00d6, 0x0026, 0x7928, 0x2168, - 0x691c, 0xa186, 0x0006, 0x01c0, 0xa186, 0x0003, 0x0904, 0x7ed3, - 0xa186, 0x0005, 0x0904, 0x7ebc, 0xa186, 0x0004, 0x05b8, 0xa186, - 0x0008, 0x0904, 0x7ec4, 0x7807, 0x0037, 0x7813, 0x1700, 0x080c, - 0x7f3b, 0x002e, 0x00de, 0x0005, 0x080c, 0x7ef7, 0x2009, 0x4000, - 0x6800, 0x0002, 0x7e9d, 0x7ea8, 0x7e9f, 0x7ea8, 0x7ea4, 0x7e9d, - 0x7e9d, 0x7ea8, 0x7ea8, 0x7ea8, 0x7ea8, 0x7e9d, 0x7e9d, 0x7e9d, - 0x7e9d, 0x7e9d, 0x7ea8, 0x7e9d, 0x7ea8, 0x080c, 0x14f6, 0x6820, - 0xd0e4, 0x0110, 0xd0cc, 0x0110, 0xa00e, 0x0010, 0x2009, 0x2000, - 0x6828, 0x20a2, 0x682c, 0x20a2, 0x0804, 0x7eed, 0x080c, 0x7ef7, - 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, 0x6a00, 0xa286, - 0x0002, 0x1108, 0xa00e, 0x0488, 0x04d1, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x2009, 0x4000, 0x0448, 0x0491, 0x20a3, 0x0000, 0x20a3, - 0x0000, 0x2009, 0x4000, 0xa286, 0x0005, 0x0118, 0xa286, 0x0002, - 0x1108, 0xa00e, 0x00d0, 0x0419, 0x6810, 0x2068, 0x697c, 0x6810, - 0xa112, 0x6980, 0x6814, 0xa103, 0x20a2, 0x22a2, 0x7928, 0xa180, - 0x0000, 0x2004, 0xa08e, 0x0002, 0x0130, 0xa08e, 0x0004, 0x0118, - 0x2009, 0x4000, 0x0010, 0x2009, 0x0000, 0x21a2, 0x20a3, 0x0000, - 0x60c3, 0x0018, 0x080c, 0x7821, 0x002e, 0x00de, 0x0005, 0x0036, - 0x0046, 0x0056, 0x0066, 0x20a1, 0x020b, 0x080c, 0x71aa, 0xa006, - 0x20a3, 0x0200, 0x20a2, 0x7934, 0x21a2, 0x7938, 0x21a2, 0x7818, - 0xa080, 0x0028, 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118, - 0xa092, 0x007e, 0x0268, 0x00d6, 0x2069, 0xad1b, 0x2d2c, 0x8d68, - 0x2d34, 0xa0e8, 0xae34, 0x2d6c, 0x6b10, 0x6c14, 0x00de, 0x0030, - 0x2019, 0x0000, 0x6498, 0x2029, 0x0000, 0x6634, 0x7828, 0xa080, - 0x0007, 0x2004, 0xa086, 0x0003, 0x1128, 0x25a2, 0x26a2, 0x23a2, - 0x24a2, 0x0020, 0x23a2, 0x24a2, 0x25a2, 0x26a2, 0x006e, 0x005e, - 0x004e, 0x003e, 0x0005, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, - 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0009, 0x7810, 0x20a2, 0x60c3, - 0x0008, 0x080c, 0x7821, 0x0005, 0x20a1, 0x020b, 0x080c, 0x7106, - 0x20a3, 0x1400, 0x20a3, 0x0000, 0x7834, 0x20a2, 0x7838, 0x20a2, - 0x7828, 0x20a2, 0x782c, 0x20a2, 0x7830, 0xa084, 0x00ff, 0x8007, - 0x20a2, 0x20a3, 0x0000, 0x60c3, 0x0010, 0x080c, 0x7821, 0x0005, - 0x20a1, 0x020b, 0x080c, 0x71a2, 0x20a3, 0x0100, 0x20a3, 0x0000, - 0x7828, 0x20a2, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7821, - 0x0005, 0x0146, 0x20a1, 0x020b, 0x0031, 0x60c3, 0x0000, 0x080c, - 0x7821, 0x014e, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, - 0xa080, 0x0028, 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, - 0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, - 0x0300, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, - 0x2da6, 0x00de, 0x0078, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, - 0xa085, 0x0300, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, - 0x6234, 0x22a2, 0x20a3, 0x0819, 0x20a3, 0x0000, 0x080c, 0x7810, - 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x7a08, 0x22a2, 0x20a3, 0x0000, - 0x20a3, 0x0000, 0x0005, 0x20a1, 0x020b, 0x0079, 0x7910, 0x21a2, - 0x20a3, 0x0000, 0x60c3, 0x0000, 0x20e1, 0x9080, 0x60a7, 0x9575, - 0x080c, 0x782b, 0x080c, 0x6578, 0x0005, 0x0156, 0x0136, 0x0036, - 0x00d6, 0x00e6, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7854, 0x2068, - 0xadf0, 0x000f, 0x7210, 0xa296, 0x00c0, 0xa294, 0xfffd, 0x7212, - 0x7214, 0xa294, 0x0300, 0x7216, 0x7100, 0xa194, 0x00ff, 0x7308, - 0xa384, 0x00ff, 0xa08d, 0xc200, 0x7102, 0xa384, 0xff00, 0xa215, - 0x720a, 0x7004, 0x720c, 0x700e, 0x7206, 0x20a9, 0x000a, 0x2e98, - 0x53a6, 0x60a3, 0x0035, 0x6a38, 0xa294, 0x7000, 0xa286, 0x3000, - 0x0110, 0x60a3, 0x0037, 0x00ee, 0x00de, 0x003e, 0x013e, 0x015e, - 0x0005, 0x2009, 0x0092, 0x0010, 0x2009, 0x0096, 0x60ab, 0x0036, - 0x6116, 0x0005, 0x2061, 0xb400, 0x2a70, 0x7064, 0x7046, 0x704b, - 0xb400, 0x0005, 0x00e6, 0x0126, 0x2071, 0xad00, 0x2091, 0x8000, - 0x7544, 0xa582, 0x0010, 0x0608, 0x7048, 0x2060, 0x6000, 0xa086, - 0x0000, 0x0148, 0xace0, 0x0018, 0x7058, 0xac02, 0x1208, 0x0cb0, - 0x2061, 0xb400, 0x0c98, 0x6003, 0x0008, 0x8529, 0x7546, 0xaca8, - 0x0018, 0x7058, 0xa502, 0x1230, 0x754a, 0xa085, 0x0001, 0x012e, - 0x00ee, 0x0005, 0x704b, 0xb400, 0x0cc0, 0xa006, 0x0cc0, 0x00e6, - 0x2071, 0xad00, 0x7544, 0xa582, 0x0010, 0x0600, 0x7048, 0x2060, - 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x0018, 0x7058, 0xac02, - 0x1208, 0x0cb0, 0x2061, 0xb400, 0x0c98, 0x6003, 0x0008, 0x8529, - 0x7546, 0xaca8, 0x0018, 0x7058, 0xa502, 0x1228, 0x754a, 0xa085, - 0x0001, 0x00ee, 0x0005, 0x704b, 0xb400, 0x0cc8, 0xa006, 0x0cc8, - 0xac82, 0xb400, 0x0a0c, 0x14f6, 0x2001, 0xad16, 0x2004, 0xac02, - 0x1a0c, 0x14f6, 0xa006, 0x6006, 0x600a, 0x600e, 0x6012, 0x6016, - 0x601a, 0x601f, 0x0000, 0x6003, 0x0000, 0x6052, 0x6056, 0x6022, - 0x6026, 0x602a, 0x602e, 0x6032, 0x6036, 0x603a, 0x603e, 0x2061, - 0xad00, 0x6044, 0x8000, 0x6046, 0xa086, 0x0001, 0x0108, 0x0005, - 0x0126, 0x2091, 0x8000, 0x080c, 0x6c50, 0x012e, 0x0cc0, 0x601c, - 0xa084, 0x000f, 0x0002, 0x80b6, 0x80c5, 0x80e0, 0x80fb, 0x9a61, - 0x9a7c, 0x9a97, 0x80b6, 0x80c5, 0x80b6, 0x8116, 0xa186, 0x0013, - 0x1128, 0x080c, 0x6b73, 0x080c, 0x6c50, 0x0005, 0xa18e, 0x0047, - 0x1118, 0xa016, 0x080c, 0x1824, 0x0005, 0x0066, 0x6000, 0xa0b2, - 0x0010, 0x1a0c, 0x14f6, 0x0013, 0x006e, 0x0005, 0x80de, 0x8478, - 0x862d, 0x80de, 0x86a2, 0x81cf, 0x80de, 0x80de, 0x840a, 0x8a91, - 0x80de, 0x80de, 0x80de, 0x80de, 0x80de, 0x80de, 0x080c, 0x14f6, - 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x14f6, 0x0013, 0x006e, - 0x0005, 0x80f9, 0x909a, 0x80f9, 0x80f9, 0x80f9, 0x80f9, 0x80f9, - 0x80f9, 0x9045, 0x9200, 0x80f9, 0x90c7, 0x913e, 0x90c7, 0x913e, - 0x80f9, 0x080c, 0x14f6, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, - 0x14f6, 0x0013, 0x006e, 0x0005, 0x8114, 0x8ad2, 0x8b98, 0x8cb8, - 0x8e12, 0x8114, 0x8114, 0x8114, 0x8aac, 0x8ff5, 0x8ff8, 0x8114, - 0x8114, 0x8114, 0x8114, 0x9022, 0x080c, 0x14f6, 0x0066, 0x6000, - 0xa0b2, 0x0010, 0x1a0c, 0x14f6, 0x0013, 0x006e, 0x0005, 0x812f, - 0x812f, 0x812f, 0x8152, 0x81a5, 0x812f, 0x812f, 0x812f, 0x8131, - 0x812f, 0x812f, 0x812f, 0x812f, 0x812f, 0x812f, 0x812f, 0x080c, - 0x14f6, 0xa186, 0x0003, 0x190c, 0x14f6, 0x00d6, 0x6003, 0x0003, - 0x6106, 0x6010, 0x2068, 0x684f, 0x0040, 0x687c, 0x680a, 0x6880, - 0x680e, 0x6813, 0x0000, 0x6817, 0x0000, 0x00de, 0x2c10, 0x080c, - 0x1e6e, 0x080c, 0x680b, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d0d, - 0x012e, 0x0005, 0xa182, 0x0047, 0x0002, 0x815e, 0x815e, 0x8160, - 0x817f, 0x815e, 0x815e, 0x815e, 0x815e, 0x8191, 0x080c, 0x14f6, - 0x00d6, 0x0016, 0x080c, 0x6c05, 0x080c, 0x6d0d, 0x6003, 0x0004, - 0x6110, 0x2168, 0x6854, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, - 0x684f, 0x0020, 0x685c, 0x685a, 0x6874, 0x687e, 0x6878, 0x6882, - 0x6897, 0x0000, 0x689b, 0x0000, 0x001e, 0x00de, 0x0005, 0x080c, - 0x6c05, 0x00d6, 0x6110, 0x2168, 0x080c, 0x9596, 0x0120, 0x684b, - 0x0006, 0x080c, 0x510c, 0x00de, 0x080c, 0x8078, 0x080c, 0x6d0d, - 0x0005, 0x080c, 0x6c05, 0x080c, 0x2ad9, 0x00d6, 0x6110, 0x2168, - 0x080c, 0x9596, 0x0120, 0x684b, 0x0029, 0x080c, 0x510c, 0x00de, - 0x080c, 0x8078, 0x080c, 0x6d0d, 0x0005, 0xa182, 0x0047, 0x0002, - 0x81b3, 0x81c2, 0x81b1, 0x81b1, 0x81b1, 0x81b1, 0x81b1, 0x81b1, - 0x81b1, 0x080c, 0x14f6, 0x00d6, 0x6010, 0x2068, 0x684c, 0xc0f4, - 0x684e, 0x00de, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, - 0x1824, 0x0005, 0x00d6, 0x6110, 0x2168, 0x684b, 0x0000, 0x6853, - 0x0000, 0x080c, 0x510c, 0x00de, 0x080c, 0x8078, 0x0005, 0xa1b6, - 0x0015, 0x1118, 0x080c, 0x8078, 0x0030, 0xa1b6, 0x0016, 0x190c, - 0x14f6, 0x080c, 0x8078, 0x0005, 0x20a9, 0x000e, 0x2e98, 0x6010, - 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, 0x9398, 0x94a0, - 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, 0xa5a8, 0x0002, - 0xa398, 0x0002, 0xa4a0, 0x0002, 0x1f04, 0x81ea, 0x00e6, 0x080c, - 0x9596, 0x0130, 0x6010, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, - 0x00ee, 0x080c, 0x8078, 0x0005, 0x00d6, 0x0036, 0x7330, 0xa386, - 0x0200, 0x1130, 0x6018, 0x2068, 0x6813, 0x00ff, 0x6817, 0xfffd, - 0x6010, 0xa005, 0x0130, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, - 0x6b32, 0x080c, 0x8078, 0x003e, 0x00de, 0x0005, 0x0016, 0x20a9, - 0x002a, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080, 0x0002, 0x20a0, - 0x53a3, 0x20a9, 0x002a, 0x6010, 0xa080, 0x0001, 0x2004, 0xa080, - 0x0002, 0x20a0, 0x53a3, 0x00e6, 0x6010, 0x2004, 0x2070, 0x7037, - 0x0103, 0x00ee, 0x080c, 0x8078, 0x001e, 0x0005, 0x0016, 0x2009, - 0x0000, 0x7030, 0xa086, 0x0100, 0x0140, 0x7038, 0xa084, 0x00ff, - 0x808e, 0x703c, 0xa084, 0x00ff, 0x8086, 0xa080, 0x0004, 0xa108, - 0x21a8, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080, 0x0002, 0x20a0, - 0x080c, 0x48be, 0x00e6, 0x080c, 0x9596, 0x0140, 0x6010, 0x2070, - 0x7007, 0x0000, 0x7034, 0x70b2, 0x7037, 0x0103, 0x00ee, 0x080c, - 0x8078, 0x001e, 0x0005, 0x00e6, 0x00d6, 0x603f, 0x0000, 0x2c68, - 0x0016, 0x2009, 0x0035, 0x080c, 0x9a34, 0x001e, 0x1168, 0x0026, - 0x6228, 0x2268, 0x002e, 0x2071, 0xb28c, 0x6b1c, 0xa386, 0x0003, - 0x0130, 0xa386, 0x0006, 0x0128, 0x080c, 0x8078, 0x0020, 0x0031, - 0x0010, 0x080c, 0x8323, 0x00de, 0x00ee, 0x0005, 0x00f6, 0x6810, - 0x2078, 0xa186, 0x0015, 0x0904, 0x830c, 0xa18e, 0x0016, 0x1904, - 0x8321, 0x700c, 0xa084, 0xff00, 0xa086, 0x1700, 0x1904, 0x82eb, - 0x8fff, 0x0904, 0x831f, 0x6808, 0xa086, 0xffff, 0x1904, 0x830e, - 0x784c, 0xa084, 0x0060, 0xa086, 0x0020, 0x1150, 0x797c, 0x7810, - 0xa106, 0x1904, 0x830e, 0x7980, 0x7814, 0xa106, 0x1904, 0x830e, - 0x080c, 0x9742, 0x6858, 0x7852, 0x784c, 0xc0dc, 0xc0f4, 0xc0d4, - 0x784e, 0x0026, 0xa00e, 0x6a14, 0x2001, 0x000a, 0x080c, 0x6665, - 0x7854, 0xa20a, 0x0208, 0x8011, 0x7a56, 0x82ff, 0x002e, 0x1138, - 0x00c6, 0x2d60, 0x080c, 0x9374, 0x00ce, 0x0804, 0x831f, 0x00c6, - 0x00d6, 0x2f68, 0x6838, 0xd0fc, 0x1118, 0x080c, 0x4993, 0x0010, - 0x080c, 0x4b7c, 0x00de, 0x00ce, 0x1548, 0x00c6, 0x2d60, 0x080c, - 0x8078, 0x00ce, 0x04a0, 0x7008, 0xa086, 0x000b, 0x11a0, 0x6018, - 0x200c, 0xc1bc, 0x2102, 0x00c6, 0x2d60, 0x7853, 0x0003, 0x6007, - 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x67a8, 0x080c, - 0x6c50, 0x00ce, 0x00e0, 0x700c, 0xa086, 0x2a00, 0x1138, 0x2001, - 0xafa5, 0x2004, 0x683e, 0x0098, 0x0471, 0x0098, 0x8fff, 0x090c, - 0x14f6, 0x00c6, 0x00d6, 0x2d60, 0x2f68, 0x684b, 0x0003, 0x080c, - 0x926f, 0x080c, 0x9742, 0x080c, 0x974e, 0x00de, 0x00ce, 0x080c, - 0x8078, 0x00fe, 0x0005, 0xa186, 0x0015, 0x1128, 0x2001, 0xafa5, - 0x2004, 0x683e, 0x0068, 0xa18e, 0x0016, 0x1160, 0x00c6, 0x2d00, - 0x2060, 0x080c, 0xabb4, 0x080c, 0x6618, 0x080c, 0x8078, 0x00ce, - 0x080c, 0x8078, 0x0005, 0x0026, 0x0036, 0x0046, 0x7228, 0x7c80, - 0x7b7c, 0xd2f4, 0x0130, 0x2001, 0xafa5, 0x2004, 0x683e, 0x0804, - 0x839d, 0x00c6, 0x2d60, 0x080c, 0x928f, 0x00ce, 0x6804, 0xa086, - 0x0050, 0x1168, 0x00c6, 0x2d00, 0x2060, 0x6003, 0x0001, 0x6007, - 0x0050, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x00ce, 0x04f0, 0x6800, - 0xa086, 0x000f, 0x01c8, 0x8fff, 0x090c, 0x14f6, 0x6820, 0xd0dc, - 0x1198, 0x6800, 0xa086, 0x0004, 0x1198, 0x784c, 0xd0ac, 0x0180, - 0x784c, 0xc0dc, 0xc0f4, 0x784e, 0x7850, 0xc0f4, 0xc0fc, 0x7852, - 0x2001, 0x0001, 0x682e, 0x00e0, 0x2001, 0x0007, 0x682e, 0x00c0, - 0x784c, 0xd0b4, 0x1130, 0xd0ac, 0x0db8, 0x784c, 0xd0f4, 0x1da0, - 0x0c38, 0xd2ec, 0x1d88, 0x7024, 0xa306, 0x1118, 0x7020, 0xa406, - 0x0d58, 0x7020, 0x6836, 0x7024, 0x683a, 0x2001, 0x0005, 0x682e, - 0x080c, 0x9894, 0x080c, 0x6c50, 0x0010, 0x080c, 0x8078, 0x004e, - 0x003e, 0x002e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x6034, 0x2068, - 0x6a1c, 0xa286, 0x0007, 0x0904, 0x83ee, 0xa286, 0x0002, 0x05f0, - 0xa286, 0x0000, 0x05d8, 0x6808, 0x6338, 0xa306, 0x15b8, 0x2071, - 0xb28c, 0xa186, 0x0015, 0x0560, 0xa18e, 0x0016, 0x1190, 0x6030, - 0xa084, 0x00ff, 0xa086, 0x0001, 0x1160, 0x700c, 0xa086, 0x2a00, - 0x1140, 0x6034, 0xa080, 0x0008, 0x200c, 0xc1dd, 0xc1f5, 0x2102, - 0x00b8, 0x00c6, 0x6034, 0x2060, 0x6010, 0x2068, 0x080c, 0x9596, - 0x090c, 0x14f6, 0x6853, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b, - 0x601f, 0x0002, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x00ce, 0x0030, - 0x6034, 0x2070, 0x2001, 0xafa5, 0x2004, 0x703e, 0x080c, 0x8078, - 0x002e, 0x00de, 0x00ee, 0x0005, 0x00d6, 0x20a9, 0x000e, 0x2e98, - 0x6010, 0x20a0, 0x53a3, 0xa1b6, 0x0015, 0x1148, 0x6018, 0x2068, - 0x7038, 0x680a, 0x703c, 0x680e, 0x6800, 0xc08d, 0x6802, 0x00de, - 0x0804, 0x81f6, 0x2100, 0xa1b2, 0x0080, 0x1a0c, 0x14f6, 0xa1b2, - 0x0040, 0x1a04, 0x846e, 0x0002, 0x8462, 0x8456, 0x8462, 0x8462, - 0x8462, 0x8462, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, - 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, - 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, - 0x8454, 0x8454, 0x8454, 0x8462, 0x8454, 0x8462, 0x8462, 0x8454, - 0x8454, 0x8454, 0x8454, 0x8454, 0x8462, 0x8454, 0x8454, 0x8454, - 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8462, 0x8462, - 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, - 0x8454, 0x8462, 0x8454, 0x8454, 0x080c, 0x14f6, 0x6003, 0x0001, - 0x6106, 0x080c, 0x67ee, 0x0126, 0x2091, 0x8000, 0x080c, 0x6c50, - 0x012e, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c, 0x67ee, 0x0126, - 0x2091, 0x8000, 0x080c, 0x6c50, 0x012e, 0x0005, 0x2600, 0x0002, - 0x8462, 0x8476, 0x8476, 0x8462, 0x8462, 0x8476, 0x080c, 0x14f6, - 0x6004, 0xa0b2, 0x0080, 0x1a0c, 0x14f6, 0xa1b6, 0x0013, 0x0904, - 0x8518, 0xa1b6, 0x0027, 0x1904, 0x84de, 0x080c, 0x6b73, 0x6004, - 0x080c, 0x9778, 0x0188, 0x080c, 0x9789, 0x0904, 0x84d8, 0xa08e, - 0x0021, 0x0904, 0x84db, 0xa08e, 0x0022, 0x0904, 0x84d8, 0xa08e, - 0x003d, 0x0904, 0x84db, 0x04a8, 0x080c, 0x2aff, 0x2001, 0x0007, - 0x080c, 0x4c30, 0x6018, 0xa080, 0x0028, 0x200c, 0x080c, 0x85f3, - 0xa186, 0x007e, 0x1148, 0x2001, 0xad34, 0x2014, 0xc285, 0x080c, - 0x574f, 0x1108, 0xc2ad, 0x2202, 0x0016, 0x0026, 0x0036, 0x2110, - 0x2019, 0x0028, 0x080c, 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, - 0x681d, 0x00c6, 0x6018, 0xa065, 0x0110, 0x080c, 0x4ecf, 0x00ce, - 0x2c08, 0x080c, 0xa712, 0x007e, 0x003e, 0x002e, 0x001e, 0x080c, - 0x4c9f, 0x080c, 0x994e, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005, - 0x080c, 0x85f3, 0x0cb0, 0x080c, 0x8621, 0x0c98, 0xa186, 0x0014, - 0x1db0, 0x080c, 0x6b73, 0x080c, 0x2ad9, 0x080c, 0x9778, 0x1188, - 0x080c, 0x2aff, 0x6018, 0xa080, 0x0028, 0x200c, 0x080c, 0x85f3, - 0xa186, 0x007e, 0x1128, 0x2001, 0xad34, 0x200c, 0xc185, 0x2102, - 0x08c0, 0x080c, 0x9789, 0x1118, 0x080c, 0x85f3, 0x0890, 0x6004, - 0xa08e, 0x0032, 0x1158, 0x00e6, 0x00f6, 0x2071, 0xad81, 0x2079, - 0x0000, 0x080c, 0x2df1, 0x00fe, 0x00ee, 0x0818, 0x6004, 0xa08e, - 0x0021, 0x0d50, 0xa08e, 0x0022, 0x090c, 0x85f3, 0x0804, 0x84d1, - 0xa0b2, 0x0040, 0x1a04, 0x85db, 0x2008, 0x0002, 0x8560, 0x8561, - 0x8564, 0x8567, 0x856a, 0x856d, 0x855e, 0x855e, 0x855e, 0x855e, - 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, - 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, - 0x855e, 0x855e, 0x855e, 0x855e, 0x8570, 0x857f, 0x855e, 0x8581, - 0x857f, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x857f, 0x857f, - 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, - 0x85bb, 0x857f, 0x855e, 0x857b, 0x855e, 0x855e, 0x855e, 0x857c, - 0x855e, 0x855e, 0x855e, 0x857f, 0x85b2, 0x855e, 0x080c, 0x14f6, - 0x00f0, 0x2001, 0x000b, 0x0460, 0x2001, 0x0003, 0x0448, 0x2001, - 0x0005, 0x0430, 0x2001, 0x0001, 0x0418, 0x2001, 0x0009, 0x0400, - 0x080c, 0x6b73, 0x6003, 0x0005, 0x2001, 0xafa5, 0x2004, 0x603e, - 0x080c, 0x6c50, 0x00a0, 0x0018, 0x0010, 0x080c, 0x4c30, 0x0804, - 0x85cc, 0x080c, 0x6b73, 0x2001, 0xafa3, 0x2004, 0x6016, 0x2001, - 0xafa5, 0x2004, 0x603e, 0x6003, 0x0004, 0x080c, 0x6c50, 0x0005, - 0x080c, 0x4c30, 0x080c, 0x6b73, 0x6003, 0x0002, 0x2001, 0xafa5, - 0x2004, 0x603e, 0x0036, 0x2019, 0xad5c, 0x2304, 0xa084, 0xff00, - 0x1120, 0x2001, 0xafa3, 0x201c, 0x0040, 0x8007, 0xa09a, 0x0004, - 0x0ec0, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x003e, 0x080c, - 0x6c50, 0x08e8, 0x080c, 0x6b73, 0x080c, 0x994e, 0x080c, 0x8078, - 0x080c, 0x6c50, 0x08a0, 0x00e6, 0x00f6, 0x2071, 0xad81, 0x2079, - 0x0000, 0x080c, 0x2df1, 0x00fe, 0x00ee, 0x080c, 0x6b73, 0x080c, - 0x8078, 0x080c, 0x6c50, 0x0818, 0x080c, 0x6b73, 0x2001, 0xafa5, - 0x2004, 0x603e, 0x6003, 0x0002, 0x2001, 0xafa3, 0x2004, 0x6016, - 0x080c, 0x6c50, 0x0005, 0x2600, 0x2008, 0x0002, 0x85e6, 0x85e4, - 0x85e4, 0x85cc, 0x85cc, 0x85e4, 0x080c, 0x14f6, 0x080c, 0x6b73, - 0x00d6, 0x6010, 0x2068, 0x080c, 0x15f0, 0x00de, 0x080c, 0x8078, - 0x080c, 0x6c50, 0x0005, 0x00e6, 0x0026, 0x0016, 0x080c, 0x9596, - 0x0508, 0x6010, 0x2070, 0x7034, 0xa086, 0x0139, 0x1148, 0x2001, - 0x0030, 0x2009, 0x0000, 0x2011, 0x4005, 0x080c, 0x9a05, 0x0090, - 0x7038, 0xd0fc, 0x0178, 0x7007, 0x0000, 0x0016, 0x6004, 0xa08e, - 0x0021, 0x0160, 0xa08e, 0x003d, 0x0148, 0x001e, 0x7037, 0x0103, - 0x7033, 0x0100, 0x001e, 0x002e, 0x00ee, 0x0005, 0x001e, 0x0009, - 0x0cc8, 0x00e6, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, - 0x0103, 0x7023, 0x8001, 0x00ee, 0x0005, 0x00d6, 0x6618, 0x2668, - 0x6804, 0xa084, 0x00ff, 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x14f6, - 0x6604, 0xa6b6, 0x0043, 0x1120, 0x080c, 0x99c1, 0x0804, 0x8692, - 0x6604, 0xa6b6, 0x0033, 0x1120, 0x080c, 0x9971, 0x0804, 0x8692, - 0x6604, 0xa6b6, 0x0028, 0x1120, 0x080c, 0x97b9, 0x0804, 0x8692, - 0x6604, 0xa6b6, 0x0029, 0x1118, 0x080c, 0x97d0, 0x04d8, 0x6604, - 0xa6b6, 0x001f, 0x1118, 0x080c, 0x81dc, 0x04a0, 0x6604, 0xa6b6, - 0x0000, 0x1118, 0x080c, 0x83f4, 0x0468, 0x6604, 0xa6b6, 0x0022, - 0x1118, 0x080c, 0x8204, 0x0430, 0x6604, 0xa6b6, 0x0035, 0x1118, - 0x080c, 0x826b, 0x00f8, 0x6604, 0xa6b6, 0x0039, 0x1118, 0x080c, - 0x83a3, 0x00c0, 0x6604, 0xa6b6, 0x003d, 0x1118, 0x080c, 0x821e, - 0x0088, 0x6604, 0xa6b6, 0x0044, 0x1118, 0x080c, 0x823e, 0x0050, - 0xa1b6, 0x0015, 0x1110, 0x0053, 0x0028, 0xa1b6, 0x0016, 0x1118, - 0x0804, 0x883f, 0x0005, 0x080c, 0x80be, 0x0ce0, 0x86b9, 0x86bc, - 0x86b9, 0x86fe, 0x86b9, 0x87cc, 0x884d, 0x86b9, 0x86b9, 0x881b, - 0x86b9, 0x882f, 0xa1b6, 0x0048, 0x0140, 0x20e1, 0x0005, 0x3d18, - 0x3e20, 0x2c10, 0x080c, 0x1824, 0x0005, 0x00e6, 0xacf0, 0x0004, - 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, 0x8078, - 0x0005, 0xe000, 0xe000, 0x0005, 0x00e6, 0x2071, 0xad00, 0x7080, - 0xa086, 0x0074, 0x1530, 0x080c, 0xa6e9, 0x11b0, 0x00d6, 0x6018, - 0x2068, 0x7030, 0xd08c, 0x0128, 0x6800, 0xd0bc, 0x0110, 0xc0c5, - 0x6802, 0x00d9, 0x00de, 0x2001, 0x0006, 0x080c, 0x4c30, 0x080c, - 0x2aff, 0x080c, 0x8078, 0x0078, 0x2001, 0x000a, 0x080c, 0x4c30, - 0x080c, 0x2aff, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x67ee, - 0x0010, 0x080c, 0x87bd, 0x00ee, 0x0005, 0x6800, 0xd084, 0x0168, - 0x2001, 0x0000, 0x080c, 0x4c1e, 0x2069, 0xad51, 0x6804, 0xd0a4, - 0x0120, 0x2001, 0x0006, 0x080c, 0x4c5d, 0x0005, 0x00d6, 0x2011, - 0xad20, 0x2204, 0xa086, 0x0074, 0x1904, 0x87ba, 0x6018, 0x2068, - 0x6aa0, 0xa286, 0x007e, 0x1120, 0x080c, 0x894d, 0x0804, 0x875e, - 0x080c, 0x8943, 0x6018, 0x2068, 0xa080, 0x0028, 0x2014, 0xa286, - 0x0080, 0x11c0, 0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005, - 0x0138, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6833, 0x0200, - 0x2001, 0x0006, 0x080c, 0x4c30, 0x080c, 0x2aff, 0x080c, 0x8078, - 0x0804, 0x87bb, 0x00e6, 0x2071, 0xad34, 0x2e04, 0xd09c, 0x0188, - 0x2071, 0xb280, 0x7108, 0x720c, 0xa18c, 0x00ff, 0x1118, 0xa284, - 0xff00, 0x0138, 0x6018, 0x2070, 0x70a0, 0xd0bc, 0x1110, 0x7112, - 0x7216, 0x00ee, 0x6010, 0xa005, 0x0128, 0x2068, 0x6838, 0xd0f4, - 0x0108, 0x0880, 0x2001, 0x0004, 0x080c, 0x4c30, 0x6003, 0x0001, - 0x6007, 0x0003, 0x080c, 0x67ee, 0x0804, 0x87bb, 0x685c, 0xd0e4, - 0x01d0, 0x080c, 0x9903, 0x080c, 0x574f, 0x0110, 0xd0dc, 0x1900, - 0x2011, 0xad34, 0x2204, 0xc0ad, 0x2012, 0x2001, 0xaf8e, 0x2004, - 0x00f6, 0x2079, 0x0100, 0x78e3, 0x0000, 0x080c, 0x26cb, 0x78e2, - 0x00fe, 0x0804, 0x8728, 0x080c, 0x9937, 0x2011, 0xad34, 0x2204, - 0xc0a5, 0x2012, 0x0006, 0x080c, 0xa801, 0x000e, 0x1904, 0x8728, - 0xc0b5, 0x2012, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x00c6, 0x2009, - 0x00ef, 0x00f6, 0x2079, 0x0100, 0x79ea, 0x7932, 0x7936, 0x00fe, - 0x080c, 0x26a0, 0x00f6, 0x2079, 0xad00, 0x7972, 0x2100, 0x2009, - 0x0000, 0x080c, 0x2676, 0x794e, 0x00fe, 0x8108, 0x080c, 0x4c80, - 0x2c00, 0x00ce, 0x1904, 0x8728, 0x601a, 0x2001, 0x0002, 0x080c, - 0x4c30, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, - 0x67ee, 0x0008, 0x0011, 0x00de, 0x0005, 0x2001, 0xad00, 0x2004, - 0xa086, 0x0003, 0x0120, 0x2001, 0x0007, 0x080c, 0x4c30, 0x080c, - 0x2aff, 0x080c, 0x8078, 0x0005, 0x00e6, 0x0026, 0x0016, 0x2071, - 0xad00, 0x7080, 0xa086, 0x0014, 0x15f0, 0x7000, 0xa086, 0x0003, - 0x1128, 0x6010, 0xa005, 0x1110, 0x080c, 0x3cce, 0x00d6, 0x6018, - 0x2068, 0x080c, 0x4d72, 0x080c, 0x86ed, 0x00de, 0x080c, 0x89f7, - 0x1550, 0x00d6, 0x6018, 0x2068, 0x6890, 0x00de, 0xa005, 0x0518, - 0x2001, 0x0006, 0x080c, 0x4c30, 0x00e6, 0x6010, 0xa075, 0x01a8, - 0x7034, 0xa084, 0x00ff, 0xa086, 0x0039, 0x1148, 0x2001, 0x0000, - 0x2009, 0x0000, 0x2011, 0x4000, 0x080c, 0x9a05, 0x0030, 0x7007, - 0x0000, 0x7037, 0x0103, 0x7033, 0x0200, 0x00ee, 0x080c, 0x2aff, - 0x080c, 0x8078, 0x0020, 0x080c, 0x85f3, 0x080c, 0x87bd, 0x001e, - 0x002e, 0x00ee, 0x0005, 0x2011, 0xad20, 0x2204, 0xa086, 0x0014, - 0x1158, 0x2001, 0x0002, 0x080c, 0x4c30, 0x6003, 0x0001, 0x6007, - 0x0001, 0x080c, 0x67ee, 0x0010, 0x080c, 0x87bd, 0x0005, 0x2011, - 0xad20, 0x2204, 0xa086, 0x0004, 0x1138, 0x2001, 0x0007, 0x080c, - 0x4c30, 0x080c, 0x8078, 0x0010, 0x080c, 0x87bd, 0x0005, 0x000b, - 0x0005, 0x86b9, 0x8854, 0x86b9, 0x888a, 0x86b9, 0x88ff, 0x884d, - 0x86b9, 0x86b9, 0x8912, 0x86b9, 0x8922, 0x6604, 0xa6b6, 0x001e, - 0x1110, 0x080c, 0x8078, 0x0005, 0x00d6, 0x00c6, 0x080c, 0x8932, - 0x1178, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x2001, 0x0002, 0x080c, - 0x4c30, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x67ee, 0x00f8, - 0x2009, 0xb28e, 0x2104, 0xa086, 0x0009, 0x1160, 0x6018, 0x2068, - 0x6840, 0xa084, 0x00ff, 0xa005, 0x0180, 0x8001, 0x6842, 0x6017, - 0x000a, 0x0068, 0x2009, 0xb28f, 0x2104, 0xa084, 0xff00, 0xa086, - 0x1900, 0x1118, 0x080c, 0x8078, 0x0010, 0x080c, 0x87bd, 0x00ce, - 0x00de, 0x0005, 0x080c, 0x8940, 0x00d6, 0x2069, 0xaf9d, 0x2d04, - 0xa005, 0x0168, 0x6018, 0x2068, 0x68a0, 0xa086, 0x007e, 0x1138, - 0x2069, 0xad1c, 0x2d04, 0x8000, 0x206a, 0x00de, 0x0010, 0x00de, - 0x0078, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x2001, 0x0002, 0x080c, - 0x4c30, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x67ee, 0x0428, - 0x080c, 0x85f3, 0x2009, 0xb28e, 0x2134, 0xa6b4, 0x00ff, 0xa686, - 0x0005, 0x01e0, 0xa686, 0x000b, 0x01b0, 0x2009, 0xb28f, 0x2104, - 0xa084, 0xff00, 0x1118, 0xa686, 0x0009, 0x0180, 0xa086, 0x1900, - 0x1150, 0xa686, 0x0009, 0x0150, 0x2001, 0x0004, 0x080c, 0x4c30, - 0x080c, 0x8078, 0x0010, 0x080c, 0x87bd, 0x0005, 0x00d6, 0x6010, - 0x2068, 0x080c, 0x9596, 0x0128, 0x6838, 0xd0fc, 0x0110, 0x00de, - 0x0c90, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0140, - 0x8001, 0x6842, 0x6017, 0x000a, 0x6007, 0x0016, 0x00de, 0x0c28, - 0x68a0, 0xa086, 0x007e, 0x1138, 0x00e6, 0x2071, 0xad00, 0x080c, - 0x48f5, 0x00ee, 0x0010, 0x080c, 0x2ad9, 0x00de, 0x08a0, 0x080c, - 0x8940, 0x1158, 0x2001, 0x0004, 0x080c, 0x4c30, 0x6003, 0x0001, - 0x6007, 0x0003, 0x080c, 0x67ee, 0x0020, 0x080c, 0x85f3, 0x080c, - 0x87bd, 0x0005, 0x0469, 0x1158, 0x2001, 0x0008, 0x080c, 0x4c30, - 0x6003, 0x0001, 0x6007, 0x0005, 0x080c, 0x67ee, 0x0010, 0x080c, - 0x87bd, 0x0005, 0x00e9, 0x1158, 0x2001, 0x000a, 0x080c, 0x4c30, - 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x67ee, 0x0010, 0x080c, - 0x87bd, 0x0005, 0x2009, 0xb28e, 0x2104, 0xa086, 0x0003, 0x1138, - 0x2009, 0xb28f, 0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, 0x0005, - 0xa085, 0x0001, 0x0005, 0x00c6, 0x0016, 0xac88, 0x0006, 0x2164, - 0x080c, 0x4ceb, 0x001e, 0x00ce, 0x0005, 0x00f6, 0x00e6, 0x00d6, - 0x0036, 0x0016, 0x6018, 0x2068, 0x2071, 0xad34, 0x2e04, 0xa085, - 0x0003, 0x2072, 0x080c, 0x89cc, 0x0538, 0x2001, 0xad52, 0x2004, - 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, 0x002a, 0x080c, 0xa96c, - 0x2001, 0xad0c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, - 0x0001, 0x080c, 0x2aac, 0x2071, 0xad00, 0x080c, 0x28fa, 0x00c6, - 0x0156, 0x20a9, 0x0081, 0x2009, 0x007f, 0x080c, 0x2bc9, 0x8108, - 0x1f04, 0x897d, 0x015e, 0x00ce, 0x080c, 0x8943, 0x6813, 0x00ff, - 0x6817, 0xfffe, 0x2071, 0xb280, 0x2079, 0x0100, 0x2e04, 0xa084, - 0x00ff, 0x2069, 0xad1b, 0x206a, 0x78e6, 0x0006, 0x8e70, 0x2e04, - 0x2069, 0xad1c, 0x206a, 0x78ea, 0x7832, 0x7836, 0x2010, 0xa084, - 0xff00, 0x001e, 0xa105, 0x2009, 0xad27, 0x200a, 0x2200, 0xa084, - 0x00ff, 0x2008, 0x080c, 0x26a0, 0x080c, 0x574f, 0x0170, 0x2069, - 0xb28e, 0x2071, 0xaf9f, 0x6810, 0x2072, 0x6814, 0x7006, 0x6818, - 0x700a, 0x681c, 0x700e, 0x080c, 0x9903, 0x0040, 0x2001, 0x0006, - 0x080c, 0x4c30, 0x080c, 0x2aff, 0x080c, 0x8078, 0x001e, 0x003e, - 0x00de, 0x00ee, 0x00fe, 0x0005, 0x0026, 0x0036, 0x00e6, 0x0156, - 0x2019, 0xad27, 0x231c, 0x83ff, 0x01e8, 0x2071, 0xb280, 0x2e14, - 0xa294, 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205, 0xa306, 0x1190, - 0x2011, 0xb296, 0xad98, 0x000a, 0x20a9, 0x0004, 0x080c, 0x8a7c, - 0x1148, 0x2011, 0xb29a, 0xad98, 0x0006, 0x20a9, 0x0004, 0x080c, - 0x8a7c, 0x1100, 0x015e, 0x00ee, 0x003e, 0x002e, 0x0005, 0x00e6, - 0x2071, 0xb28c, 0x7004, 0xa086, 0x0014, 0x11a8, 0x7008, 0xa086, - 0x0800, 0x1188, 0x700c, 0xd0ec, 0x0160, 0xa084, 0x0f00, 0xa086, - 0x0100, 0x1138, 0x7024, 0xd0a4, 0x1110, 0xd0ac, 0x0110, 0xa006, - 0x0010, 0xa085, 0x0001, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6, - 0x0076, 0x0056, 0x0046, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, - 0x2029, 0xafd0, 0x252c, 0x2021, 0xafd6, 0x2424, 0x2061, 0xb400, - 0x2071, 0xad00, 0x7244, 0x7064, 0xa202, 0x16f0, 0x080c, 0xa990, - 0x05a0, 0x671c, 0xa786, 0x0001, 0x0580, 0xa786, 0x0007, 0x0568, - 0x2500, 0xac06, 0x0550, 0x2400, 0xac06, 0x0538, 0x00c6, 0x6000, - 0xa086, 0x0004, 0x1110, 0x080c, 0x190b, 0xa786, 0x0008, 0x1148, - 0x080c, 0x9789, 0x1130, 0x00ce, 0x080c, 0x85f3, 0x080c, 0x974e, - 0x00a0, 0x6010, 0x2068, 0x080c, 0x9596, 0x0160, 0xa786, 0x0003, - 0x11e8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x510c, - 0x080c, 0x9742, 0x080c, 0x974e, 0x00ce, 0xace0, 0x0018, 0x7058, - 0xac02, 0x1210, 0x0804, 0x8a2a, 0x012e, 0x000e, 0x002e, 0x004e, - 0x005e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0xa786, 0x0006, - 0x1d00, 0x080c, 0xa91f, 0x0c30, 0x220c, 0x2304, 0xa106, 0x1130, - 0x8210, 0x8318, 0x1f04, 0x8a7c, 0xa006, 0x0005, 0x2304, 0xa102, - 0x0218, 0x2001, 0x0001, 0x0010, 0x2001, 0x0000, 0xa18d, 0x0001, - 0x0005, 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x14f6, 0x080c, 0x9778, - 0x0120, 0x080c, 0x9789, 0x0168, 0x0028, 0x080c, 0x2aff, 0x080c, - 0x9789, 0x0138, 0x080c, 0x6b73, 0x080c, 0x8078, 0x080c, 0x6c50, - 0x0005, 0x080c, 0x85f3, 0x0cb0, 0xa182, 0x0040, 0x0002, 0x8ac2, - 0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2, - 0x8ac2, 0x8ac2, 0x8ac4, 0x8ac4, 0x8ac4, 0x8ac4, 0x8ac2, 0x8ac2, - 0x8ac2, 0x8ac4, 0x080c, 0x14f6, 0x600b, 0xffff, 0x6003, 0x0001, - 0x6106, 0x080c, 0x67a8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6c50, - 0x012e, 0x0005, 0xa186, 0x0013, 0x1128, 0x6004, 0xa082, 0x0040, - 0x0804, 0x8b5e, 0xa186, 0x0027, 0x11e8, 0x080c, 0x6b73, 0x080c, - 0x2ad9, 0x00d6, 0x6110, 0x2168, 0x080c, 0x9596, 0x0168, 0x6837, - 0x0103, 0x684b, 0x0029, 0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e, - 0x080c, 0x510c, 0x080c, 0x9742, 0x00de, 0x080c, 0x8078, 0x080c, - 0x6c50, 0x0005, 0xa186, 0x0014, 0x1120, 0x6004, 0xa082, 0x0040, - 0x0428, 0xa186, 0x0046, 0x0138, 0xa186, 0x0045, 0x0120, 0xa186, - 0x0047, 0x190c, 0x14f6, 0x2001, 0x0109, 0x2004, 0xd084, 0x0198, - 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x6699, - 0x002e, 0x001e, 0x000e, 0x012e, 0xe000, 0x6000, 0xa086, 0x0002, - 0x1110, 0x0804, 0x8b98, 0x080c, 0x80be, 0x0005, 0x0002, 0x8b3c, - 0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a, - 0x8b3a, 0x8b3a, 0x8b57, 0x8b57, 0x8b57, 0x8b57, 0x8b3a, 0x8b57, - 0x8b3a, 0x8b57, 0x080c, 0x14f6, 0x080c, 0x6b73, 0x00d6, 0x6110, - 0x2168, 0x080c, 0x9596, 0x0168, 0x6837, 0x0103, 0x684b, 0x0006, - 0x6847, 0x0000, 0x6850, 0xc0ec, 0x6852, 0x080c, 0x510c, 0x080c, - 0x9742, 0x00de, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005, 0x080c, - 0x6b73, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005, 0x0002, 0x8b74, - 0x8b72, 0x8b72, 0x8b72, 0x8b72, 0x8b72, 0x8b72, 0x8b72, 0x8b72, - 0x8b72, 0x8b72, 0x8b86, 0x8b86, 0x8b86, 0x8b86, 0x8b72, 0x8b91, - 0x8b72, 0x8b86, 0x080c, 0x14f6, 0x080c, 0x6b73, 0x2001, 0xafa5, - 0x2004, 0x603e, 0x6003, 0x0002, 0x080c, 0x6c50, 0x6010, 0xa088, - 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x0005, 0x080c, 0x6b73, - 0x2001, 0xafa5, 0x2004, 0x603e, 0x6003, 0x000f, 0x080c, 0x6c50, - 0x0005, 0x080c, 0x6b73, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005, - 0xa182, 0x0040, 0x0002, 0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x8bae, - 0x8bb0, 0x8c88, 0x8ca9, 0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x8bae, - 0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x080c, 0x14f6, - 0x00e6, 0x00d6, 0x603f, 0x0000, 0x2071, 0xb280, 0x7124, 0x610a, - 0x2071, 0xb28c, 0x6110, 0x2168, 0x7614, 0xa6b4, 0x0fff, 0x86ff, - 0x0904, 0x8c54, 0xa68c, 0x0c00, 0x01e8, 0x00f6, 0x2c78, 0x080c, - 0x5029, 0x00fe, 0x0198, 0x684c, 0xd0ac, 0x0180, 0x6020, 0xd0dc, - 0x1168, 0x6850, 0xd0bc, 0x1150, 0x7318, 0x6814, 0xa306, 0x1904, - 0x8c66, 0x731c, 0x6810, 0xa306, 0x1904, 0x8c66, 0x7318, 0x6b62, - 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0518, 0xa186, - 0x0028, 0x1128, 0x080c, 0x9767, 0x684b, 0x001c, 0x00e8, 0xd6dc, - 0x01a0, 0x684b, 0x0015, 0x684c, 0xd0ac, 0x0170, 0x6914, 0x6a10, - 0x2100, 0xa205, 0x0148, 0x7018, 0xa106, 0x1118, 0x701c, 0xa206, - 0x0118, 0x6962, 0x6a5e, 0xc6dc, 0x0038, 0xd6d4, 0x0118, 0x684b, - 0x0007, 0x0010, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0xa01e, - 0xd6c4, 0x01f0, 0xa686, 0x0100, 0x1140, 0x2001, 0xb299, 0x2004, - 0xa005, 0x1118, 0xc6c4, 0x0804, 0x8bbf, 0x7328, 0x732c, 0x6b56, - 0x83ff, 0x0170, 0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, - 0x2308, 0x2019, 0xb298, 0xad90, 0x0019, 0x080c, 0x927f, 0x003e, - 0xd6cc, 0x0904, 0x8c79, 0x7124, 0x695a, 0x81ff, 0x0904, 0x8c79, - 0xa192, 0x0021, 0x1250, 0x2071, 0xb298, 0x831c, 0x2300, 0xae18, - 0xad90, 0x001d, 0x080c, 0x927f, 0x04a0, 0x6838, 0xd0fc, 0x0120, - 0x2009, 0x0020, 0x695a, 0x0c78, 0x00f6, 0x2d78, 0x080c, 0x9224, - 0x00fe, 0x080c, 0x926f, 0x0438, 0x00f6, 0x2c78, 0x080c, 0x5029, - 0x00fe, 0x0188, 0x684c, 0xd0ac, 0x0170, 0x6020, 0xd0dc, 0x1158, - 0x6850, 0xd0bc, 0x1140, 0x684c, 0xd0f4, 0x1128, 0x080c, 0x9866, - 0x00de, 0x00ee, 0x00e0, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, - 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, - 0x8e04, 0x080c, 0x510c, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, - 0x080c, 0x9834, 0x00de, 0x00ee, 0x1110, 0x080c, 0x8078, 0x0005, - 0x00f6, 0x6003, 0x0003, 0x2079, 0xb28c, 0x7c04, 0x7b00, 0x7e0c, - 0x7d08, 0x6010, 0x2078, 0x784c, 0xd0ac, 0x0120, 0x6003, 0x0002, - 0x00fe, 0x0005, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x00fe, 0x603f, - 0x0000, 0x2c10, 0x080c, 0x1e6e, 0x080c, 0x680b, 0x080c, 0x6d0d, - 0x0005, 0x2001, 0xafa5, 0x2004, 0x603e, 0x6003, 0x0004, 0x6110, - 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x1824, 0x0005, - 0xa182, 0x0040, 0x0002, 0x8cce, 0x8cce, 0x8cce, 0x8cce, 0x8cce, - 0x8cd0, 0x8d61, 0x8cce, 0x8cce, 0x8d77, 0x8ddb, 0x8cce, 0x8cce, - 0x8cce, 0x8cce, 0x8dea, 0x8cce, 0x8cce, 0x8cce, 0x080c, 0x14f6, - 0x0076, 0x00f6, 0x00e6, 0x00d6, 0x2071, 0xb28c, 0x6110, 0x2178, - 0x7614, 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, - 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0904, 0x8d5c, 0xa694, - 0xff00, 0xa284, 0x0c00, 0x0120, 0x7018, 0x7862, 0x701c, 0x785e, - 0xa284, 0x0300, 0x0904, 0x8d5c, 0x080c, 0x15d9, 0x090c, 0x14f6, - 0x2d00, 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, - 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, - 0x0120, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, - 0x0002, 0x0180, 0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, - 0xd6dc, 0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, - 0x0007, 0x0010, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, - 0x6856, 0xa01e, 0xd6c4, 0x0198, 0x7328, 0x732c, 0x6b56, 0x83ff, - 0x0170, 0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, - 0x2019, 0xb298, 0xad90, 0x0019, 0x080c, 0x927f, 0x003e, 0xd6cc, - 0x01d8, 0x7124, 0x695a, 0x81ff, 0x01b8, 0xa192, 0x0021, 0x1250, - 0x2071, 0xb298, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, - 0x927f, 0x0050, 0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, - 0x0c78, 0x2d78, 0x080c, 0x9224, 0x00de, 0x00ee, 0x00fe, 0x007e, - 0x0005, 0x00f6, 0x6003, 0x0003, 0x2079, 0xb28c, 0x7c04, 0x7b00, - 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, - 0x00fe, 0x2c10, 0x080c, 0x1e6e, 0x080c, 0x781a, 0x0005, 0x00d6, - 0x00f6, 0x2c78, 0x080c, 0x5029, 0x00fe, 0x0120, 0x2001, 0xafa5, - 0x2004, 0x603e, 0x6003, 0x0002, 0x080c, 0x6c05, 0x080c, 0x6d0d, - 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0904, 0x8dd9, 0xd1cc, 0x0540, - 0x6948, 0x6838, 0xd0fc, 0x01e8, 0x0016, 0x684c, 0x0006, 0x6850, - 0x0006, 0xad90, 0x000d, 0xa198, 0x000d, 0x2009, 0x0020, 0x0156, - 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, 0x1f04, 0x8da1, 0x015e, - 0x000e, 0x6852, 0x000e, 0x684e, 0x001e, 0x2168, 0x080c, 0x1600, - 0x0418, 0x0016, 0x080c, 0x1600, 0x00de, 0x080c, 0x926f, 0x00e0, - 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0180, - 0xa086, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd1dc, 0x0118, - 0x684b, 0x0015, 0x0038, 0xd1d4, 0x0118, 0x684b, 0x0007, 0x0010, - 0x684b, 0x0000, 0x080c, 0x510c, 0x080c, 0x9834, 0x1110, 0x080c, - 0x8078, 0x00de, 0x0005, 0x2019, 0x0001, 0x080c, 0x7a64, 0x6003, - 0x0002, 0x2001, 0xafa5, 0x2004, 0x603e, 0x080c, 0x6c05, 0x080c, - 0x6d0d, 0x0005, 0x080c, 0x6c05, 0x080c, 0x2ad9, 0x00d6, 0x6110, - 0x2168, 0x080c, 0x9596, 0x0150, 0x6837, 0x0103, 0x684b, 0x0029, - 0x6847, 0x0000, 0x080c, 0x510c, 0x080c, 0x9742, 0x00de, 0x080c, - 0x8078, 0x080c, 0x6d0d, 0x0005, 0x684b, 0x0015, 0xd1fc, 0x0138, - 0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, 0x0000, 0x6962, - 0x685e, 0x0005, 0xa182, 0x0040, 0x0002, 0x8e28, 0x8e28, 0x8e28, - 0x8e28, 0x8e28, 0x8e2a, 0x8e28, 0x8ee3, 0x8eef, 0x8e28, 0x8e28, - 0x8e28, 0x8e28, 0x8e28, 0x8e28, 0x8e28, 0x8e28, 0x8e28, 0x8e28, - 0x080c, 0x14f6, 0x0076, 0x00f6, 0x00e6, 0x00d6, 0x2071, 0xb28c, - 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x00f6, 0x2c78, 0x080c, - 0x5029, 0x00fe, 0x0150, 0xa684, 0x00ff, 0x1138, 0x6020, 0xd0f4, - 0x0120, 0x080c, 0x9866, 0x0804, 0x8ede, 0x7e46, 0x7f4c, 0xc7e5, - 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0904, - 0x8ed4, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0120, 0x7018, 0x7862, - 0x701c, 0x785e, 0xa284, 0x0300, 0x0904, 0x8ed2, 0xa686, 0x0100, - 0x1140, 0x2001, 0xb299, 0x2004, 0xa005, 0x1118, 0xc6c4, 0x7e46, - 0x0c28, 0x080c, 0x15d9, 0x090c, 0x14f6, 0x2d00, 0x784a, 0x7f4c, - 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c, - 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, 0x0120, 0x7318, - 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0180, - 0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd6dc, 0x0118, - 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007, 0x0010, - 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, - 0xd6c4, 0x0198, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0170, 0xa38a, - 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0xb298, - 0xad90, 0x0019, 0x080c, 0x927f, 0x003e, 0xd6cc, 0x01d8, 0x7124, - 0x695a, 0x81ff, 0x01b8, 0xa192, 0x0021, 0x1250, 0x2071, 0xb298, - 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x927f, 0x0050, - 0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78, 0x2d78, - 0x080c, 0x9224, 0xd6dc, 0x1110, 0xa006, 0x0030, 0x2001, 0x0001, - 0x2071, 0xb28c, 0x7218, 0x731c, 0x080c, 0x186f, 0x00de, 0x00ee, - 0x00fe, 0x007e, 0x0005, 0x2001, 0xafa5, 0x2004, 0x603e, 0x20e1, - 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x1824, 0x0005, 0x2001, - 0xafa5, 0x2004, 0x603e, 0x00d6, 0x6003, 0x0002, 0x6110, 0x2168, - 0x694c, 0xd1e4, 0x0904, 0x8ff3, 0x603f, 0x0000, 0x00f6, 0x2c78, - 0x080c, 0x5029, 0x00fe, 0x0548, 0x6814, 0x6910, 0xa115, 0x0528, - 0x6a60, 0xa206, 0x1118, 0x685c, 0xa106, 0x01f8, 0x684c, 0xc0e4, - 0x684e, 0x6847, 0x0000, 0x6863, 0x0000, 0x685f, 0x0000, 0x697c, - 0x6810, 0xa102, 0x603a, 0x6980, 0x6814, 0xa103, 0x6036, 0x6020, - 0xc0f5, 0x6022, 0x00d6, 0x6018, 0x2068, 0x683c, 0x8000, 0x683e, - 0x00de, 0x080c, 0x9866, 0x0804, 0x8ff3, 0x694c, 0xd1cc, 0x0904, - 0x8fc3, 0x6948, 0x6838, 0xd0fc, 0x0904, 0x8f88, 0x0016, 0x684c, - 0x0006, 0x6850, 0x0006, 0x00f6, 0x2178, 0x7944, 0xa184, 0x00ff, - 0xa0b6, 0x0002, 0x01e0, 0xa086, 0x0028, 0x1128, 0x684b, 0x001c, - 0x784b, 0x001c, 0x00e8, 0xd1dc, 0x0158, 0x684b, 0x0015, 0x784b, - 0x0015, 0x080c, 0x99ee, 0x0118, 0x7944, 0xc1dc, 0x7946, 0x0080, - 0xd1d4, 0x0128, 0x684b, 0x0007, 0x784b, 0x0007, 0x0048, 0x684c, - 0xd0ac, 0x0130, 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x8e04, - 0x6848, 0x784a, 0x6860, 0x7862, 0x685c, 0x785e, 0xad90, 0x000d, - 0xaf98, 0x000d, 0x2009, 0x0020, 0x0156, 0x21a8, 0x2304, 0x2012, - 0x8318, 0x8210, 0x1f04, 0x8f76, 0x015e, 0x00fe, 0x000e, 0x6852, - 0x000e, 0x684e, 0x001e, 0x2168, 0x080c, 0x1600, 0x0804, 0x8fee, - 0x0016, 0x00f6, 0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, 0x0002, - 0x01e0, 0xa086, 0x0028, 0x1128, 0x684b, 0x001c, 0x784b, 0x001c, - 0x00e8, 0xd1dc, 0x0158, 0x684b, 0x0015, 0x784b, 0x0015, 0x080c, - 0x99ee, 0x0118, 0x7944, 0xc1dc, 0x7946, 0x0080, 0xd1d4, 0x0128, - 0x684b, 0x0007, 0x784b, 0x0007, 0x0048, 0x684c, 0xd0ac, 0x0130, - 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x8e04, 0x6860, 0x7862, - 0x685c, 0x785e, 0x684c, 0x784e, 0x00fe, 0x080c, 0x1600, 0x00de, - 0x080c, 0x926f, 0x0458, 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, - 0xa0b6, 0x0002, 0x01b0, 0xa086, 0x0028, 0x1118, 0x684b, 0x001c, - 0x00d8, 0xd1dc, 0x0148, 0x684b, 0x0015, 0x080c, 0x99ee, 0x0118, - 0x6944, 0xc1dc, 0x6946, 0x0080, 0xd1d4, 0x0118, 0x684b, 0x0007, - 0x0058, 0x684b, 0x0000, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914, - 0xa115, 0x0110, 0x080c, 0x8e04, 0x080c, 0x510c, 0x080c, 0x9834, - 0x1110, 0x080c, 0x8078, 0x00de, 0x0005, 0x080c, 0x6b73, 0x0010, - 0x080c, 0x6c05, 0x080c, 0x9596, 0x01c0, 0x00d6, 0x6110, 0x2168, - 0x6837, 0x0103, 0x2009, 0xad0c, 0x210c, 0xd18c, 0x11c0, 0xd184, - 0x1198, 0x6108, 0x694a, 0xa18e, 0x0029, 0x1110, 0x080c, 0xabfa, - 0x6847, 0x0000, 0x080c, 0x510c, 0x00de, 0x080c, 0x8078, 0x080c, - 0x6c50, 0x080c, 0x6d0d, 0x0005, 0x684b, 0x0004, 0x0c88, 0x684b, - 0x0004, 0x0c70, 0xa182, 0x0040, 0x0002, 0x9038, 0x9038, 0x9038, - 0x9038, 0x9038, 0x903a, 0x9038, 0x903d, 0x9038, 0x9038, 0x9038, - 0x9038, 0x9038, 0x9038, 0x9038, 0x9038, 0x9038, 0x9038, 0x9038, - 0x080c, 0x14f6, 0x080c, 0x8078, 0x0005, 0x0006, 0x0026, 0xa016, - 0x080c, 0x1824, 0x002e, 0x000e, 0x0005, 0xa182, 0x0085, 0x0002, - 0x9051, 0x904f, 0x904f, 0x905d, 0x904f, 0x904f, 0x904f, 0x080c, - 0x14f6, 0x6003, 0x0001, 0x6106, 0x080c, 0x67a8, 0x0126, 0x2091, - 0x8000, 0x080c, 0x6c50, 0x012e, 0x0005, 0x0026, 0x0056, 0x00d6, - 0x00e6, 0x2071, 0xb280, 0x7224, 0x6212, 0x7220, 0x080c, 0x9586, - 0x01a0, 0x2268, 0x6800, 0xa086, 0x0000, 0x0178, 0x6018, 0x6d18, - 0xa52e, 0x1158, 0x00c6, 0x2d60, 0x080c, 0x928f, 0x00ce, 0x0128, - 0x6803, 0x0002, 0x6007, 0x0086, 0x0010, 0x6007, 0x0087, 0x6003, - 0x0001, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x00f6, 0x2278, 0x080c, - 0x5029, 0x00fe, 0x0150, 0x6820, 0xd0ec, 0x0138, 0x00c6, 0x2260, - 0x603f, 0x0000, 0x080c, 0x9866, 0x00ce, 0x00ee, 0x00de, 0x005e, - 0x002e, 0x0005, 0xa186, 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085, - 0x0a0c, 0x14f6, 0xa08a, 0x008c, 0x1a0c, 0x14f6, 0xa082, 0x0085, - 0x0072, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c, 0x14f6, - 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, 0x90be, - 0x90c0, 0x90c0, 0x90be, 0x90be, 0x90be, 0x90be, 0x080c, 0x14f6, - 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, 0xa186, - 0x0013, 0x1128, 0x6004, 0xa082, 0x0085, 0x2008, 0x04a8, 0xa186, - 0x0027, 0x11e8, 0x080c, 0x6b73, 0x080c, 0x2ad9, 0x00d6, 0x6010, - 0x2068, 0x080c, 0x9596, 0x0150, 0x6837, 0x0103, 0x6847, 0x0000, - 0x684b, 0x0029, 0x080c, 0x510c, 0x080c, 0x9742, 0x00de, 0x080c, - 0x8078, 0x080c, 0x6c50, 0x0005, 0x080c, 0x80be, 0x0ce0, 0xa186, - 0x0014, 0x1dd0, 0x080c, 0x6b73, 0x00d6, 0x6010, 0x2068, 0x080c, - 0x9596, 0x0d60, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, 0x0006, - 0x6850, 0xc0ec, 0x6852, 0x08f0, 0x0002, 0x910e, 0x910c, 0x910c, - 0x910c, 0x910c, 0x910c, 0x9126, 0x080c, 0x14f6, 0x080c, 0x6b73, - 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186, - 0x0035, 0x1118, 0x2001, 0xafa3, 0x0010, 0x2001, 0xafa4, 0x2004, - 0x6016, 0x6003, 0x000c, 0x080c, 0x6c50, 0x0005, 0x080c, 0x6b73, - 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186, - 0x0035, 0x1118, 0x2001, 0xafa3, 0x0010, 0x2001, 0xafa4, 0x2004, - 0x6016, 0x6003, 0x000e, 0x080c, 0x6c50, 0x0005, 0xa182, 0x008c, - 0x1220, 0xa182, 0x0085, 0x0208, 0x001a, 0x080c, 0x80be, 0x0005, - 0x914f, 0x914f, 0x914f, 0x914f, 0x9151, 0x91a4, 0x914f, 0x080c, - 0x14f6, 0x00d6, 0x00f6, 0x2c78, 0x080c, 0x5029, 0x00fe, 0x0168, - 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186, - 0x0035, 0x1118, 0x00de, 0x0804, 0x91b7, 0x080c, 0x9742, 0x080c, - 0x9596, 0x01c8, 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, 0xd0b4, - 0x0128, 0x684b, 0x0006, 0xc0ec, 0x6852, 0x0048, 0xd0bc, 0x0118, - 0x684b, 0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x9803, 0x6847, - 0x0000, 0x080c, 0x510c, 0x2c68, 0x080c, 0x8022, 0x01c0, 0x6003, - 0x0001, 0x6007, 0x001e, 0x600b, 0xffff, 0x2009, 0xb28e, 0x210c, - 0x6136, 0x2009, 0xb28f, 0x210c, 0x613a, 0x6918, 0x611a, 0x080c, - 0x9956, 0x6950, 0x6152, 0x601f, 0x0001, 0x080c, 0x67a8, 0x2d60, - 0x080c, 0x8078, 0x00de, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5029, - 0x00fe, 0x0598, 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0035, - 0x0130, 0xa186, 0x001e, 0x0118, 0xa186, 0x0039, 0x1530, 0x00d6, - 0x2c68, 0x080c, 0x9a34, 0x1904, 0x91fc, 0x080c, 0x8022, 0x01d8, - 0x6106, 0x6003, 0x0001, 0x601f, 0x0001, 0x6918, 0x611a, 0x6928, - 0x612a, 0x692c, 0x612e, 0x6930, 0xa18c, 0x00ff, 0x6132, 0x6934, - 0x6136, 0x6938, 0x613a, 0x6950, 0x6152, 0x080c, 0x9956, 0x080c, - 0x67a8, 0x080c, 0x6c50, 0x2d60, 0x00f8, 0x00d6, 0x6010, 0x2068, - 0x080c, 0x9596, 0x01c8, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0128, - 0xc0ec, 0x6852, 0x684b, 0x0006, 0x0048, 0xd0bc, 0x0118, 0x684b, - 0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x9803, 0x6847, 0x0000, - 0x080c, 0x510c, 0x080c, 0x9742, 0x00de, 0x080c, 0x8078, 0x0005, - 0x0016, 0x00d6, 0x6010, 0x2068, 0x080c, 0x9596, 0x0140, 0x6837, - 0x0103, 0x684b, 0x0028, 0x6847, 0x0000, 0x080c, 0x510c, 0x00de, - 0x001e, 0xa186, 0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, - 0x0027, 0x0118, 0x080c, 0x80be, 0x0030, 0x080c, 0x6b73, 0x080c, - 0x974e, 0x080c, 0x6c50, 0x0005, 0x0056, 0x0066, 0x00d6, 0x00f6, - 0x2029, 0x0001, 0xa182, 0x0101, 0x1208, 0x0010, 0x2009, 0x0100, - 0x2130, 0x2069, 0xb298, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, - 0xaf90, 0x001d, 0x080c, 0x927f, 0xa6b2, 0x0020, 0x7804, 0xa06d, - 0x0110, 0x080c, 0x1600, 0x080c, 0x15d9, 0x0500, 0x8528, 0x6837, - 0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, 0x1228, - 0x2608, 0xad90, 0x000f, 0x0459, 0x0088, 0xa6b2, 0x003c, 0x2009, - 0x003c, 0x2d78, 0xad90, 0x000f, 0x0411, 0x0c28, 0x00fe, 0x852f, - 0xa5ad, 0x0003, 0x7d36, 0xa5ac, 0x0000, 0x0028, 0x00fe, 0x852f, - 0xa5ad, 0x0003, 0x7d36, 0x00de, 0x006e, 0x005e, 0x0005, 0x00f6, - 0x8dff, 0x0158, 0x6804, 0xa07d, 0x0130, 0x6807, 0x0000, 0x080c, - 0x510c, 0x2f68, 0x0cb8, 0x080c, 0x510c, 0x00fe, 0x0005, 0x0156, - 0xa184, 0x0001, 0x0108, 0x8108, 0x810c, 0x21a8, 0x2304, 0x8007, - 0x2012, 0x8318, 0x8210, 0x1f04, 0x9286, 0x015e, 0x0005, 0x0066, - 0x0126, 0x2091, 0x8000, 0x2031, 0x0001, 0x601c, 0xa084, 0x000f, - 0x0083, 0x012e, 0x006e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0066, - 0x2031, 0x0000, 0x601c, 0xa084, 0x000f, 0x001b, 0x006e, 0x012e, - 0x0005, 0x92c3, 0x92c3, 0x92be, 0x92e5, 0x92b1, 0x92be, 0x92e5, - 0x92be, 0x080c, 0x14f6, 0x0036, 0x2019, 0x0010, 0x080c, 0xa566, - 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0xa006, 0x0005, - 0xa085, 0x0001, 0x0005, 0x00d6, 0x86ff, 0x11d8, 0x6010, 0x2068, - 0x080c, 0x9596, 0x01c0, 0x6834, 0xa086, 0x0139, 0x1128, 0x684b, - 0x0005, 0x6853, 0x0000, 0x0028, 0xa00e, 0x2001, 0x0005, 0x080c, - 0x51df, 0x080c, 0x9803, 0x080c, 0x510c, 0x080c, 0x8078, 0xa085, - 0x0001, 0x00de, 0x0005, 0xa006, 0x0ce0, 0x6000, 0xa08a, 0x0010, - 0x1a0c, 0x14f6, 0x000b, 0x0005, 0x92fc, 0x9319, 0x92fe, 0x9338, - 0x9316, 0x92fc, 0x92be, 0x92c3, 0x92c3, 0x92be, 0x92be, 0x92be, - 0x92be, 0x92be, 0x92be, 0x92be, 0x080c, 0x14f6, 0x86ff, 0x1198, - 0x00d6, 0x6010, 0x2068, 0x080c, 0x9596, 0x0110, 0x080c, 0x9803, - 0x00de, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, - 0x67a8, 0x080c, 0x6c50, 0xa085, 0x0001, 0x0005, 0x080c, 0x190b, - 0x0c28, 0x00e6, 0x2071, 0xafc7, 0x7024, 0xac06, 0x1110, 0x080c, - 0x79e1, 0x601c, 0xa084, 0x000f, 0xa086, 0x0006, 0x1150, 0x0086, - 0x0096, 0x2049, 0x0001, 0x2c40, 0x080c, 0x7b9a, 0x009e, 0x008e, - 0x0010, 0x080c, 0x78de, 0x00ee, 0x1948, 0x080c, 0x92be, 0x0005, - 0x0036, 0x00e6, 0x2071, 0xafc7, 0x703c, 0xac06, 0x1140, 0x2019, - 0x0000, 0x080c, 0x7a64, 0x00ee, 0x003e, 0x0804, 0x92fe, 0x080c, - 0x7cb8, 0x00ee, 0x003e, 0x1904, 0x92fe, 0x080c, 0x92be, 0x0005, - 0x00c6, 0x601c, 0xa084, 0x000f, 0x0013, 0x00ce, 0x0005, 0x9369, - 0x93d3, 0x9501, 0x9374, 0x974e, 0x9369, 0xa558, 0x8078, 0x93d3, - 0x9362, 0x955f, 0x080c, 0x14f6, 0x080c, 0x9789, 0x1110, 0x080c, - 0x85f3, 0x0005, 0x080c, 0x6b73, 0x080c, 0x6c50, 0x080c, 0x8078, - 0x0005, 0x6017, 0x0001, 0x0005, 0x6010, 0xa080, 0x0019, 0x2c02, - 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14f6, 0x000b, 0x0005, 0x938f, - 0x9391, 0x93b1, 0x93c3, 0x93d0, 0x938f, 0x9369, 0x9369, 0x9369, - 0x93c3, 0x93c3, 0x938f, 0x938f, 0x938f, 0x938f, 0x93cd, 0x080c, - 0x14f6, 0x00e6, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, - 0xafc7, 0x7024, 0xac06, 0x0190, 0x080c, 0x78de, 0x6007, 0x0085, - 0x6003, 0x000b, 0x601f, 0x0002, 0x2001, 0xafa4, 0x2004, 0x6016, - 0x080c, 0x67a8, 0x080c, 0x6c50, 0x00ee, 0x0005, 0x6017, 0x0001, - 0x0cd8, 0x00d6, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x00de, - 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x67a8, - 0x080c, 0x6c50, 0x0005, 0x00d6, 0x6017, 0x0001, 0x6010, 0x2068, - 0x6850, 0xc0b5, 0x6852, 0x00de, 0x0005, 0x080c, 0x8078, 0x0005, - 0x080c, 0x190b, 0x08f0, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14f6, - 0x000b, 0x0005, 0x93ea, 0x9371, 0x93ec, 0x93ea, 0x93ec, 0x93ec, - 0x936a, 0x93ea, 0x9364, 0x9364, 0x93ea, 0x93ea, 0x93ea, 0x93ea, - 0x93ea, 0x93ea, 0x080c, 0x14f6, 0x00d6, 0x6018, 0x2068, 0x6804, - 0xa084, 0x00ff, 0x00de, 0xa08a, 0x000c, 0x1a0c, 0x14f6, 0x000b, - 0x0005, 0x9405, 0x94a7, 0x9407, 0x9441, 0x9407, 0x9441, 0x9407, - 0x9411, 0x9405, 0x9441, 0x9405, 0x942d, 0x080c, 0x14f6, 0x6004, - 0xa08e, 0x0016, 0x0588, 0xa08e, 0x0004, 0x0570, 0xa08e, 0x0002, - 0x0558, 0x6004, 0x080c, 0x9789, 0x0904, 0x94c0, 0xa08e, 0x0021, - 0x0904, 0x94c4, 0xa08e, 0x0022, 0x0904, 0x94c0, 0xa08e, 0x003d, - 0x0904, 0x94c4, 0xa08e, 0x0039, 0x0904, 0x94c8, 0xa08e, 0x0035, - 0x0904, 0x94c8, 0xa08e, 0x001e, 0x0188, 0xa08e, 0x0001, 0x1150, - 0x00d6, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x00de, 0xa086, - 0x0006, 0x0110, 0x080c, 0x2ad9, 0x080c, 0x85f3, 0x080c, 0x974e, - 0x0005, 0x00c6, 0x00d6, 0x6104, 0xa186, 0x0016, 0x0904, 0x9498, - 0xa186, 0x0002, 0x1518, 0x6018, 0x2068, 0x2001, 0xad34, 0x2004, - 0xd0ac, 0x1904, 0x94ea, 0x68a0, 0xd0bc, 0x1904, 0x94ea, 0x6840, - 0xa084, 0x00ff, 0xa005, 0x0190, 0x8001, 0x6842, 0x6013, 0x0000, - 0x601f, 0x0007, 0x6017, 0x0398, 0x603f, 0x0000, 0x080c, 0x8022, - 0x0128, 0x2d00, 0x601a, 0x601f, 0x0001, 0x0450, 0x00de, 0x00ce, - 0x6004, 0xa08e, 0x0002, 0x11a8, 0x6018, 0xa080, 0x0028, 0x2004, - 0xa086, 0x007e, 0x1170, 0x2009, 0xad34, 0x2104, 0xc085, 0x200a, - 0x00e6, 0x2071, 0xad00, 0x080c, 0x48f5, 0x00ee, 0x080c, 0x85f3, - 0x0020, 0x080c, 0x85f3, 0x080c, 0x2ad9, 0x00e6, 0x0126, 0x2091, - 0x8000, 0x080c, 0x2aff, 0x012e, 0x00ee, 0x080c, 0x974e, 0x0005, - 0x2001, 0x0002, 0x080c, 0x4c30, 0x6003, 0x0001, 0x6007, 0x0002, - 0x080c, 0x67ee, 0x080c, 0x6c50, 0x00de, 0x00ce, 0x0c80, 0x00c6, - 0x00d6, 0x6104, 0xa186, 0x0016, 0x0d58, 0x6018, 0x2068, 0x6840, - 0xa084, 0x00ff, 0xa005, 0x0904, 0x946e, 0x8001, 0x6842, 0x6003, - 0x0001, 0x080c, 0x67ee, 0x080c, 0x6c50, 0x00de, 0x00ce, 0x08b8, - 0x080c, 0x85f3, 0x0804, 0x943e, 0x080c, 0x8621, 0x0804, 0x943e, - 0x00d6, 0x2c68, 0x6104, 0x080c, 0x9a34, 0x00de, 0x0118, 0x080c, - 0x8078, 0x00b8, 0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105, - 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038, - 0x600a, 0x2001, 0xafa4, 0x2004, 0x6016, 0x080c, 0x67a8, 0x080c, - 0x6c50, 0x0005, 0x00de, 0x00ce, 0x080c, 0x85f3, 0x080c, 0x2ad9, - 0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2aff, 0x6013, 0x0000, - 0x601f, 0x0007, 0x6017, 0x0398, 0x603f, 0x0000, 0x012e, 0x00ee, - 0x0005, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14f6, 0x000b, 0x0005, - 0x9518, 0x9518, 0x9518, 0x9518, 0x9518, 0x9518, 0x9518, 0x9518, - 0x9518, 0x9369, 0x9518, 0x9371, 0x951a, 0x9371, 0x9527, 0x9518, - 0x080c, 0x14f6, 0x6004, 0xa086, 0x008b, 0x0148, 0x6007, 0x008b, - 0x6003, 0x000d, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0005, 0x080c, - 0x9742, 0x080c, 0x9596, 0x0580, 0x080c, 0x2ad9, 0x00d6, 0x080c, - 0x9596, 0x0168, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006, - 0x6847, 0x0000, 0x6850, 0xc0ed, 0x6852, 0x080c, 0x510c, 0x2c68, - 0x080c, 0x8022, 0x0150, 0x6818, 0x601a, 0x080c, 0x9956, 0x00c6, - 0x2d60, 0x080c, 0x974e, 0x00ce, 0x0008, 0x2d60, 0x00de, 0x6013, - 0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, - 0x67ee, 0x080c, 0x6c50, 0x0010, 0x080c, 0x974e, 0x0005, 0x6000, - 0xa08a, 0x0010, 0x1a0c, 0x14f6, 0x000b, 0x0005, 0x9576, 0x9576, - 0x9576, 0x9578, 0x9579, 0x9576, 0x9576, 0x9576, 0x9576, 0x9576, - 0x9576, 0x9576, 0x9576, 0x9576, 0x9576, 0x9576, 0x080c, 0x14f6, - 0x0005, 0x080c, 0x7cb8, 0x190c, 0x14f6, 0x6110, 0x2168, 0x684b, - 0x0006, 0x080c, 0x510c, 0x080c, 0x8078, 0x0005, 0xa284, 0x0007, - 0x1158, 0xa282, 0xb400, 0x0240, 0x2001, 0xad16, 0x2004, 0xa202, - 0x1218, 0xa085, 0x0001, 0x0005, 0xa006, 0x0ce8, 0x0026, 0x6210, - 0xa294, 0xf000, 0x002e, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0006, - 0x0126, 0x2091, 0x8000, 0x2061, 0xb400, 0x2071, 0xad00, 0x7344, - 0x7064, 0xa302, 0x12a8, 0x601c, 0xa206, 0x1160, 0x080c, 0x98e3, - 0x0148, 0x080c, 0x9789, 0x1110, 0x080c, 0x85f3, 0x00c6, 0x080c, - 0x8078, 0x00ce, 0xace0, 0x0018, 0x7058, 0xac02, 0x1208, 0x0c38, - 0x012e, 0x000e, 0x003e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, - 0x0016, 0xa188, 0xae34, 0x210c, 0x81ff, 0x0170, 0x2061, 0xb400, - 0x2071, 0xad00, 0x0016, 0x080c, 0x8022, 0x001e, 0x0138, 0x611a, - 0x080c, 0x2ad9, 0x080c, 0x8078, 0xa006, 0x0010, 0xa085, 0x0001, - 0x001e, 0x00ce, 0x00ee, 0x0005, 0x00c6, 0x0056, 0x0126, 0x2091, - 0x8000, 0x00c6, 0x080c, 0x8022, 0x005e, 0x0180, 0x6612, 0x651a, - 0x080c, 0x9956, 0x601f, 0x0003, 0x2009, 0x004b, 0x080c, 0x80a7, - 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, 0x0005, 0xa006, 0x0cd0, - 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, 0x62a0, 0x00c6, 0x080c, - 0x8022, 0x005e, 0x0508, 0x6013, 0x0000, 0x651a, 0x080c, 0x9956, - 0x601f, 0x0003, 0x00c6, 0x2560, 0x080c, 0x4ecf, 0x00ce, 0x080c, - 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x2c08, 0x080c, - 0xa712, 0x007e, 0x2009, 0x004c, 0x080c, 0x80a7, 0xa085, 0x0001, - 0x012e, 0x005e, 0x00ce, 0x0005, 0xa006, 0x0cd0, 0x00f6, 0x00c6, - 0x0046, 0x00c6, 0x080c, 0x8022, 0x2c78, 0x00ce, 0x0180, 0x7e12, - 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, 0x0005, 0x080c, 0x9683, - 0x2f60, 0x2009, 0x004d, 0x080c, 0x80a7, 0xa085, 0x0001, 0x004e, - 0x00ce, 0x00fe, 0x0005, 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c, - 0x8022, 0x2c78, 0x00ce, 0x0178, 0x7e12, 0x2c00, 0x781a, 0x781f, - 0x0003, 0x2021, 0x0005, 0x0439, 0x2f60, 0x2009, 0x004e, 0x080c, - 0x80a7, 0xa085, 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6, - 0x00c6, 0x0046, 0x00c6, 0x080c, 0x8022, 0x2c78, 0x00ce, 0x0178, - 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, 0x0004, 0x0059, - 0x2f60, 0x2009, 0x0052, 0x080c, 0x80a7, 0xa085, 0x0001, 0x004e, - 0x00ce, 0x00fe, 0x0005, 0x0096, 0x0076, 0x0126, 0x2091, 0x8000, - 0x080c, 0x4e71, 0x0118, 0x2001, 0x9688, 0x0028, 0x080c, 0x4e43, - 0x0158, 0x2001, 0x968e, 0x0006, 0xa00e, 0x2400, 0x080c, 0x51df, - 0x080c, 0x510c, 0x000e, 0x0807, 0x2418, 0x080c, 0x6b15, 0x62a0, - 0x0086, 0x2041, 0x0001, 0x2039, 0x0001, 0x2608, 0x080c, 0x6900, - 0x008e, 0x080c, 0x681d, 0x2f08, 0x2648, 0x080c, 0xa712, 0x613c, - 0x81ff, 0x090c, 0x69a9, 0x012e, 0x007e, 0x009e, 0x0005, 0x00c6, - 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0188, - 0x660a, 0x611a, 0x080c, 0x9956, 0x601f, 0x0001, 0x2d00, 0x6012, - 0x2009, 0x001f, 0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, - 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, - 0x080c, 0x8022, 0x001e, 0x0188, 0x660a, 0x611a, 0x080c, 0x9956, - 0x601f, 0x0008, 0x2d00, 0x6012, 0x2009, 0x0021, 0x080c, 0x80a7, - 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, - 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0188, - 0x660a, 0x611a, 0x080c, 0x9956, 0x601f, 0x0001, 0x2d00, 0x6012, - 0x2009, 0x003d, 0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, - 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, - 0x080c, 0x9807, 0x001e, 0x0180, 0x611a, 0x080c, 0x9956, 0x601f, - 0x0001, 0x2d00, 0x6012, 0x2009, 0x0000, 0x080c, 0x80a7, 0xa085, - 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, - 0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0188, 0x660a, - 0x611a, 0x080c, 0x9956, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, - 0x0044, 0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, - 0xa006, 0x0cd8, 0x0026, 0x00d6, 0x6218, 0x2268, 0x6a3c, 0x82ff, - 0x0110, 0x8211, 0x6a3e, 0x00de, 0x002e, 0x0005, 0x0006, 0x6000, - 0xa086, 0x0000, 0x0190, 0x6013, 0x0000, 0x601f, 0x0007, 0x2001, - 0xafa3, 0x2004, 0x0006, 0xa082, 0x0051, 0x000e, 0x0208, 0x8004, - 0x6016, 0x080c, 0xabb4, 0x603f, 0x0000, 0x000e, 0x0005, 0x0066, - 0x00c6, 0x00d6, 0x2031, 0xad52, 0x2634, 0xd6e4, 0x0128, 0x6618, - 0x2660, 0x6e48, 0x080c, 0x4dfc, 0x00de, 0x00ce, 0x006e, 0x0005, - 0x0006, 0x0016, 0x6004, 0xa08e, 0x0002, 0x0140, 0xa08e, 0x0003, - 0x0128, 0xa08e, 0x0004, 0x0110, 0xa085, 0x0001, 0x001e, 0x000e, - 0x0005, 0x0006, 0x00d6, 0x6010, 0xa06d, 0x0148, 0x6834, 0xa086, - 0x0139, 0x0138, 0x6838, 0xd0fc, 0x0110, 0xa006, 0x0010, 0xa085, - 0x0001, 0x00de, 0x000e, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, - 0x00c6, 0x080c, 0x8022, 0x001e, 0x0190, 0x611a, 0x080c, 0x9956, - 0x601f, 0x0001, 0x2d00, 0x6012, 0x080c, 0x2ad9, 0x2009, 0x0028, - 0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, - 0x0cd8, 0xa186, 0x0015, 0x1178, 0x2011, 0xad20, 0x2204, 0xa086, - 0x0074, 0x1148, 0x080c, 0x8943, 0x6003, 0x0001, 0x6007, 0x0029, - 0x080c, 0x67ee, 0x0020, 0x080c, 0x85f3, 0x080c, 0x8078, 0x0005, - 0xa186, 0x0016, 0x1128, 0x2001, 0x0004, 0x080c, 0x4c30, 0x00e8, - 0xa186, 0x0015, 0x11e8, 0x2011, 0xad20, 0x2204, 0xa086, 0x0014, - 0x11b8, 0x00d6, 0x6018, 0x2068, 0x080c, 0x4d72, 0x00de, 0x080c, - 0x89f7, 0x1170, 0x00d6, 0x6018, 0x2068, 0x6890, 0x00de, 0xa005, - 0x0138, 0x2001, 0x0006, 0x080c, 0x4c30, 0x080c, 0x81f6, 0x0020, - 0x080c, 0x85f3, 0x080c, 0x8078, 0x0005, 0x6848, 0xa086, 0x0005, - 0x1108, 0x0009, 0x0005, 0x6850, 0xc0ad, 0x6852, 0x0005, 0x00e6, - 0x0126, 0x2071, 0xad00, 0x2091, 0x8000, 0x7544, 0xa582, 0x0001, - 0x0608, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, - 0x0018, 0x7058, 0xac02, 0x1208, 0x0cb0, 0x2061, 0xb400, 0x0c98, - 0x6003, 0x0008, 0x8529, 0x7546, 0xaca8, 0x0018, 0x7058, 0xa502, - 0x1230, 0x754a, 0xa085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x704b, - 0xb400, 0x0cc0, 0xa006, 0x0cc0, 0x00e6, 0x2071, 0xb28c, 0x7014, - 0xd0e4, 0x0150, 0x6013, 0x0000, 0x6003, 0x0001, 0x6007, 0x0050, - 0x080c, 0x67a8, 0x080c, 0x6c50, 0x00ee, 0x0005, 0x00c6, 0x00f6, - 0x2c78, 0x080c, 0x5029, 0x00fe, 0x0120, 0x601c, 0xa084, 0x000f, - 0x0013, 0x00ce, 0x0005, 0x9369, 0x985e, 0x9861, 0x9864, 0xa9a7, - 0xa9c2, 0xa9c5, 0x9369, 0x9369, 0x080c, 0x14f6, 0xe000, 0xe000, - 0x0005, 0xe000, 0xe000, 0x0005, 0x0009, 0x0005, 0x00f6, 0x2c78, - 0x080c, 0x5029, 0x0538, 0x080c, 0x8022, 0x1128, 0x2001, 0xafa5, - 0x2004, 0x783e, 0x00f8, 0x7818, 0x601a, 0x080c, 0x9956, 0x781c, - 0xa086, 0x0003, 0x0128, 0x7808, 0x6036, 0x2f00, 0x603a, 0x0020, - 0x7808, 0x603a, 0x2f00, 0x6036, 0x602a, 0x601f, 0x0001, 0x6007, - 0x0035, 0x6003, 0x0001, 0x7950, 0x6152, 0x080c, 0x67a8, 0x080c, - 0x6c50, 0x2f60, 0x00fe, 0x0005, 0x0016, 0x00f6, 0x682c, 0x6032, - 0xa08e, 0x0001, 0x0138, 0xa086, 0x0005, 0x0140, 0xa006, 0x602a, - 0x602e, 0x00a0, 0x6820, 0xc0f4, 0xc0d5, 0x6822, 0x6810, 0x2078, - 0x787c, 0x6938, 0xa102, 0x7880, 0x6934, 0xa103, 0x1e78, 0x6834, - 0x602a, 0x6838, 0xa084, 0xfffc, 0x683a, 0x602e, 0x2d00, 0x6036, - 0x6808, 0x603a, 0x6918, 0x611a, 0x6950, 0x6152, 0x601f, 0x0001, - 0x6007, 0x0039, 0x6003, 0x0001, 0x080c, 0x67a8, 0x6803, 0x0002, - 0x00fe, 0x001e, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5029, 0x1118, - 0xa085, 0x0001, 0x0070, 0x6020, 0xd0f4, 0x1150, 0xc0f5, 0x6022, - 0x6010, 0x2078, 0x7828, 0x603a, 0x782c, 0x6036, 0x080c, 0x190b, - 0xa006, 0x00fe, 0x0005, 0x0006, 0x0016, 0x6004, 0xa08e, 0x0034, - 0x01b8, 0xa08e, 0x0035, 0x01a0, 0xa08e, 0x0036, 0x0188, 0xa08e, - 0x0037, 0x0170, 0xa08e, 0x0038, 0x0158, 0xa08e, 0x0039, 0x0140, - 0xa08e, 0x003a, 0x0128, 0xa08e, 0x003b, 0x0110, 0xa085, 0x0001, - 0x001e, 0x000e, 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x00e6, - 0x2001, 0xaf9f, 0x200c, 0x8000, 0x2014, 0x2001, 0x0032, 0x080c, - 0x6665, 0x2001, 0xafa3, 0x82ff, 0x1110, 0x2011, 0x0002, 0x2202, - 0x2001, 0xafa1, 0x200c, 0x8000, 0x2014, 0x2071, 0xaf8d, 0x711a, - 0x721e, 0x2001, 0x0064, 0x080c, 0x6665, 0x2001, 0xafa4, 0x82ff, - 0x1110, 0x2011, 0x0002, 0x2202, 0x2009, 0xafa5, 0xa280, 0x000a, - 0x200a, 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, 0x0006, - 0x00e6, 0x2001, 0xafa3, 0x2003, 0x0028, 0x2001, 0xafa4, 0x2003, - 0x0014, 0x2071, 0xaf8d, 0x701b, 0x0000, 0x701f, 0x07d0, 0x2001, - 0xafa5, 0x2003, 0x001e, 0x00ee, 0x000e, 0x0005, 0x00d6, 0x6054, - 0xa06d, 0x0110, 0x080c, 0x15f0, 0x00de, 0x0005, 0x0005, 0x00c6, - 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0178, - 0x611a, 0x0ca1, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0033, - 0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, - 0x0cd8, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xad00, 0xa186, 0x0015, - 0x1500, 0x7080, 0xa086, 0x0018, 0x11e0, 0x6010, 0x2068, 0x6a3c, - 0xd2e4, 0x1160, 0x2c78, 0x080c, 0x6e05, 0x01d8, 0x706c, 0x6a50, - 0xa206, 0x1160, 0x7070, 0x6a54, 0xa206, 0x1140, 0x6218, 0xa290, - 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x2b1e, 0x080c, 0x81f6, - 0x0020, 0x080c, 0x85f3, 0x080c, 0x8078, 0x00fe, 0x00ee, 0x00de, - 0x0005, 0x7050, 0x6a54, 0xa206, 0x0d48, 0x0c80, 0x00c6, 0x0126, - 0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0180, 0x611a, - 0x080c, 0x9956, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0043, - 0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, - 0x0cd8, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xad00, 0xa186, 0x0015, - 0x11c0, 0x7080, 0xa086, 0x0004, 0x11a0, 0x6010, 0xa0e8, 0x000f, - 0x2c78, 0x080c, 0x6e05, 0x01a8, 0x706c, 0x6a08, 0xa206, 0x1130, - 0x7070, 0x6a0c, 0xa206, 0x1110, 0x080c, 0x2ad9, 0x080c, 0x81f6, - 0x0020, 0x080c, 0x85f3, 0x080c, 0x8078, 0x00fe, 0x00ee, 0x00de, - 0x0005, 0x7050, 0x6a0c, 0xa206, 0x0d78, 0x0c80, 0x0016, 0x0026, - 0x684c, 0xd0ac, 0x0178, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0150, - 0x6860, 0xa106, 0x1118, 0x685c, 0xa206, 0x0120, 0x6962, 0x6a5e, - 0xa085, 0x0001, 0x002e, 0x001e, 0x0005, 0x00d6, 0x0036, 0x6310, - 0x2368, 0x684a, 0x6952, 0xa29e, 0x4000, 0x1188, 0x00c6, 0x6318, - 0x2360, 0x2009, 0x0000, 0x080c, 0x4f6e, 0x1108, 0xc185, 0x6000, - 0xd0bc, 0x0108, 0xc18d, 0x6a66, 0x696a, 0x00ce, 0x0080, 0x6a66, - 0x3918, 0xa398, 0x0006, 0x231c, 0x686b, 0x0004, 0x6b72, 0x00c6, - 0x6318, 0x2360, 0x6004, 0xa084, 0x00ff, 0x686e, 0x00ce, 0x080c, - 0x510c, 0x003e, 0x00de, 0x0005, 0x00c6, 0x0026, 0x0016, 0xa186, - 0x0035, 0x0110, 0x6a34, 0x0008, 0x6a28, 0x080c, 0x9586, 0x01f0, - 0x2260, 0x611c, 0xa186, 0x0003, 0x0118, 0xa186, 0x0006, 0x1190, - 0x6834, 0xa206, 0x0140, 0x6838, 0xa206, 0x1160, 0x6108, 0x6834, - 0xa106, 0x1140, 0x0020, 0x6008, 0x6938, 0xa106, 0x1118, 0x6018, - 0x6918, 0xa106, 0x001e, 0x002e, 0x00ce, 0x0005, 0xa085, 0x0001, - 0x0cc8, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x14f6, 0x0013, - 0x006e, 0x0005, 0x9a7a, 0x9eff, 0xa027, 0x9a7a, 0x9a7a, 0x9a7a, - 0x9a7a, 0x9a7a, 0x9ab2, 0xa0a3, 0x9a7a, 0x9a7a, 0x9a7a, 0x9a7a, - 0x9a7a, 0x9a7a, 0x080c, 0x14f6, 0x0066, 0x6000, 0xa0b2, 0x0010, - 0x1a0c, 0x14f6, 0x0013, 0x006e, 0x0005, 0x9a95, 0xa4fd, 0x9a95, - 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0xa4c1, 0xa545, 0x9a95, - 0xaaea, 0xab1a, 0xaaea, 0xab1a, 0x9a95, 0x080c, 0x14f6, 0x0066, - 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x14f6, 0x0013, 0x006e, 0x0005, - 0x9ab0, 0xa1d8, 0xa295, 0xa2c2, 0xa346, 0x9ab0, 0xa433, 0xa3de, - 0xa0af, 0xa497, 0xa4ac, 0x9ab0, 0x9ab0, 0x9ab0, 0x9ab0, 0x9ab0, - 0x080c, 0x14f6, 0xa1b2, 0x0080, 0x1a0c, 0x14f6, 0x2100, 0xa1b2, - 0x0040, 0x1a04, 0x9e79, 0x0002, 0x9afc, 0x9cab, 0x9afc, 0x9afc, - 0x9afc, 0x9cb2, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, - 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, - 0x9afc, 0x9afc, 0x9afc, 0x9afe, 0x9b5a, 0x9b65, 0x9ba6, 0x9bc0, - 0x9c3e, 0x9c9c, 0x9afc, 0x9afc, 0x9cb5, 0x9afc, 0x9afc, 0x9cc4, - 0x9ccb, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9d42, 0x9afc, - 0x9afc, 0x9d4d, 0x9afc, 0x9afc, 0x9d18, 0x9afc, 0x9afc, 0x9afc, - 0x9d61, 0x9afc, 0x9afc, 0x9afc, 0x9dd5, 0x9afc, 0x9afc, 0x9afc, - 0x9afc, 0x9afc, 0x9afc, 0x9e40, 0x080c, 0x14f6, 0x080c, 0x502d, - 0x1140, 0x2001, 0xad34, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, - 0x1140, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0804, - 0x9ca6, 0x080c, 0x501d, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, - 0x6218, 0x2270, 0x72a0, 0x0026, 0x2019, 0x0029, 0x080c, 0x68e7, - 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x2c08, 0x080c, 0xa712, - 0x007e, 0x001e, 0x2e60, 0x080c, 0x4ecf, 0x001e, 0x002e, 0x003e, - 0x00ce, 0x00ee, 0x6618, 0x00c6, 0x2660, 0x080c, 0x4ceb, 0x00ce, - 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0278, - 0x080c, 0xa656, 0x1904, 0x9ba0, 0x080c, 0xa5f6, 0x1120, 0x6007, - 0x0008, 0x0804, 0x9ca6, 0x6007, 0x0009, 0x0804, 0x9ca6, 0x080c, - 0xa801, 0x0128, 0x080c, 0xa656, 0x0d78, 0x0804, 0x9ba0, 0x6013, - 0x1900, 0x0c88, 0x6106, 0x080c, 0xa5a6, 0x6007, 0x0006, 0x0804, - 0x9ca6, 0x6007, 0x0007, 0x0804, 0x9ca6, 0x080c, 0xab4e, 0x1904, - 0x9e76, 0x00d6, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637, - 0xa686, 0x0006, 0x0188, 0xa686, 0x0004, 0x0170, 0x6e04, 0xa6b4, - 0x00ff, 0xa686, 0x0006, 0x0140, 0xa686, 0x0004, 0x0128, 0xa686, - 0x0005, 0x0110, 0x00de, 0x00e0, 0x080c, 0xa6b4, 0x11a0, 0xa686, - 0x0006, 0x1150, 0x0026, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009, - 0x0000, 0x080c, 0x2b1e, 0x002e, 0x080c, 0x4d72, 0x6007, 0x000a, - 0x00de, 0x0804, 0x9ca6, 0x6007, 0x000b, 0x00de, 0x0804, 0x9ca6, - 0x080c, 0x2ad9, 0x6007, 0x0001, 0x0804, 0x9ca6, 0x080c, 0xab4e, - 0x1904, 0x9e76, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa686, - 0x0707, 0x0d70, 0x0026, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009, - 0x0000, 0x080c, 0x2b1e, 0x002e, 0x6007, 0x000c, 0x0804, 0x9ca6, - 0x080c, 0x502d, 0x1140, 0x2001, 0xad34, 0x2004, 0xa084, 0x0009, - 0xa086, 0x0008, 0x1110, 0x0804, 0x9b09, 0x080c, 0x501d, 0x6618, - 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x06e8, - 0x1138, 0x0026, 0x2001, 0x0006, 0x080c, 0x4c5d, 0x002e, 0x0050, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0004, 0x0120, 0xa686, 0x0006, - 0x1904, 0x9ba0, 0x080c, 0xa6c1, 0x1120, 0x6007, 0x000e, 0x0804, - 0x9ca6, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, 0x00ff, - 0x8427, 0x0046, 0x080c, 0x2ad9, 0x004e, 0x0016, 0xa006, 0x2009, - 0xad52, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c, 0xa96c, - 0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de, 0x001e, - 0x004e, 0x6007, 0x0001, 0x0804, 0x9ca6, 0x2001, 0x0001, 0x080c, - 0x4c1e, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, - 0xad05, 0x2011, 0xb290, 0x080c, 0x8a7c, 0x003e, 0x002e, 0x001e, - 0x015e, 0xa005, 0x0168, 0xa6b4, 0xff00, 0x8637, 0xa682, 0x0004, - 0x0a04, 0x9ba0, 0xa682, 0x0007, 0x0a04, 0x9bea, 0x0804, 0x9ba0, - 0x6013, 0x1900, 0x6007, 0x0009, 0x0804, 0x9ca6, 0x080c, 0x502d, - 0x1140, 0x2001, 0xad34, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, - 0x1110, 0x0804, 0x9b09, 0x080c, 0x501d, 0x6618, 0xa6b0, 0x0001, - 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x06b0, 0xa6b4, 0xff00, - 0x8637, 0xa686, 0x0004, 0x0120, 0xa686, 0x0006, 0x1904, 0x9ba0, - 0x080c, 0xa6e9, 0x1130, 0x080c, 0xa5f6, 0x1118, 0x6007, 0x0010, - 0x04e8, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, 0x00ff, - 0x8427, 0x0046, 0x080c, 0x2ad9, 0x004e, 0x0016, 0xa006, 0x2009, - 0xad52, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c, 0xa96c, - 0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de, 0x001e, - 0x004e, 0x6007, 0x0001, 0x00d0, 0x080c, 0xa801, 0x0140, 0xa6b4, - 0xff00, 0x8637, 0xa686, 0x0006, 0x0958, 0x0804, 0x9ba0, 0x6013, - 0x1900, 0x6007, 0x0009, 0x0050, 0x080c, 0xab4e, 0x1904, 0x9e76, - 0x080c, 0x9e98, 0x1904, 0x9ba0, 0x6007, 0x0012, 0x6003, 0x0001, - 0x080c, 0x67ee, 0x0005, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, - 0x67ee, 0x0cc0, 0x6007, 0x0005, 0x0cc0, 0x080c, 0xab4e, 0x1904, - 0x9e76, 0x080c, 0x9e98, 0x1904, 0x9ba0, 0x6007, 0x0020, 0x6003, - 0x0001, 0x080c, 0x67ee, 0x0005, 0x6007, 0x0023, 0x6003, 0x0001, - 0x080c, 0x67ee, 0x0005, 0x080c, 0xab4e, 0x1904, 0x9e76, 0x080c, - 0x9e98, 0x1904, 0x9ba0, 0x0016, 0x0026, 0x2011, 0xb291, 0x2214, - 0xa286, 0xffff, 0x0190, 0x2c08, 0x080c, 0x9586, 0x01d8, 0x2260, - 0x2011, 0xb290, 0x2214, 0x6008, 0xa206, 0x11a0, 0x6018, 0xa190, - 0x0006, 0x2214, 0xa206, 0x01e0, 0x0068, 0x2011, 0xb290, 0x2214, - 0x2c08, 0x080c, 0xa940, 0x11a0, 0x2011, 0xb291, 0x2214, 0xa286, - 0xffff, 0x01a0, 0x2160, 0x6007, 0x0026, 0x6013, 0x1700, 0x2011, - 0xb289, 0x2214, 0xa296, 0xffff, 0x1160, 0x6007, 0x0025, 0x0048, - 0x601c, 0xa086, 0x0007, 0x1d70, 0x080c, 0x8078, 0x2160, 0x6007, - 0x0025, 0x6003, 0x0001, 0x080c, 0x67ee, 0x002e, 0x001e, 0x0005, - 0x2001, 0x0001, 0x080c, 0x4c1e, 0x0156, 0x0016, 0x0026, 0x0036, - 0x20a9, 0x0004, 0x2019, 0xad05, 0x2011, 0xb296, 0x080c, 0x8a7c, - 0x003e, 0x002e, 0x001e, 0x015e, 0x0120, 0x6007, 0x0031, 0x0804, - 0x9ca6, 0x080c, 0x87bd, 0x080c, 0x574f, 0x1158, 0x0006, 0x0026, - 0x0036, 0x080c, 0x576b, 0x0110, 0x080c, 0x5726, 0x003e, 0x002e, - 0x000e, 0x0005, 0x6106, 0x080c, 0x9eb4, 0x6007, 0x002b, 0x0804, - 0x9ca6, 0x6007, 0x002c, 0x0804, 0x9ca6, 0x080c, 0xab4e, 0x1904, - 0x9e76, 0x080c, 0x9e98, 0x1904, 0x9ba0, 0x6106, 0x080c, 0x9eb8, - 0x1120, 0x6007, 0x002e, 0x0804, 0x9ca6, 0x6007, 0x002f, 0x0804, - 0x9ca6, 0x00e6, 0x00d6, 0x00c6, 0x6018, 0xa080, 0x0001, 0x200c, - 0xa184, 0x00ff, 0xa086, 0x0006, 0x0158, 0xa184, 0xff00, 0x8007, - 0xa086, 0x0006, 0x0128, 0x00ce, 0x00de, 0x00ee, 0x0804, 0x9cab, - 0x2001, 0xad71, 0x2004, 0xd0e4, 0x0904, 0x9dd2, 0x2071, 0xb28c, - 0x7010, 0x6036, 0x7014, 0x603a, 0x7108, 0x720c, 0x2001, 0xad52, - 0x2004, 0xd0a4, 0x0140, 0x6018, 0x2068, 0x6810, 0xa106, 0x1118, - 0x6814, 0xa206, 0x01f8, 0x2001, 0xad52, 0x2004, 0xd0ac, 0x1580, - 0x2069, 0xad00, 0x6870, 0xa206, 0x1558, 0x686c, 0xa106, 0x1540, - 0x7210, 0x080c, 0x9586, 0x0548, 0x080c, 0xa9d4, 0x0530, 0x622a, - 0x6007, 0x0036, 0x6003, 0x0001, 0x080c, 0x67a8, 0x00ce, 0x00de, - 0x00ee, 0x0005, 0x7214, 0xa286, 0xffff, 0x0150, 0x080c, 0x9586, - 0x01a0, 0xa280, 0x0002, 0x2004, 0x7110, 0xa106, 0x1170, 0x0c08, - 0x7210, 0x2c08, 0x080c, 0xa940, 0x2c10, 0x2160, 0x0130, 0x08c8, - 0x6007, 0x0037, 0x6013, 0x1500, 0x08e8, 0x6007, 0x0037, 0x6013, - 0x1700, 0x08c0, 0x6007, 0x0012, 0x08a8, 0x6018, 0xa080, 0x0001, - 0x2004, 0xa084, 0xff00, 0x8007, 0xa086, 0x0006, 0x1904, 0x9cab, - 0x00e6, 0x00d6, 0x00c6, 0x2001, 0xad71, 0x2004, 0xd0e4, 0x0904, - 0x9e38, 0x2069, 0xad00, 0x2071, 0xb28c, 0x7008, 0x6036, 0x720c, - 0x623a, 0xa286, 0xffff, 0x1140, 0x7208, 0x00c6, 0x2c08, 0x080c, - 0xa940, 0x2c10, 0x00ce, 0x0588, 0x080c, 0x9586, 0x0570, 0x00c6, - 0x0026, 0x2260, 0x080c, 0x928f, 0x002e, 0x00ce, 0x7118, 0xa18c, - 0xff00, 0x810f, 0xa186, 0x0001, 0x0158, 0xa186, 0x0005, 0x0118, - 0xa186, 0x0007, 0x1178, 0xa280, 0x0004, 0x2004, 0xa005, 0x0150, - 0x0056, 0x7510, 0x7614, 0x080c, 0xa9eb, 0x005e, 0x00ce, 0x00de, - 0x00ee, 0x0005, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00, - 0x6003, 0x0001, 0x080c, 0x67a8, 0x0c88, 0x6007, 0x003b, 0x602b, - 0x0009, 0x6013, 0x1700, 0x6003, 0x0001, 0x080c, 0x67a8, 0x0c30, - 0x6007, 0x003b, 0x602b, 0x000b, 0x6013, 0x0000, 0x0804, 0x9daa, - 0x00e6, 0x0026, 0x080c, 0x502d, 0x0558, 0x080c, 0x501d, 0x080c, - 0xabc5, 0x1520, 0x2071, 0xad00, 0x70d0, 0xc085, 0x70d2, 0x00f6, - 0x2079, 0x0100, 0x729c, 0xa284, 0x00ff, 0x706e, 0x78e6, 0xa284, - 0xff00, 0x7270, 0xa205, 0x7072, 0x78ea, 0x00fe, 0x70db, 0x0000, - 0x2001, 0xad52, 0x2004, 0xd0a4, 0x0120, 0x2011, 0xafe0, 0x2013, - 0x07d0, 0xd0ac, 0x1128, 0x080c, 0x28fa, 0x0010, 0x080c, 0xabf1, - 0x002e, 0x00ee, 0x080c, 0x8078, 0x0804, 0x9caa, 0x080c, 0x8078, - 0x0005, 0x2600, 0x0002, 0x9e81, 0x9e81, 0x9e81, 0x9e81, 0x9e81, - 0x9e83, 0x080c, 0x14f6, 0x080c, 0xab4e, 0x1d80, 0x0089, 0x1138, - 0x6007, 0x0045, 0x6003, 0x0001, 0x080c, 0x67ee, 0x0005, 0x080c, - 0x2ad9, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x67ee, 0x0005, - 0x00d6, 0x0066, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637, - 0xa686, 0x0006, 0x0170, 0xa686, 0x0004, 0x0158, 0x6e04, 0xa6b4, - 0x00ff, 0xa686, 0x0006, 0x0128, 0xa686, 0x0004, 0x0110, 0xa085, - 0x0001, 0x006e, 0x00de, 0x0005, 0x00d6, 0x0449, 0x00de, 0x0005, - 0x00d6, 0x0491, 0x11f0, 0x680c, 0xa08c, 0xff00, 0x6820, 0xa084, - 0x00ff, 0xa115, 0x6212, 0x6824, 0x602a, 0xd1e4, 0x0118, 0x2009, - 0x0001, 0x0060, 0xd1ec, 0x0168, 0x6920, 0xa18c, 0x00ff, 0x6824, - 0x080c, 0x2676, 0x1130, 0x2110, 0x2009, 0x0000, 0x080c, 0x2b1e, - 0x0018, 0xa085, 0x0001, 0x0008, 0xa006, 0x00de, 0x0005, 0x2069, - 0xb28d, 0x6800, 0xa082, 0x0010, 0x1228, 0x6013, 0x0000, 0xa085, - 0x0001, 0x0008, 0xa006, 0x0005, 0x6013, 0x0000, 0x2069, 0xb28c, - 0x6808, 0xa084, 0xff00, 0xa086, 0x0800, 0x1140, 0x6800, 0xa084, - 0x00ff, 0xa08e, 0x0014, 0x0110, 0xa08e, 0x0010, 0x0005, 0x6004, - 0xa0b2, 0x0080, 0x1a0c, 0x14f6, 0xa1b6, 0x0013, 0x1130, 0x2008, - 0xa1b2, 0x0040, 0x1a04, 0x9ffb, 0x0092, 0xa1b6, 0x0027, 0x0120, - 0xa1b6, 0x0014, 0x190c, 0x14f6, 0x2001, 0x0007, 0x080c, 0x4c5d, - 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, 0x9f5f, - 0x9f61, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f61, 0x9f6f, 0x9ff4, 0x9fbf, - 0x9ff4, 0x9fd0, 0x9ff4, 0x9f6f, 0x9ff4, 0x9fec, 0x9ff4, 0x9fec, - 0x9ff4, 0x9ff4, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, - 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f61, 0x9f5f, 0x9ff4, - 0x9f5f, 0x9f5f, 0x9ff4, 0x9f5f, 0x9ff1, 0x9ff4, 0x9f5f, 0x9f5f, - 0x9f5f, 0x9f5f, 0x9ff4, 0x9ff4, 0x9f5f, 0x9ff4, 0x9ff4, 0x9f5f, - 0x9f69, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9ff0, 0x9ff4, 0x9f5f, - 0x9f5f, 0x9ff4, 0x9ff4, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x080c, - 0x14f6, 0x080c, 0x6b73, 0x6003, 0x0002, 0x080c, 0x6c50, 0x0804, - 0x9ffa, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x0804, 0x9ff4, 0x00f6, - 0x2079, 0xad51, 0x7804, 0x00fe, 0xd0ac, 0x1904, 0x9ff4, 0x2001, - 0x0000, 0x080c, 0x4c1e, 0x6018, 0xa080, 0x0004, 0x2004, 0xa086, - 0x00ff, 0x1140, 0x00f6, 0x2079, 0xad00, 0x7894, 0x8000, 0x7896, - 0x00fe, 0x00e0, 0x00c6, 0x6018, 0x2060, 0x6000, 0xd0f4, 0x1140, - 0x6010, 0xa005, 0x0128, 0x00ce, 0x080c, 0x3cce, 0x0804, 0x9ff4, - 0x00ce, 0x2001, 0xad00, 0x2004, 0xa086, 0x0002, 0x1138, 0x00f6, - 0x2079, 0xad00, 0x7894, 0x8000, 0x7896, 0x00fe, 0x2001, 0x0002, - 0x080c, 0x4c30, 0x080c, 0x6b73, 0x601f, 0x0001, 0x6003, 0x0001, - 0x6007, 0x0002, 0x080c, 0x67ee, 0x080c, 0x6c50, 0x00c6, 0x6118, - 0x2160, 0x2009, 0x0001, 0x080c, 0x6519, 0x00ce, 0x04d8, 0x6618, - 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa6b4, 0xff00, 0x8637, 0xa686, - 0x0006, 0x0550, 0xa686, 0x0004, 0x0538, 0x2001, 0x0004, 0x0410, - 0x2001, 0xad00, 0x2004, 0xa086, 0x0003, 0x1110, 0x080c, 0x3cce, - 0x2001, 0x0006, 0x0489, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, - 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0170, 0x2001, 0x0006, - 0x0048, 0x2001, 0x0004, 0x0030, 0x2001, 0x0006, 0x00e9, 0x0020, - 0x0018, 0x0010, 0x080c, 0x4c5d, 0x080c, 0x6b73, 0x080c, 0x8078, - 0x080c, 0x6c50, 0x0005, 0x2600, 0x0002, 0xa003, 0xa003, 0xa003, - 0xa003, 0xa003, 0xa005, 0x080c, 0x14f6, 0x080c, 0x6b73, 0x080c, - 0x8078, 0x080c, 0x6c50, 0x0005, 0x0016, 0x00d6, 0x6118, 0x2168, - 0x6900, 0xd184, 0x0188, 0x6104, 0xa18e, 0x000a, 0x1128, 0x699c, - 0xd1a4, 0x1110, 0x2001, 0x0007, 0x080c, 0x4c30, 0x2001, 0x0000, - 0x080c, 0x4c1e, 0x080c, 0x2aff, 0x00de, 0x001e, 0x0005, 0x00d6, - 0x6618, 0x2668, 0x6804, 0xa084, 0xff00, 0x8007, 0x00de, 0xa0b2, - 0x000c, 0x1a0c, 0x14f6, 0xa1b6, 0x0015, 0x1110, 0x003b, 0x0028, - 0xa1b6, 0x0016, 0x190c, 0x14f6, 0x006b, 0x0005, 0x86b9, 0x86b9, - 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0xa08f, 0xa056, 0x86b9, 0x86b9, - 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x86b9, - 0xa08f, 0xa096, 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x00f6, 0x2079, - 0xad51, 0x7804, 0xd0ac, 0x11e0, 0x6018, 0xa07d, 0x01c8, 0x7800, - 0xd0f4, 0x1118, 0x7810, 0xa005, 0x1198, 0x2001, 0x0000, 0x080c, - 0x4c1e, 0x2001, 0x0002, 0x080c, 0x4c30, 0x601f, 0x0001, 0x6003, - 0x0001, 0x6007, 0x0002, 0x080c, 0x67ee, 0x080c, 0x6c50, 0x00a8, - 0x2011, 0xb283, 0x2204, 0x8211, 0x220c, 0x080c, 0x2676, 0x1168, - 0x00c6, 0x080c, 0x4cdc, 0x0120, 0x00ce, 0x080c, 0x8078, 0x0028, - 0x080c, 0x493a, 0x00ce, 0x080c, 0x8078, 0x00fe, 0x0005, 0x6604, - 0xa6b6, 0x001e, 0x1110, 0x080c, 0x8078, 0x0005, 0x080c, 0x8940, - 0x1138, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x67ee, 0x0010, - 0x080c, 0x8078, 0x0005, 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x14f6, - 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, 0xa182, - 0x0040, 0x0002, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c7, 0xa0c5, - 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, - 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0x080c, 0x14f6, 0x00d6, - 0x00e6, 0x00f6, 0x0156, 0x0046, 0x0026, 0x6218, 0xa280, 0x002b, - 0x2004, 0xa005, 0x0120, 0x2021, 0x0000, 0x080c, 0xab96, 0x6106, - 0x2071, 0xb280, 0x7444, 0xa4a4, 0xff00, 0x0904, 0xa129, 0xa486, - 0x2000, 0x1130, 0x2009, 0x0001, 0x2011, 0x0200, 0x080c, 0x663f, - 0x080c, 0x15d9, 0x090c, 0x14f6, 0x6003, 0x0007, 0x2d00, 0x6837, - 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, - 0x6008, 0x68b2, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x694a, - 0x0016, 0xa084, 0xff00, 0x6846, 0x684f, 0x0000, 0x6857, 0x0036, - 0x080c, 0x510c, 0x001e, 0xa486, 0x2000, 0x1130, 0x2019, 0x0017, - 0x080c, 0xa8eb, 0x0804, 0xa186, 0xa486, 0x0400, 0x1130, 0x2019, - 0x0002, 0x080c, 0xa89d, 0x0804, 0xa186, 0xa486, 0x0200, 0x1110, - 0x080c, 0xa882, 0xa486, 0x1000, 0x1110, 0x080c, 0xa8d0, 0x0804, - 0xa186, 0x2069, 0xb048, 0x6a00, 0xd284, 0x0904, 0xa1d5, 0xa284, - 0x0300, 0x1904, 0xa1cf, 0x6804, 0xa005, 0x0904, 0xa1c0, 0x2d78, - 0x6003, 0x0007, 0x080c, 0x15c0, 0x0904, 0xa18d, 0x7800, 0xd08c, - 0x1118, 0x7804, 0x8001, 0x7806, 0x6013, 0x0000, 0x6803, 0x0000, - 0x6837, 0x0116, 0x683b, 0x0000, 0x6008, 0x68b2, 0x2c00, 0x684a, - 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x6986, 0x6846, 0x7928, - 0x698a, 0x792c, 0x698e, 0x7930, 0x6992, 0x7934, 0x6996, 0x6853, - 0x003d, 0x7244, 0xa294, 0x0003, 0xa286, 0x0002, 0x1118, 0x684f, - 0x0040, 0x0040, 0xa286, 0x0001, 0x1118, 0x684f, 0x0080, 0x0010, - 0x684f, 0x0000, 0x20a9, 0x000a, 0x2001, 0xb290, 0xad90, 0x0015, - 0x200c, 0x810f, 0x2112, 0x8000, 0x8210, 0x1f04, 0xa178, 0x200c, - 0x6982, 0x8000, 0x200c, 0x697e, 0x080c, 0x510c, 0x002e, 0x004e, - 0x015e, 0x00fe, 0x00ee, 0x00de, 0x0005, 0x6013, 0x0100, 0x6003, - 0x0001, 0x6007, 0x0041, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0c70, - 0x2069, 0xb292, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x11a8, - 0x2069, 0xb280, 0x686c, 0xa084, 0x00ff, 0x0016, 0x6110, 0xa18c, - 0x0700, 0xa10d, 0x6112, 0x001e, 0x6003, 0x0001, 0x6007, 0x0043, - 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0888, 0x6013, 0x0200, 0x6003, - 0x0001, 0x6007, 0x0041, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0830, - 0x6013, 0x0300, 0x0010, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, - 0x0041, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0804, 0xa186, 0x6013, - 0x0500, 0x0c98, 0x6013, 0x0600, 0x0818, 0x6013, 0x0200, 0x0800, - 0xa186, 0x0013, 0x1170, 0x6004, 0xa08a, 0x0040, 0x0a0c, 0x14f6, - 0xa08a, 0x0053, 0x1a0c, 0x14f6, 0xa082, 0x0040, 0x2008, 0x0804, - 0xa252, 0xa186, 0x0051, 0x0138, 0xa186, 0x0047, 0x11d8, 0x6004, - 0xa086, 0x0041, 0x0518, 0x2001, 0x0109, 0x2004, 0xd084, 0x01f0, - 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x6699, - 0x002e, 0x001e, 0x000e, 0x012e, 0x6000, 0xa086, 0x0002, 0x1170, - 0x0804, 0xa295, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c, - 0x14f6, 0x6004, 0xa082, 0x0040, 0x2008, 0x001a, 0x080c, 0x80be, - 0x0005, 0xa22c, 0xa22e, 0xa22e, 0xa22c, 0xa22c, 0xa22c, 0xa22c, - 0xa22c, 0xa22c, 0xa22c, 0xa22c, 0xa22c, 0xa22c, 0xa22c, 0xa22c, - 0xa22c, 0xa22c, 0xa22c, 0xa22c, 0x080c, 0x14f6, 0x080c, 0x6b73, - 0x080c, 0x6c50, 0x0036, 0x00d6, 0x6010, 0xa06d, 0x01c0, 0xad84, - 0xf000, 0x01a8, 0x6003, 0x0002, 0x6018, 0x2004, 0xd0bc, 0x1178, - 0x2019, 0x0004, 0x080c, 0xa91f, 0x6013, 0x0000, 0x6014, 0xa005, - 0x1120, 0x2001, 0xafa4, 0x2004, 0x6016, 0x6003, 0x0007, 0x00de, - 0x003e, 0x0005, 0x0002, 0xa266, 0xa283, 0xa26f, 0xa28f, 0xa266, - 0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0xa266, - 0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0x080c, 0x14f6, - 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x080c, - 0x6b73, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, 0x0138, 0x6003, - 0x0007, 0x2009, 0x0043, 0x080c, 0x80a7, 0x0010, 0x6003, 0x0002, - 0x080c, 0x6c50, 0x0005, 0x080c, 0x6b73, 0x080c, 0xab55, 0x1120, - 0x080c, 0x6618, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005, 0x080c, - 0x6b73, 0x2009, 0x0041, 0x0804, 0xa3de, 0xa182, 0x0040, 0x0002, - 0xa2ab, 0xa2ad, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ae, - 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, - 0xa2ab, 0xa2b9, 0xa2ab, 0x080c, 0x14f6, 0x0005, 0x6003, 0x0004, - 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x1824, - 0x0005, 0x00d6, 0x080c, 0x6618, 0x00de, 0x080c, 0xabb4, 0x080c, - 0x8078, 0x0005, 0xa182, 0x0040, 0x0002, 0xa2d8, 0xa2d8, 0xa2d8, - 0xa2d8, 0xa2d8, 0xa2d8, 0xa2d8, 0xa2da, 0xa2d8, 0xa2dd, 0xa316, - 0xa2d8, 0xa2d8, 0xa2d8, 0xa2d8, 0xa316, 0xa2d8, 0xa2d8, 0xa2d8, - 0x080c, 0x14f6, 0x080c, 0x80be, 0x0005, 0x2001, 0xad71, 0x2004, - 0xd0e4, 0x0158, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x0228, - 0x2001, 0x011f, 0x2004, 0x6036, 0x0010, 0x6037, 0x0000, 0x080c, - 0x6c05, 0x080c, 0x6d0d, 0x6010, 0x00d6, 0x2068, 0x684c, 0xd0fc, - 0x0150, 0xa08c, 0x0003, 0xa18e, 0x0002, 0x0168, 0x2009, 0x0041, - 0x00de, 0x0804, 0xa3de, 0x6003, 0x0007, 0x6017, 0x0000, 0x080c, - 0x6618, 0x00de, 0x0005, 0x080c, 0xab55, 0x0110, 0x00de, 0x0005, - 0x080c, 0x6618, 0x080c, 0x8078, 0x00de, 0x0ca0, 0x0036, 0x080c, - 0x6c05, 0x080c, 0x6d0d, 0x6010, 0x00d6, 0x2068, 0x6018, 0x2004, - 0xd0bc, 0x0188, 0x684c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0140, - 0x687c, 0x632c, 0xa31a, 0x632e, 0x6880, 0x6328, 0xa31b, 0x632a, - 0x6003, 0x0002, 0x0080, 0x2019, 0x0004, 0x080c, 0xa91f, 0x6014, - 0xa005, 0x1128, 0x2001, 0xafa4, 0x2004, 0x8003, 0x6016, 0x6013, - 0x0000, 0x6003, 0x0007, 0x00de, 0x003e, 0x0005, 0xa186, 0x0013, - 0x1150, 0x6004, 0xa086, 0x0042, 0x190c, 0x14f6, 0x080c, 0x6b73, - 0x080c, 0x6c50, 0x0005, 0xa186, 0x0027, 0x0118, 0xa186, 0x0014, - 0x1180, 0x6004, 0xa086, 0x0042, 0x190c, 0x14f6, 0x2001, 0x0007, - 0x080c, 0x4c5d, 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, - 0x0005, 0xa182, 0x0040, 0x0002, 0xa37f, 0xa37f, 0xa37f, 0xa37f, - 0xa37f, 0xa37f, 0xa37f, 0xa381, 0xa38d, 0xa37f, 0xa37f, 0xa37f, - 0xa37f, 0xa37f, 0xa37f, 0xa37f, 0xa37f, 0xa37f, 0xa37f, 0x080c, - 0x14f6, 0x0036, 0x0046, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, - 0x080c, 0x1824, 0x004e, 0x003e, 0x0005, 0x6010, 0x00d6, 0x2068, - 0x6810, 0x6a14, 0x0006, 0x0046, 0x0056, 0x6c7c, 0xa422, 0x6d80, - 0x2200, 0xa52b, 0x602c, 0xa420, 0x642e, 0x6028, 0xa529, 0x652a, - 0x005e, 0x004e, 0x000e, 0xa20d, 0x1178, 0x684c, 0xd0fc, 0x0120, - 0x2009, 0x0041, 0x00de, 0x0490, 0x6003, 0x0007, 0x6017, 0x0000, - 0x080c, 0x6618, 0x00de, 0x0005, 0x0006, 0x00f6, 0x2c78, 0x080c, - 0x5029, 0x00fe, 0x000e, 0x0120, 0x6003, 0x0002, 0x00de, 0x0005, - 0x2009, 0xad0d, 0x210c, 0xd19c, 0x0118, 0x6003, 0x0007, 0x0010, - 0x6003, 0x0006, 0x0021, 0x080c, 0x661a, 0x00de, 0x0005, 0xd2fc, - 0x0140, 0x8002, 0x8000, 0x8212, 0xa291, 0x0000, 0x2009, 0x0009, - 0x0010, 0x2009, 0x0015, 0x6a6a, 0x6866, 0x0005, 0xa182, 0x0040, - 0x0208, 0x0062, 0xa186, 0x0013, 0x0120, 0xa186, 0x0014, 0x190c, - 0x14f6, 0x6020, 0xd0dc, 0x090c, 0x14f6, 0x0005, 0xa401, 0xa408, - 0xa414, 0xa420, 0xa401, 0xa401, 0xa401, 0xa42f, 0xa401, 0xa403, - 0xa403, 0xa401, 0xa401, 0xa401, 0xa401, 0xa403, 0xa401, 0xa403, - 0xa401, 0x080c, 0x14f6, 0x6020, 0xd0dc, 0x090c, 0x14f6, 0x0005, - 0x6003, 0x0001, 0x6106, 0x080c, 0x67a8, 0x0126, 0x2091, 0x8000, - 0x080c, 0x6c50, 0x012e, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c, - 0x67a8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6c50, 0x012e, 0x0005, - 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1e6e, 0x0126, 0x2091, - 0x8000, 0x080c, 0x680b, 0x080c, 0x6d0d, 0x012e, 0x0005, 0xa016, - 0x080c, 0x1824, 0x0005, 0x0126, 0x2091, 0x8000, 0x0036, 0x00d6, - 0xa182, 0x0040, 0x0023, 0x00de, 0x003e, 0x012e, 0x0005, 0xa44f, - 0xa451, 0xa463, 0xa47e, 0xa44f, 0xa44f, 0xa44f, 0xa493, 0xa44f, - 0xa44f, 0xa44f, 0xa44f, 0xa44f, 0xa44f, 0xa44f, 0xa44f, 0x080c, - 0x14f6, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x01f8, 0xa09c, 0x0003, - 0xa39e, 0x0003, 0x01d0, 0x6003, 0x0001, 0x6106, 0x080c, 0x67a8, - 0x080c, 0x6c50, 0x0498, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0168, - 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0140, 0x6003, 0x0001, 0x6106, - 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0408, 0x6013, 0x0000, 0x6017, - 0x0000, 0x2019, 0x0004, 0x080c, 0xa91f, 0x00c0, 0x6010, 0x2068, - 0x684c, 0xd0fc, 0x0d90, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0d68, - 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1e6e, 0x080c, 0x680b, - 0x080c, 0x6d0d, 0x0018, 0xa016, 0x080c, 0x1824, 0x0005, 0x080c, - 0x6b73, 0x6110, 0x81ff, 0x0158, 0x00d6, 0x2168, 0x080c, 0xabfa, - 0x0036, 0x2019, 0x0029, 0x080c, 0xa91f, 0x003e, 0x00de, 0x080c, - 0x974e, 0x080c, 0x6c50, 0x0005, 0x080c, 0x6c05, 0x6110, 0x81ff, - 0x0158, 0x00d6, 0x2168, 0x080c, 0xabfa, 0x0036, 0x2019, 0x0029, - 0x080c, 0xa91f, 0x003e, 0x00de, 0x080c, 0x974e, 0x080c, 0x6d0d, - 0x0005, 0xa182, 0x0085, 0x0002, 0xa4cd, 0xa4cb, 0xa4cb, 0xa4d9, - 0xa4cb, 0xa4cb, 0xa4cb, 0x080c, 0x14f6, 0x6003, 0x000b, 0x6106, - 0x080c, 0x67a8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6c50, 0x012e, - 0x0005, 0x0026, 0x00e6, 0x080c, 0xab4e, 0x0118, 0x080c, 0x8078, - 0x00c8, 0x2071, 0xb280, 0x7224, 0x6212, 0x7220, 0x080c, 0xa7ce, - 0x0118, 0x6007, 0x0086, 0x0040, 0x6007, 0x0087, 0x7224, 0xa296, - 0xffff, 0x1110, 0x6007, 0x0086, 0x6003, 0x0001, 0x080c, 0x67a8, - 0x080c, 0x6c50, 0x00ee, 0x002e, 0x0005, 0xa186, 0x0013, 0x1160, - 0x6004, 0xa08a, 0x0085, 0x0a0c, 0x14f6, 0xa08a, 0x008c, 0x1a0c, - 0x14f6, 0xa082, 0x0085, 0x00a2, 0xa186, 0x0027, 0x0130, 0xa186, - 0x0014, 0x0118, 0x080c, 0x80be, 0x0050, 0x2001, 0x0007, 0x080c, - 0x4c5d, 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, - 0xa527, 0xa529, 0xa529, 0xa527, 0xa527, 0xa527, 0xa527, 0x080c, - 0x14f6, 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, - 0xa182, 0x0085, 0x0a0c, 0x14f6, 0xa182, 0x008c, 0x1a0c, 0x14f6, - 0xa182, 0x0085, 0x0002, 0xa542, 0xa542, 0xa542, 0xa544, 0xa542, - 0xa542, 0xa542, 0x080c, 0x14f6, 0x0005, 0xa186, 0x0013, 0x0148, - 0xa186, 0x0014, 0x0130, 0xa186, 0x0027, 0x0118, 0x080c, 0x80be, - 0x0030, 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, - 0x0036, 0x080c, 0xabb4, 0x603f, 0x0000, 0x2019, 0x000b, 0x0031, - 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0x0126, 0x0036, - 0x2091, 0x8000, 0x0086, 0x2c40, 0x0096, 0x2049, 0x0000, 0x080c, - 0x7b9a, 0x009e, 0x008e, 0x1578, 0x0076, 0x2c38, 0x080c, 0x7c34, - 0x007e, 0x1548, 0x6000, 0xa086, 0x0000, 0x0528, 0x601c, 0xa086, - 0x0007, 0x0508, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1150, 0x080c, - 0xabb4, 0x601f, 0x0007, 0x2001, 0xafa3, 0x2004, 0x6016, 0x080c, - 0x190b, 0x6010, 0x2068, 0x080c, 0x9596, 0x0110, 0x080c, 0xa91f, - 0x00de, 0x6013, 0x0000, 0x080c, 0xabb4, 0x601f, 0x0007, 0x2001, - 0xafa3, 0x2004, 0x6016, 0x003e, 0x012e, 0x0005, 0x00f6, 0x00c6, - 0x0036, 0x0156, 0x2079, 0xb280, 0x7938, 0x783c, 0x080c, 0x2676, - 0x1904, 0xa5f1, 0x0016, 0x00c6, 0x080c, 0x4cdc, 0x15c0, 0x2011, - 0xb290, 0xac98, 0x000a, 0x20a9, 0x0004, 0x080c, 0x8a7c, 0x1578, - 0x001e, 0x002e, 0x0026, 0x0016, 0x2019, 0x0029, 0x080c, 0x7cf4, - 0x080c, 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x007e, - 0x001e, 0x0076, 0x2039, 0x0000, 0x080c, 0xa712, 0x007e, 0x080c, - 0x4ecf, 0x0026, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, - 0x0118, 0xa286, 0x0004, 0x1118, 0x62a0, 0x080c, 0x2b87, 0x002e, - 0x001e, 0x080c, 0x493a, 0x6612, 0x6516, 0xa006, 0x0010, 0x00ce, - 0x001e, 0x015e, 0x003e, 0x00ce, 0x00fe, 0x0005, 0x00c6, 0x00d6, - 0x00e6, 0x0016, 0x2009, 0xad20, 0x2104, 0xa086, 0x0074, 0x1904, - 0xa64b, 0x2069, 0xb28e, 0x690c, 0xa182, 0x0100, 0x06c0, 0x6908, - 0xa184, 0x8000, 0x05e8, 0x2001, 0xaf9d, 0x2004, 0xa005, 0x1160, - 0x6018, 0x2070, 0x7010, 0xa084, 0x00ff, 0x0118, 0x7000, 0xd0f4, - 0x0118, 0xa184, 0x0800, 0x0560, 0x6910, 0xa18a, 0x0001, 0x0610, - 0x6914, 0x2069, 0xb2ae, 0x6904, 0x81ff, 0x1198, 0x690c, 0xa182, - 0x0100, 0x02a8, 0x6908, 0x81ff, 0x1178, 0x6910, 0xa18a, 0x0001, - 0x0288, 0x6918, 0xa18a, 0x0001, 0x0298, 0x00d0, 0x6013, 0x0100, - 0x00a0, 0x6013, 0x0300, 0x0088, 0x6013, 0x0500, 0x0070, 0x6013, - 0x0700, 0x0058, 0x6013, 0x0900, 0x0040, 0x6013, 0x0b00, 0x0028, - 0x6013, 0x0f00, 0x0010, 0x6013, 0x2d00, 0xa085, 0x0001, 0x0008, - 0xa006, 0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6, - 0x0026, 0x0036, 0x0156, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff, - 0xa286, 0x0006, 0x0190, 0xa286, 0x0004, 0x0178, 0xa394, 0xff00, - 0x8217, 0xa286, 0x0006, 0x0148, 0xa286, 0x0004, 0x0130, 0x00c6, - 0x2d60, 0x080c, 0x4ceb, 0x00ce, 0x04c0, 0x2011, 0xb296, 0xad98, - 0x000a, 0x20a9, 0x0004, 0x080c, 0x8a7c, 0x1580, 0x2011, 0xb29a, - 0xad98, 0x0006, 0x20a9, 0x0004, 0x080c, 0x8a7c, 0x1538, 0x0046, - 0x0016, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0xad52, - 0x210c, 0xd1a4, 0x0138, 0x2009, 0x0029, 0x080c, 0xa96c, 0x6800, - 0xc0e5, 0x6802, 0x2019, 0x0029, 0x080c, 0x68e7, 0x0076, 0x2039, - 0x0000, 0x080c, 0x681d, 0x2c08, 0x080c, 0xa712, 0x007e, 0x2001, - 0x0007, 0x080c, 0x4c5d, 0x001e, 0x004e, 0xa006, 0x015e, 0x003e, - 0x002e, 0x00de, 0x00ce, 0x0005, 0x00d6, 0x2069, 0xb28e, 0x6800, - 0xa086, 0x0800, 0x0118, 0x6013, 0x0000, 0x0008, 0xa006, 0x00de, - 0x0005, 0x00c6, 0x00f6, 0x0016, 0x0026, 0x0036, 0x0156, 0x2079, - 0xb28c, 0x7930, 0x7834, 0x080c, 0x2676, 0x11a0, 0x080c, 0x4cdc, - 0x1188, 0x2011, 0xb290, 0xac98, 0x000a, 0x20a9, 0x0004, 0x080c, - 0x8a7c, 0x1140, 0x2011, 0xb294, 0xac98, 0x0006, 0x20a9, 0x0004, - 0x080c, 0x8a7c, 0x015e, 0x003e, 0x002e, 0x001e, 0x00fe, 0x00ce, - 0x0005, 0x00c6, 0x0006, 0x0016, 0x0026, 0x0036, 0x0156, 0x2011, - 0xb283, 0x2204, 0x8211, 0x220c, 0x080c, 0x2676, 0x11a0, 0x080c, - 0x4cdc, 0x1188, 0x2011, 0xb296, 0xac98, 0x000a, 0x20a9, 0x0004, - 0x080c, 0x8a7c, 0x1140, 0x2011, 0xb29a, 0xac98, 0x0006, 0x20a9, - 0x0004, 0x080c, 0x8a7c, 0x015e, 0x003e, 0x002e, 0x001e, 0x000e, - 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0056, - 0x0046, 0x0026, 0x0126, 0x2091, 0x8000, 0x2740, 0x2029, 0xafd0, - 0x252c, 0x2021, 0xafd6, 0x2424, 0x2061, 0xb400, 0x2071, 0xad00, - 0x7644, 0x7064, 0x81ff, 0x0128, 0x8001, 0xa602, 0x1a04, 0xa78e, - 0x0018, 0xa606, 0x0904, 0xa78e, 0x2100, 0xac06, 0x0904, 0xa785, - 0x080c, 0xa990, 0x0904, 0xa785, 0x671c, 0xa786, 0x0001, 0x0904, - 0xa7a5, 0xa786, 0x0004, 0x0904, 0xa7a5, 0xa786, 0x0007, 0x05e8, - 0x2500, 0xac06, 0x05d0, 0x2400, 0xac06, 0x05b8, 0x080c, 0xa9a0, - 0x15a0, 0x88ff, 0x0118, 0x6050, 0xa906, 0x1578, 0x00d6, 0x6000, - 0xa086, 0x0004, 0x1120, 0x0016, 0x080c, 0x190b, 0x001e, 0xa786, - 0x0008, 0x1148, 0x080c, 0x9789, 0x1130, 0x080c, 0x85f3, 0x00de, - 0x080c, 0x974e, 0x00d0, 0x6010, 0x2068, 0x080c, 0x9596, 0x0190, - 0xa786, 0x0003, 0x1528, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, - 0x080c, 0xabfa, 0x0016, 0x080c, 0x97fd, 0x080c, 0x510c, 0x001e, - 0x080c, 0x9742, 0x00de, 0x080c, 0x974e, 0xace0, 0x0018, 0x2001, - 0xad16, 0x2004, 0xac02, 0x1210, 0x0804, 0xa726, 0x012e, 0x002e, - 0x004e, 0x005e, 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x0005, - 0xa786, 0x0006, 0x19c0, 0xa386, 0x0005, 0x0128, 0x080c, 0xabfa, - 0x080c, 0xa91f, 0x08f8, 0x00de, 0x0c00, 0x080c, 0xa9a0, 0x19e8, - 0x81ff, 0x09d8, 0xa180, 0x0001, 0x2004, 0xa086, 0x0018, 0x0130, - 0xa180, 0x0001, 0x2004, 0xa086, 0x002d, 0x1978, 0x6000, 0xa086, - 0x0002, 0x1958, 0x080c, 0x9778, 0x0130, 0x080c, 0x9789, 0x1928, - 0x080c, 0x85f3, 0x0038, 0x080c, 0x2aff, 0x080c, 0x9789, 0x1110, - 0x080c, 0x85f3, 0x080c, 0x974e, 0x0804, 0xa785, 0x00c6, 0x00e6, - 0x0016, 0x2c08, 0x2170, 0x080c, 0xa940, 0x001e, 0x0120, 0x601c, - 0xa084, 0x000f, 0x001b, 0x00ee, 0x00ce, 0x0005, 0xa7e6, 0xa7e6, - 0xa7e6, 0xa7e6, 0xa7e6, 0xa7e6, 0xa7e8, 0xa7e6, 0xa006, 0x0005, - 0x0046, 0x0016, 0x7018, 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff, - 0x8427, 0x2c00, 0x2009, 0x0020, 0x080c, 0xa96c, 0x001e, 0x004e, - 0x0036, 0x2019, 0x0002, 0x080c, 0xa566, 0x003e, 0xa085, 0x0001, - 0x0005, 0x2001, 0x0001, 0x080c, 0x4c1e, 0x0156, 0x0016, 0x0026, - 0x0036, 0x20a9, 0x0004, 0x2019, 0xad05, 0x2011, 0xb296, 0x080c, - 0x8a7c, 0x003e, 0x002e, 0x001e, 0x015e, 0xa005, 0x0005, 0x00f6, - 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0026, 0x0126, 0x2091, - 0x8000, 0x2740, 0x2061, 0xb400, 0x2079, 0x0001, 0x8fff, 0x0904, - 0xa875, 0x2071, 0xad00, 0x7644, 0x7064, 0x8001, 0xa602, 0x1a04, - 0xa875, 0x88ff, 0x0128, 0x2800, 0xac06, 0x15b0, 0x2079, 0x0000, - 0x080c, 0xa990, 0x0588, 0x2400, 0xac06, 0x0570, 0x671c, 0xa786, - 0x0006, 0x1550, 0xa786, 0x0007, 0x0538, 0x88ff, 0x1140, 0x6018, - 0xa206, 0x1510, 0x85ff, 0x0118, 0x6050, 0xa106, 0x11e8, 0x00d6, - 0x6000, 0xa086, 0x0004, 0x1150, 0x080c, 0xabb4, 0x601f, 0x0007, - 0x2001, 0xafa3, 0x2004, 0x6016, 0x080c, 0x190b, 0x6010, 0x2068, - 0x080c, 0x9596, 0x0120, 0x0046, 0x080c, 0xa91f, 0x004e, 0x00de, - 0x080c, 0x974e, 0x88ff, 0x1198, 0xace0, 0x0018, 0x2001, 0xad16, - 0x2004, 0xac02, 0x1210, 0x0804, 0xa826, 0xa006, 0x012e, 0x002e, - 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0xa8c5, - 0x0001, 0x0ca0, 0x0076, 0x0056, 0x0086, 0x2041, 0x0000, 0x2029, - 0x0001, 0x2c20, 0x2019, 0x0002, 0x6218, 0x0096, 0x2049, 0x0000, - 0x080c, 0x7b9a, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, 0x7c34, - 0x080c, 0xa817, 0x005e, 0x007e, 0x0005, 0x0026, 0x0046, 0x0056, - 0x0076, 0x00c6, 0x0156, 0x2c20, 0x2128, 0x20a9, 0x007f, 0x2009, - 0x0000, 0x0016, 0x0036, 0x080c, 0x4cdc, 0x11b0, 0x2c10, 0x0056, - 0x0086, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001, 0x0096, 0x2049, - 0x0000, 0x080c, 0x7b9a, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, - 0x7c34, 0x080c, 0xa817, 0x005e, 0x003e, 0x001e, 0x8108, 0x1f04, - 0xa8a9, 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x002e, 0x0005, - 0x0076, 0x0056, 0x6218, 0x0086, 0x2041, 0x0000, 0x2029, 0x0001, - 0x2019, 0x0048, 0x0096, 0x2049, 0x0000, 0x080c, 0x7b9a, 0x009e, - 0x008e, 0x2039, 0x0000, 0x080c, 0x7c34, 0x2c20, 0x080c, 0xa817, - 0x005e, 0x007e, 0x0005, 0x0026, 0x0046, 0x0056, 0x0076, 0x00c6, - 0x0156, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x0036, - 0x080c, 0x4cdc, 0x11c0, 0x2c10, 0x0086, 0x2041, 0x0000, 0x2828, - 0x0046, 0x2021, 0x0001, 0x080c, 0xab96, 0x004e, 0x0096, 0x2049, - 0x0000, 0x080c, 0x7b9a, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, - 0x7c34, 0x080c, 0xa817, 0x003e, 0x001e, 0x8108, 0x1f04, 0xa8f6, - 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x002e, 0x0005, 0x0016, - 0x00f6, 0x3800, 0xd08c, 0x0130, 0xad82, 0x1000, 0x02b0, 0xad82, - 0xad00, 0x0230, 0xad82, 0xe400, 0x0280, 0xad82, 0xffff, 0x1268, - 0x6800, 0xa07d, 0x0138, 0x6803, 0x0000, 0x6b52, 0x080c, 0x510c, - 0x2f68, 0x0cb0, 0x6b52, 0x080c, 0x510c, 0x00fe, 0x001e, 0x0005, - 0x00e6, 0x0046, 0x0036, 0x2061, 0xb400, 0x2071, 0xad00, 0x7444, - 0x7064, 0x8001, 0xa402, 0x12d8, 0x2100, 0xac06, 0x0168, 0x6000, - 0xa086, 0x0000, 0x0148, 0x6008, 0xa206, 0x1130, 0x6018, 0xa1a0, - 0x0006, 0x2424, 0xa406, 0x0140, 0xace0, 0x0018, 0x2001, 0xad16, - 0x2004, 0xac02, 0x1220, 0x0c08, 0xa085, 0x0001, 0x0008, 0xa006, - 0x003e, 0x004e, 0x00ee, 0x0005, 0x00d6, 0x0006, 0x080c, 0x15d9, - 0x000e, 0x090c, 0x14f6, 0x6837, 0x010d, 0x685e, 0x0026, 0x2010, - 0x080c, 0x9586, 0x2001, 0x0000, 0x0120, 0x2200, 0xa080, 0x0014, - 0x2004, 0x002e, 0x684a, 0x6956, 0x6c46, 0x684f, 0x0000, 0xa006, - 0x68b2, 0x6802, 0x683a, 0x685a, 0x080c, 0x510c, 0x00de, 0x0005, - 0x6700, 0xa786, 0x0000, 0x0158, 0xa786, 0x0001, 0x0140, 0xa786, - 0x000a, 0x0128, 0xa786, 0x0009, 0x0110, 0xa085, 0x0001, 0x0005, - 0x00e6, 0x6018, 0x2070, 0x70a0, 0xa206, 0x00ee, 0x0005, 0x0016, - 0x6004, 0xa08e, 0x001e, 0x11a0, 0x8007, 0x6130, 0xa18c, 0x00ff, - 0xa105, 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0005, - 0x2001, 0xafa4, 0x2004, 0x6016, 0x080c, 0x67a8, 0x080c, 0x6c50, - 0x001e, 0x0005, 0xe000, 0xe000, 0x0005, 0x6020, 0xd0e4, 0x0158, - 0xd0cc, 0x0118, 0x080c, 0x9866, 0x0030, 0x080c, 0xabb4, 0x080c, - 0x6618, 0x080c, 0x8078, 0x0005, 0xa280, 0x0007, 0x2004, 0xa084, - 0x000f, 0x0002, 0xa9e3, 0xa9e3, 0xa9e3, 0xa9e8, 0xa9e3, 0xa9e5, - 0xa9e5, 0xa9e3, 0xa9e5, 0xa006, 0x0005, 0x00c6, 0x2260, 0x00ce, - 0xa085, 0x0001, 0x0005, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f, - 0x0002, 0xa9fa, 0xa9fa, 0xa9fa, 0xa9fa, 0xa9fa, 0xa9fa, 0xaa05, - 0xa9fa, 0xa9fa, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00, - 0x6003, 0x0001, 0x080c, 0x67a8, 0x0005, 0x00c6, 0x2260, 0x080c, - 0xabb4, 0x603f, 0x0000, 0x6020, 0xc0f4, 0xc0cc, 0x6022, 0x6037, - 0x0000, 0x00ce, 0x00d6, 0x2268, 0xa186, 0x0007, 0x1904, 0xaa60, - 0x6810, 0xa005, 0x0138, 0xa080, 0x0013, 0x2004, 0xd0fc, 0x1110, - 0x00de, 0x08c0, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c, 0x67a8, - 0x080c, 0x6c50, 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002, 0x1904, - 0xaae7, 0x6010, 0xa005, 0x1138, 0x6000, 0xa086, 0x0007, 0x190c, - 0x14f6, 0x0804, 0xaae7, 0xa08c, 0xf000, 0x1130, 0x0028, 0x2068, - 0x6800, 0xa005, 0x1de0, 0x2d00, 0xa080, 0x0013, 0x2004, 0xa084, - 0x0003, 0xa086, 0x0002, 0x1180, 0x6010, 0x2068, 0x684c, 0xc0dc, - 0xc0f4, 0x684e, 0x6850, 0xc0f4, 0xc0fc, 0x6852, 0x2009, 0x0043, - 0x080c, 0xa3de, 0x0804, 0xaae7, 0x2009, 0x0041, 0x0804, 0xaae1, - 0xa186, 0x0005, 0x15f0, 0x6810, 0xa080, 0x0013, 0x2004, 0xd0bc, - 0x1118, 0x00de, 0x0804, 0xa9fa, 0xd0b4, 0x0128, 0xd0fc, 0x090c, - 0x14f6, 0x0804, 0xaa18, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c, - 0x67a8, 0x080c, 0x6c50, 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002, - 0x0120, 0xa186, 0x0004, 0x1904, 0xaae7, 0x2071, 0xaffd, 0x7000, - 0xa086, 0x0003, 0x1128, 0x7004, 0xac06, 0x1110, 0x7003, 0x0000, - 0x6810, 0xa080, 0x0013, 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000, - 0x200c, 0xc1f4, 0xc1fc, 0xc1bc, 0x2102, 0x2009, 0x0042, 0x0804, - 0xaae1, 0x0036, 0x00d6, 0x00d6, 0x080c, 0x15d9, 0x003e, 0x090c, - 0x14f6, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b, - 0x0000, 0x6b5e, 0x6857, 0x0045, 0x2c00, 0x6862, 0x6034, 0x6872, - 0x2360, 0x6020, 0xc0dd, 0x6022, 0x6018, 0xa080, 0x0028, 0x2004, - 0xa084, 0x00ff, 0x8007, 0x6350, 0x6b4a, 0x6846, 0x684f, 0x0000, - 0x6d6a, 0x6e66, 0x686f, 0x0001, 0x080c, 0x510c, 0x2019, 0x0045, - 0x6008, 0x2068, 0x080c, 0xa566, 0x2d00, 0x600a, 0x601f, 0x0006, - 0x6003, 0x0007, 0x6017, 0x0000, 0x603f, 0x0000, 0x00de, 0x003e, - 0x0038, 0x603f, 0x0000, 0x6003, 0x0007, 0x080c, 0xa3de, 0x00ce, - 0x00de, 0x0005, 0xa186, 0x0013, 0x1128, 0x6004, 0xa082, 0x0085, - 0x2008, 0x00c2, 0xa186, 0x0027, 0x1178, 0x080c, 0x6b73, 0x0036, - 0x00d6, 0x6010, 0x2068, 0x2019, 0x0004, 0x080c, 0xa91f, 0x00de, - 0x003e, 0x080c, 0x6c50, 0x0005, 0xa186, 0x0014, 0x0d70, 0x080c, - 0x80be, 0x0005, 0xab13, 0xab11, 0xab11, 0xab11, 0xab11, 0xab11, - 0xab13, 0x080c, 0x14f6, 0x080c, 0x6b73, 0x6003, 0x000c, 0x080c, - 0x6c50, 0x0005, 0xa182, 0x008c, 0x1220, 0xa182, 0x0085, 0x0208, - 0x001a, 0x080c, 0x80be, 0x0005, 0xab2b, 0xab2b, 0xab2b, 0xab2b, - 0xab2d, 0xab4b, 0xab2b, 0x080c, 0x14f6, 0x00d6, 0x2c68, 0x080c, - 0x8022, 0x01a0, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0xb28e, - 0x210c, 0x6136, 0x2009, 0xb28f, 0x210c, 0x613a, 0x600b, 0xffff, - 0x6918, 0x611a, 0x601f, 0x0004, 0x080c, 0x67a8, 0x2d60, 0x080c, - 0x8078, 0x00de, 0x0005, 0x080c, 0x8078, 0x0005, 0x00e6, 0x6018, - 0x2070, 0x7000, 0xd0ec, 0x00ee, 0x0005, 0x6010, 0xa080, 0x0013, - 0x200c, 0xd1ec, 0x05d0, 0x2001, 0xad71, 0x2004, 0xd0ec, 0x05a8, - 0x6003, 0x0002, 0x6020, 0xc0e5, 0x6022, 0xd1ac, 0x0180, 0x00f6, - 0x2c78, 0x080c, 0x5025, 0x00fe, 0x0150, 0x2001, 0xafa5, 0x2004, - 0x603e, 0x2009, 0xad71, 0x210c, 0xd1f4, 0x11e8, 0x0080, 0x2009, - 0xad71, 0x210c, 0xd1f4, 0x0128, 0x6020, 0xc0e4, 0x6022, 0xa006, - 0x00a0, 0x2001, 0xafa5, 0x200c, 0x8103, 0xa100, 0x603e, 0x6018, - 0xa088, 0x002b, 0x2104, 0xa005, 0x0118, 0xa088, 0x0003, 0x0cd0, - 0x2c0a, 0x600f, 0x0000, 0xa085, 0x0001, 0x0005, 0x0016, 0x00c6, - 0x00e6, 0x6150, 0xa2f0, 0x002b, 0x2e04, 0x2060, 0x8cff, 0x0180, - 0x84ff, 0x1118, 0x6050, 0xa106, 0x1138, 0x600c, 0x2072, 0x080c, - 0x6618, 0x080c, 0x8078, 0x0010, 0xacf0, 0x0003, 0x2e64, 0x0c70, - 0x00ee, 0x00ce, 0x001e, 0x0005, 0x00d6, 0x6018, 0xa0e8, 0x002b, - 0x2d04, 0xa005, 0x0140, 0xac06, 0x0120, 0x2d04, 0xa0e8, 0x0003, - 0x0cb8, 0x600c, 0x206a, 0x00de, 0x0005, 0x0026, 0x0036, 0x0156, - 0x2011, 0xad27, 0x2204, 0xa084, 0x00ff, 0x2019, 0xb28e, 0x2334, - 0xa636, 0x11d8, 0x8318, 0x2334, 0x2204, 0xa084, 0xff00, 0xa636, - 0x11a0, 0x2011, 0xb290, 0x6018, 0xa098, 0x000a, 0x20a9, 0x0004, - 0x080c, 0x8a7c, 0x1150, 0x2011, 0xb294, 0x6018, 0xa098, 0x0006, - 0x20a9, 0x0004, 0x080c, 0x8a7c, 0x1100, 0x015e, 0x003e, 0x002e, - 0x0005, 0x00e6, 0x2071, 0xad00, 0x080c, 0x48f5, 0x080c, 0x28fa, - 0x00ee, 0x0005, 0x00e6, 0x6018, 0x2070, 0x7000, 0xd0fc, 0x0108, - 0x0011, 0x00ee, 0x0005, 0x6850, 0xc0e5, 0x6852, 0x0005, 0x00e6, - 0x00c6, 0x0076, 0x0066, 0x0056, 0x0046, 0x0026, 0x0016, 0x0126, - 0x2091, 0x8000, 0x2029, 0xafd0, 0x252c, 0x2021, 0xafd6, 0x2424, - 0x2061, 0xb400, 0x2071, 0xad00, 0x7644, 0x7064, 0xa606, 0x0578, - 0x671c, 0xa786, 0x0001, 0x0118, 0xa786, 0x0008, 0x1500, 0x2500, - 0xac06, 0x01e8, 0x2400, 0xac06, 0x01d0, 0x080c, 0xa990, 0x01b8, - 0x080c, 0xa9a0, 0x11a0, 0x6000, 0xa086, 0x0004, 0x1120, 0x0016, - 0x080c, 0x190b, 0x001e, 0x080c, 0x9778, 0x1110, 0x080c, 0x2aff, - 0x080c, 0x9789, 0x1110, 0x080c, 0x85f3, 0x080c, 0x974e, 0xace0, - 0x0018, 0x2001, 0xad16, 0x2004, 0xac02, 0x1208, 0x0858, 0x012e, - 0x001e, 0x002e, 0x004e, 0x005e, 0x006e, 0x007e, 0x00ce, 0x00ee, - 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0xad40, - 0xd5a4, 0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, - 0x8000, 0x7032, 0xd5ac, 0x0118, 0x2071, 0xad4a, 0x0451, 0x00ee, - 0x000e, 0x012e, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, - 0x2071, 0xad40, 0xd5a4, 0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, - 0x0118, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0118, 0x2071, 0xad4a, - 0x0081, 0x00ee, 0x000e, 0x012e, 0x0005, 0x0126, 0x0006, 0x00e6, - 0x2091, 0x8000, 0x2071, 0xad42, 0x0021, 0x00ee, 0x000e, 0x012e, - 0x0005, 0x2e04, 0x8000, 0x2072, 0x1220, 0x8e70, 0x2e04, 0x8000, - 0x2072, 0x0005, 0x00e6, 0x2071, 0xad40, 0x0c99, 0x00ee, 0x0005, - 0x00e6, 0x2071, 0xad44, 0x0c69, 0x00ee, 0x0005, 0x0001, 0x0002, - 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, - 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x8529 -}; - diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 275ed9bd898c..d5fdcb9a8842 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -378,7 +378,6 @@ static struct scsi_host_template mv_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = MV_USE_Q_DEPTH, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = MV_MAX_SG_CT / 2, @@ -748,7 +747,7 @@ static void mv_dump_all_regs(void __iomem *mmio_base, int port, mv_dump_mem(mmio_base+0xf00, 0x4); mv_dump_mem(mmio_base+0x1d00, 0x6c); for (hc = start_hc; hc < start_hc + num_hcs; hc++) { - hc_base = mv_hc_base(mmio_base, port >> MV_PORT_HC_SHIFT); + hc_base = mv_hc_base(mmio_base, hc); DPRINTK("HC regs (HC %i):\n", hc); mv_dump_mem(hc_base, 0x1c); } @@ -1010,7 +1009,7 @@ static void mv_fill_sg(struct ata_queued_cmd *qc) pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff); pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); - pp->sg_tbl[i].flags_size = cpu_to_le32(len); + pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff); sg_len -= len; addr += len; @@ -1350,7 +1349,6 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, { void __iomem *mmio = host_set->mmio_base; void __iomem *hc_mmio = mv_hc_base(mmio, hc); - struct ata_port *ap; struct ata_queued_cmd *qc; u32 hc_irq_cause; int shift, port, port0, hard_port, handled; @@ -1373,25 +1371,32 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) { u8 ata_status = 0; - ap = host_set->ports[port]; + struct ata_port *ap = host_set->ports[port]; + struct mv_port_priv *pp = ap->private_data; + hard_port = port & MV_PORT_MASK; /* range 0-3 */ handled = 0; /* ensure ata_status is set if handled++ */ - if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) { - /* new CRPB on the queue; just one at a time until NCQ - */ - ata_status = mv_get_crpb_status(ap); - handled++; - } else if ((DEV_IRQ << hard_port) & hc_irq_cause) { - /* received ATA IRQ; read the status reg to clear INTRQ - */ - ata_status = readb((void __iomem *) + /* Note that DEV_IRQ might happen spuriously during EDMA, + * and should be ignored in such cases. We could mask it, + * but it's pretty rare and may not be worth the overhead. + */ + if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) { + /* EDMA: check for response queue interrupt */ + if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) { + ata_status = mv_get_crpb_status(ap); + handled = 1; + } + } else { + /* PIO: check for device (drive) interrupt */ + if ((DEV_IRQ << hard_port) & hc_irq_cause) { + ata_status = readb((void __iomem *) ap->ioaddr.status_addr); - handled++; + handled = 1; + } } - if (ap && - (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) + if (ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR)) continue; err_mask = ac_err_mask(ata_status); @@ -1403,12 +1408,12 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant, if ((PORT0_ERR << shift) & relevant) { mv_err_intr(ap); err_mask |= AC_ERR_OTHER; - handled++; + handled = 1; } - if (handled && ap) { + if (handled) { qc = ata_qc_from_tag(ap, ap->active_tag); - if (NULL != qc) { + if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) { VPRINTK("port %u IRQ found for qc, " "ata_status 0x%x\n", port,ata_status); /* mark qc status appropriately */ diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index f77bf183dfab..9f553081b5e8 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -201,7 +201,6 @@ static struct scsi_host_template nv_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index cc928c68a479..7eb67a6bdc64 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -111,7 +111,6 @@ static struct scsi_host_template pdc_ata_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index 9ffe1ef0d205..886f3447dd48 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -132,7 +132,6 @@ static struct scsi_host_template qs_ata_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = QS_MAX_PRD, diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 18c296c56899..106627299d55 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -146,7 +146,6 @@ static struct scsi_host_template sil_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 068c98a4111b..f7264fd611c2 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -281,7 +281,6 @@ static struct scsi_host_template sil24_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index acc8439dea23..728530df2e07 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -87,7 +87,6 @@ static struct scsi_host_template sis_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = ATA_MAX_PRD, diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index 724f0ed6a52d..53b0d5c0a61f 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -290,7 +290,6 @@ static struct scsi_host_template k2_sata_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index ae70f60c7c0d..4139ad4b1df0 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -182,7 +182,6 @@ static struct scsi_host_template pdc_sata_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c index 7ac5a5f5a905..38b52bd3fa3f 100644 --- a/drivers/scsi/sata_uli.c +++ b/drivers/scsi/sata_uli.c @@ -81,7 +81,6 @@ static struct scsi_host_template uli_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 791bf652ba63..9e7ae4e0db32 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -94,7 +94,6 @@ static struct scsi_host_template svia_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 836bbbb26ff2..8a29ce340b47 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -263,7 +263,6 @@ static struct scsi_host_template vsc_sata_sht = { .name = DRV_NAME, .ioctl = ata_scsi_ioctl, .queuecommand = ata_scsi_queuecmd, - .eh_strategy_handler = ata_scsi_error, .can_queue = ATA_DEF_QUEUE, .this_id = ATA_SHT_THIS_ID, .sg_tablesize = LIBATA_MAX_PRD, diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 6913b0623167..73994e2ac2cb 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -565,7 +565,8 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) /* * If SCSI-2 or lower, store the LUN value in cmnd. */ - if (cmd->device->scsi_level <= SCSI_2) { + if (cmd->device->scsi_level <= SCSI_2 && + cmd->device->scsi_level != SCSI_UNKNOWN) { cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) | (cmd->device->lun << 5 & 0xe0); } @@ -1243,7 +1244,7 @@ static int __init init_scsi(void) if (error) goto cleanup_sysctl; - for_each_cpu(i) + for_each_possible_cpu(i) INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); printk(KERN_NOTICE "SCSI subsystem initialized\n"); diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 84c3937ae8fb..c750d3399a97 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -132,7 +132,9 @@ static struct { {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */ {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */ {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */ - {"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN}, + {"COMPAQ", "ARRAY CONTROLLER", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | + BLIST_MAX_512 | BLIST_REPORTLUN2}, /* Compaq RA4x00 */ + {"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN | BLIST_MAX_512}, /* Compaq RA4x00 */ {"COMPAQ", "CR3500", NULL, BLIST_FORCELUN}, {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 5f0fdfb2618c..1c75646f9689 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1537,8 +1537,8 @@ int scsi_error_handler(void *data) * what we need to do to get it up and online again (if we can). * If we fail, we end up taking the thing offline. */ - if (shost->hostt->eh_strategy_handler) - shost->hostt->eh_strategy_handler(shost); + if (shost->transportt->eh_strategy_handler) + shost->transportt->eh_strategy_handler(shost); else scsi_unjam_host(shost); diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 36e930066649..a89aff61d3d8 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -157,180 +157,6 @@ int scsi_set_medium_removal(struct scsi_device *sdev, char state) } EXPORT_SYMBOL(scsi_set_medium_removal); -/* - * This interface is deprecated - users should use the scsi generic (sg) - * interface instead, as this is a more flexible approach to performing - * generic SCSI commands on a device. - * - * The structure that we are passed should look like: - * - * struct sdata { - * unsigned int inlen; [i] Length of data to be written to device - * unsigned int outlen; [i] Length of data to be read from device - * unsigned char cmd[x]; [i] SCSI command (6 <= x <= 12). - * [o] Data read from device starts here. - * [o] On error, sense buffer starts here. - * unsigned char wdata[y]; [i] Data written to device starts here. - * }; - * Notes: - * - The SCSI command length is determined by examining the 1st byte - * of the given command. There is no way to override this. - * - Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha). - * - The length (x + y) must be at least OMAX_SB_LEN bytes long to - * accommodate the sense buffer when an error occurs. - * The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that - * old code will not be surprised. - * - If a Unix error occurs (e.g. ENOMEM) then the user will receive - * a negative return and the Unix error code in 'errno'. - * If the SCSI command succeeds then 0 is returned. - * Positive numbers returned are the compacted SCSI error codes (4 - * bytes in one int) where the lowest byte is the SCSI status. - * See the drivers/scsi/scsi.h file for more information on this. - * - */ -#define OMAX_SB_LEN 16 /* Old sense buffer length */ - -int scsi_ioctl_send_command(struct scsi_device *sdev, - struct scsi_ioctl_command __user *sic) -{ - char *buf; - unsigned char cmd[MAX_COMMAND_SIZE]; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - char __user *cmd_in; - unsigned char opcode; - unsigned int inlen, outlen, cmdlen; - unsigned int needed, buf_needed; - int timeout, retries, result; - int data_direction; - gfp_t gfp_mask = GFP_KERNEL; - - if (!sic) - return -EINVAL; - - if (sdev->host->unchecked_isa_dma) - gfp_mask |= GFP_DMA; - - /* - * Verify that we can read at least this much. - */ - if (!access_ok(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) - return -EFAULT; - - if(__get_user(inlen, &sic->inlen)) - return -EFAULT; - - if(__get_user(outlen, &sic->outlen)) - return -EFAULT; - - /* - * We do not transfer more than MAX_BUF with this interface. - * If the user needs to transfer more data than this, they - * should use scsi_generics (sg) instead. - */ - if (inlen > MAX_BUF) - return -EINVAL; - if (outlen > MAX_BUF) - return -EINVAL; - - cmd_in = sic->data; - if(get_user(opcode, cmd_in)) - return -EFAULT; - - needed = buf_needed = (inlen > outlen ? inlen : outlen); - if (buf_needed) { - buf_needed = (buf_needed + 511) & ~511; - if (buf_needed > MAX_BUF) - buf_needed = MAX_BUF; - buf = kzalloc(buf_needed, gfp_mask); - if (!buf) - return -ENOMEM; - if (inlen == 0) { - data_direction = DMA_FROM_DEVICE; - } else if (outlen == 0 ) { - data_direction = DMA_TO_DEVICE; - } else { - /* - * Can this ever happen? - */ - data_direction = DMA_BIDIRECTIONAL; - } - - } else { - buf = NULL; - data_direction = DMA_NONE; - } - - /* - * Obtain the command from the user's address space. - */ - cmdlen = COMMAND_SIZE(opcode); - - result = -EFAULT; - - if (!access_ok(VERIFY_READ, cmd_in, cmdlen + inlen)) - goto error; - - if(__copy_from_user(cmd, cmd_in, cmdlen)) - goto error; - - /* - * Obtain the data to be sent to the device (if any). - */ - - if(inlen && copy_from_user(buf, cmd_in + cmdlen, inlen)) - goto error; - - switch (opcode) { - case SEND_DIAGNOSTIC: - case FORMAT_UNIT: - timeout = FORMAT_UNIT_TIMEOUT; - retries = 1; - break; - case START_STOP: - timeout = START_STOP_TIMEOUT; - retries = NORMAL_RETRIES; - break; - case MOVE_MEDIUM: - timeout = MOVE_MEDIUM_TIMEOUT; - retries = NORMAL_RETRIES; - break; - case READ_ELEMENT_STATUS: - timeout = READ_ELEMENT_STATUS_TIMEOUT; - retries = NORMAL_RETRIES; - break; - case READ_DEFECT_DATA: - timeout = READ_DEFECT_DATA_TIMEOUT; - retries = 1; - break; - default: - timeout = IOCTL_NORMAL_TIMEOUT; - retries = NORMAL_RETRIES; - break; - } - - result = scsi_execute(sdev, cmd, data_direction, buf, needed, - sense, timeout, retries, 0); - - /* - * If there was an error condition, pass the info back to the user. - */ - if (result) { - int sb_len = sizeof(*sense); - - sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; - if (copy_to_user(cmd_in, sense, sb_len)) - result = -EFAULT; - } else { - if (outlen && copy_to_user(cmd_in, buf, outlen)) - result = -EFAULT; - } - -error: - kfree(buf); - return result; -} -EXPORT_SYMBOL(scsi_ioctl_send_command); - /* * The scsi_ioctl_get_pci() function places into arg the value * pci_dev::slot_name (8 characters) for the PCI device (if any). @@ -409,7 +235,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) case SCSI_IOCTL_SEND_COMMAND: if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; - return scsi_ioctl_send_command(sdev, arg); + return sg_scsi_ioctl(NULL, sdev->request_queue, NULL, arg); case SCSI_IOCTL_DOORLOCK: return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); case SCSI_IOCTL_DOORUNLOCK: diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 8f010a314a3d..7b0f9a3810d2 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1479,6 +1479,8 @@ static inline int scsi_host_queue_ready(struct request_queue *q, static void scsi_kill_request(struct request *req, request_queue_t *q) { struct scsi_cmnd *cmd = req->special; + struct scsi_device *sdev = cmd->device; + struct Scsi_Host *shost = sdev->host; blkdev_dequeue_request(req); @@ -1491,6 +1493,19 @@ static void scsi_kill_request(struct request *req, request_queue_t *q) scsi_init_cmd_errh(cmd); cmd->result = DID_NO_CONNECT << 16; atomic_inc(&cmd->device->iorequest_cnt); + + /* + * SCSI request completion path will do scsi_device_unbusy(), + * bump busy counts. To bump the counters, we need to dance + * with the locks as normal issue path does. + */ + sdev->device_busy++; + spin_unlock(sdev->request_queue->queue_lock); + spin_lock(shost->host_lock); + shost->host_busy++; + spin_unlock(shost->host_lock); + spin_lock(sdev->request_queue->queue_lock); + __scsi_done(cmd); } diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h new file mode 100644 index 000000000000..d76e6e3d8ca5 --- /dev/null +++ b/drivers/scsi/scsi_sas_internal.h @@ -0,0 +1,38 @@ +#ifndef _SCSI_SAS_INTERNAL_H +#define _SCSI_SAS_INTERNAL_H + +#define SAS_HOST_ATTRS 0 +#define SAS_PORT_ATTRS 17 +#define SAS_RPORT_ATTRS 7 +#define SAS_END_DEV_ATTRS 3 +#define SAS_EXPANDER_ATTRS 7 + +struct sas_internal { + struct scsi_transport_template t; + struct sas_function_template *f; + struct sas_domain_function_template *dft; + + struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; + struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; + struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; + struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS]; + struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS]; + + struct transport_container phy_attr_cont; + struct transport_container rphy_attr_cont; + struct transport_container end_dev_attr_cont; + struct transport_container expander_attr_cont; + + /* + * The array of null terminated pointers to attributes + * needed by scsi_sysfs.c + */ + struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; + struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; + struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; + struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1]; + struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1]; +}; +#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t) + +#endif diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index f14945996ede..1a5474bd11a1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -673,6 +673,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) case TYPE_MEDIUM_CHANGER: case TYPE_ENCLOSURE: case TYPE_COMM: + case TYPE_RAID: case TYPE_RBC: sdev->writeable = 1; break; @@ -737,6 +738,13 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) if (*bflags & BLIST_SELECT_NO_ATN) sdev->select_no_atn = 1; + /* + * Maximum 512 sector transfer length + * broken RA4x00 Compaq Disk Array + */ + if (*bflags & BLIST_MAX_512) + blk_queue_max_sectors(sdev->request_queue, 512); + /* * Some devices may not want to have a start command automatically * issued when a device is added. @@ -1123,10 +1131,13 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, * Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does * support more than 8 LUNs. */ - if ((bflags & BLIST_NOREPORTLUN) || - starget->scsi_level < SCSI_2 || - (starget->scsi_level < SCSI_3 && - (!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8)) ) + if (bflags & BLIST_NOREPORTLUN) + return 1; + if (starget->scsi_level < SCSI_2 && + starget->scsi_level != SCSI_UNKNOWN) + return 1; + if (starget->scsi_level < SCSI_3 && + (!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8)) return 1; if (bflags & BLIST_NOLUN) return 0; diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 8db656214b5c..95c5478dcdfd 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -34,6 +34,8 @@ #include #include "scsi_priv.h" +static int fc_queue_work(struct Scsi_Host *, struct work_struct *); + /* * Redefine so that we can have same named attributes in the * sdev/starget/host objects. @@ -213,10 +215,8 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) #define FC_MGMTSRVR_PORTID 0x00000a -static void fc_shost_remove_rports(void *data); static void fc_timeout_deleted_rport(void *data); static void fc_scsi_scan_rport(void *data); -static void fc_rport_terminate(struct fc_rport *rport); /* * Attribute counts pre object type... @@ -288,42 +288,58 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, struct class_device *cdev) { struct Scsi_Host *shost = dev_to_shost(dev); + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); /* * Set default values easily detected by the midlayer as * failure cases. The scsi lldd is responsible for initializing * all transport attributes to valid values per host. */ - fc_host_node_name(shost) = -1; - fc_host_port_name(shost) = -1; - fc_host_permanent_port_name(shost) = -1; - fc_host_supported_classes(shost) = FC_COS_UNSPECIFIED; - memset(fc_host_supported_fc4s(shost), 0, - sizeof(fc_host_supported_fc4s(shost))); - memset(fc_host_symbolic_name(shost), 0, - sizeof(fc_host_symbolic_name(shost))); - fc_host_supported_speeds(shost) = FC_PORTSPEED_UNKNOWN; - fc_host_maxframe_size(shost) = -1; - memset(fc_host_serial_number(shost), 0, - sizeof(fc_host_serial_number(shost))); + fc_host->node_name = -1; + fc_host->port_name = -1; + fc_host->permanent_port_name = -1; + fc_host->supported_classes = FC_COS_UNSPECIFIED; + memset(fc_host->supported_fc4s, 0, + sizeof(fc_host->supported_fc4s)); + memset(fc_host->symbolic_name, 0, + sizeof(fc_host->symbolic_name)); + fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN; + fc_host->maxframe_size = -1; + memset(fc_host->serial_number, 0, + sizeof(fc_host->serial_number)); - fc_host_port_id(shost) = -1; - fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; - fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; - memset(fc_host_active_fc4s(shost), 0, - sizeof(fc_host_active_fc4s(shost))); - fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; - fc_host_fabric_name(shost) = -1; + fc_host->port_id = -1; + fc_host->port_type = FC_PORTTYPE_UNKNOWN; + fc_host->port_state = FC_PORTSTATE_UNKNOWN; + memset(fc_host->active_fc4s, 0, + sizeof(fc_host->active_fc4s)); + fc_host->speed = FC_PORTSPEED_UNKNOWN; + fc_host->fabric_name = -1; - fc_host_tgtid_bind_type(shost) = FC_TGTID_BIND_BY_WWPN; + fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN; - INIT_LIST_HEAD(&fc_host_rports(shost)); - INIT_LIST_HEAD(&fc_host_rport_bindings(shost)); - fc_host_next_rport_number(shost) = 0; - fc_host_next_target_id(shost) = 0; + INIT_LIST_HEAD(&fc_host->rports); + INIT_LIST_HEAD(&fc_host->rport_bindings); + fc_host->next_rport_number = 0; + fc_host->next_target_id = 0; + + snprintf(fc_host->work_q_name, KOBJ_NAME_LEN, "fc_wq_%d", + shost->host_no); + fc_host->work_q = create_singlethread_workqueue( + fc_host->work_q_name); + if (!fc_host->work_q) + return -ENOMEM; + + snprintf(fc_host->devloss_work_q_name, KOBJ_NAME_LEN, "fc_dl_%d", + shost->host_no); + fc_host->devloss_work_q = create_singlethread_workqueue( + fc_host->devloss_work_q_name); + if (!fc_host->devloss_work_q) { + destroy_workqueue(fc_host->work_q); + fc_host->work_q = NULL; + return -ENOMEM; + } - fc_host_flags(shost) = 0; - INIT_WORK(&fc_host_rport_del_work(shost), fc_shost_remove_rports, shost); return 0; } @@ -879,9 +895,9 @@ store_fc_private_host_tgtid_bind_type(struct class_device *cdev, while (!list_empty(&fc_host_rport_bindings(shost))) { get_list_head_entry(rport, &fc_host_rport_bindings(shost), peers); - spin_unlock_irqrestore(shost->host_lock, flags); - fc_rport_terminate(rport); - spin_lock_irqsave(shost->host_lock, flags); + list_del(&rport->peers); + rport->port_state = FC_PORTSTATE_DELETED; + fc_queue_work(shost, &rport->rport_delete_work); } spin_unlock_irqrestore(shost->host_lock, flags); } @@ -1262,6 +1278,90 @@ void fc_release_transport(struct scsi_transport_template *t) } EXPORT_SYMBOL(fc_release_transport); +/** + * fc_queue_work - Queue work to the fc_host workqueue. + * @shost: Pointer to Scsi_Host bound to fc_host. + * @work: Work to queue for execution. + * + * Return value: + * 0 on success / != 0 for error + **/ +static int +fc_queue_work(struct Scsi_Host *shost, struct work_struct *work) +{ + if (unlikely(!fc_host_work_q(shost))) { + printk(KERN_ERR + "ERROR: FC host '%s' attempted to queue work, " + "when no workqueue created.\n", shost->hostt->name); + dump_stack(); + + return -EINVAL; + } + + return queue_work(fc_host_work_q(shost), work); +} + +/** + * fc_flush_work - Flush a fc_host's workqueue. + * @shost: Pointer to Scsi_Host bound to fc_host. + **/ +static void +fc_flush_work(struct Scsi_Host *shost) +{ + if (!fc_host_work_q(shost)) { + printk(KERN_ERR + "ERROR: FC host '%s' attempted to flush work, " + "when no workqueue created.\n", shost->hostt->name); + dump_stack(); + return; + } + + flush_workqueue(fc_host_work_q(shost)); +} + +/** + * fc_queue_devloss_work - Schedule work for the fc_host devloss workqueue. + * @shost: Pointer to Scsi_Host bound to fc_host. + * @work: Work to queue for execution. + * @delay: jiffies to delay the work queuing + * + * Return value: + * 0 on success / != 0 for error + **/ +static int +fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work, + unsigned long delay) +{ + if (unlikely(!fc_host_devloss_work_q(shost))) { + printk(KERN_ERR + "ERROR: FC host '%s' attempted to queue work, " + "when no workqueue created.\n", shost->hostt->name); + dump_stack(); + + return -EINVAL; + } + + return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay); +} + +/** + * fc_flush_devloss - Flush a fc_host's devloss workqueue. + * @shost: Pointer to Scsi_Host bound to fc_host. + **/ +static void +fc_flush_devloss(struct Scsi_Host *shost) +{ + if (!fc_host_devloss_work_q(shost)) { + printk(KERN_ERR + "ERROR: FC host '%s' attempted to flush work, " + "when no workqueue created.\n", shost->hostt->name); + dump_stack(); + return; + } + + flush_workqueue(fc_host_devloss_work_q(shost)); +} + /** * fc_remove_host - called to terminate any fc_transport-related elements @@ -1283,36 +1383,103 @@ void fc_remove_host(struct Scsi_Host *shost) { struct fc_rport *rport, *next_rport; + struct workqueue_struct *work_q; + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); /* Remove any remote ports */ list_for_each_entry_safe(rport, next_rport, - &fc_host_rports(shost), peers) - fc_rport_terminate(rport); + &fc_host->rports, peers) { + list_del(&rport->peers); + rport->port_state = FC_PORTSTATE_DELETED; + fc_queue_work(shost, &rport->rport_delete_work); + } + list_for_each_entry_safe(rport, next_rport, - &fc_host_rport_bindings(shost), peers) - fc_rport_terminate(rport); + &fc_host->rport_bindings, peers) { + list_del(&rport->peers); + rport->port_state = FC_PORTSTATE_DELETED; + fc_queue_work(shost, &rport->rport_delete_work); + } + + /* flush all scan work items */ + scsi_flush_work(shost); + + /* flush all stgt delete, and rport delete work items, then kill it */ + if (fc_host->work_q) { + work_q = fc_host->work_q; + fc_host->work_q = NULL; + destroy_workqueue(work_q); + } + + /* flush all devloss work items, then kill it */ + if (fc_host->devloss_work_q) { + work_q = fc_host->devloss_work_q; + fc_host->devloss_work_q = NULL; + destroy_workqueue(work_q); + } } EXPORT_SYMBOL(fc_remove_host); -/* - * fc_rport_tgt_remove - Removes the scsi target on the remote port - * @rport: The remote port to be operated on - */ + +/** + * fc_starget_delete - called to delete the scsi decendents of an rport + * (target and all sdevs) + * + * @data: remote port to be operated on. + **/ static void -fc_rport_tgt_remove(struct fc_rport *rport) +fc_starget_delete(void *data) { + struct fc_rport *rport = (struct fc_rport *)data; struct Scsi_Host *shost = rport_to_shost(rport); + unsigned long flags; scsi_target_unblock(&rport->dev); - /* Stop anything on the workq */ - if (!cancel_delayed_work(&rport->dev_loss_work)) - flush_scheduled_work(); - scsi_flush_work(shost); + spin_lock_irqsave(shost->host_lock, flags); + if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { + spin_unlock_irqrestore(shost->host_lock, flags); + if (!cancel_delayed_work(&rport->dev_loss_work)) + fc_flush_devloss(shost); + spin_lock_irqsave(shost->host_lock, flags); + rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; + } + spin_unlock_irqrestore(shost->host_lock, flags); scsi_remove_target(&rport->dev); } + +/** + * fc_rport_final_delete - finish rport termination and delete it. + * + * @data: remote port to be deleted. + **/ +static void +fc_rport_final_delete(void *data) +{ + struct fc_rport *rport = (struct fc_rport *)data; + struct device *dev = &rport->dev; + struct Scsi_Host *shost = rport_to_shost(rport); + + /* Delete SCSI target and sdevs */ + if (rport->scsi_target_id != -1) + fc_starget_delete(data); + + /* + * if a scan is pending, flush the SCSI Host work_q so that + * that we can reclaim the rport scan work element. + */ + if (rport->flags & FC_RPORT_SCAN_PENDING) + scsi_flush_work(shost); + + transport_remove_device(dev); + device_del(dev); + transport_destroy_device(dev); + put_device(&shost->shost_gendev); +} + + /** * fc_rport_create - allocates and creates a remote FC port. * @shost: scsi host the remote port is connected to. @@ -1330,8 +1497,7 @@ struct fc_rport * fc_rport_create(struct Scsi_Host *shost, int channel, struct fc_rport_identifiers *ids) { - struct fc_host_attrs *fc_host = - (struct fc_host_attrs *)shost->shost_data; + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); struct fc_internal *fci = to_fc_internal(shost->transportt); struct fc_rport *rport; struct device *dev; @@ -1360,6 +1526,8 @@ fc_rport_create(struct Scsi_Host *shost, int channel, INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport); INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); + INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport); + INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport); spin_lock_irqsave(shost->host_lock, flags); @@ -1368,7 +1536,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel, rport->scsi_target_id = fc_host->next_target_id++; else rport->scsi_target_id = -1; - list_add_tail(&rport->peers, &fc_host_rports(shost)); + list_add_tail(&rport->peers, &fc_host->rports); get_device(&shost->shost_gendev); spin_unlock_irqrestore(shost->host_lock, flags); @@ -1389,9 +1557,11 @@ fc_rport_create(struct Scsi_Host *shost, int channel, transport_add_device(dev); transport_configure_device(dev); - if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) + if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) { /* initiate a scan of the target */ + rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); + } return rport; @@ -1451,10 +1621,14 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, struct fc_rport_identifiers *ids) { struct fc_internal *fci = to_fc_internal(shost->transportt); + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); struct fc_rport *rport; unsigned long flags; int match = 0; + /* ensure any stgt delete functions are done */ + fc_flush_work(shost); + /* * Search the list of "active" rports, for an rport that has been * deleted, but we've held off the real delete while the target @@ -1462,12 +1636,12 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, */ spin_lock_irqsave(shost->host_lock, flags); - list_for_each_entry(rport, &fc_host_rports(shost), peers) { + list_for_each_entry(rport, &fc_host->rports, peers) { if ((rport->port_state == FC_PORTSTATE_BLOCKED) && (rport->channel == channel)) { - switch (fc_host_tgtid_bind_type(shost)) { + switch (fc_host->tgtid_bind_type) { case FC_TGTID_BIND_BY_WWPN: case FC_TGTID_BIND_NONE: if (rport->port_name == ids->port_name) @@ -1521,27 +1695,34 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, * transaction. */ if (!cancel_delayed_work(work)) - flush_scheduled_work(); + fc_flush_devloss(shost); + + spin_lock_irqsave(shost->host_lock, flags); + + rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; /* initiate a scan of the target */ + rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); + spin_unlock_irqrestore(shost->host_lock, flags); + return rport; } } } /* Search the bindings array */ - if (fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE) { + if (fc_host->tgtid_bind_type != FC_TGTID_BIND_NONE) { /* search for a matching consistent binding */ - list_for_each_entry(rport, &fc_host_rport_bindings(shost), + list_for_each_entry(rport, &fc_host->rport_bindings, peers) { if (rport->channel != channel) continue; - switch (fc_host_tgtid_bind_type(shost)) { + switch (fc_host->tgtid_bind_type) { case FC_TGTID_BIND_BY_WWPN: if (rport->port_name == ids->port_name) match = 1; @@ -1559,8 +1740,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, } if (match) { - list_move_tail(&rport->peers, - &fc_host_rports(shost)); + list_move_tail(&rport->peers, &fc_host->rports); break; } } @@ -1574,15 +1754,17 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, rport->roles = ids->roles; rport->port_state = FC_PORTSTATE_ONLINE; - spin_unlock_irqrestore(shost->host_lock, flags); - if (fci->f->dd_fcrport_size) memset(rport->dd_data, 0, fci->f->dd_fcrport_size); - if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) + if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) { /* initiate a scan of the target */ + rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); + } + + spin_unlock_irqrestore(shost->host_lock, flags); return rport; } @@ -1597,30 +1779,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, } EXPORT_SYMBOL(fc_remote_port_add); -/* - * fc_rport_terminate - this routine tears down and deallocates a remote port. - * @rport: The remote port to be terminated - * - * Notes: - * This routine assumes no locks are held on entry. - */ -static void -fc_rport_terminate(struct fc_rport *rport) -{ - struct Scsi_Host *shost = rport_to_shost(rport); - struct device *dev = &rport->dev; - unsigned long flags; - - fc_rport_tgt_remove(rport); - - transport_remove_device(dev); - device_del(dev); - transport_destroy_device(dev); - spin_lock_irqsave(shost->host_lock, flags); - list_del(&rport->peers); - spin_unlock_irqrestore(shost->host_lock, flags); - put_device(&shost->shost_gendev); -} /** * fc_remote_port_delete - notifies the fc transport that a remote @@ -1675,20 +1833,39 @@ fc_rport_terminate(struct fc_rport *rport) void fc_remote_port_delete(struct fc_rport *rport) { + struct Scsi_Host *shost = rport_to_shost(rport); int timeout = rport->dev_loss_tmo; + unsigned long flags; + + /* + * No need to flush the fc_host work_q's, as all adds are synchronous. + * + * We do need to reclaim the rport scan work element, so eventually + * (in fc_rport_final_delete()) we'll flush the scsi host work_q if + * there's still a scan pending. + */ + + spin_lock_irqsave(shost->host_lock, flags); /* If no scsi target id mapping, delete it */ if (rport->scsi_target_id == -1) { - fc_rport_terminate(rport); + list_del(&rport->peers); + rport->port_state = FC_PORTSTATE_DELETED; + fc_queue_work(shost, &rport->rport_delete_work); + spin_unlock_irqrestore(shost->host_lock, flags); return; } + rport->port_state = FC_PORTSTATE_BLOCKED; + + rport->flags |= FC_RPORT_DEVLOSS_PENDING; + + spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_block(&rport->dev); /* cap the length the devices can be blocked until they are deleted */ - schedule_delayed_work(&rport->dev_loss_work, timeout * HZ); - - rport->port_state = FC_PORTSTATE_BLOCKED; + fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ); } EXPORT_SYMBOL(fc_remote_port_delete); @@ -1716,8 +1893,7 @@ void fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) { struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_host_attrs *fc_host = - (struct fc_host_attrs *)shost->shost_data; + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); unsigned long flags; int create = 0; @@ -1729,10 +1905,11 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) } else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) create = 1; } - spin_unlock_irqrestore(shost->host_lock, flags); rport->roles = roles; + spin_unlock_irqrestore(shost->host_lock, flags); + if (create) { /* * There may have been a delete timer running on the @@ -1747,10 +1924,20 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) * transaction. */ if (!cancel_delayed_work(&rport->dev_loss_work)) - flush_scheduled_work(); + fc_flush_devloss(shost); + + spin_lock_irqsave(shost->host_lock, flags); + rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; + spin_unlock_irqrestore(shost->host_lock, flags); + + /* ensure any stgt delete functions are done */ + fc_flush_work(shost); /* initiate a scan of the target */ + spin_lock_irqsave(shost->host_lock, flags); + rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); + spin_unlock_irqrestore(shost->host_lock, flags); } } EXPORT_SYMBOL(fc_remote_port_rolechg); @@ -1767,22 +1954,24 @@ fc_timeout_deleted_rport(void *data) { struct fc_rport *rport = (struct fc_rport *)data; struct Scsi_Host *shost = rport_to_shost(rport); + struct fc_host_attrs *fc_host = shost_to_fc_host(shost); unsigned long flags; spin_lock_irqsave(shost->host_lock, flags); + rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; + /* - * If the port is ONLINE, then it came back, but was no longer an - * FCP target. Thus we need to tear down the scsi_target on it. + * If the port is ONLINE, then it came back. Validate it's still an + * FCP target. If not, tear down the scsi_target on it. */ - if (rport->port_state == FC_PORTSTATE_ONLINE) { - spin_unlock_irqrestore(shost->host_lock, flags); - + if ((rport->port_state == FC_PORTSTATE_ONLINE) && + !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { dev_printk(KERN_ERR, &rport->dev, - "blocked FC remote port time out: removing target\n"); - - fc_rport_tgt_remove(rport); - + "blocked FC remote port time out: no longer" + " a FCP target, removing starget\n"); + fc_queue_work(shost, &rport->stgt_delete_work); + spin_unlock_irqrestore(shost->host_lock, flags); return; } @@ -1793,11 +1982,13 @@ fc_timeout_deleted_rport(void *data) return; } - if (fc_host_tgtid_bind_type(shost) == FC_TGTID_BIND_NONE) { - spin_unlock_irqrestore(shost->host_lock, flags); + if (fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) { + list_del(&rport->peers); + rport->port_state = FC_PORTSTATE_DELETED; dev_printk(KERN_ERR, &rport->dev, "blocked FC remote port time out: removing target\n"); - fc_rport_terminate(rport); + fc_queue_work(shost, &rport->rport_delete_work); + spin_unlock_irqrestore(shost->host_lock, flags); return; } @@ -1805,7 +1996,7 @@ fc_timeout_deleted_rport(void *data) "blocked FC remote port time out: removing target and " "saving binding\n"); - list_move_tail(&rport->peers, &fc_host_rport_bindings(shost)); + list_move_tail(&rport->peers, &fc_host->rport_bindings); /* * Note: We do not remove or clear the hostdata area. This allows @@ -1819,10 +2010,10 @@ fc_timeout_deleted_rport(void *data) rport->maxframe_size = -1; rport->supported_classes = FC_COS_UNSPECIFIED; rport->roles = FC_RPORT_ROLE_UNKNOWN; - rport->port_state = FC_PORTSTATE_DELETED; + rport->port_state = FC_PORTSTATE_NOTPRESENT; /* remove the identifiers that aren't used in the consisting binding */ - switch (fc_host_tgtid_bind_type(shost)) { + switch (fc_host->tgtid_bind_type) { case FC_TGTID_BIND_BY_WWPN: rport->node_name = -1; rport->port_id = -1; @@ -1843,17 +2034,8 @@ fc_timeout_deleted_rport(void *data) * As this only occurs if the remote port (scsi target) * went away and didn't come back - we'll remove * all attached scsi devices. - * - * We'll schedule the shost work item to perform the actual removal - * to avoid recursion in the different flush calls if we perform - * the removal in each target - and there are lots of targets - * whose timeouts fire at the same time. */ - - if ( !(fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED)) { - fc_host_flags(shost) |= FC_SHOST_RPORT_DEL_SCHEDULED; - scsi_queue_work(shost, &fc_host_rport_del_work(shost)); - } + fc_queue_work(shost, &rport->stgt_delete_work); spin_unlock_irqrestore(shost->host_lock, flags); } @@ -1870,44 +2052,18 @@ static void fc_scsi_scan_rport(void *data) { struct fc_rport *rport = (struct fc_rport *)data; - - scsi_target_unblock(&rport->dev); - scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id, - SCAN_WILD_CARD, 1); -} - - -/** - * fc_shost_remove_rports - called to remove all rports that are marked - * as in a deleted (not connected) state. - * - * @data: shost whose rports are to be looked at - **/ -static void -fc_shost_remove_rports(void *data) -{ - struct Scsi_Host *shost = (struct Scsi_Host *)data; - struct fc_rport *rport, *next_rport; + struct Scsi_Host *shost = rport_to_shost(rport); unsigned long flags; - spin_lock_irqsave(shost->host_lock, flags); - while (fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED) { - - fc_host_flags(shost) &= ~FC_SHOST_RPORT_DEL_SCHEDULED; - -restart_search: - list_for_each_entry_safe(rport, next_rport, - &fc_host_rport_bindings(shost), peers) { - if (rport->port_state == FC_PORTSTATE_DELETED) { - rport->port_state = FC_PORTSTATE_NOTPRESENT; - spin_unlock_irqrestore(shost->host_lock, flags); - fc_rport_tgt_remove(rport); - spin_lock_irqsave(shost->host_lock, flags); - goto restart_search; - } - } - + if ((rport->port_state == FC_PORTSTATE_ONLINE) && + (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { + scsi_target_unblock(&rport->dev); + scsi_scan_target(&rport->dev, rport->channel, + rport->scsi_target_id, SCAN_WILD_CARD, 1); } + + spin_lock_irqsave(shost->host_lock, flags); + rport->flags &= ~FC_RPORT_SCAN_PENDING; spin_unlock_irqrestore(shost->host_lock, flags); } diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 134c44c8538a..8b6d65e21bae 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -35,40 +35,7 @@ #include #include - -#define SAS_HOST_ATTRS 0 -#define SAS_PORT_ATTRS 17 -#define SAS_RPORT_ATTRS 7 -#define SAS_END_DEV_ATTRS 3 -#define SAS_EXPANDER_ATTRS 7 - -struct sas_internal { - struct scsi_transport_template t; - struct sas_function_template *f; - - struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; - struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; - struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; - struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS]; - struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS]; - - struct transport_container phy_attr_cont; - struct transport_container rphy_attr_cont; - struct transport_container end_dev_attr_cont; - struct transport_container expander_attr_cont; - - /* - * The array of null terminated pointers to attributes - * needed by scsi_sysfs.c - */ - struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; - struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; - struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; - struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1]; - struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1]; -}; -#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t) - +#include "scsi_sas_internal.h" struct sas_host_attrs { struct list_head rphy_list; struct mutex lock; @@ -406,8 +373,6 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number) if (!phy) return NULL; - get_device(parent); - phy->number = number; device_initialize(&phy->dev); @@ -459,10 +424,7 @@ EXPORT_SYMBOL(sas_phy_add); void sas_phy_free(struct sas_phy *phy) { transport_destroy_device(&phy->dev); - put_device(phy->dev.parent); - put_device(phy->dev.parent); - put_device(phy->dev.parent); - kfree(phy); + put_device(&phy->dev); } EXPORT_SYMBOL(sas_phy_free); @@ -484,7 +446,7 @@ sas_phy_delete(struct sas_phy *phy) transport_remove_device(dev); device_del(dev); transport_destroy_device(dev); - put_device(dev->parent); + put_device(dev); } EXPORT_SYMBOL(sas_phy_delete); @@ -800,7 +762,6 @@ struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); if (!rdev) { - put_device(&parent->dev); return NULL; } @@ -836,7 +797,6 @@ struct sas_rphy *sas_expander_alloc(struct sas_phy *parent, rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); if (!rdev) { - put_device(&parent->dev); return NULL; } @@ -885,6 +845,8 @@ int sas_rphy_add(struct sas_rphy *rphy) (identify->target_port_protocols & (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) rphy->scsi_target_id = sas_host->next_target_id++; + else if (identify->device_type == SAS_END_DEVICE) + rphy->scsi_target_id = -1; mutex_unlock(&sas_host->lock); if (identify->device_type == SAS_END_DEVICE && @@ -910,6 +872,7 @@ EXPORT_SYMBOL(sas_rphy_add); */ void sas_rphy_free(struct sas_rphy *rphy) { + struct device *dev = &rphy->dev; struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); @@ -917,21 +880,9 @@ void sas_rphy_free(struct sas_rphy *rphy) list_del(&rphy->list); mutex_unlock(&sas_host->lock); - transport_destroy_device(&rphy->dev); - put_device(rphy->dev.parent); - put_device(rphy->dev.parent); - put_device(rphy->dev.parent); - if (rphy->identify.device_type == SAS_END_DEVICE) { - struct sas_end_device *edev = rphy_to_end_device(rphy); + transport_destroy_device(dev); - kfree(edev); - } else { - /* must be expander */ - struct sas_expander_device *edev = - rphy_to_expander_device(rphy); - - kfree(edev); - } + put_device(dev); } EXPORT_SYMBOL(sas_rphy_free); @@ -971,7 +922,7 @@ sas_rphy_delete(struct sas_rphy *rphy) parent->rphy = NULL; - put_device(&parent->dev); + put_device(dev); } EXPORT_SYMBOL(sas_rphy_delete); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 7405d0df95db..b098942445ec 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -748,6 +748,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, /* * most likely out of mem, but could also be a bad map */ + sg_finish_rem_req(srp); return -ENOMEM; } else return 0; @@ -1044,7 +1045,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (!sg_allow_access(opcode, sdp->device->type)) return -EPERM; } - return scsi_ioctl_send_command(sdp->device, p); + return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p); case SG_SET_DEBUG: result = get_user(val, ip); if (result) @@ -1798,8 +1799,10 @@ sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len) res = st_map_user_pages(schp->buffer, mx_sc_elems, (unsigned long)hp->dxferp, dxfer_len, (SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0); - if (res <= 0) + if (res <= 0) { + sg_remove_scat(schp); return 1; + } schp->k_use_sg = res; schp->dio_in_use = 1; hp->info |= SG_INFO_DIRECT_IO; diff --git a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h index 3659dd7b9d76..defccc477d1e 100644 --- a/drivers/scsi/sym53c8xx_2/sym_defs.h +++ b/drivers/scsi/sym53c8xx_2/sym_defs.h @@ -40,7 +40,7 @@ #ifndef SYM_DEFS_H #define SYM_DEFS_H -#define SYM_VERSION "2.2.2" +#define SYM_VERSION "2.2.3" #define SYM_DRIVER_NAME "sym-" SYM_VERSION /* diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 1fffd2b3c654..9c83b4d39a26 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -134,66 +134,17 @@ static void sym2_setup_params(void) } } -/* - * We used to try to deal with 64-bit BARs here, but don't any more. - * There are many parts of this driver which would need to be modified - * to handle a 64-bit base address, including scripts. I'm uncomfortable - * with making those changes when I have no way of testing it, so I'm - * just going to disable it. - * - * Note that some machines (eg HP rx8620 and Superdome) have bus addresses - * below 4GB and physical addresses above 4GB. These will continue to work. - */ -static int __devinit -pci_get_base_address(struct pci_dev *pdev, int index, unsigned long *basep) -{ - u32 tmp; - unsigned long base; -#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2)) - - pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp); - base = tmp; - if ((tmp & 0x7) == PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp); - if (tmp > 0) { - dev_err(&pdev->dev, - "BAR %d is 64-bit, disabling\n", index - 1); - base = 0; - } - } - - if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { - base &= PCI_BASE_ADDRESS_IO_MASK; - } else { - base &= PCI_BASE_ADDRESS_MEM_MASK; - } - - *basep = base; - return index; -#undef PCI_BAR_OFFSET -} - static struct scsi_transport_template *sym2_transport_template = NULL; -/* - * Used by the eh thread to wait for command completion. - * It is allocated on the eh thread stack. - */ -struct sym_eh_wait { - struct completion done; - struct timer_list timer; - void (*old_done)(struct scsi_cmnd *); - int to_do; - int timed_out; -}; - /* * Driver private area in the SCSI command structure. */ struct sym_ucmd { /* Override the SCSI pointer structure */ - dma_addr_t data_mapping; - u_char data_mapped; - struct sym_eh_wait *eh_wait; + dma_addr_t data_mapping; + unsigned char data_mapped; + unsigned char to_do; /* For error handling */ + void (*old_done)(struct scsi_cmnd *); /* For error handling */ + struct completion *eh_done; /* For error handling */ }; #define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp)) @@ -514,8 +465,6 @@ static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *cmd, struc */ int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) { - struct sym_tcb *tp = &np->target[cp->target]; - struct sym_lcb *lp = sym_lp(tp, cp->lun); u32 lastp, goalp; int dir; @@ -596,7 +545,7 @@ int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct s /* * activate this job. */ - sym_start_next_ccbs(np, lp, 2); + sym_put_start_queue(np, cp); return 0; out_abort: @@ -751,44 +700,22 @@ static void sym53c8xx_timer(unsigned long npref) * What we will do regarding the involved SCSI command. */ #define SYM_EH_DO_IGNORE 0 -#define SYM_EH_DO_COMPLETE 1 #define SYM_EH_DO_WAIT 2 /* - * Our general completion handler. + * scsi_done() alias when error recovery is in progress. */ -static void __sym_eh_done(struct scsi_cmnd *cmd, int timed_out) +static void sym_eh_done(struct scsi_cmnd *cmd) { - struct sym_eh_wait *ep = SYM_UCMD_PTR(cmd)->eh_wait; - if (!ep) - return; + struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd); + BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd)); - /* Try to avoid a race here (not 100% safe) */ - if (!timed_out) { - ep->timed_out = 0; - if (ep->to_do == SYM_EH_DO_WAIT && !del_timer(&ep->timer)) - return; - } + cmd->scsi_done = ucmd->old_done; - /* Revert everything */ - SYM_UCMD_PTR(cmd)->eh_wait = NULL; - cmd->scsi_done = ep->old_done; - - /* Wake up the eh thread if it wants to sleep */ - if (ep->to_do == SYM_EH_DO_WAIT) - complete(&ep->done); + if (ucmd->to_do == SYM_EH_DO_WAIT) + complete(ucmd->eh_done); } -/* - * scsi_done() alias when error recovery is in progress. - */ -static void sym_eh_done(struct scsi_cmnd *cmd) { __sym_eh_done(cmd, 0); } - -/* - * Some timeout handler to avoid waiting too long. - */ -static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); } - /* * Generic method for our eh processing. * The 'op' argument tells what we have to do. @@ -796,35 +723,31 @@ static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) { struct sym_hcb *np = SYM_SOFTC_PTR(cmd); + struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd); + struct Scsi_Host *host = cmd->device->host; SYM_QUEHEAD *qp; int to_do = SYM_EH_DO_IGNORE; int sts = -1; - struct sym_eh_wait eh, *ep = &eh; + struct completion eh_done; dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname); + spin_lock_irq(host->host_lock); /* This one is queued in some place -> to wait for completion */ FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); if (cp->cmd == cmd) { to_do = SYM_EH_DO_WAIT; - goto prepare; + break; } } -prepare: - /* Prepare stuff to either ignore, complete or wait for completion */ - switch(to_do) { - default: - case SYM_EH_DO_IGNORE: - break; - case SYM_EH_DO_WAIT: - init_completion(&ep->done); - /* fall through */ - case SYM_EH_DO_COMPLETE: - ep->old_done = cmd->scsi_done; + if (to_do == SYM_EH_DO_WAIT) { + init_completion(&eh_done); + ucmd->old_done = cmd->scsi_done; + ucmd->eh_done = &eh_done; + wmb(); cmd->scsi_done = sym_eh_done; - SYM_UCMD_PTR(cmd)->eh_wait = ep; } /* Try to proceed the operation we have been asked for */ @@ -851,29 +774,19 @@ prepare: /* On error, restore everything and cross fingers :) */ if (sts) { - SYM_UCMD_PTR(cmd)->eh_wait = NULL; - cmd->scsi_done = ep->old_done; + cmd->scsi_done = ucmd->old_done; to_do = SYM_EH_DO_IGNORE; } - ep->to_do = to_do; - /* Complete the command with locks held as required by the driver */ - if (to_do == SYM_EH_DO_COMPLETE) - sym_xpt_done2(np, cmd, DID_ABORT); + ucmd->to_do = to_do; + spin_unlock_irq(host->host_lock); - /* Wait for completion with locks released, as required by kernel */ if (to_do == SYM_EH_DO_WAIT) { - init_timer(&ep->timer); - ep->timer.expires = jiffies + (5*HZ); - ep->timer.function = sym_eh_timeout; - ep->timer.data = (u_long)cmd; - ep->timed_out = 1; /* Be pessimistic for once :) */ - add_timer(&ep->timer); - spin_unlock_irq(np->s.host->host_lock); - wait_for_completion(&ep->done); - spin_lock_irq(np->s.host->host_lock); - if (ep->timed_out) + if (!wait_for_completion_timeout(&eh_done, 5*HZ)) { + ucmd->to_do = SYM_EH_DO_IGNORE; + wmb(); sts = -2; + } } dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); @@ -886,46 +799,22 @@ prepare: */ static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd) { - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; + return sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd); } static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd) { - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; + return sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd); } static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd) { - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; + return sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd); } static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd) { - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; + return sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd); } /* @@ -944,15 +833,12 @@ static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags) if (reqtags > lp->s.scdev_depth) reqtags = lp->s.scdev_depth; - lp->started_limit = reqtags ? reqtags : 2; - lp->started_max = 1; lp->s.reqtags = reqtags; if (reqtags != oldtags) { dev_info(&tp->starget->dev, "tagged command queuing %s, command queue depth %d.\n", - lp->s.reqtags ? "enabled" : "disabled", - lp->started_limit); + lp->s.reqtags ? "enabled" : "disabled", reqtags); } } @@ -1866,15 +1752,25 @@ static int __devinit sym_set_workarounds(struct sym_device *device) static void __devinit sym_init_device(struct pci_dev *pdev, struct sym_device *device) { - int i; + int i = 2; + struct pci_bus_region bus_addr; device->host_id = SYM_SETUP_HOST_ID; device->pdev = pdev; - i = pci_get_base_address(pdev, 1, &device->mmio_base); - pci_get_base_address(pdev, i, &device->ram_base); + pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]); + device->mmio_base = bus_addr.start; -#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED + /* + * If the BAR is 64-bit, resource 2 will be occupied by the + * upper 32 bits + */ + if (!pdev->resource[i].flags) + i++; + pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]); + device->ram_base = bus_addr.start; + +#ifdef CONFIG_SCSI_SYM53C8XX_MMIO if (device->mmio_base) device->s.ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1)); @@ -1978,7 +1874,8 @@ static struct scsi_host_template sym2_template = { .eh_bus_reset_handler = sym53c8xx_eh_bus_reset_handler, .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, .this_id = 7, - .use_clustering = DISABLE_CLUSTERING, + .use_clustering = ENABLE_CLUSTERING, + .max_sectors = 0xFFFF, #ifdef SYM_LINUX_PROC_INFO_SUPPORT .proc_info = sym53c8xx_proc_info, .proc_name = NAME53C8XX, diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h index cc92d0c70cd7..a446cda3f64c 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.h +++ b/drivers/scsi/sym53c8xx_2/sym_glue.h @@ -68,7 +68,7 @@ */ #define SYM_CONF_TIMER_INTERVAL ((HZ+1)/2) -#define SYM_OPT_HANDLE_DEVICE_QUEUEING +#undef SYM_OPT_HANDLE_DEVICE_QUEUEING #define SYM_OPT_LIMIT_COMMAND_REORDERING /* diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 60850cbe3a85..a671bdc07450 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -72,7 +72,10 @@ static void sym_printl_hex(u_char *p, int n) static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg) { - sym_print_addr(cp->cmd, "%s: ", label); + if (label) + sym_print_addr(cp->cmd, "%s: ", label); + else + sym_print_addr(cp->cmd, ""); spi_print_msg(msg); printf("\n"); @@ -472,7 +475,7 @@ static int sym_getpciclock (struct sym_hcb *np) * calculations more simple. */ #define _5M 5000000 -static u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; +static const u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; /* * Get clock factor and sync divisor for a given @@ -644,6 +647,37 @@ static void sym_save_initial_setting (struct sym_hcb *np) np->sv_ctest5 = INB(np, nc_ctest5) & 0x24; } +/* + * Set SCSI BUS mode. + * - LVD capable chips (895/895A/896/1010) report the current BUS mode + * through the STEST4 IO register. + * - For previous generation chips (825/825A/875), the user has to tell us + * how to check against HVD, since a 100% safe algorithm is not possible. + */ +static void sym_set_bus_mode(struct sym_hcb *np, struct sym_nvram *nvram) +{ + if (np->scsi_mode) + return; + + np->scsi_mode = SMODE_SE; + if (np->features & (FE_ULTRA2|FE_ULTRA3)) + np->scsi_mode = (np->sv_stest4 & SMODE); + else if (np->features & FE_DIFF) { + if (SYM_SETUP_SCSI_DIFF == 1) { + if (np->sv_scntl3) { + if (np->sv_stest2 & 0x20) + np->scsi_mode = SMODE_HVD; + } else if (nvram->type == SYM_SYMBIOS_NVRAM) { + if (!(INB(np, nc_gpreg) & 0x08)) + np->scsi_mode = SMODE_HVD; + } + } else if (SYM_SETUP_SCSI_DIFF == 2) + np->scsi_mode = SMODE_HVD; + } + if (np->scsi_mode == SMODE_HVD) + np->rv_stest2 |= 0x20; +} + /* * Prepare io register values used by sym_start_up() * according to selected and supported features. @@ -654,10 +688,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru u32 period; int i; - /* - * Wide ? - */ - np->maxwide = (np->features & FE_WIDE)? 1 : 0; + np->maxwide = (np->features & FE_WIDE) ? 1 : 0; /* * Guess the frequency of the chip's clock. @@ -838,6 +869,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru * Get parity checking, host ID and verbose mode from NVRAM */ np->myaddr = 255; + np->scsi_mode = 0; sym_nvram_setup_host(shost, np, nvram); /* @@ -854,33 +886,7 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru */ sym_init_burst(np, burst_max); - /* - * Set SCSI BUS mode. - * - LVD capable chips (895/895A/896/1010) report the - * current BUS mode through the STEST4 IO register. - * - For previous generation chips (825/825A/875), - * user has to tell us how to check against HVD, - * since a 100% safe algorithm is not possible. - */ - np->scsi_mode = SMODE_SE; - if (np->features & (FE_ULTRA2|FE_ULTRA3)) - np->scsi_mode = (np->sv_stest4 & SMODE); - else if (np->features & FE_DIFF) { - if (SYM_SETUP_SCSI_DIFF == 1) { - if (np->sv_scntl3) { - if (np->sv_stest2 & 0x20) - np->scsi_mode = SMODE_HVD; - } - else if (nvram->type == SYM_SYMBIOS_NVRAM) { - if (!(INB(np, nc_gpreg) & 0x08)) - np->scsi_mode = SMODE_HVD; - } - } - else if (SYM_SETUP_SCSI_DIFF == 2) - np->scsi_mode = SMODE_HVD; - } - if (np->scsi_mode == SMODE_HVD) - np->rv_stest2 |= 0x20; + sym_set_bus_mode(np, nvram); /* * Set LED support from SCRIPTS. @@ -973,8 +979,8 @@ static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, stru * * Has to be called with interrupts disabled. */ -#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED -static int sym_regtest (struct sym_hcb *np) +#ifdef CONFIG_SCSI_SYM53C8XX_MMIO +static int sym_regtest(struct sym_hcb *np) { register volatile u32 data; /* @@ -992,20 +998,25 @@ static int sym_regtest (struct sym_hcb *np) #endif printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", (unsigned) data); - return (0x10); + return 0x10; } - return (0); + return 0; +} +#else +static inline int sym_regtest(struct sym_hcb *np) +{ + return 0; } #endif -static int sym_snooptest (struct sym_hcb *np) +static int sym_snooptest(struct sym_hcb *np) { - u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat; - int i, err=0; -#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED - err |= sym_regtest (np); - if (err) return (err); -#endif + u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat; + int i, err; + + err = sym_regtest(np); + if (err) + return err; restart_test: /* * Enable Master Parity Checking as we intend @@ -1094,7 +1105,7 @@ restart_test: err |= 4; } - return (err); + return err; } /* @@ -1464,7 +1475,7 @@ static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgp /* * Insert a job into the start queue. */ -static void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp) +void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp) { u_short qidx; @@ -4481,7 +4492,7 @@ static void sym_int_sir (struct sym_hcb *np) switch (np->msgin [2]) { case M_X_MODIFY_DP: if (DEBUG_FLAGS & DEBUG_POINTER) - sym_print_msg(cp,"modify DP",np->msgin); + sym_print_msg(cp, NULL, np->msgin); tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + (np->msgin[5]<<8) + (np->msgin[6]); sym_modify_dp(np, tp, cp, tmp); @@ -4508,7 +4519,7 @@ static void sym_int_sir (struct sym_hcb *np) */ case M_IGN_RESIDUE: if (DEBUG_FLAGS & DEBUG_POINTER) - sym_print_msg(cp,"ign wide residue", np->msgin); + sym_print_msg(cp, NULL, np->msgin); if (cp->host_flags & HF_SENSE) OUTL_DSP(np, SCRIPTA_BA(np, clrack)); else @@ -4597,7 +4608,8 @@ struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char t * Debugging purpose. */ #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - assert(lp->busy_itl == 0); + if (lp->busy_itl != 0) + goto out_free; #endif /* * Allocate resources for tags if not yet. @@ -4642,7 +4654,8 @@ struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char t * Debugging purpose. */ #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - assert(lp->busy_itl == 0 && lp->busy_itlq == 0); + if (lp->busy_itl != 0 || lp->busy_itlq != 0) + goto out_free; #endif /* * Count this nexus for this LUN. diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h index 2456090bb241..79ab6a177039 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h @@ -1049,6 +1049,8 @@ int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int); struct sym_chip *sym_lookup_chip_table(u_short device_id, u_char revision); #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn); +#else +void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp); #endif void sym_start_up(struct sym_hcb *np, int reason); void sym_interrupt(struct sym_hcb *np); diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index b131432c677d..a6cfbb3b361c 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -88,7 +88,7 @@ zalon_probe(struct parisc_device *dev) struct gsc_irq gsc_irq; u32 zalon_vers; int error = -ENODEV; - void __iomem *zalon = ioremap(dev->hpa.start, 4096); + void __iomem *zalon = ioremap_nocache(dev->hpa.start, 4096); void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET; static int unit = 0; struct Scsi_Host *host; diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index 8b4947933d9b..913c71cc0569 100644 --- a/drivers/serial/8250_gsc.c +++ b/drivers/serial/8250_gsc.c @@ -52,13 +52,14 @@ serial_init_chip(struct parisc_device *dev) address += 0x800; } - memset(&port, 0, sizeof(struct uart_port)); - port.mapbase = address; - port.irq = dev->irq; - port.iotype = UPIO_MEM; - port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF; - port.uartclk = LASI_BASE_BAUD * 16; - port.dev = &dev->dev; + memset(&port, 0, sizeof(port)); + port.iotype = UPIO_MEM; + port.uartclk = LASI_BASE_BAUD * 16; + port.mapbase = address; + port.membase = ioremap_nocache(address, 16); + port.irq = dev->irq; + port.flags = UPF_BOOT_AUTOCONF; + port.dev = &dev->dev; err = serial8250_register_port(&port); if (err < 0) { diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index fe0d8b8e91c8..7d22dc0478d3 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -63,6 +63,33 @@ config SERIAL_8250_CONSOLE If unsure, say N. +config SERIAL_8250_GSC + tristate + depends on SERIAL_8250 && GSC + default SERIAL_8250 + +config SERIAL_8250_PCI + tristate "8250/16550 PCI device support" if EMBEDDED + depends on SERIAL_8250 && PCI + default SERIAL_8250 + help + This builds standard PCI serial support. You may be able to + disable this feature if you only need legacy serial support. + Saves about 9K. + +config SERIAL_8250_PNP + tristate "8250/16550 PNP device support" if EMBEDDED + depends on SERIAL_8250 && PNP + default SERIAL_8250 + help + This builds standard PNP serial support. You may be able to + disable this feature if you only need legacy serial support. + +config SERIAL_8250_HP300 + tristate + depends on SERIAL_8250 && HP300 + default SERIAL_8250 + config SERIAL_8250_CS tristate "8250/16550 PCMCIA device support" depends on PCMCIA && SERIAL_8250 diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index d2b4c214876b..0a71bf68a03f 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -4,15 +4,13 @@ # $Id: Makefile,v 1.8 2002/07/21 21:32:30 rmk Exp $ # -serial-8250-y := -serial-8250-$(CONFIG_PNP) += 8250_pnp.o -serial-8250-$(CONFIG_GSC) += 8250_gsc.o -serial-8250-$(CONFIG_PCI) += 8250_pci.o -serial-8250-$(CONFIG_HP300) += 8250_hp300.o - obj-$(CONFIG_SERIAL_CORE) += serial_core.o obj-$(CONFIG_SERIAL_21285) += 21285.o -obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y) +obj-$(CONFIG_SERIAL_8250) += 8250.o +obj-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o +obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o +obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o +obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h index dfc1e86d3aa1..043f50b1d10c 100644 --- a/drivers/serial/jsm/jsm.h +++ b/drivers/serial/jsm/jsm.h @@ -20,7 +20,7 @@ * * Contact Information: * Scott H Kilau - * Wendy Xiong + * Wendy Xiong * ***********************************************************************/ diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c index b1b66e71d281..b3e1f71be4da 100644 --- a/drivers/serial/jsm/jsm_driver.c +++ b/drivers/serial/jsm/jsm_driver.c @@ -20,7 +20,7 @@ * * Contact Information: * Scott H Kilau - * Wendy Xiong + * Wendy Xiong * * ***********************************************************************/ diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c index 87e4e2cf8ce7..a5fc589d6ef5 100644 --- a/drivers/serial/jsm/jsm_neo.c +++ b/drivers/serial/jsm/jsm_neo.c @@ -20,7 +20,7 @@ * * Contact Information: * Scott H Kilau - * Wendy Xiong + * Wendy Xiong * ***********************************************************************/ #include /* For udelay */ diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c index 4d48b625cd3d..7d823705193c 100644 --- a/drivers/serial/jsm/jsm_tty.c +++ b/drivers/serial/jsm/jsm_tty.c @@ -142,12 +142,14 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch) { unsigned long lock_flags; struct jsm_channel *channel = (struct jsm_channel *)port; + struct termios *termios; spin_lock_irqsave(&port->lock, lock_flags); - if (ch == port->info->tty->termios->c_cc[VSTART]) + termios = port->info->tty->termios; + if (ch == termios->c_cc[VSTART]) channel->ch_bd->bd_ops->send_start_character(channel); - if (ch == port->info->tty->termios->c_cc[VSTOP]) + if (ch == termios->c_cc[VSTOP]) channel->ch_bd->bd_ops->send_stop_character(channel); spin_unlock_irqrestore(&port->lock, lock_flags); } @@ -178,6 +180,7 @@ static int jsm_tty_open(struct uart_port *port) struct jsm_board *brd; int rc = 0; struct jsm_channel *channel = (struct jsm_channel *)port; + struct termios *termios; /* Get board pointer from our array of majors we have allocated */ brd = channel->ch_bd; @@ -239,12 +242,13 @@ static int jsm_tty_open(struct uart_port *port) channel->ch_cached_lsr = 0; channel->ch_stops_sent = 0; - channel->ch_c_cflag = port->info->tty->termios->c_cflag; - channel->ch_c_iflag = port->info->tty->termios->c_iflag; - channel->ch_c_oflag = port->info->tty->termios->c_oflag; - channel->ch_c_lflag = port->info->tty->termios->c_lflag; - channel->ch_startc = port->info->tty->termios->c_cc[VSTART]; - channel->ch_stopc = port->info->tty->termios->c_cc[VSTOP]; + termios = port->info->tty->termios; + channel->ch_c_cflag = termios->c_cflag; + channel->ch_c_iflag = termios->c_iflag; + channel->ch_c_oflag = termios->c_oflag; + channel->ch_c_lflag = termios->c_lflag; + channel->ch_startc = termios->c_cc[VSTART]; + channel->ch_stopc = termios->c_cc[VSTOP]; /* Tell UART to init itself */ brd->bd_ops->uart_init(channel); @@ -784,6 +788,7 @@ static void jsm_carrier(struct jsm_channel *ch) void jsm_check_queue_flow_control(struct jsm_channel *ch) { + struct board_ops *bd_ops = ch->ch_bd->bd_ops; int qleft = 0; /* Store how much space we have left in the queue */ @@ -809,7 +814,7 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) /* HWFLOW */ if (ch->ch_c_cflag & CRTSCTS) { if(!(ch->ch_flags & CH_RECEIVER_OFF)) { - ch->ch_bd->bd_ops->disable_receiver(ch); + bd_ops->disable_receiver(ch); ch->ch_flags |= (CH_RECEIVER_OFF); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Internal queue hit hilevel mark (%d)! Turning off interrupts.\n", @@ -819,7 +824,7 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) /* SWFLOW */ else if (ch->ch_c_iflag & IXOFF) { if (ch->ch_stops_sent <= MAX_STOPS_SENT) { - ch->ch_bd->bd_ops->send_stop_character(ch); + bd_ops->send_stop_character(ch); ch->ch_stops_sent++; jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending stop char! Times sent: %x\n", ch->ch_stops_sent); @@ -846,7 +851,7 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) /* HWFLOW */ if (ch->ch_c_cflag & CRTSCTS) { if (ch->ch_flags & CH_RECEIVER_OFF) { - ch->ch_bd->bd_ops->enable_receiver(ch); + bd_ops->enable_receiver(ch); ch->ch_flags &= ~(CH_RECEIVER_OFF); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Internal queue hit lowlevel mark (%d)! Turning on interrupts.\n", @@ -856,7 +861,7 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) /* SWFLOW */ else if (ch->ch_c_iflag & IXOFF && ch->ch_stops_sent) { ch->ch_stops_sent = 0; - ch->ch_bd->bd_ops->send_start_character(ch); + bd_ops->send_start_character(ch); jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "Sending start char!\n"); } } diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index 868eaf4a1a68..64c0e89124c9 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -51,7 +51,7 @@ #define MUX_BREAK(status) ((status & 0xF000) == 0x2000) #define MUX_NR 256 -static unsigned int port_cnt = 0; +static unsigned int port_cnt __read_mostly; static struct uart_port mux_ports[MUX_NR]; static struct uart_driver mux_driver = { @@ -461,7 +461,7 @@ static int __init mux_probe(struct parisc_device *dev) port->iobase = 0; port->mapbase = dev->hpa.start + MUX_OFFSET + (i * MUX_LINE_OFFSET); - port->membase = ioremap(port->mapbase, MUX_LINE_OFFSET); + port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET); port->iotype = UPIO_MEM; port->type = PORT_MUX; port->irq = NO_IRQ; diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index c30333694fde..2c70773543e0 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -97,11 +98,13 @@ static const struct multi_id multi_id[] = { #define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id)) struct serial_info { - dev_link_t link; + struct pcmcia_device *p_dev; int ndev; int multi; int slave; int manfid; + int prodid; + int c950ctrl; dev_node_t node[4]; int line[4]; }; @@ -113,9 +116,36 @@ struct serial_cfg_mem { }; -static void serial_config(dev_link_t * link); +static int serial_config(struct pcmcia_device * link); +static void wakeup_card(struct serial_info *info) +{ + int ctrl = info->c950ctrl; + + if (info->manfid == MANFID_OXSEMI) { + outb(12, ctrl + 1); + } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) { + /* request_region? oxsemi branch does no request_region too... */ + /* This sequence is needed to properly initialize MC45 attached to OXCF950. + * I tried decreasing these msleep()s, but it worked properly (survived + * 1000 stop/start operations) with these timeouts (or bigger). */ + outb(0xA, ctrl + 1); + msleep(100); + outb(0xE, ctrl + 1); + msleep(300); + outb(0xC, ctrl + 1); + msleep(100); + outb(0xE, ctrl + 1); + msleep(200); + outb(0xF, ctrl + 1); + msleep(100); + outb(0xE, ctrl + 1); + msleep(100); + outb(0xC, ctrl + 1); + } +} + /*====================================================================== After a card is removed, serial_remove() will unregister @@ -123,67 +153,45 @@ static void serial_config(dev_link_t * link); ======================================================================*/ -static void serial_remove(dev_link_t *link) +static void serial_remove(struct pcmcia_device *link) { struct serial_info *info = link->priv; int i; - link->state &= ~DEV_PRESENT; - DEBUG(0, "serial_release(0x%p)\n", link); /* * Recheck to see if the device is still configured. */ - if (info->link.state & DEV_CONFIG) { - for (i = 0; i < info->ndev; i++) - serial8250_unregister_port(info->line[i]); + for (i = 0; i < info->ndev; i++) + serial8250_unregister_port(info->line[i]); - info->link.dev = NULL; + info->p_dev->dev_node = NULL; - if (!info->slave) { - pcmcia_release_configuration(info->link.handle); - pcmcia_release_io(info->link.handle, &info->link.io); - pcmcia_release_irq(info->link.handle, &info->link.irq); - } - - info->link.state &= ~DEV_CONFIG; - } + if (!info->slave) + pcmcia_disable_device(link); } -static int serial_suspend(struct pcmcia_device *dev) +static int serial_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); - link->state |= DEV_SUSPEND; + struct serial_info *info = link->priv; + int i; - if (link->state & DEV_CONFIG) { - struct serial_info *info = link->priv; - int i; - - for (i = 0; i < info->ndev; i++) - serial8250_suspend_port(info->line[i]); - - if (!info->slave) - pcmcia_release_configuration(link->handle); - } + for (i = 0; i < info->ndev; i++) + serial8250_suspend_port(info->line[i]); return 0; } -static int serial_resume(struct pcmcia_device *dev) +static int serial_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(dev); - link->state &= ~DEV_SUSPEND; - - if (DEV_OK(link)) { + if (pcmcia_dev_present(link)) { struct serial_info *info = link->priv; int i; - if (!info->slave) - pcmcia_request_configuration(link->handle, &link->conf); - for (i = 0; i < info->ndev; i++) serial8250_resume_port(info->line[i]); + wakeup_card(info); } return 0; @@ -197,10 +205,9 @@ static int serial_resume(struct pcmcia_device *dev) ======================================================================*/ -static int serial_probe(struct pcmcia_device *p_dev) +static int serial_probe(struct pcmcia_device *link) { struct serial_info *info; - dev_link_t *link; DEBUG(0, "serial_attach()\n"); @@ -209,7 +216,7 @@ static int serial_probe(struct pcmcia_device *p_dev) if (!info) return -ENOMEM; memset(info, 0, sizeof (*info)); - link = &info->link; + info->p_dev = link; link->priv = info; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; @@ -223,12 +230,7 @@ static int serial_probe(struct pcmcia_device *p_dev) } link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - serial_config(link); - - return 0; + return serial_config(link); } /*====================================================================== @@ -240,9 +242,8 @@ static int serial_probe(struct pcmcia_device *p_dev) ======================================================================*/ -static void serial_detach(struct pcmcia_device *p_dev) +static void serial_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct serial_info *info = link->priv; DEBUG(0, "serial_detach(0x%p)\n", link); @@ -263,7 +264,7 @@ static void serial_detach(struct pcmcia_device *p_dev) /*====================================================================*/ -static int setup_serial(client_handle_t handle, struct serial_info * info, +static int setup_serial(struct pcmcia_device *handle, struct serial_info * info, kio_addr_t iobase, int irq) { struct uart_port port; @@ -298,7 +299,7 @@ static int setup_serial(client_handle_t handle, struct serial_info * info, /*====================================================================*/ static int -first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) +first_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) { int i; i = pcmcia_get_first_tuple(handle, tuple); @@ -311,7 +312,7 @@ first_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) } static int -next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) +next_tuple(struct pcmcia_device *handle, tuple_t * tuple, cisparse_t * parse) { int i; i = pcmcia_get_next_tuple(handle, tuple); @@ -325,11 +326,10 @@ next_tuple(client_handle_t handle, tuple_t * tuple, cisparse_t * parse) /*====================================================================*/ -static int simple_config(dev_link_t *link) +static int simple_config(struct pcmcia_device *link) { static const kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; static const int size_table[2] = { 8, 16 }; - client_handle_t handle = link->handle; struct serial_info *info = link->priv; struct serial_cfg_mem *cfg_mem; tuple_t *tuple; @@ -350,7 +350,7 @@ static int simple_config(dev_link_t *link) buf = cfg_mem->buf; /* If the card is already configured, look up the port and irq */ - i = pcmcia_get_configuration_info(handle, &config); + i = pcmcia_get_configuration_info(link, &config); if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { kio_addr_t port = 0; if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { @@ -363,10 +363,9 @@ static int simple_config(dev_link_t *link) } if (info->slave) { kfree(cfg_mem); - return setup_serial(handle, info, port, config.AssignedIRQ); + return setup_serial(link, info, port, config.AssignedIRQ); } } - link->conf.Vcc = config.Vcc; /* First pass: look for a config entry that looks normal. */ tuple->TupleData = (cisdata_t *) buf; @@ -377,12 +376,12 @@ static int simple_config(dev_link_t *link) /* Two tries: without IO aliases, then with aliases */ for (s = 0; s < 2; s++) { for (try = 0; try < 2; try++) { - i = first_tuple(handle, tuple, parse); + i = first_tuple(link, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if (i != CS_SUCCESS) goto next_entry; if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[s]) && (cf->io.win[0].base != 0)) { @@ -390,19 +389,19 @@ static int simple_config(dev_link_t *link) link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } next_entry: - i = next_tuple(handle, tuple, parse); + i = next_tuple(link, tuple, parse); } } } /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ - i = first_tuple(handle, tuple, parse); + i = first_tuple(link, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { @@ -410,50 +409,48 @@ next_entry: for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; link->io.IOAddrLines = base[j] ? 16 : 3; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } } - i = next_tuple(handle, tuple, parse); + i = next_tuple(link, tuple, parse); } found_port: if (i != CS_SUCCESS) { printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); kfree(cfg_mem); return -1; } - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); + cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } if (info->multi && (info->manfid == MANFID_3COM)) link->conf.ConfigIndex &= ~(0x08); - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); + cs_error(link, RequestConfiguration, i); kfree(cfg_mem); return -1; } kfree(cfg_mem); - return setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); + return setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); } -static int multi_config(dev_link_t * link) +static int multi_config(struct pcmcia_device * link) { - client_handle_t handle = link->handle; struct serial_info *info = link->priv; struct serial_cfg_mem *cfg_mem; tuple_t *tuple; u_char *buf; cisparse_t *parse; cistpl_cftable_entry_t *cf; - config_info_t config; int i, rc, base2 = 0; cfg_mem = kmalloc(sizeof(struct serial_cfg_mem), GFP_KERNEL); @@ -464,14 +461,6 @@ static int multi_config(dev_link_t * link) cf = &parse->cftable_entry; buf = cfg_mem->buf; - i = pcmcia_get_configuration_info(handle, &config); - if (i != CS_SUCCESS) { - cs_error(handle, GetConfigurationInfo, i); - rc = -1; - goto free_cfg_mem; - } - link->conf.Vcc = config.Vcc; - tuple->TupleData = (cisdata_t *) buf; tuple->TupleOffset = 0; tuple->TupleDataMax = 255; @@ -480,7 +469,7 @@ static int multi_config(dev_link_t * link) /* First, look for a generic full-sized window */ link->io.NumPorts1 = info->multi * 8; - i = first_tuple(handle, tuple, parse); + i = first_tuple(link, tuple, parse); while (i != CS_NO_MORE_ITEMS) { /* The quad port cards have bad CIS's, so just look for a window larger than 8 ports and assume it will be right */ @@ -490,19 +479,19 @@ static int multi_config(dev_link_t * link) link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); base2 = link->io.BasePort1 + 8; if (i == CS_SUCCESS) break; } - i = next_tuple(handle, tuple, parse); + i = next_tuple(link, tuple, parse); } /* If that didn't work, look for two windows */ if (i != CS_SUCCESS) { link->io.NumPorts1 = link->io.NumPorts2 = 8; info->multi = 2; - i = first_tuple(handle, tuple, parse); + i = first_tuple(link, tuple, parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { link->conf.ConfigIndex = cf->index; @@ -510,26 +499,26 @@ static int multi_config(dev_link_t * link) link->io.BasePort2 = cf->io.win[1].base; link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = pcmcia_request_io(link->handle, &link->io); + i = pcmcia_request_io(link, &link->io); base2 = link->io.BasePort2; if (i == CS_SUCCESS) break; } - i = next_tuple(handle, tuple, parse); + i = next_tuple(link, tuple, parse); } } if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); + cs_error(link, RequestIO, i); rc = -1; goto free_cfg_mem; } - i = pcmcia_request_irq(link->handle, &link->irq); + i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); - cs_error(link->handle, RequestIRQ, i); + cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } /* Socket Dual IO: this enables irq's for second port */ @@ -537,35 +526,43 @@ static int multi_config(dev_link_t * link) link->conf.Present |= PRESENT_EXT_STATUS; link->conf.ExtStatus = ESR_REQ_ATTN_ENA; } - i = pcmcia_request_configuration(link->handle, &link->conf); + i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); + cs_error(link, RequestConfiguration, i); rc = -1; goto free_cfg_mem; } /* The Oxford Semiconductor OXCF950 cards are in fact single-port: - 8 registers are for the UART, the others are extra registers */ - if (info->manfid == MANFID_OXSEMI) { + * 8 registers are for the UART, the others are extra registers. + * Siemen's MC45 PCMCIA (Possio's GCC) is OXCF950 based too. + */ + if (info->manfid == MANFID_OXSEMI || (info->manfid == MANFID_POSSIO && + info->prodid == PRODID_POSSIO_GCC)) { + int err; + if (cf->index == 1 || cf->index == 3) { - setup_serial(handle, info, base2, link->irq.AssignedIRQ); - outb(12, link->io.BasePort1 + 1); + err = setup_serial(link, info, base2, + link->irq.AssignedIRQ); + base2 = link->io.BasePort1; } else { - setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); - outb(12, base2 + 1); + err = setup_serial(link, info, link->io.BasePort1, + link->irq.AssignedIRQ); } + info->c950ctrl = base2; + wakeup_card(info); rc = 0; goto free_cfg_mem; } - setup_serial(handle, info, link->io.BasePort1, link->irq.AssignedIRQ); + setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ); /* The Nokia cards are not really multiport cards */ if (info->manfid == MANFID_NOKIA) { rc = 0; goto free_cfg_mem; } for (i = 0; i < info->multi - 1; i++) - setup_serial(handle, info, base2 + (8 * i), + setup_serial(link, info, base2 + (8 * i), link->irq.AssignedIRQ); rc = 0; free_cfg_mem: @@ -581,9 +578,8 @@ free_cfg_mem: ======================================================================*/ -void serial_config(dev_link_t * link) +static int serial_config(struct pcmcia_device * link) { - client_handle_t handle = link->handle; struct serial_info *info = link->priv; struct serial_cfg_mem *cfg_mem; tuple_t *tuple; @@ -609,7 +605,7 @@ void serial_config(dev_link_t * link) tuple->Attributes = 0; /* Get configuration register information */ tuple->DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(handle, tuple, parse); + last_ret = first_tuple(link, tuple, parse); if (last_ret != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; @@ -617,18 +613,16 @@ void serial_config(dev_link_t * link) link->conf.ConfigBase = parse->config.base; link->conf.Present = parse->config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - /* Is this a compliant multifunction card? */ tuple->DesiredTuple = CISTPL_LONGLINK_MFC; tuple->Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; - info->multi = (first_tuple(handle, tuple, parse) == CS_SUCCESS); + info->multi = (first_tuple(link, tuple, parse) == CS_SUCCESS); /* Is this a multiport card? */ tuple->DesiredTuple = CISTPL_MANFID; - if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { + if (first_tuple(link, tuple, parse) == CS_SUCCESS) { info->manfid = parse->manfid.manf; + info->prodid = le16_to_cpu(buf[1]); for (i = 0; i < MULTI_COUNT; i++) if ((info->manfid == multi_id[i].manfid) && (parse->manfid.card == multi_id[i].prodid)) @@ -641,11 +635,11 @@ void serial_config(dev_link_t * link) multifunction cards that ask for appropriate IO port ranges */ tuple->DesiredTuple = CISTPL_FUNCID; if ((info->multi == 0) && - ((first_tuple(handle, tuple, parse) != CS_SUCCESS) || + ((first_tuple(link, tuple, parse) != CS_SUCCESS) || (parse->funcid.func == CISTPL_FUNCID_MULTI) || (parse->funcid.func == CISTPL_FUNCID_SERIAL))) { tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY; - if (first_tuple(handle, tuple, parse) == CS_SUCCESS) { + if (first_tuple(link, tuple, parse) == CS_SUCCESS) { if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) info->multi = cf->io.win[0].len >> 3; if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && @@ -664,31 +658,30 @@ void serial_config(dev_link_t * link) if (info->manfid == MANFID_IBM) { conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; - last_ret = pcmcia_access_configuration_register(link->handle, ®); + last_ret = pcmcia_access_configuration_register(link, ®); if (last_ret) { last_fn = AccessConfigurationRegister; goto cs_failed; } reg.Action = CS_WRITE; reg.Value = reg.Value | 1; - last_ret = pcmcia_access_configuration_register(link->handle, ®); + last_ret = pcmcia_access_configuration_register(link, ®); if (last_ret) { last_fn = AccessConfigurationRegister; goto cs_failed; } } - link->dev = &info->node[0]; - link->state &= ~DEV_CONFIG_PENDING; + link->dev_node = &info->node[0]; kfree(cfg_mem); - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: serial_remove(link); - link->state &= ~DEV_CONFIG_PENDING; kfree(cfg_mem); + return -ENODEV; } static struct pcmcia_device_id serial_ids[] = { @@ -739,6 +732,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77), PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302), PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301), + PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276), PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039), PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006), PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a), @@ -757,6 +751,7 @@ static struct pcmcia_device_id serial_ids[] = { PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef), PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef), PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0), + PCMCIA_DEVICE_PROD_ID123("Novatel Wireless", "Merlin UMTS Modem", "U630", 0x32607776, 0xd9e73b13, 0xe87332e), PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a), PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02), PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa), diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c index 93449a1a0065..0b49ff78efc1 100644 --- a/drivers/sn/ioc3.c +++ b/drivers/sn/ioc3.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -619,9 +620,9 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) pci_set_master(pdev); #ifdef USE_64BIT_DMA - ret = pci_set_dma_mask(pdev, 0xffffffffffffffffULL); + ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK); if (!ret) { - ret = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); + ret = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); if (ret < 0) { printk(KERN_WARNING "%s: Unable to obtain 64 bit DMA " "for consistent allocations\n", diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index d3a7b0c3d38b..dda0ca45d904 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c @@ -35,73 +35,52 @@ typedef struct ixj_info_t { } ixj_info_t; static void ixj_detach(struct pcmcia_device *p_dev); -static void ixj_config(dev_link_t * link); -static void ixj_cs_release(dev_link_t * link); +static int ixj_config(struct pcmcia_device * link); +static void ixj_cs_release(struct pcmcia_device * link); -static int ixj_attach(struct pcmcia_device *p_dev) +static int ixj_probe(struct pcmcia_device *p_dev) { - dev_link_t *link; - DEBUG(0, "ixj_attach()\n"); /* Create new ixj device */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - if (!link) - return -ENOMEM; - memset(link, 0, sizeof(struct dev_link_t)); - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; - link->io.IOAddrLines = 3; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - link->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL); - if (!link->priv) { - kfree(link); + p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + p_dev->io.IOAddrLines = 3; + p_dev->conf.IntType = INT_MEMORY_AND_IO; + p_dev->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL); + if (!p_dev->priv) { return -ENOMEM; } - memset(link->priv, 0, sizeof(struct ixj_info_t)); + memset(p_dev->priv, 0, sizeof(struct ixj_info_t)); - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - ixj_config(link); - - return 0; + return ixj_config(p_dev); } -static void ixj_detach(struct pcmcia_device *p_dev) +static void ixj_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - DEBUG(0, "ixj_detach(0x%p)\n", link); - link->state &= ~DEV_RELEASE_PENDING; - if (link->state & DEV_CONFIG) - ixj_cs_release(link); + ixj_cs_release(link); kfree(link->priv); - kfree(link); } #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void ixj_get_serial(dev_link_t * link, IXJ * j) +static void ixj_get_serial(struct pcmcia_device * link, IXJ * j) { - client_handle_t handle; tuple_t tuple; u_short buf[128]; char *str; int last_ret, last_fn, i, place; - handle = link->handle; DEBUG(0, "ixj_get_serial(0x%p)\n", link); tuple.TupleData = (cisdata_t *) buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 80; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_VERS_1; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); str = (char *) buf; printk("PCMCIA Version %d.%d\n", str[0], str[1]); str += 2; @@ -149,22 +128,19 @@ static void ixj_get_serial(dev_link_t * link, IXJ * j) return; } -static void ixj_config(dev_link_t * link) +static int ixj_config(struct pcmcia_device * link) { IXJ *j; - client_handle_t handle; ixj_info_t *info; tuple_t tuple; u_short buf[128]; cisparse_t parse; - config_info_t conf; cistpl_cftable_entry_t *cfg = &parse.cftable_entry; cistpl_cftable_entry_t dflt = { 0 }; int last_ret, last_fn; - handle = link->handle; info = link->priv; DEBUG(0, "ixj_config(0x%p)\n", link); tuple.TupleData = (cisdata_t *) buf; @@ -172,19 +148,17 @@ static void ixj_config(dev_link_t * link) tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - link->state |= DEV_CONFIG; - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0) + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; @@ -195,7 +169,7 @@ static void ixj_config(dev_link_t * link) link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; /* If we've got this far, we're done */ break; @@ -203,10 +177,10 @@ static void ixj_config(dev_link_t * link) next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; - CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple)); + CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple)); } - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); /* * Register the card with the core. @@ -215,46 +189,21 @@ static void ixj_config(dev_link_t * link) info->ndev = 1; info->node.major = PHONE_MAJOR; - link->dev = &info->node; + link->dev_node = &info->node; ixj_get_serial(link, j); - link->state &= ~DEV_CONFIG_PENDING; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); ixj_cs_release(link); + return -ENODEV; } -static void ixj_cs_release(dev_link_t *link) +static void ixj_cs_release(struct pcmcia_device *link) { ixj_info_t *info = link->priv; DEBUG(0, "ixj_cs_release(0x%p)\n", link); info->ndev = 0; - link->dev = NULL; - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - link->state &= ~DEV_CONFIG; -} - -static int ixj_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - - return 0; -} - -static int ixj_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (DEV_OK(link)) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; + pcmcia_disable_device(link); } static struct pcmcia_device_id ixj_ids[] = { @@ -268,11 +217,9 @@ static struct pcmcia_driver ixj_driver = { .drv = { .name = "ixj_cs", }, - .probe = ixj_attach, + .probe = ixj_probe, .remove = ixj_detach, .id_table = ixj_ids, - .suspend = ixj_suspend, - .resume = ixj_resume, }; static int __init ixj_pcmcia_init(void) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 830d2c982670..b38990adf1cd 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -68,7 +68,7 @@ #include "usbatm.h" -#define EAGLEUSBVERSION "ueagle 1.2" +#define EAGLEUSBVERSION "ueagle 1.3" /* @@ -243,7 +243,7 @@ enum { #define BULK_TIMEOUT 300 #define CTRL_TIMEOUT 1000 -#define ACK_TIMEOUT msecs_to_jiffies(1500) +#define ACK_TIMEOUT msecs_to_jiffies(3000) #define UEA_INTR_IFACE_NO 0 #define UEA_US_IFACE_NO 1 @@ -314,6 +314,10 @@ struct cmv { ((d) & 0xff) << 16 | \ ((a) & 0xff) << 8 | \ ((b) & 0xff)) +#define GETSA1(a) ((a >> 8) & 0xff) +#define GETSA2(a) (a & 0xff) +#define GETSA3(a) ((a >> 24) & 0xff) +#define GETSA4(a) ((a >> 16) & 0xff) #define SA_CNTL MAKESA('C', 'N', 'T', 'L') #define SA_DIAG MAKESA('D', 'I', 'A', 'G') @@ -728,11 +732,12 @@ bad2: uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", i); return; bad1: - uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n",pageno); + uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno); } static inline void wake_up_cmv_ack(struct uea_softc *sc) { + BUG_ON(sc->cmv_ack); sc->cmv_ack = 1; wake_up(&sc->cmv_ack_wait); } @@ -743,6 +748,9 @@ static inline int wait_cmv_ack(struct uea_softc *sc) sc->cmv_ack, ACK_TIMEOUT); sc->cmv_ack = 0; + uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n", + jiffies_to_msecs(ret)); + if (ret < 0) return ret; @@ -791,6 +799,12 @@ static int uea_cmv(struct uea_softc *sc, struct cmv cmv; int ret; + uea_enters(INS_TO_USBDEV(sc)); + uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, " + "offset : 0x%04x, data : 0x%08x\n", + FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function), + GETSA1(address), GETSA2(address), GETSA3(address), + GETSA4(address), offset, data); /* we send a request, but we expect a reply */ sc->cmv_function = function | 0x2; sc->cmv_idx++; @@ -808,7 +822,9 @@ static int uea_cmv(struct uea_softc *sc, ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv); if (ret < 0) return ret; - return wait_cmv_ack(sc); + ret = wait_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); + return ret; } static inline int uea_read_cmv(struct uea_softc *sc, @@ -922,7 +938,7 @@ static int uea_stat(struct uea_softc *sc) * we check the status again in order to detect the failure earlier */ if (sc->stats.phy.flags) { - uea_dbg(INS_TO_USBDEV(sc), "Stat flag = %d\n", + uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n", sc->stats.phy.flags); return 0; } @@ -1063,7 +1079,13 @@ static int uea_start_reset(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); uea_info(INS_TO_USBDEV(sc), "(re)booting started\n"); + /* mask interrupt */ sc->booting = 1; + /* We need to set this here because, a ack timeout could have occured, + * but before we start the reboot, the ack occurs and set this to 1. + * So we will failed to wait Ready CMV. + */ + sc->cmv_ack = 0; UPDATE_ATM_STAT(signal, ATM_PHY_SIG_LOST); /* reset statistics */ @@ -1089,6 +1111,7 @@ static int uea_start_reset(struct uea_softc *sc) msleep(1000); sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY); + /* demask interrupt */ sc->booting = 0; /* start loading DSP */ @@ -1101,6 +1124,8 @@ static int uea_start_reset(struct uea_softc *sc) if (ret < 0) return ret; + uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n"); + /* Enter in R-IDLE (cmv) until instructed otherwise */ ret = uea_write_cmv(sc, SA_CNTL, 0, 1); if (ret < 0) @@ -1121,6 +1146,7 @@ static int uea_start_reset(struct uea_softc *sc) } /* Enter in R-ACT-REQ */ ret = uea_write_cmv(sc, SA_CNTL, 0, 2); + uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); out: release_firmware(cmvs_fw); sc->reset = 0; @@ -1235,6 +1261,7 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) { wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); return; } @@ -1249,6 +1276,7 @@ static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv) sc->data = sc->data << 16 | sc->data >> 16; wake_up_cmv_ack(sc); + uea_leaves(INS_TO_USBDEV(sc)); return; bad2: @@ -1256,12 +1284,14 @@ bad2: "Function : %d, Subfunction : %d\n", FUNCTION_TYPE(cmv->bFunction), FUNCTION_SUBTYPE(cmv->bFunction)); + uea_leaves(INS_TO_USBDEV(sc)); return; bad1: uea_err(INS_TO_USBDEV(sc), "invalid cmv received, " "wPreamble %d, bDirection %d\n", le16_to_cpu(cmv->wPreamble), cmv->bDirection); + uea_leaves(INS_TO_USBDEV(sc)); } /* @@ -1346,7 +1376,7 @@ static int uea_boot(struct uea_softc *sc) if (ret < 0) { uea_err(INS_TO_USBDEV(sc), "urb submition failed with error %d\n", ret); - goto err1; + goto err; } sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm"); @@ -1360,10 +1390,10 @@ static int uea_boot(struct uea_softc *sc) err2: usb_kill_urb(sc->urb_int); -err1: - kfree(intr); err: usb_free_urb(sc->urb_int); + sc->urb_int = NULL; + kfree(intr); uea_leaves(INS_TO_USBDEV(sc)); return -ENOMEM; } @@ -1508,7 +1538,7 @@ static ssize_t read_##name(struct device *dev, \ int ret = -ENODEV; \ struct uea_softc *sc; \ \ - mutex_lock(&uea_mutex); \ + mutex_lock(&uea_mutex); \ sc = dev_to_uea(dev); \ if (!sc) \ goto out; \ @@ -1516,7 +1546,7 @@ static ssize_t read_##name(struct device *dev, \ if (reset) \ sc->stats.phy.name = 0; \ out: \ - mutex_unlock(&uea_mutex); \ + mutex_unlock(&uea_mutex); \ return ret; \ } \ \ @@ -1643,7 +1673,7 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, sc = kzalloc(sizeof(struct uea_softc), GFP_KERNEL); if (!sc) { - uea_err(INS_TO_USBDEV(sc), "uea_init: not enough memory !\n"); + uea_err(usb, "uea_init: not enough memory !\n"); return -ENOMEM; } diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index ff03184da403..a08787e253aa 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -99,4 +99,11 @@ config USB_OTG_WHITELIST normal Linux-USB hosts do (other than the warning), and is convenient for many stages of product development. +config USB_OTG_BLACKLIST_HUB + bool "Disable external hubs" + depends on USB_OTG + help + If you say Y here, then Linux will refuse to enumerate + external hubs. OTG hosts are allowed to reduce hardware + and software costs by not supporting external hubs. diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index e0afb5ad29e5..66b78404ab34 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -213,11 +213,9 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) if (hcd->driver->suspend) { retval = hcd->driver->suspend(hcd, message); - if (retval) { - dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n", - retval); + suspend_report_result(hcd->driver->suspend, retval); + if (retval) goto done; - } } synchronize_irq(dev->irq); @@ -263,6 +261,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) * some device state (e.g. as part of clock reinit). */ retval = pci_set_power_state (dev, PCI_D3hot); + suspend_report_result(pci_set_power_state, retval); if (retval == 0) { int wake = device_can_wakeup(&hcd->self.root_hub->dev); @@ -296,7 +295,7 @@ done: #ifdef CONFIG_PPC_PMAC /* Disable ASIC clocks for USB */ - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { struct device_node *of_node; of_node = pci_device_to_OF_node (dev); @@ -331,7 +330,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) #ifdef CONFIG_PPC_PMAC /* Reenable ASIC clocks for USB */ - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { struct device_node *of_node; of_node = pci_device_to_OF_node (dev); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8e65f7a237e4..0c87f73f2933 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -836,6 +836,13 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) desc = intf->cur_altsetting; hdev = interface_to_usbdev(intf); +#ifdef CONFIG_USB_OTG_BLACKLIST_HUB + if (hdev->parent) { + dev_warn(&intf->dev, "ignoring external hub\n"); + return -ENODEV; + } +#endif + /* Some hubs have a subclass of 1, which AFAICT according to the */ /* specs is not defined, but it works */ if ((desc->desc.bInterfaceSubClass != 0) && @@ -1022,7 +1029,6 @@ void usb_set_device_state(struct usb_device *udev, recursively_mark_NOTATTACHED(udev); spin_unlock_irqrestore(&device_state_lock, flags); } -EXPORT_SYMBOL(usb_set_device_state); #ifdef CONFIG_PM diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index d7352aa73b5e..b7fdc1cd134a 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1194,7 +1194,6 @@ EXPORT_SYMBOL(usb_disabled); EXPORT_SYMBOL_GPL(usb_get_intf); EXPORT_SYMBOL_GPL(usb_put_intf); -EXPORT_SYMBOL(usb_alloc_dev); EXPORT_SYMBOL(usb_put_dev); EXPORT_SYMBOL(usb_get_dev); EXPORT_SYMBOL(usb_hub_tt_clear_buffer); @@ -1208,7 +1207,6 @@ EXPORT_SYMBOL(usb_ifnum_to_if); EXPORT_SYMBOL(usb_altnum_to_altsetting); EXPORT_SYMBOL(usb_reset_device); -EXPORT_SYMBOL(usb_disconnect); EXPORT_SYMBOL(__usb_get_extra_descriptor); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index d80f71877d68..363b2ad74ae6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -69,11 +69,11 @@ choice often need board-specific hooks. config USB_GADGET_NET2280 - boolean "NetChip 2280" + boolean "NetChip 228x" depends on PCI select USB_GADGET_DUALSPEED help - NetChip 2280 is a PCI based USB peripheral controller which + NetChip 2280 / 2282 is a PCI based USB peripheral controller which supports both full and high speed USB 2.0 data transfers. It has six configurable endpoints, as well as endpoint zero diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 865858cfd1c2..b8d0b7825bf3 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1709,7 +1709,7 @@ static int __devexit at91udc_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int at91udc_suspend(struct platform_device *dev, u32 state, u32 level) +static int at91udc_suspend(struct platform_device *dev, pm_message_t mesg) { struct at91_udc *udc = platform_get_drvdata(dev); @@ -1731,7 +1731,7 @@ static int at91udc_suspend(struct platform_device *dev, u32 state, u32 level) return 0; } -static int at91udc_resume(struct platform_device *dev, u32 level) +static int at91udc_resume(struct platform_device *dev) { struct at91_udc *udc = platform_get_drvdata(dev); diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index c3d8e5c5bf28..9c4422ac9de4 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -2338,6 +2338,9 @@ autoconf_fail: hs_subset_descriptors(); } + device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; + usb_gadget_set_selfpowered (gadget); + /* For now RNDIS is always a second config */ if (rndis) device_desc.bNumConfigurations = 2; @@ -2361,9 +2364,6 @@ autoconf_fail: #endif #endif /* DUALSPEED */ - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - usb_gadget_set_selfpowered (gadget); - if (gadget->is_otg) { otg_descriptor.bmAttributes |= USB_OTG_HNP, eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index cf3be299e353..6f887478b148 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -71,6 +71,12 @@ * requirement amounts to two 16K buffers, size configurable by a parameter. * Support is included for both full-speed and high-speed operation. * + * Note that the driver is slightly non-portable in that it assumes a + * single memory/DMA buffer will be useable for bulk-in, bulk-out, and + * interrupt-in endpoints. With most device controllers this isn't an + * issue, but there may be some with hardware restrictions that prevent + * a buffer from being used by more than one endpoint. + * * Module options: * * file=filename[,filename...] @@ -108,6 +114,14 @@ * setting are not allowed when the medium is loaded. * * This gadget driver is heavily based on "Gadget Zero" by David Brownell. + * The driver's SCSI command interface was based on the "Information + * technology - Small Computer System Interface - 2" document from + * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at + * . The single exception + * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the + * "Universal Serial Bus Mass Storage Class UFI Command Specification" + * document, Revision 1.0, December 14, 1998, available at + * . */ @@ -334,11 +348,9 @@ MODULE_LICENSE("Dual BSD/GPL"); #define MAX_LUNS 8 - /* Arggh! There should be a module_param_array_named macro! */ -static char *file[MAX_LUNS]; -static int ro[MAX_LUNS]; - static struct { + char *file[MAX_LUNS]; + int ro[MAX_LUNS]; int num_filenames; int num_ros; unsigned int nluns; @@ -370,10 +382,11 @@ static struct { }; -module_param_array(file, charp, &mod_data.num_filenames, S_IRUGO); +module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, + S_IRUGO); MODULE_PARM_DESC(file, "names of backing files or devices"); -module_param_array(ro, bool, &mod_data.num_ros, S_IRUGO); +module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); MODULE_PARM_DESC(ro, "true to force read-only"); module_param_named(luns, mod_data.nluns, uint, S_IRUGO); @@ -1795,6 +1808,7 @@ static int do_write(struct fsg_dev *fsg) * the bulk-out maxpacket size */ bh->outreq->length = bh->bulk_out_intended_length = amount; + bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); fsg->next_buffhd_to_fill = bh->next; @@ -2398,6 +2412,7 @@ static int throw_away_data(struct fsg_dev *fsg) * the bulk-out maxpacket size */ bh->outreq->length = bh->bulk_out_intended_length = amount; + bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); fsg->next_buffhd_to_fill = bh->next; @@ -3029,6 +3044,7 @@ static int get_next_command(struct fsg_dev *fsg) /* Queue a request to read a Bulk-only CBW */ set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN); + bh->outreq->short_not_ok = 1; start_transfer(fsg, fsg->bulk_out, bh->outreq, &bh->outreq_busy, &bh->state); @@ -3859,7 +3875,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) for (i = 0; i < fsg->nluns; ++i) { curlun = &fsg->luns[i]; - curlun->ro = ro[i]; + curlun->ro = mod_data.ro[i]; curlun->dev.parent = &gadget->dev; curlun->dev.driver = &fsg_driver.driver; dev_set_drvdata(&curlun->dev, fsg); @@ -3876,8 +3892,9 @@ static int __init fsg_bind(struct usb_gadget *gadget) kref_get(&fsg->ref); } - if (file[i] && *file[i]) { - if ((rc = open_backing_file(curlun, file[i])) != 0) + if (mod_data.file[i] && *mod_data.file[i]) { + if ((rc = open_backing_file(curlun, + mod_data.file[i])) != 0) goto out; } else if (!mod_data.removable) { ERROR(fsg, "no file given for LUN%d\n", i); @@ -3953,6 +3970,9 @@ static int __init fsg_bind(struct usb_gadget *gadget) for (i = 0; i < NUM_BUFFERS; ++i) { struct fsg_buffhd *bh = &fsg->buffhds[i]; + /* Allocate for the bulk-in endpoint. We assume that + * the buffer will also work with the bulk-out (and + * interrupt-in) endpoint. */ bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen, &bh->dma, GFP_KERNEL); if (!bh->buf) diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index c4081407171f..aa80f0910720 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -100,9 +100,9 @@ #define gadget_is_musbhsfc(g) 0 #endif -/* Mentor high speed "dual role" controller, peripheral mode */ -#ifdef CONFIG_USB_GADGET_MUSBHDRC -#define gadget_is_musbhdrc(g) !strcmp("musbhdrc_udc", (g)->name) +/* Mentor high speed "dual role" controller, in peripheral role */ +#ifdef CONFIG_USB_GADGET_MUSB_HDRC +#define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name) #else #define gadget_is_musbhdrc(g) 0 #endif diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 3f618ce6998d..42b457030b03 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -810,7 +810,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (value == 0) data->state = STATE_EP_ENABLED; break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_SPEED_HIGH: /* fails if caller didn't provide that descriptor... */ value = usb_ep_enable (ep, &data->hs_desc); @@ -982,7 +982,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* assume that was SET_CONFIGURATION */ if (dev->current_config) { unsigned power; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED if (dev->gadget->speed == USB_SPEED_HIGH) power = dev->hs_config->bMaxPower; else @@ -1262,7 +1262,7 @@ static struct file_operations ep0_io_operations = { * Unrecognized ep0 requests may be handled in user space. */ -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED static void make_qualifier (struct dev_data *dev) { struct usb_qualifier_descriptor qual; @@ -1291,7 +1291,7 @@ static int config_buf (struct dev_data *dev, u8 type, unsigned index) { int len; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED int hs; #endif @@ -1299,7 +1299,7 @@ config_buf (struct dev_data *dev, u8 type, unsigned index) if (index > 0) return -EINVAL; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED hs = (dev->gadget->speed == USB_SPEED_HIGH); if (type == USB_DT_OTHER_SPEED_CONFIG) hs = !hs; @@ -1335,12 +1335,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) dev->state = STATE_CONNECTED; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) { ERROR (dev, "no high speed config??\n"); return -EINVAL; } -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ INFO (dev, "connected\n"); event = next_event (dev, GADGETFS_CONNECT); @@ -1352,11 +1352,11 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) /* ... down_trylock (&data->lock) ... */ if (data->state != STATE_EP_DEFER_ENABLE) continue; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH) value = usb_ep_enable (ep, &data->hs_desc); else -#endif /* HIGHSPEED */ +#endif /* CONFIG_USB_GADGET_DUALSPEED */ value = usb_ep_enable (ep, &data->desc); if (value) { ERROR (dev, "deferred %s enable --> %d\n", @@ -1391,7 +1391,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min (w_length, (u16) sizeof *dev->dev); req->buf = dev->dev; break; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED case USB_DT_DEVICE_QUALIFIER: if (!dev->hs_config) break; @@ -1428,7 +1428,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) // user mode expected to disable endpoints } else { u8 config, power; -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED if (gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; power = dev->hs_config->bMaxPower; @@ -1728,7 +1728,7 @@ gadgetfs_suspend (struct usb_gadget *gadget) } static struct usb_gadget_driver gadgetfs_driver = { -#ifdef HIGHSPEED +#ifdef CONFIG_USB_GADGET_DUALSPEED .speed = USB_SPEED_HIGH, #else .speed = USB_SPEED_FULL, diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index fb73dc100535..6a4b93ad1082 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -26,6 +26,8 @@ * Copyright (C) 2003 David Brownell * Copyright (C) 2003-2005 PLX Technology, Inc. * + * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip + * * 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 @@ -71,8 +73,8 @@ #include -#define DRIVER_DESC "PLX NET2280 USB Peripheral Controller" -#define DRIVER_VERSION "2005 Feb 03" +#define DRIVER_DESC "PLX NET228x USB Peripheral Controller" +#define DRIVER_VERSION "2005 Sept 27" #define DMA_ADDR_INVALID (~(dma_addr_t)0) #define EP_DONTUSE 13 /* nonzero */ @@ -118,7 +120,7 @@ module_param (fifo_mode, ushort, 0644); /* enable_suspend -- When enabled, the driver will respond to * USB suspend requests by powering down the NET2280. Otherwise, * USB suspend requests will be ignored. This is acceptible for - * self-powered devices, and helps avoid some quirks. + * self-powered devices */ static int enable_suspend = 0; @@ -223,6 +225,11 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ep->is_in = (tmp & USB_DIR_IN) != 0; if (!ep->is_in) writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); + else if (dev->pdev->device != 0x2280) { + /* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */ + writel ((1 << CLEAR_NAK_OUT_PACKETS) + | (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp); + } writel (tmp, &ep->regs->ep_cfg); @@ -232,8 +239,9 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) writel (tmp, &dev->regs->pciirqenb0); tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) - | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) - | readl (&ep->regs->ep_irqenb); + | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE); + if (dev->pdev->device == 0x2280) + tmp |= readl (&ep->regs->ep_irqenb); writel (tmp, &ep->regs->ep_irqenb); } else { /* dma, per-request */ tmp = (1 << (8 + ep->num)); /* completion */ @@ -314,10 +322,18 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) /* init to our chosen defaults, notably so that we NAK OUT * packets until the driver queues a read (+note erratum 0112) */ - tmp = (1 << SET_NAK_OUT_PACKETS_MODE) + if (!ep->is_in || ep->dev->pdev->device == 0x2280) { + tmp = (1 << SET_NAK_OUT_PACKETS_MODE) | (1 << SET_NAK_OUT_PACKETS) | (1 << CLEAR_EP_HIDE_STATUS_PHASE) | (1 << CLEAR_INTERRUPT_MODE); + } else { + /* added for 2282 */ + tmp = (1 << CLEAR_NAK_OUT_PACKETS_MODE) + | (1 << CLEAR_NAK_OUT_PACKETS) + | (1 << CLEAR_EP_HIDE_STATUS_PHASE) + | (1 << CLEAR_INTERRUPT_MODE); + } if (ep->num != 0) { tmp |= (1 << CLEAR_ENDPOINT_TOGGLE) @@ -326,14 +342,18 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) writel (tmp, &ep->regs->ep_rsp); /* scrub most status bits, and flush any fifo state */ - writel ( (1 << TIMEOUT) + if (ep->dev->pdev->device == 0x2280) + tmp = (1 << FIFO_OVERFLOW) + | (1 << FIFO_UNDERFLOW); + else + tmp = 0; + + writel (tmp | (1 << TIMEOUT) | (1 << USB_STALL_SENT) | (1 << USB_IN_NAK_SENT) | (1 << USB_IN_ACK_RCVD) | (1 << USB_OUT_PING_NAK_SENT) | (1 << USB_OUT_ACK_SENT) - | (1 << FIFO_OVERFLOW) - | (1 << FIFO_UNDERFLOW) | (1 << FIFO_FLUSH) | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) @@ -718,7 +738,7 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid) */ if (ep->is_in) dmacount |= (1 << DMA_DIRECTION); - else if ((dmacount % ep->ep.maxpacket) != 0) + if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280) dmacount |= (1 << END_OF_CHAIN); req->valid = valid; @@ -760,9 +780,12 @@ static inline void stop_dma (struct net2280_dma_regs __iomem *dma) static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) { struct net2280_dma_regs __iomem *dma = ep->dma; + unsigned int tmp = (1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION); - writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION), - &dma->dmacount); + if (ep->dev->pdev->device != 0x2280) + tmp |= (1 << END_OF_CHAIN); + + writel (tmp, &dma->dmacount); writel (readl (&dma->dmastat), &dma->dmastat); writel (td_dma, &dma->dmadesc); @@ -2110,7 +2133,11 @@ static void handle_ep_small (struct net2280_ep *ep) VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n", ep->ep.name, t, req ? &req->req : 0); #endif - writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat); + if (!ep->is_in || ep->dev->pdev->device == 0x2280) + writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat); + else + /* Added for 2282 */ + writel (t, &ep->regs->ep_stat); /* for ep0, monitor token irqs to catch data stage length errors * and to synchronize on status. @@ -2214,7 +2241,8 @@ static void handle_ep_small (struct net2280_ep *ep) if (likely (req)) { req->td->dmacount = 0; t = readl (&ep->regs->ep_avail); - dma_done (ep, req, count, t); + dma_done (ep, req, count, + (ep->out_overflow || t) ? -EOVERFLOW : 0); } /* also flush to prevent erratum 0106 trouble */ @@ -2337,7 +2365,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) u32 raw [2]; struct usb_ctrlrequest r; } u; - int tmp = 0; + int tmp; struct net2280_request *req; if (dev->gadget.speed == USB_SPEED_UNKNOWN) { @@ -2364,14 +2392,19 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) } ep->stopped = 0; dev->protocol_stall = 0; - writel ( (1 << TIMEOUT) + + if (ep->dev->pdev->device == 0x2280) + tmp = (1 << FIFO_OVERFLOW) + | (1 << FIFO_UNDERFLOW); + else + tmp = 0; + + writel (tmp | (1 << TIMEOUT) | (1 << USB_STALL_SENT) | (1 << USB_IN_NAK_SENT) | (1 << USB_IN_ACK_RCVD) | (1 << USB_OUT_PING_NAK_SENT) | (1 << USB_OUT_ACK_SENT) - | (1 << FIFO_OVERFLOW) - | (1 << FIFO_UNDERFLOW) | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | (1 << DATA_PACKET_RECEIVED_INTERRUPT) @@ -2385,6 +2418,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) cpu_to_le32s (&u.raw [0]); cpu_to_le32s (&u.raw [1]); + tmp = 0; + #define w_value le16_to_cpup (&u.r.wValue) #define w_index le16_to_cpup (&u.r.wIndex) #define w_length le16_to_cpup (&u.r.wLength) @@ -2594,10 +2629,17 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat) writel (stat, &dev->regs->irqstat1); /* some status we can just ignore */ - stat &= ~((1 << CONTROL_STATUS_INTERRUPT) - | (1 << SUSPEND_REQUEST_INTERRUPT) - | (1 << RESUME_INTERRUPT) - | (1 << SOF_INTERRUPT)); + if (dev->pdev->device == 0x2280) + stat &= ~((1 << CONTROL_STATUS_INTERRUPT) + | (1 << SUSPEND_REQUEST_INTERRUPT) + | (1 << RESUME_INTERRUPT) + | (1 << SOF_INTERRUPT)); + else + stat &= ~((1 << CONTROL_STATUS_INTERRUPT) + | (1 << RESUME_INTERRUPT) + | (1 << SOF_DOWN_INTERRUPT) + | (1 << SOF_INTERRUPT)); + if (!stat) return; // DEBUG (dev, "irqstat1 %08x\n", stat); @@ -2939,6 +2981,13 @@ static struct pci_device_id pci_ids [] = { { .device = 0x2280, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, +}, { + .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), + .class_mask = ~0, + .vendor = 0x17cc, + .device = 0x2282, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { /* end: all zeroes */ } }; diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index fff4509cf340..957d6df34015 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -22,420 +22,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/*-------------------------------------------------------------------------*/ - -/* NET2280 MEMORY MAPPED REGISTERS - * - * The register layout came from the chip documentation, and the bit - * number definitions were extracted from chip specification. - * - * Use the shift operator ('<<') to build bit masks, with readl/writel - * to access the registers through PCI. - */ - -/* main registers, BAR0 + 0x0000 */ -struct net2280_regs { - // offset 0x0000 - u32 devinit; -#define LOCAL_CLOCK_FREQUENCY 8 -#define FORCE_PCI_RESET 7 -#define PCI_ID 6 -#define PCI_ENABLE 5 -#define FIFO_SOFT_RESET 4 -#define CFG_SOFT_RESET 3 -#define PCI_SOFT_RESET 2 -#define USB_SOFT_RESET 1 -#define M8051_RESET 0 - u32 eectl; -#define EEPROM_ADDRESS_WIDTH 23 -#define EEPROM_CHIP_SELECT_ACTIVE 22 -#define EEPROM_PRESENT 21 -#define EEPROM_VALID 20 -#define EEPROM_BUSY 19 -#define EEPROM_CHIP_SELECT_ENABLE 18 -#define EEPROM_BYTE_READ_START 17 -#define EEPROM_BYTE_WRITE_START 16 -#define EEPROM_READ_DATA 8 -#define EEPROM_WRITE_DATA 0 - u32 eeclkfreq; - u32 _unused0; - // offset 0x0010 - - u32 pciirqenb0; /* interrupt PCI master ... */ -#define SETUP_PACKET_INTERRUPT_ENABLE 7 -#define ENDPOINT_F_INTERRUPT_ENABLE 6 -#define ENDPOINT_E_INTERRUPT_ENABLE 5 -#define ENDPOINT_D_INTERRUPT_ENABLE 4 -#define ENDPOINT_C_INTERRUPT_ENABLE 3 -#define ENDPOINT_B_INTERRUPT_ENABLE 2 -#define ENDPOINT_A_INTERRUPT_ENABLE 1 -#define ENDPOINT_0_INTERRUPT_ENABLE 0 - u32 pciirqenb1; -#define PCI_INTERRUPT_ENABLE 31 -#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 -#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 -#define PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE 18 -#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 -#define GPIO_INTERRUPT_ENABLE 13 -#define DMA_D_INTERRUPT_ENABLE 12 -#define DMA_C_INTERRUPT_ENABLE 11 -#define DMA_B_INTERRUPT_ENABLE 10 -#define DMA_A_INTERRUPT_ENABLE 9 -#define EEPROM_DONE_INTERRUPT_ENABLE 8 -#define VBUS_INTERRUPT_ENABLE 7 -#define CONTROL_STATUS_INTERRUPT_ENABLE 6 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 -#define RESUME_INTERRUPT_ENABLE 1 -#define SOF_INTERRUPT_ENABLE 0 - u32 cpu_irqenb0; /* ... or onboard 8051 */ -#define SETUP_PACKET_INTERRUPT_ENABLE 7 -#define ENDPOINT_F_INTERRUPT_ENABLE 6 -#define ENDPOINT_E_INTERRUPT_ENABLE 5 -#define ENDPOINT_D_INTERRUPT_ENABLE 4 -#define ENDPOINT_C_INTERRUPT_ENABLE 3 -#define ENDPOINT_B_INTERRUPT_ENABLE 2 -#define ENDPOINT_A_INTERRUPT_ENABLE 1 -#define ENDPOINT_0_INTERRUPT_ENABLE 0 - u32 cpu_irqenb1; -#define CPU_INTERRUPT_ENABLE 31 -#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 -#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 -#define PCI_INTA_INTERRUPT_ENABLE 24 -#define PCI_PME_INTERRUPT_ENABLE 23 -#define PCI_SERR_INTERRUPT_ENABLE 22 -#define PCI_PERR_INTERRUPT_ENABLE 21 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 -#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 -#define GPIO_INTERRUPT_ENABLE 13 -#define DMA_D_INTERRUPT_ENABLE 12 -#define DMA_C_INTERRUPT_ENABLE 11 -#define DMA_B_INTERRUPT_ENABLE 10 -#define DMA_A_INTERRUPT_ENABLE 9 -#define EEPROM_DONE_INTERRUPT_ENABLE 8 -#define VBUS_INTERRUPT_ENABLE 7 -#define CONTROL_STATUS_INTERRUPT_ENABLE 6 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 -#define RESUME_INTERRUPT_ENABLE 1 -#define SOF_INTERRUPT_ENABLE 0 - - // offset 0x0020 - u32 _unused1; - u32 usbirqenb1; -#define USB_INTERRUPT_ENABLE 31 -#define POWER_STATE_CHANGE_INTERRUPT_ENABLE 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE 26 -#define PCI_PARITY_ERROR_INTERRUPT_ENABLE 25 -#define PCI_INTA_INTERRUPT_ENABLE 24 -#define PCI_PME_INTERRUPT_ENABLE 23 -#define PCI_SERR_INTERRUPT_ENABLE 22 -#define PCI_PERR_INTERRUPT_ENABLE 21 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE 19 -#define PCI_RETRY_ABORT_INTERRUPT_ENABLE 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE 16 -#define GPIO_INTERRUPT_ENABLE 13 -#define DMA_D_INTERRUPT_ENABLE 12 -#define DMA_C_INTERRUPT_ENABLE 11 -#define DMA_B_INTERRUPT_ENABLE 10 -#define DMA_A_INTERRUPT_ENABLE 9 -#define EEPROM_DONE_INTERRUPT_ENABLE 8 -#define VBUS_INTERRUPT_ENABLE 7 -#define CONTROL_STATUS_INTERRUPT_ENABLE 6 -#define ROOT_PORT_RESET_INTERRUPT_ENABLE 4 -#define SUSPEND_REQUEST_INTERRUPT_ENABLE 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE 2 -#define RESUME_INTERRUPT_ENABLE 1 -#define SOF_INTERRUPT_ENABLE 0 - u32 irqstat0; -#define INTA_ASSERTED 12 -#define SETUP_PACKET_INTERRUPT 7 -#define ENDPOINT_F_INTERRUPT 6 -#define ENDPOINT_E_INTERRUPT 5 -#define ENDPOINT_D_INTERRUPT 4 -#define ENDPOINT_C_INTERRUPT 3 -#define ENDPOINT_B_INTERRUPT 2 -#define ENDPOINT_A_INTERRUPT 1 -#define ENDPOINT_0_INTERRUPT 0 - u32 irqstat1; -#define POWER_STATE_CHANGE_INTERRUPT 27 -#define PCI_ARBITER_TIMEOUT_INTERRUPT 26 -#define PCI_PARITY_ERROR_INTERRUPT 25 -#define PCI_INTA_INTERRUPT 24 -#define PCI_PME_INTERRUPT 23 -#define PCI_SERR_INTERRUPT 22 -#define PCI_PERR_INTERRUPT 21 -#define PCI_MASTER_ABORT_RECEIVED_INTERRUPT 20 -#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 -#define PCI_RETRY_ABORT_INTERRUPT 17 -#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 -#define GPIO_INTERRUPT 13 -#define DMA_D_INTERRUPT 12 -#define DMA_C_INTERRUPT 11 -#define DMA_B_INTERRUPT 10 -#define DMA_A_INTERRUPT 9 -#define EEPROM_DONE_INTERRUPT 8 -#define VBUS_INTERRUPT 7 -#define CONTROL_STATUS_INTERRUPT 6 -#define ROOT_PORT_RESET_INTERRUPT 4 -#define SUSPEND_REQUEST_INTERRUPT 3 -#define SUSPEND_REQUEST_CHANGE_INTERRUPT 2 -#define RESUME_INTERRUPT 1 -#define SOF_INTERRUPT 0 - // offset 0x0030 - u32 idxaddr; - u32 idxdata; - u32 fifoctl; -#define PCI_BASE2_RANGE 16 -#define IGNORE_FIFO_AVAILABILITY 3 -#define PCI_BASE2_SELECT 2 -#define FIFO_CONFIGURATION_SELECT 0 - u32 _unused2; - // offset 0x0040 - u32 memaddr; -#define START 28 -#define DIRECTION 27 -#define FIFO_DIAGNOSTIC_SELECT 24 -#define MEMORY_ADDRESS 0 - u32 memdata0; - u32 memdata1; - u32 _unused3; - // offset 0x0050 - u32 gpioctl; -#define GPIO3_LED_SELECT 12 -#define GPIO3_INTERRUPT_ENABLE 11 -#define GPIO2_INTERRUPT_ENABLE 10 -#define GPIO1_INTERRUPT_ENABLE 9 -#define GPIO0_INTERRUPT_ENABLE 8 -#define GPIO3_OUTPUT_ENABLE 7 -#define GPIO2_OUTPUT_ENABLE 6 -#define GPIO1_OUTPUT_ENABLE 5 -#define GPIO0_OUTPUT_ENABLE 4 -#define GPIO3_DATA 3 -#define GPIO2_DATA 2 -#define GPIO1_DATA 1 -#define GPIO0_DATA 0 - u32 gpiostat; -#define GPIO3_INTERRUPT 3 -#define GPIO2_INTERRUPT 2 -#define GPIO1_INTERRUPT 1 -#define GPIO0_INTERRUPT 0 -} __attribute__ ((packed)); - -/* usb control, BAR0 + 0x0080 */ -struct net2280_usb_regs { - // offset 0x0080 - u32 stdrsp; -#define STALL_UNSUPPORTED_REQUESTS 31 -#define SET_TEST_MODE 16 -#define GET_OTHER_SPEED_CONFIGURATION 15 -#define GET_DEVICE_QUALIFIER 14 -#define SET_ADDRESS 13 -#define ENDPOINT_SET_CLEAR_HALT 12 -#define DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP 11 -#define GET_STRING_DESCRIPTOR_2 10 -#define GET_STRING_DESCRIPTOR_1 9 -#define GET_STRING_DESCRIPTOR_0 8 -#define GET_SET_INTERFACE 6 -#define GET_SET_CONFIGURATION 5 -#define GET_CONFIGURATION_DESCRIPTOR 4 -#define GET_DEVICE_DESCRIPTOR 3 -#define GET_ENDPOINT_STATUS 2 -#define GET_INTERFACE_STATUS 1 -#define GET_DEVICE_STATUS 0 - u32 prodvendid; -#define PRODUCT_ID 16 -#define VENDOR_ID 0 - u32 relnum; - u32 usbctl; -#define SERIAL_NUMBER_INDEX 16 -#define PRODUCT_ID_STRING_ENABLE 13 -#define VENDOR_ID_STRING_ENABLE 12 -#define USB_ROOT_PORT_WAKEUP_ENABLE 11 -#define VBUS_PIN 10 -#define TIMED_DISCONNECT 9 -#define SUSPEND_IMMEDIATELY 7 -#define SELF_POWERED_USB_DEVICE 6 -#define REMOTE_WAKEUP_SUPPORT 5 -#define PME_POLARITY 4 -#define USB_DETECT_ENABLE 3 -#define PME_WAKEUP_ENABLE 2 -#define DEVICE_REMOTE_WAKEUP_ENABLE 1 -#define SELF_POWERED_STATUS 0 - // offset 0x0090 - u32 usbstat; -#define HIGH_SPEED 7 -#define FULL_SPEED 6 -#define GENERATE_RESUME 5 -#define GENERATE_DEVICE_REMOTE_WAKEUP 4 - u32 xcvrdiag; -#define FORCE_HIGH_SPEED_MODE 31 -#define FORCE_FULL_SPEED_MODE 30 -#define USB_TEST_MODE 24 -#define LINE_STATE 16 -#define TRANSCEIVER_OPERATION_MODE 2 -#define TRANSCEIVER_SELECT 1 -#define TERMINATION_SELECT 0 - u32 setup0123; - u32 setup4567; - // offset 0x0090 - u32 _unused0; - u32 ouraddr; -#define FORCE_IMMEDIATE 7 -#define OUR_USB_ADDRESS 0 - u32 ourconfig; -} __attribute__ ((packed)); - -/* pci control, BAR0 + 0x0100 */ -struct net2280_pci_regs { - // offset 0x0100 - u32 pcimstctl; -#define PCI_ARBITER_PARK_SELECT 13 -#define PCI_MULTI LEVEL_ARBITER 12 -#define PCI_RETRY_ABORT_ENABLE 11 -#define DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE 10 -#define DMA_READ_MULTIPLE_ENABLE 9 -#define DMA_READ_LINE_ENABLE 8 -#define PCI_MASTER_COMMAND_SELECT 6 -#define MEM_READ_OR_WRITE 0 -#define IO_READ_OR_WRITE 1 -#define CFG_READ_OR_WRITE 2 -#define PCI_MASTER_START 5 -#define PCI_MASTER_READ_WRITE 4 -#define PCI_MASTER_WRITE 0 -#define PCI_MASTER_READ 1 -#define PCI_MASTER_BYTE_WRITE_ENABLES 0 - u32 pcimstaddr; - u32 pcimstdata; - u32 pcimststat; -#define PCI_ARBITER_CLEAR 2 -#define PCI_EXTERNAL_ARBITER 1 -#define PCI_HOST_MODE 0 -} __attribute__ ((packed)); - -/* dma control, BAR0 + 0x0180 ... array of four structs like this, - * for channels 0..3. see also struct net2280_dma: descriptor - * that can be loaded into some of these registers. - */ -struct net2280_dma_regs { /* [11.7] */ - // offset 0x0180, 0x01a0, 0x01c0, 0x01e0, - u32 dmactl; -#define DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE 25 -#define DMA_CLEAR_COUNT_ENABLE 21 -#define DESCRIPTOR_POLLING_RATE 19 -#define POLL_CONTINUOUS 0 -#define POLL_1_USEC 1 -#define POLL_100_USEC 2 -#define POLL_1_MSEC 3 -#define DMA_VALID_BIT_POLLING_ENABLE 18 -#define DMA_VALID_BIT_ENABLE 17 -#define DMA_SCATTER_GATHER_ENABLE 16 -#define DMA_OUT_AUTO_START_ENABLE 4 -#define DMA_PREEMPT_ENABLE 3 -#define DMA_FIFO_VALIDATE 2 -#define DMA_ENABLE 1 -#define DMA_ADDRESS_HOLD 0 - u32 dmastat; -#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 -#define DMA_TRANSACTION_DONE_INTERRUPT 24 -#define DMA_ABORT 1 -#define DMA_START 0 - u32 _unused0 [2]; - // offset 0x0190, 0x01b0, 0x01d0, 0x01f0, - u32 dmacount; -#define VALID_BIT 31 -#define DMA_DIRECTION 30 -#define DMA_DONE_INTERRUPT_ENABLE 29 -#define END_OF_CHAIN 28 -#define DMA_BYTE_COUNT_MASK ((1<<24)-1) -#define DMA_BYTE_COUNT 0 - u32 dmaaddr; - u32 dmadesc; - u32 _unused1; -} __attribute__ ((packed)); - -/* dedicated endpoint registers, BAR0 + 0x0200 */ - -struct net2280_dep_regs { /* [11.8] */ - // offset 0x0200, 0x0210, 0x220, 0x230, 0x240 - u32 dep_cfg; - // offset 0x0204, 0x0214, 0x224, 0x234, 0x244 - u32 dep_rsp; - u32 _unused [2]; -} __attribute__ ((packed)); - -/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs - * like this, for ep0 then the configurable endpoints A..F - * ep0 reserved for control; E and F have only 64 bytes of fifo - */ -struct net2280_ep_regs { /* [11.9] */ - // offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0 - u32 ep_cfg; -#define ENDPOINT_BYTE_COUNT 16 -#define ENDPOINT_ENABLE 10 -#define ENDPOINT_TYPE 8 -#define ENDPOINT_DIRECTION 7 -#define ENDPOINT_NUMBER 0 - u32 ep_rsp; -#define SET_NAK_OUT_PACKETS 15 -#define SET_EP_HIDE_STATUS_PHASE 14 -#define SET_EP_FORCE_CRC_ERROR 13 -#define SET_INTERRUPT_MODE 12 -#define SET_CONTROL_STATUS_PHASE_HANDSHAKE 11 -#define SET_NAK_OUT_PACKETS_MODE 10 -#define SET_ENDPOINT_TOGGLE 9 -#define SET_ENDPOINT_HALT 8 -#define CLEAR_NAK_OUT_PACKETS 7 -#define CLEAR_EP_HIDE_STATUS_PHASE 6 -#define CLEAR_EP_FORCE_CRC_ERROR 5 -#define CLEAR_INTERRUPT_MODE 4 -#define CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE 3 -#define CLEAR_NAK_OUT_PACKETS_MODE 2 -#define CLEAR_ENDPOINT_TOGGLE 1 -#define CLEAR_ENDPOINT_HALT 0 - u32 ep_irqenb; -#define SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE 6 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE 5 -#define DATA_PACKET_RECEIVED_INTERRUPT_ENABLE 3 -#define DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE 2 -#define DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE 1 -#define DATA_IN_TOKEN_INTERRUPT_ENABLE 0 - u32 ep_stat; -#define FIFO_VALID_COUNT 24 -#define HIGH_BANDWIDTH_OUT_TRANSACTION_PID 22 -#define TIMEOUT 21 -#define USB_STALL_SENT 20 -#define USB_IN_NAK_SENT 19 -#define USB_IN_ACK_RCVD 18 -#define USB_OUT_PING_NAK_SENT 17 -#define USB_OUT_ACK_SENT 16 -#define FIFO_OVERFLOW 13 -#define FIFO_UNDERFLOW 12 -#define FIFO_FULL 11 -#define FIFO_EMPTY 10 -#define FIFO_FLUSH 9 -#define SHORT_PACKET_OUT_DONE_INTERRUPT 6 -#define SHORT_PACKET_TRANSFERRED_INTERRUPT 5 -#define NAK_OUT_PACKETS 4 -#define DATA_PACKET_RECEIVED_INTERRUPT 3 -#define DATA_PACKET_TRANSMITTED_INTERRUPT 2 -#define DATA_OUT_PING_TOKEN_INTERRUPT 1 -#define DATA_IN_TOKEN_INTERRUPT 0 - // offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0 - u32 ep_avail; - u32 ep_data; - u32 _unused0 [2]; -} __attribute__ ((packed)); +#include /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 51424f66a765..68e3d8f5da89 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -572,9 +572,10 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req) switch (status) { case 0: /* normal completion? */ - if (ep == dev->out_ep) + if (ep == dev->out_ep) { check_read_data (dev, ep, req); - else + memset (req->buf, 0x55, req->length); + } else reinit_write_data (dev, ep, req); break; @@ -626,6 +627,8 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags) if (strcmp (ep->name, EP_IN_NAME) == 0) reinit_write_data (ep->driver_data, ep, req); + else + memset (req->buf, 0x55, req->length); status = usb_ep_queue (ep, req, gfp_flags); if (status) { diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 980030d684d5..6b7350b52419 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -20,7 +20,7 @@ #include #ifndef CONFIG_ARCH_AT91RM9200 -#error "This file is AT91RM9200 bus glue. CONFIG_ARCH_AT91RM9200 must be defined." +#error "CONFIG_ARCH_AT91RM9200 must be defined." #endif /* interface and function clocks */ @@ -84,8 +84,6 @@ static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); * Allocates basic resources for this USB host controller, and * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data. - * - * Store this function in the HCD's struct pci_driver as probe(). */ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *pdev) { @@ -148,7 +146,6 @@ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device * } -/* may be called without controller electrically present */ /* may be called with controller, bus, and devices active */ /** @@ -166,11 +163,11 @@ static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pde usb_remove_hcd(hcd); at91_stop_hc(pdev); iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - clk_put(fclk); - clk_put(iclk); - fclk = iclk = NULL; + clk_put(fclk); + clk_put(iclk); + fclk = iclk = NULL; dev_set_drvdata(&pdev->dev, NULL); return 0; @@ -235,8 +232,8 @@ static const struct hc_driver ohci_at91_hc_driver = { .hub_control = ohci_hub_control, #ifdef CONFIG_PM - .hub_suspend = ohci_hub_suspend, - .hub_resume = ohci_hub_resume, + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, #endif .start_port_reset = ohci_start_port_reset, }; @@ -254,21 +251,21 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int ohci_hcd_at91_drv_suspend(struct platform_device *dev, u32 state, u32 level) -{ - printk("%s(%s:%d): not implemented yet\n", - __func__, __FILE__, __LINE__); +/* REVISIT suspend/resume look "too" simple here */ + +static int +ohci_hcd_at91_drv_suspend(struct platform_device *dev, pm_message_t mesg) +{ clk_disable(fclk); + clk_disable(iclk); return 0; } -static int ohci_hcd_at91_drv_resume(struct platform_device *dev, u32 state) +static int ohci_hcd_at91_drv_resume(struct platform_device *dev) { - printk("%s(%s:%d): not implemented yet\n", - __func__, __FILE__, __LINE__); - + clk_enable(iclk); clk_enable(fclk); return 0; @@ -278,6 +275,8 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *dev, u32 state) #define ohci_hcd_at91_drv_resume NULL #endif +MODULE_ALIAS("at91rm9200-ohci"); + static struct platform_driver ohci_hcd_at91_driver = { .probe = ohci_hcd_at91_drv_probe, .remove = ohci_hcd_at91_drv_remove, diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 682bf2215660..1da5de573a6f 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -30,6 +30,7 @@ /* clock device associated with the hcd */ static struct clk *clk; +static struct clk *usb_clk; /* forward definitions */ @@ -37,7 +38,7 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc); /* conversion functions */ -struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd) +static struct s3c2410_hcd_info *to_s3c2410_info(struct usb_hcd *hcd) { return hcd->self.controller->platform_data; } @@ -47,6 +48,10 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd) struct s3c2410_hcd_info *info = dev->dev.platform_data; dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); + + clk_enable(usb_clk); + mdelay(2); /* let the bus clock stabilise */ + clk_enable(clk); if (info != NULL) { @@ -75,6 +80,7 @@ static void s3c2410_stop_hc(struct platform_device *dev) } clk_disable(clk); + clk_disable(usb_clk); } /* ohci_s3c2410_hub_status_data @@ -316,7 +322,8 @@ static void s3c2410_hcd_oc(struct s3c2410_hcd_info *info, int port_oc) * */ -void usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev) +static void +usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev) { usb_remove_hcd(hcd); s3c2410_stop_hc(dev); @@ -334,8 +341,8 @@ void usb_hcd_s3c2410_remove (struct usb_hcd *hcd, struct platform_device *dev) * through the hotplug entry's driver_data. * */ -int usb_hcd_s3c2410_probe (const struct hc_driver *driver, - struct platform_device *dev) +static int usb_hcd_s3c2410_probe (const struct hc_driver *driver, + struct platform_device *dev) { struct usb_hcd *hcd = NULL; int retval; @@ -353,14 +360,21 @@ int usb_hcd_s3c2410_probe (const struct hc_driver *driver, if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { dev_err(&dev->dev, "request_mem_region failed"); retval = -EBUSY; - goto err0; + goto err_put; } - clk = clk_get(NULL, "usb-host"); + clk = clk_get(&dev->dev, "usb-host"); if (IS_ERR(clk)) { dev_err(&dev->dev, "cannot get usb-host clock\n"); retval = -ENOENT; - goto err1; + goto err_mem; + } + + usb_clk = clk_get(&dev->dev, "upll"); + if (IS_ERR(usb_clk)) { + dev_err(&dev->dev, "cannot get usb-host clock\n"); + retval = -ENOENT; + goto err_clk; } s3c2410_start_hc(dev, hcd); @@ -369,26 +383,29 @@ int usb_hcd_s3c2410_probe (const struct hc_driver *driver, if (!hcd->regs) { dev_err(&dev->dev, "ioremap failed\n"); retval = -ENOMEM; - goto err2; + goto err_ioremap; } ohci_hcd_init(hcd_to_ohci(hcd)); retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT); if (retval != 0) - goto err2; + goto err_ioremap; return 0; - err2: + err_ioremap: s3c2410_stop_hc(dev); iounmap(hcd->regs); + clk_put(usb_clk); + + err_clk: clk_put(clk); - err1: + err_mem: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err0: + err_put: usb_put_hcd(hcd); return retval; } diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 9e81c26313f9..1045f846fbe2 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -15,6 +15,7 @@ #include #include #include +#include "pci-quirks.h" #define UHCI_USBLEGSUP 0xc0 /* legacy support */ diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h new file mode 100644 index 000000000000..1564edfff6fe --- /dev/null +++ b/drivers/usb/host/pci-quirks.h @@ -0,0 +1,7 @@ +#ifndef __LINUX_USB_PCI_QUIRKS_H +#define __LINUX_USB_PCI_QUIRKS_H + +void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); +int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); + +#endif /* __LINUX_USB_PCI_QUIRKS_H */ diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 134d2000128a..302aa1ec312f 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -67,11 +67,11 @@ module_param(pc_debug, int, 0644); static const char driver_name[DEV_NAME_LEN] = "sl811_cs"; typedef struct local_info_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; } local_info_t; -static void sl811_cs_release(dev_link_t * link); +static void sl811_cs_release(struct pcmcia_device * link); /*====================================================================*/ @@ -138,41 +138,27 @@ static int sl811_hc_init(struct device *parent, ioaddr_t base_addr, int irq) /*====================================================================*/ -static void sl811_cs_detach(struct pcmcia_device *p_dev) +static void sl811_cs_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); - DBG(0, "sl811_cs_detach(0x%p)\n", link); - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) - sl811_cs_release(link); + sl811_cs_release(link); /* This points to the parent local_info_t struct */ kfree(link->priv); } -static void sl811_cs_release(dev_link_t * link) +static void sl811_cs_release(struct pcmcia_device * link) { - DBG(0, "sl811_cs_release(0x%p)\n", link); - /* Unlink the device chain */ - link->dev = NULL; - + pcmcia_disable_device(link); platform_device_unregister(&platform_dev); - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - if (link->irq.AssignedIRQ) - pcmcia_release_irq(link->handle, &link->irq); - link->state &= ~DEV_CONFIG; } -static void sl811_cs_config(dev_link_t *link) +static int sl811_cs_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; - struct device *parent = &handle_to_dev(handle); + struct device *parent = &handle_to_dev(link); local_info_t *dev = link->priv; tuple_t tuple; cisparse_t parse; @@ -188,27 +174,23 @@ static void sl811_cs_config(dev_link_t *link) tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - /* Configure card */ - link->state |= DEV_CONFIG; - /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, - pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; + pcmcia_get_configuration_info(link, &conf)); tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); - if (pcmcia_get_tuple_data(handle, &tuple) != 0 - || pcmcia_parse_tuple(handle, &tuple, &parse) + if (pcmcia_get_tuple_data(link, &tuple) != 0 + || pcmcia_parse_tuple(link, &tuple, &parse) != 0) goto next_entry; @@ -234,10 +216,10 @@ static void sl811_cs_config(dev_link_t *link) } if (cfg->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + link->conf.Vpp = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; /* we need an interrupt */ @@ -254,15 +236,14 @@ static void sl811_cs_config(dev_link_t *link) link->io.BasePort1 = io->win[0].base; link->io.NumPorts1 = io->win[0].len; - if (pcmcia_request_io(link->handle, &link->io) != 0) + if (pcmcia_request_io(link, &link->io) != 0) goto next_entry; } break; next_entry: - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - last_ret = pcmcia_get_next_tuple(handle, &tuple); + pcmcia_disable_device(link); + last_ret = pcmcia_get_next_tuple(link, &tuple); } /* require an IRQ and two registers */ @@ -270,71 +251,46 @@ next_entry: goto cs_failed; if (link->conf.Attributes & CONF_ENABLE_IRQ) CS_CHECK(RequestIRQ, - pcmcia_request_irq(link->handle, &link->irq)); + pcmcia_request_irq(link, &link->irq)); else goto cs_failed; CS_CHECK(RequestConfiguration, - pcmcia_request_configuration(link->handle, &link->conf)); + pcmcia_request_configuration(link, &link->conf)); sprintf(dev->node.dev_name, driver_name); dev->node.major = dev->node.minor = 0; - link->dev = &dev->node; + link->dev_node = &dev->node; - printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", - dev->node.dev_name, link->conf.ConfigIndex, - link->conf.Vcc/10, link->conf.Vcc%10); - if (link->conf.Vpp1) - printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + printk(KERN_INFO "%s: index 0x%02x: ", + dev->node.dev_name, link->conf.ConfigIndex); + if (link->conf.Vpp) + printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); printk(", irq %d", link->irq.AssignedIRQ); printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); printk("\n"); - link->state &= ~DEV_CONFIG_PENDING; - if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ) < 0) { cs_failed: printk("sl811_cs_config failed\n"); - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); sl811_cs_release(link); - link->state &= ~DEV_CONFIG_PENDING; + return -ENODEV; } -} - -static int sl811_suspend(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - return 0; } -static int sl811_resume(struct pcmcia_device *dev) -{ - dev_link_t *link = dev_to_instance(dev); - - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); - - return 0; -} - -static int sl811_cs_attach(struct pcmcia_device *p_dev) +static int sl811_cs_probe(struct pcmcia_device *link) { local_info_t *local; - dev_link_t *link; local = kmalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) return -ENOMEM; memset(local, 0, sizeof(local_info_t)); - link = &local->link; + local->p_dev = link; link->priv = local; /* Initialize */ @@ -343,16 +299,9 @@ static int sl811_cs_attach(struct pcmcia_device *p_dev) link->irq.Handler = NULL; link->conf.Attributes = 0; - link->conf.Vcc = 33; link->conf.IntType = INT_MEMORY_AND_IO; - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - sl811_cs_config(link); - - return 0; + return sl811_cs_config(link); } static struct pcmcia_device_id sl811_ids[] = { @@ -366,11 +315,9 @@ static struct pcmcia_driver sl811_cs_driver = { .drv = { .name = (char *)driver_name, }, - .probe = sl811_cs_attach, + .probe = sl811_cs_probe, .remove = sl811_cs_detach, .id_table = sl811_ids, - .suspend = sl811_suspend, - .resume = sl811_resume, }; /*====================================================================*/ diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 4edb8330c440..c0c4db78b590 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -50,6 +50,7 @@ #include "../core/hcd.h" #include "uhci-hcd.h" +#include "pci-quirks.h" /* * Version Information @@ -100,9 +101,6 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); #include "uhci-q.c" #include "uhci-hub.c" -extern void uhci_reset_hc(struct pci_dev *pdev, unsigned long base); -extern int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base); - /* * Finish up a host controller reset and update the recorded state. */ @@ -117,8 +115,7 @@ static void finish_reset(struct uhci_hcd *uhci) for (port = 0; port < uhci->rh_numports; ++port) outw(0, uhci->io_addr + USBPORTSC1 + (port * 2)); - uhci->port_c_suspend = uhci->suspended_ports = - uhci->resuming_ports = 0; + uhci->port_c_suspend = uhci->resuming_ports = 0; uhci->rh_state = UHCI_RH_RESET; uhci->is_stopped = UHCI_IS_STOPPED; uhci_to_hcd(uhci)->state = HC_STATE_HALT; diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 4a69c7eb09bd..d5c8f4d92823 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -415,7 +415,6 @@ struct uhci_hcd { /* Support for port suspend/resume/reset */ unsigned long port_c_suspend; /* Bit-arrays of ports */ - unsigned long suspended_ports; unsigned long resuming_ports; unsigned long ports_timeout; /* Time to stop signalling */ diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 152971d16769..c8451d9578f1 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -85,11 +85,10 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, { int status; - if (test_bit(port, &uhci->suspended_ports)) { + if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) { CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD); - clear_bit(port, &uhci->suspended_ports); - clear_bit(port, &uhci->resuming_ports); - set_bit(port, &uhci->port_c_suspend); + if (test_bit(port, &uhci->resuming_ports)) + set_bit(port, &uhci->port_c_suspend); /* The controller won't actually turn off the RD bit until * it has had a chance to send a low-speed EOP sequence, @@ -97,6 +96,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port, * slightly longer for good luck. */ udelay(4); } + clear_bit(port, &uhci->resuming_ports); } /* Wait for the UHCI controller in HP's iLO2 server management chip. @@ -265,8 +265,6 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, wPortChange |= USB_PORT_STAT_C_SUSPEND; lstatus |= 1; } - if (test_bit(port, &uhci->suspended_ports)) - lstatus |= 2; if (test_bit(port, &uhci->resuming_ports)) lstatus |= 4; @@ -309,7 +307,6 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, switch (wValue) { case USB_PORT_FEAT_SUSPEND: - set_bit(port, &uhci->suspended_ports); SET_RH_PORTSTAT(USBPORTSC_SUSP); OK(0); case USB_PORT_FEAT_RESET: @@ -343,8 +340,11 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, CLR_RH_PORTSTAT(USBPORTSC_PEC); OK(0); case USB_PORT_FEAT_SUSPEND: - if (test_bit(port, &uhci->suspended_ports) && - !test_and_set_bit(port, + if (!(inw(port_addr) & USBPORTSC_SUSP)) { + + /* Make certain the port isn't suspended */ + uhci_finish_suspend(uhci, port, port_addr); + } else if (!test_and_set_bit(port, &uhci->resuming_ports)) { SET_RH_PORTSTAT(USBPORTSC_RD); diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 5246b35301de..650103bc9618 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -200,45 +200,41 @@ config USB_POWERMATE To compile this driver as a module, choose M here: the module will be called powermate. -config USB_MTOUCH - tristate "MicroTouch USB Touchscreen Driver" +config USB_TOUCHSCREEN + tristate "USB Touchscreen Driver" depends on USB && INPUT ---help--- - Say Y here if you want to use a MicroTouch (Now 3M) USB - Touchscreen controller. - - See for additional information. - - To compile this driver as a module, choose M here: the - module will be called mtouchusb. - -config USB_ITMTOUCH - tristate "ITM Touch USB Touchscreen Driver" - depends on USB && INPUT - ---help--- - Say Y here if you want to use a ITM Touch USB - Touchscreen controller. - - This touchscreen is used in LG 1510SF monitors. - - To compile this driver as a module, choose M here: the - module will be called itmtouch. - -config USB_EGALAX - tristate "eGalax TouchKit USB Touchscreen Driver" - depends on USB && INPUT - ---help--- - Say Y here if you want to use a eGalax TouchKit USB - Touchscreen controller. - - The driver has been tested on a Xenarc 700TSV monitor - with eGalax touchscreen. + USB Touchscreen driver for: + - eGalax Touchkit USB + - PanJit TouchSet USB + - 3M MicroTouch USB + - ITM Have a look at for a usage description and the required user-space stuff. To compile this driver as a module, choose M here: the - module will be called touchkitusb. + module will be called usbtouchscreen. + +config USB_TOUCHSCREEN_EGALAX + default y + bool "eGalax device support" if EMBEDDED + depends on USB_TOUCHSCREEN + +config USB_TOUCHSCREEN_PANJIT + default y + bool "PanJit device support" if EMBEDDED + depends on USB_TOUCHSCREEN + +config USB_TOUCHSCREEN_3M + default y + bool "3M/Microtouch device support" if EMBEDDED + depends on USB_TOUCHSCREEN + +config USB_TOUCHSCREEN_ITM + default y + bool "ITM device support" if EMBEDDED + depends on USB_TOUCHSCREEN config USB_YEALINK tristate "Yealink usb-p1k voip phone" diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index d512d9f488fe..764114529c56 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o obj-$(CONFIG_USB_EGALAX) += touchkitusb.o +obj-$(CONFIG_USB_TOUCHSCREEN) += usbtouchscreen.o obj-$(CONFIG_USB_POWERMATE) += powermate.o obj-$(CONFIG_USB_WACOM) += wacom.o obj-$(CONFIG_USB_ACECAD) += acecad.o diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index d4bf1701046b..f419bd82ab7f 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1372,6 +1372,11 @@ void hid_close(struct hid_device *hid) usb_kill_urb(hid->urbin); } +#define USB_VENDOR_ID_PANJIT 0x134c + +#define USB_VENDOR_ID_SILVERCREST 0x062a +#define USB_DEVICE_ID_SILVERCREST_KB 0x0201 + /* * Initialize all reports */ @@ -1655,9 +1660,12 @@ static const struct hid_blacklist { { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 2, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 3, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 4, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_CINTIQ, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF + 3, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, @@ -1675,6 +1683,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_HP, USB_DEVICE_ID_HP_USBHUB_KB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TANGTOP, USB_DEVICE_ID_TANGTOP_USBPS2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_SILVERCREST, USB_DEVICE_ID_SILVERCREST_KB, HID_QUIRK_NOGET }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_POWERMOUSE, HID_QUIRK_2WHEEL_POWERMOUSE }, { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, @@ -1701,6 +1710,11 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE }, + { 0, 0 } }; diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 72e698658b53..d5c91ee67991 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -34,12 +34,6 @@ #include "hid.h" -/* Drivers' initializing functions */ -extern int hid_lgff_init(struct hid_device* hid); -extern int hid_lg3d_init(struct hid_device* hid); -extern int hid_pid_init(struct hid_device* hid); -extern int hid_tmff_init(struct hid_device* hid); - /* * This table contains pointers to initializers. To add support for new * devices, you need to add the USB vendor and product ids here. diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c index cb0d80f49252..25bc85f8ce39 100644 --- a/drivers/usb/input/hid-input.c +++ b/drivers/usb/input/hid-input.c @@ -510,7 +510,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x025: map_key_clear(KEY_TV); break; case 0x026: map_key_clear(KEY_MENU); break; case 0x031: map_key_clear(KEY_AUDIO); break; - case 0x032: map_key_clear(KEY_SUBTITLE); break; + case 0x032: map_key_clear(KEY_TEXT); break; case 0x033: map_key_clear(KEY_LAST); break; case 0x047: map_key_clear(KEY_MP3); break; case 0x048: map_key_clear(KEY_DVD); break; diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 4e1b784fe527..9c62837b5b89 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -533,3 +533,8 @@ static inline int hid_ff_event(struct hid_device *hid, struct input_dev *input, return hid->ff_event(hid, input, type, code, value); return -ENOSYS; } + +int hid_lgff_init(struct hid_device* hid); +int hid_tmff_init(struct hid_device* hid); +int hid_pid_init(struct hid_device* hid); + diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c index b4a051b549d1..3d911976f378 100644 --- a/drivers/usb/input/keyspan_remote.c +++ b/drivers/usb/input/keyspan_remote.c @@ -297,6 +297,8 @@ static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs) remote->data.bits_left -= 6; } else { err("%s - Error in message, invalid toggle.\n", __FUNCTION__); + remote->stage = 0; + return; } keyspan_load_tester(remote, 5); diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c new file mode 100644 index 000000000000..e9a07c1e905b --- /dev/null +++ b/drivers/usb/input/usbtouchscreen.c @@ -0,0 +1,605 @@ +/****************************************************************************** + * usbtouchscreen.c + * Driver for USB Touchscreens, supporting those devices: + * - eGalax Touchkit + * - 3M/Microtouch + * - ITM + * - PanJit TouchSet + * + * Copyright (C) 2004-2006 by Daniel Ritz + * Copyright (C) by Todd E. Johnson (mtouchusb.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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Driver is based on touchkitusb.c + * - ITM parts are from itmtouch.c + * - 3M parts are from mtouchusb.c + * - PanJit parts are from an unmerged driver by Lanslott Gish + * + *****************************************************************************/ + +//#define DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DRIVER_VERSION "v0.3" +#define DRIVER_AUTHOR "Daniel Ritz " +#define DRIVER_DESC "USB Touchscreen Driver" + +static int swap_xy; +module_param(swap_xy, bool, 0644); +MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped."); + +/* device specifc data/functions */ +struct usbtouch_usb; +struct usbtouch_device_info { + int min_xc, max_xc; + int min_yc, max_yc; + int min_press, max_press; + int rept_size; + int flags; + + void (*process_pkt) (struct usbtouch_usb *usbtouch, struct pt_regs *regs, unsigned char *pkt, int len); + int (*read_data) (unsigned char *pkt, int *x, int *y, int *touch, int *press); + int (*init) (struct usbtouch_usb *usbtouch); +}; + +#define USBTOUCH_FLG_BUFFER 0x01 + + +/* a usbtouch device */ +struct usbtouch_usb { + unsigned char *data; + dma_addr_t data_dma; + unsigned char *buffer; + int buf_len; + struct urb *irq; + struct usb_device *udev; + struct input_dev *input; + struct usbtouch_device_info *type; + char name[128]; + char phys[64]; +}; + +static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, + struct pt_regs *regs, unsigned char *pkt, int len); + +/* device types */ +enum { + DEVTPYE_DUMMY = -1, + DEVTYPE_EGALAX, + DEVTYPE_PANJIT, + DEVTYPE_3M, + DEVTYPE_ITM, +}; + +static struct usb_device_id usbtouch_devices[] = { +#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX + {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX}, + {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX}, + {USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX}, + {USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX}, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT + {USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT}, + {USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT}, + {USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT}, + {USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT}, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_3M + {USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M}, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_ITM + {USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM}, +#endif + + {} +}; + + +/***************************************************************************** + * eGalax part + */ + +#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX + +#define EGALAX_PKT_TYPE_MASK 0xFE +#define EGALAX_PKT_TYPE_REPT 0x80 +#define EGALAX_PKT_TYPE_DIAG 0x0A + +static int egalax_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +{ + if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT) + return 0; + + *x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F); + *y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F); + *touch = pkt[0] & 0x01; + + return 1; + +} + +static int egalax_get_pkt_len(unsigned char *buf) +{ + switch (buf[0] & EGALAX_PKT_TYPE_MASK) { + case EGALAX_PKT_TYPE_REPT: + return 5; + + case EGALAX_PKT_TYPE_DIAG: + return buf[1] + 2; + } + + return 0; +} + +static void egalax_process(struct usbtouch_usb *usbtouch, struct pt_regs *regs, + unsigned char *pkt, int len) +{ + unsigned char *buffer; + int pkt_len, buf_len, pos; + + /* if the buffer contains data, append */ + if (unlikely(usbtouch->buf_len)) { + int tmp; + + /* if only 1 byte in buffer, add another one to get length */ + if (usbtouch->buf_len == 1) + usbtouch->buffer[1] = pkt[0]; + + pkt_len = egalax_get_pkt_len(usbtouch->buffer); + + /* unknown packet: drop everything */ + if (!pkt_len) + return; + + /* append, process */ + tmp = pkt_len - usbtouch->buf_len; + memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp); + usbtouch_process_pkt(usbtouch, regs, usbtouch->buffer, pkt_len); + + buffer = pkt + tmp; + buf_len = len - tmp; + } else { + buffer = pkt; + buf_len = len; + } + + /* only one byte left in buffer */ + if (unlikely(buf_len == 1)) { + usbtouch->buffer[0] = buffer[0]; + usbtouch->buf_len = 1; + return; + } + + /* loop over the buffer */ + pos = 0; + while (pos < buf_len) { + /* get packet len */ + pkt_len = egalax_get_pkt_len(buffer + pos); + + /* unknown packet: drop everything */ + if (unlikely(!pkt_len)) + return; + + /* full packet: process */ + if (likely(pkt_len <= buf_len)) { + usbtouch_process_pkt(usbtouch, regs, buffer + pos, pkt_len); + } else { + /* incomplete packet: save in buffer */ + memcpy(usbtouch->buffer, buffer + pos, buf_len - pos); + usbtouch->buf_len = buf_len - pos; + } + pos += pkt_len; + } +} +#endif + + +/***************************************************************************** + * PanJit Part + */ +#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT +static int panjit_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +{ + *x = ((pkt[2] & 0x0F) << 8) | pkt[1]; + *y = ((pkt[4] & 0x0F) << 8) | pkt[3]; + *touch = pkt[0] & 0x01; + + return 1; +} +#endif + + +/***************************************************************************** + * 3M/Microtouch Part + */ +#ifdef CONFIG_USB_TOUCHSCREEN_3M + +#define MTOUCHUSB_ASYNC_REPORT 1 +#define MTOUCHUSB_RESET 7 +#define MTOUCHUSB_REQ_CTRLLR_ID 10 + +static int mtouch_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +{ + *x = (pkt[8] << 8) | pkt[7]; + *y = (pkt[10] << 8) | pkt[9]; + *touch = (pkt[2] & 0x40) ? 1 : 0; + + return 1; +} + +static int mtouch_init(struct usbtouch_usb *usbtouch) +{ + int ret; + + ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), + MTOUCHUSB_RESET, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d", + __FUNCTION__, ret); + if (ret < 0) + return ret; + + ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0), + MTOUCHUSB_ASYNC_REPORT, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", + __FUNCTION__, ret); + if (ret < 0) + return ret; + + return 0; +} +#endif + + +/***************************************************************************** + * ITM Part + */ +#ifdef CONFIG_USB_TOUCHSCREEN_ITM +static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +{ + *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); + *x = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); + *press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F); + *touch = ~pkt[7] & 0x20; + + return 1; +} +#endif + + +/***************************************************************************** + * the different device descriptors + */ +static struct usbtouch_device_info usbtouch_dev_info[] = { +#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX + [DEVTYPE_EGALAX] = { + .min_xc = 0x0, + .max_xc = 0x07ff, + .min_yc = 0x0, + .max_yc = 0x07ff, + .rept_size = 16, + .flags = USBTOUCH_FLG_BUFFER, + .process_pkt = egalax_process, + .read_data = egalax_read_data, + }, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT + [DEVTYPE_PANJIT] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .rept_size = 8, + .read_data = panjit_read_data, + }, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_3M + [DEVTYPE_3M] = { + .min_xc = 0x0, + .max_xc = 0x4000, + .min_yc = 0x0, + .max_yc = 0x4000, + .rept_size = 11, + .read_data = mtouch_read_data, + .init = mtouch_init, + }, +#endif + +#ifdef CONFIG_USB_TOUCHSCREEN_ITM + [DEVTYPE_ITM] = { + .min_xc = 0x0, + .max_xc = 0x0fff, + .min_yc = 0x0, + .max_yc = 0x0fff, + .max_press = 0xff, + .rept_size = 8, + .read_data = itm_read_data, + }, +#endif +}; + + +/***************************************************************************** + * Generic Part + */ +static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch, + struct pt_regs *regs, unsigned char *pkt, int len) +{ + int x, y, touch, press; + struct usbtouch_device_info *type = usbtouch->type; + + if (!type->read_data(pkt, &x, &y, &touch, &press)) + return; + + input_regs(usbtouch->input, regs); + input_report_key(usbtouch->input, BTN_TOUCH, touch); + + if (swap_xy) { + input_report_abs(usbtouch->input, ABS_X, y); + input_report_abs(usbtouch->input, ABS_Y, x); + } else { + input_report_abs(usbtouch->input, ABS_X, x); + input_report_abs(usbtouch->input, ABS_Y, y); + } + if (type->max_press) + input_report_abs(usbtouch->input, ABS_PRESSURE, press); + input_sync(usbtouch->input); +} + + +static void usbtouch_irq(struct urb *urb, struct pt_regs *regs) +{ + struct usbtouch_usb *usbtouch = urb->context; + int retval; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ETIMEDOUT: + /* this urb is timing out */ + dbg("%s - urb timed out - was the device unplugged?", + __FUNCTION__); + return; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", + __FUNCTION__, urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", + __FUNCTION__, urb->status); + goto exit; + } + + usbtouch->type->process_pkt(usbtouch, regs, usbtouch->data, urb->actual_length); + +exit: + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) + err("%s - usb_submit_urb failed with result: %d", + __FUNCTION__, retval); +} + +static int usbtouch_open(struct input_dev *input) +{ + struct usbtouch_usb *usbtouch = input->private; + + usbtouch->irq->dev = usbtouch->udev; + + if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void usbtouch_close(struct input_dev *input) +{ + struct usbtouch_usb *usbtouch = input->private; + + usb_kill_urb(usbtouch->irq); +} + + +static void usbtouch_free_buffers(struct usb_device *udev, + struct usbtouch_usb *usbtouch) +{ + if (usbtouch->data) + usb_buffer_free(udev, usbtouch->type->rept_size, + usbtouch->data, usbtouch->data_dma); + kfree(usbtouch->buffer); +} + + +static int usbtouch_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usbtouch_usb *usbtouch; + struct input_dev *input_dev; + struct usb_host_interface *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_device *udev = interface_to_usbdev(intf); + struct usbtouch_device_info *type; + int err; + + interface = intf->cur_altsetting; + endpoint = &interface->endpoint[0].desc; + + usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!usbtouch || !input_dev) + goto out_free; + + type = &usbtouch_dev_info[id->driver_info]; + usbtouch->type = type; + if (!type->process_pkt) + type->process_pkt = usbtouch_process_pkt; + + usbtouch->data = usb_buffer_alloc(udev, type->rept_size, + SLAB_KERNEL, &usbtouch->data_dma); + if (!usbtouch->data) + goto out_free; + + if (type->flags & USBTOUCH_FLG_BUFFER) { + usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL); + if (!usbtouch->buffer) + goto out_free_buffers; + } + + usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL); + if (!usbtouch->irq) { + dbg("%s - usb_alloc_urb failed: usbtouch->irq", __FUNCTION__); + goto out_free_buffers; + } + + usbtouch->udev = udev; + usbtouch->input = input_dev; + + if (udev->manufacturer) + strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name)); + + if (udev->product) { + if (udev->manufacturer) + strlcat(usbtouch->name, " ", sizeof(usbtouch->name)); + strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name)); + } + + if (!strlen(usbtouch->name)) + snprintf(usbtouch->name, sizeof(usbtouch->name), + "USB Touchscreen %04x:%04x", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); + + usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys)); + strlcpy(usbtouch->phys, "/input0", sizeof(usbtouch->phys)); + + input_dev->name = usbtouch->name; + input_dev->phys = usbtouch->phys; + usb_to_input_id(udev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = usbtouch; + input_dev->open = usbtouch_open; + input_dev->close = usbtouch_close; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0); + input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0); + if (type->max_press) + input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, + type->max_press, 0, 0); + + usb_fill_int_urb(usbtouch->irq, usbtouch->udev, + usb_rcvintpipe(usbtouch->udev, 0x81), + usbtouch->data, type->rept_size, + usbtouch_irq, usbtouch, endpoint->bInterval); + + usbtouch->irq->transfer_dma = usbtouch->data_dma; + usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + /* device specific init */ + if (type->init) { + err = type->init(usbtouch); + if (err) { + dbg("%s - type->init() failed, err: %d", __FUNCTION__, err); + goto out_free_buffers; + } + } + + err = input_register_device(usbtouch->input); + if (err) { + dbg("%s - input_register_device failed, err: %d", __FUNCTION__, err); + goto out_free_buffers; + } + + usb_set_intfdata(intf, usbtouch); + + return 0; + +out_free_buffers: + usbtouch_free_buffers(udev, usbtouch); +out_free: + input_free_device(input_dev); + kfree(usbtouch); + return -ENOMEM; +} + +static void usbtouch_disconnect(struct usb_interface *intf) +{ + struct usbtouch_usb *usbtouch = usb_get_intfdata(intf); + + dbg("%s - called", __FUNCTION__); + + if (!usbtouch) + return; + + dbg("%s - usbtouch is initialized, cleaning up", __FUNCTION__); + usb_set_intfdata(intf, NULL); + usb_kill_urb(usbtouch->irq); + input_unregister_device(usbtouch->input); + usb_free_urb(usbtouch->irq); + usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); + kfree(usbtouch); +} + +MODULE_DEVICE_TABLE(usb, usbtouch_devices); + +static struct usb_driver usbtouch_driver = { + .name = "usbtouchscreen", + .probe = usbtouch_probe, + .disconnect = usbtouch_disconnect, + .id_table = usbtouch_devices, +}; + +static int __init usbtouch_init(void) +{ + return usb_register(&usbtouch_driver); +} + +static void __exit usbtouch_cleanup(void) +{ + usb_deregister(&usbtouch_driver); +} + +module_init(usbtouch_init); +module_exit(usbtouch_cleanup); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_ALIAS("touchkitusb"); +MODULE_ALIAS("itmtouch"); +MODULE_ALIAS("mtouchusb"); diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c index d3e15df9e815..cf84c6096f29 100644 --- a/drivers/usb/input/wacom.c +++ b/drivers/usb/input/wacom.c @@ -9,7 +9,7 @@ * Copyright (c) 2000 Daniel Egger * Copyright (c) 2001 Frederic Lepied * Copyright (c) 2004 Panagiotis Issaris - * Copyright (c) 2002-2005 Ping Cheng + * Copyright (c) 2002-2006 Ping Cheng * * ChangeLog: * v0.1 (vp) - Initial release @@ -56,6 +56,8 @@ * - Merged wacom_intuos3_irq into wacom_intuos_irq * v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc. * - Report Device IDs + * v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19 + * - Minor data report fix */ /* @@ -78,7 +80,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.44" +#define DRIVER_VERSION "v1.45" #define DRIVER_AUTHOR "Vojtech Pavlik " #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" #define DRIVER_LICENSE "GPL" @@ -99,6 +101,8 @@ enum { PL, INTUOS, INTUOS3, + INTUOS312, + INTUOS319, CINTIQ, MAX_TYPE }; @@ -127,7 +131,19 @@ struct wacom { char phys[32]; }; +#define USB_REQ_GET_REPORT 0x01 #define USB_REQ_SET_REPORT 0x09 + +static int usb_get_report(struct usb_interface *intf, unsigned char type, + unsigned char id, void *buf, int size) +{ + return usb_control_msg(interface_to_usbdev(intf), + usb_rcvctrlpipe(interface_to_usbdev(intf), 0), + USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber, + buf, size, 100); +} + static int usb_set_report(struct usb_interface *intf, unsigned char type, unsigned char id, void *buf, int size) { @@ -206,7 +222,8 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs) wacom->tool[1] = BTN_TOOL_PEN; id = STYLUS_DEVICE_ID; } - input_report_key(dev, wacom->tool[1], id); /* report in proximity for tool */ + input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */ + input_report_abs(dev, ABS_MISC, id); /* report tool id */ input_report_abs(dev, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); input_report_abs(dev, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); input_report_abs(dev, ABS_PRESSURE, pressure); @@ -239,7 +256,7 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) struct wacom *wacom = urb->context; unsigned char *data = wacom->data; struct input_dev *dev = wacom->dev; - int retval; + int retval, id; switch (urb->status) { case 0: @@ -263,12 +280,15 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs) input_regs(dev, regs); if (data[1] & 0x04) { - input_report_key(dev, BTN_TOOL_RUBBER, (data[1] & 0x20) ? ERASER_DEVICE_ID : 0); + input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20); input_report_key(dev, BTN_TOUCH, data[1] & 0x08); + id = ERASER_DEVICE_ID; } else { - input_report_key(dev, BTN_TOOL_PEN, (data[1] & 0x20) ? STYLUS_DEVICE_ID : 0); + input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20); input_report_key(dev, BTN_TOUCH, data[1] & 0x01); + id = STYLUS_DEVICE_ID; } + input_report_abs(dev, ABS_MISC, id); /* report tool id */ input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[2])); input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[4])); input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6])); @@ -312,7 +332,8 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs) } input_regs(dev, regs); - input_report_key(dev, BTN_TOOL_PEN, STYLUS_DEVICE_ID); + input_report_key(dev, BTN_TOOL_PEN, 1); + input_report_abs(dev, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */ input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[1])); input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[3])); input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127); @@ -350,6 +371,8 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) goto exit; } + if (data[0] == 99) return; /* for Volito tablets */ + if (data[0] != 2) { dbg("wacom_graphire_irq: received unknown report #%d", data[0]); goto exit; @@ -374,10 +397,10 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) case 2: /* Mouse with wheel */ input_report_key(dev, BTN_MIDDLE, data[1] & 0x04); if (wacom->features->type == WACOM_G4) { - rw = data[7] & 0x04 ? -(data[7] & 0x03) : (data[7] & 0x03); - input_report_rel(dev, REL_WHEEL, rw); + rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03); + input_report_rel(dev, REL_WHEEL, -rw); } else - input_report_rel(dev, REL_WHEEL, (signed char) data[6]); + input_report_rel(dev, REL_WHEEL, -(signed char) data[6]); /* fall through */ case 3: /* Mouse without wheel */ @@ -406,39 +429,27 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs) } } - input_report_key(dev, wacom->tool[0], (data[1] & 0x10) ? id : 0); + if (data[1] & 0x10) + input_report_abs(dev, ABS_MISC, id); /* report tool id */ + else + input_report_abs(dev, ABS_MISC, 0); /* reset tool id */ + input_report_key(dev, wacom->tool[0], data[1] & 0x10); input_sync(dev); /* send pad data */ if (wacom->features->type == WACOM_G4) { - /* fist time sending pad data */ - if (wacom->tool[1] != BTN_TOOL_FINGER) { - wacom->id[1] = 0; - wacom->serial[1] = (data[7] & 0x38) >> 2; - } - if (data[7] & 0xf8) { + if ((wacom->serial[1] & 0xc0) != (data[7] & 0xf8)) { + wacom->id[1] = 1; + wacom->serial[1] = (data[7] & 0xf8); input_report_key(dev, BTN_0, (data[7] & 0x40)); input_report_key(dev, BTN_4, (data[7] & 0x80)); - if (((data[7] & 0x38) >> 2) == (wacom->serial[1] & 0x0e)) - /* alter REL_WHEEL value so X apps can get it */ - wacom->serial[1] += (wacom->serial[1] & 0x01) ? -1 : 1; - else - wacom->serial[1] = (data[7] & 0x38 ) >> 2; - - /* don't alter the value when there is no wheel event */ - if (wacom->serial[1] == 1) - wacom->serial[1] = 0; - rw = wacom->serial[1]; - rw = (rw & 0x08) ? -(rw & 0x07) : (rw & 0x07); + rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); input_report_rel(dev, REL_WHEEL, rw); - wacom->tool[1] = BTN_TOOL_FINGER; - wacom->id[1] = data[7] & 0xf8; - input_report_key(dev, wacom->tool[1], 0xf0); + input_report_key(dev, BTN_TOOL_FINGER, 0xf0); input_event(dev, EV_MSC, MSC_SERIAL, 0xf0); } else if (wacom->id[1]) { wacom->id[1] = 0; - wacom->serial[1] = 0; - input_report_key(dev, wacom->tool[1], 0); + input_report_key(dev, BTN_TOOL_FINGER, 0); input_event(dev, EV_MSC, MSC_SERIAL, 0xf0); } input_sync(dev); @@ -516,21 +527,31 @@ static int wacom_intuos_inout(struct urb *urb) default: /* Unknown tool */ wacom->tool[idx] = BTN_TOOL_PEN; } - input_report_key(dev, wacom->tool[idx], wacom->id[idx]); - input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - input_sync(dev); + if(!((wacom->tool[idx] == BTN_TOOL_LENS) && + ((wacom->features->type == INTUOS312) + || (wacom->features->type == INTUOS319)))) { + input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */ + input_report_key(dev, wacom->tool[idx], 1); + input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + input_sync(dev); + } return 1; } /* Exit report */ if ((data[1] & 0xfe) == 0x80) { input_report_key(dev, wacom->tool[idx], 0); + input_report_abs(dev, ABS_MISC, 0); /* reset tool id */ input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); input_sync(dev); return 1; } - return 0; + if((wacom->tool[idx] == BTN_TOOL_LENS) && ((wacom->features->type == INTUOS312) + || (wacom->features->type == INTUOS319))) + return 1; + else + return 0; } static void wacom_intuos_general(struct urb *urb) @@ -600,10 +621,9 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) /* pad packets. Works as a second tool and is always in prox */ if (data[0] == 12) { /* initiate the pad as a device */ - if (wacom->tool[1] != BTN_TOOL_FINGER) { + if (wacom->tool[1] != BTN_TOOL_FINGER) wacom->tool[1] = BTN_TOOL_FINGER; - input_report_key(dev, wacom->tool[1], 1); - } + input_report_key(dev, BTN_0, (data[5] & 0x01)); input_report_key(dev, BTN_1, (data[5] & 0x02)); input_report_key(dev, BTN_2, (data[5] & 0x04)); @@ -614,6 +634,11 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) input_report_key(dev, BTN_7, (data[6] & 0x08)); input_report_abs(dev, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); input_report_abs(dev, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); + + if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2]) + input_report_key(dev, wacom->tool[1], 1); + else + input_report_key(dev, wacom->tool[1], 0); input_event(dev, EV_MSC, MSC_SERIAL, 0xffffffff); input_sync(dev); goto exit; @@ -676,8 +701,8 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) input_report_key(dev, BTN_LEFT, data[8] & 0x04); input_report_key(dev, BTN_MIDDLE, data[8] & 0x08); input_report_key(dev, BTN_RIGHT, data[8] & 0x10); - input_report_rel(dev, REL_WHEEL, ((data[8] & 0x02) >> 1) - - (data[8] & 0x01)); + input_report_rel(dev, REL_WHEEL, (data[8] & 0x01) + - ((data[8] & 0x02) >> 1)); /* I3 2D mouse side buttons */ if (wacom->features->type == INTUOS3) { @@ -695,7 +720,8 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs) } } - input_report_key(dev, wacom->tool[idx], wacom->id[idx]); + input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */ + input_report_key(dev, wacom->tool[idx], 1); input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]); input_sync(dev); @@ -733,7 +759,8 @@ static struct wacom_features wacom_features[] = { { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_pl_irq }, { "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_pl_irq }, { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq }, - { "Wacom PL710", 8, 34080, 27660, 511, 32, PL, wacom_pl_irq }, + { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_pl_irq }, + { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq }, { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_pl_irq }, { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PL, wacom_ptu_irq }, { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq }, @@ -744,6 +771,8 @@ static struct wacom_features wacom_features[] = { { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_intuos_irq }, { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_intuos_irq }, { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_intuos_irq }, + { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS312, wacom_intuos_irq }, + { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS319, wacom_intuos_irq }, { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_intuos_irq }, { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_intuos_irq }, { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq }, @@ -779,6 +808,7 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC3) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) }, @@ -788,6 +818,8 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, @@ -820,7 +852,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; struct input_dev *input_dev; - char rep_data[2] = {0x02, 0x02}; + char rep_data[2], limit = 0; wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL); input_dev = input_allocate_device(); @@ -857,6 +889,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i input_set_abs_params(input_dev, ABS_X, 0, wacom->features->x_max, 4, 0); input_set_abs_params(input_dev, ABS_Y, 0, wacom->features->y_max, 4, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0); + input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC); switch (wacom->features->type) { case WACOM_G4: @@ -875,6 +908,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i break; case INTUOS3: + case INTUOS312: + case INTUOS319: case CINTIQ: input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); @@ -916,10 +951,13 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i input_register_device(wacom->dev); - /* ask the tablet to report tablet data */ - usb_set_report(intf, 3, 2, rep_data, 2); - /* repeat once (not sure why the first call often fails) */ - usb_set_report(intf, 3, 2, rep_data, 2); + /* Ask the tablet to report tablet data. Repeat until it succeeds */ + do { + rep_data[0] = 2; + rep_data[1] = 2; + usb_set_report(intf, 3, 2, rep_data, 2); + usb_get_report(intf, 3, 2, rep_data, 2); + } while (rep_data[1] != 2 && limit++ < 5); usb_set_intfdata(intf, wacom); return 0; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 9d59b901841c..ccc5e8238bd8 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -381,6 +381,7 @@ alloc_sglist (int nents, int max, int vary) for (i = 0; i < nents; i++) { char *buf; + unsigned j; buf = kzalloc (size, SLAB_KERNEL); if (!buf) { @@ -391,6 +392,16 @@ alloc_sglist (int nents, int max, int vary) /* kmalloc pages are always physically contiguous! */ sg_init_one(&sg[i], buf, size); + switch (pattern) { + case 0: + /* already zeroed */ + break; + case 1: + for (j = 0; j < size; j++) + *buf++ = (u8) (j % 63); + break; + } + if (vary) { size += vary; size %= max; @@ -425,6 +436,8 @@ static int perform_sglist ( usb_sg_wait (req); retval = req->status; + /* FIXME check resulting data pattern */ + /* FIXME if endpoint halted, clear halt (and log) */ } diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 3094970615cb..12b599a0b539 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -37,7 +37,6 @@ #include "usbnet.h" - /* ASIX AX8817X based USB 2.0 Ethernet Devices */ #define AX_CMD_SET_SW_MII 0x06 @@ -109,7 +108,7 @@ #define AX_EEPROM_MAGIC 0xdeadbeef /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ -struct ax8817x_data { +struct asix_data { u8 multi_filter[AX_MCAST_FILTER_SIZE]; }; @@ -121,7 +120,7 @@ struct ax88172_int_data { u16 res3; } __attribute__ ((packed)); -static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, +static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { return usb_control_msg( @@ -136,7 +135,7 @@ static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, USB_CTRL_GET_TIMEOUT); } -static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, +static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { return usb_control_msg( @@ -151,19 +150,80 @@ static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, USB_CTRL_SET_TIMEOUT); } -static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) +static void asix_async_cmd_callback(struct urb *urb, struct pt_regs *regs) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; if (urb->status < 0) - printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", + printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", urb->status); kfree(req); usb_free_urb(urb); } -static void ax8817x_status(struct usbnet *dev, struct urb *urb) +static inline int asix_set_sw_mii(struct usbnet *dev) +{ + int ret; + ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); + if (ret < 0) + devdbg(dev, "Failed to enable software MII access"); + return ret; +} + +static inline int asix_set_hw_mii(struct usbnet *dev) +{ + int ret; + ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); + if (ret < 0) + devdbg(dev, "Failed to enable hardware MII access"); + return ret; +} + +static inline int asix_get_phyid(struct usbnet *dev) +{ + int ret = 0; + void *buf; + + buf = kmalloc(2, GFP_KERNEL); + if (!buf) + goto out1; + + if ((ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, + 0, 0, 2, buf)) < 2) { + devdbg(dev, "Error reading PHYID register: %02x", ret); + goto out2; + } + ret = *((u8 *)buf + 1); +out2: + kfree(buf); +out1: + return ret; +} + +static int asix_sw_reset(struct usbnet *dev, u8 flags) +{ + int ret; + + ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); + if (ret < 0) + devdbg(dev,"Failed to send software reset: %02x", ret); + + return ret; +} + +static int asix_write_rx_ctl(struct usbnet *dev, u16 mode) +{ + int ret; + + ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); + if (ret < 0) + devdbg(dev, "Failed to write RX_CTL mode: %02x", ret); + + return ret; +} + +static void asix_status(struct usbnet *dev, struct urb *urb) { struct ax88172_int_data *event; int link; @@ -179,12 +239,12 @@ static void ax8817x_status(struct usbnet *dev, struct urb *urb) usbnet_defer_kevent (dev, EVENT_LINK_RESET ); } else netif_carrier_off(dev->net); - devdbg(dev, "ax8817x - Link Status is: %d", link); + devdbg(dev, "Link Status is: %d", link); } } static void -ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, +asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, u16 size, void *data) { struct usb_ctrlrequest *req; @@ -211,7 +271,7 @@ ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), (void *)req, data, size, - ax8817x_async_cmd_callback, req); + asix_async_cmd_callback, req); if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { deverr(dev, "Error submitting the control message: status=%d", @@ -221,10 +281,10 @@ ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, } } -static void ax8817x_set_multicast(struct net_device *net) +static void asix_set_multicast(struct net_device *net) { struct usbnet *dev = netdev_priv(net); - struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; + struct asix_data *data = (struct asix_data *)&dev->data; u8 rx_ctl = 0x8c; if (net->flags & IFF_PROMISC) { @@ -255,53 +315,51 @@ static void ax8817x_set_multicast(struct net_device *net) mc_list = mc_list->next; } - ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, + asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, AX_MCAST_FILTER_SIZE, data->multi_filter); rx_ctl |= 0x10; } - ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); + asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); } -static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc) +static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) { struct usbnet *dev = netdev_priv(netdev); u16 res; - u8 buf[1]; - ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, + asix_set_sw_mii(dev); + asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); + asix_set_hw_mii(dev); return res & 0xffff; } /* same as above, but converts resulting value to cpu byte order */ -static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc) +static int asix_mdio_read_le(struct net_device *netdev, int phy_id, int loc) { - return le16_to_cpu(ax8817x_mdio_read(netdev,phy_id, loc)); + return le16_to_cpu(asix_mdio_read(netdev,phy_id, loc)); } static void -ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) +asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) { struct usbnet *dev = netdev_priv(netdev); u16 res = val; - u8 buf[1]; - ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, &buf); - ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, + asix_set_sw_mii(dev); + asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf); + asix_set_hw_mii(dev); } /* same as above, but converts new value to le16 byte order before writing */ static void -ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) +asix_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) { - ax8817x_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) ); + asix_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) ); } static int ax88172_link_reset(struct usbnet *dev) @@ -312,23 +370,23 @@ static int ax88172_link_reset(struct usbnet *dev) u8 mode; mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; - lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); - adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); + lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); + adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); res = mii_nway_result(lpa|adv); if (res & LPA_DUPLEX) mode |= AX_MEDIUM_FULL_DUPLEX; - ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); return 0; } static void -ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) { struct usbnet *dev = netdev_priv(net); u8 opt; - if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { + if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { wolinfo->supported = 0; wolinfo->wolopts = 0; return; @@ -344,7 +402,7 @@ ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) } static int -ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) { struct usbnet *dev = netdev_priv(net); u8 opt = 0; @@ -357,19 +415,19 @@ ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) if (opt != 0) opt |= AX_MONITOR_MODE; - if (ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, + if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, opt, 0, 0, &buf) < 0) return -EINVAL; return 0; } -static int ax8817x_get_eeprom_len(struct net_device *net) +static int asix_get_eeprom_len(struct net_device *net) { return AX_EEPROM_LEN; } -static int ax8817x_get_eeprom(struct net_device *net, +static int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data) { struct usbnet *dev = netdev_priv(net); @@ -386,14 +444,14 @@ static int ax8817x_get_eeprom(struct net_device *net, /* ax8817x returns 2 bytes from eeprom on read */ for (i=0; i < eeprom->len / 2; i++) { - if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, + if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, eeprom->offset + i, 0, 2, &ebuf[i]) < 0) return -EINVAL; } return 0; } -static void ax8817x_get_drvinfo (struct net_device *net, +static void asix_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) { /* Inherit standard device info */ @@ -401,14 +459,14 @@ static void ax8817x_get_drvinfo (struct net_device *net, info->eedump_len = 0x3e; } -static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd) +static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd) { struct usbnet *dev = netdev_priv(net); return mii_ethtool_gset(&dev->mii,cmd); } -static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) +static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd) { struct usbnet *dev = netdev_priv(net); @@ -418,27 +476,27 @@ static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) /* We need to override some ethtool_ops so we require our own structure so we don't interfere with other usbnet devices that may be connected at the same time. */ -static struct ethtool_ops ax8817x_ethtool_ops = { - .get_drvinfo = ax8817x_get_drvinfo, +static struct ethtool_ops ax88172_ethtool_ops = { + .get_drvinfo = asix_get_drvinfo, .get_link = ethtool_op_get_link, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, - .get_wol = ax8817x_get_wol, - .set_wol = ax8817x_set_wol, - .get_eeprom_len = ax8817x_get_eeprom_len, - .get_eeprom = ax8817x_get_eeprom, - .get_settings = ax8817x_get_settings, - .set_settings = ax8817x_set_settings, + .get_wol = asix_get_wol, + .set_wol = asix_set_wol, + .get_eeprom_len = asix_get_eeprom_len, + .get_eeprom = asix_get_eeprom, + .get_settings = asix_get_settings, + .set_settings = asix_set_settings, }; -static int ax8817x_ioctl (struct net_device *net, struct ifreq *rq, int cmd) +static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) { struct usbnet *dev = netdev_priv(net); return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); } -static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) +static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) { int ret = 0; void *buf; @@ -455,55 +513,39 @@ static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) /* Toggle the GPIOs in a manufacturer/model specific way */ for (i = 2; i >= 0; i--) { - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, (gpio_bits >> (i * 8)) & 0xff, 0, 0, buf)) < 0) goto out2; msleep(5); } - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, - 0x80, 0, 0, buf)) < 0) { - dbg("send AX_CMD_WRITE_RX_CTL failed: %d", ret); + if ((ret = asix_write_rx_ctl(dev,0x80)) < 0) goto out2; - } /* Get the MAC address */ memset(buf, 0, ETH_ALEN); - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, + if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf)) < 0) { dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); goto out2; } memcpy(dev->net->dev_addr, buf, ETH_ALEN); - /* Get the PHY id */ - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, - 0, 0, 2, buf)) < 0) { - dbg("error on read AX_CMD_READ_PHY_ID: %02x", ret); - goto out2; - } else if (ret < 2) { - /* this should always return 2 bytes */ - dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", - ret); - ret = -EIO; - goto out2; - } - /* Initialize MII structure */ dev->mii.dev = dev->net; - dev->mii.mdio_read = ax8817x_mdio_read; - dev->mii.mdio_write = ax8817x_mdio_write; + dev->mii.mdio_read = asix_mdio_read; + dev->mii.mdio_write = asix_mdio_write; dev->mii.phy_id_mask = 0x3f; dev->mii.reg_num_mask = 0x1f; - dev->mii.phy_id = *((u8 *)buf + 1); - dev->net->do_ioctl = ax8817x_ioctl; + dev->mii.phy_id = asix_get_phyid(dev); + dev->net->do_ioctl = asix_ioctl; - dev->net->set_multicast_list = ax8817x_set_multicast; - dev->net->ethtool_ops = &ax8817x_ethtool_ops; + dev->net->set_multicast_list = asix_set_multicast; + dev->net->ethtool_ops = &ax88172_ethtool_ops; - ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); mii_nway_restart(&dev->mii); @@ -515,16 +557,16 @@ out1: } static struct ethtool_ops ax88772_ethtool_ops = { - .get_drvinfo = ax8817x_get_drvinfo, + .get_drvinfo = asix_get_drvinfo, .get_link = ethtool_op_get_link, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, - .get_wol = ax8817x_get_wol, - .set_wol = ax8817x_set_wol, - .get_eeprom_len = ax8817x_get_eeprom_len, - .get_eeprom = ax8817x_get_eeprom, - .get_settings = ax8817x_get_settings, - .set_settings = ax8817x_set_settings, + .get_wol = asix_get_wol, + .set_wol = asix_set_wol, + .get_eeprom_len = asix_get_eeprom_len, + .get_eeprom = asix_get_eeprom, + .get_settings = asix_get_settings, + .set_settings = asix_set_settings, }; static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) @@ -541,62 +583,45 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) goto out1; } - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, + if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, 0x00B0, 0, 0, buf)) < 0) goto out2; msleep(5); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, + if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0x0001, 0, 0, buf)) < 0) { dbg("Select PHY #1 failed: %d", ret); goto out2; } - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, - 0, 0, buf)) < 0) { - dbg("Failed to power down internal PHY: %d", ret); + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPPD)) < 0) goto out2; - } msleep(150); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, - 0, 0, buf)) < 0) { - dbg("Failed to perform software reset: %d", ret); + if ((ret = asix_sw_reset(dev, AX_SWRESET_CLEAR)) < 0) goto out2; - } msleep(150); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, - AX_SWRESET_IPRL | AX_SWRESET_PRL, - 0, 0, buf)) < 0) { - dbg("Failed to set Internal/External PHY reset control: %d", - ret); + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0) goto out2; - } msleep(150); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, - 0x0000, 0, 0, buf)) < 0) { - dbg("Failed to reset RX_CTL: %d", ret); + if ((ret = asix_write_rx_ctl(dev, 0x00)) < 0) goto out2; - } /* Get the MAC address */ memset(buf, 0, ETH_ALEN); - if ((ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, + if ((ret = asix_read_cmd(dev, AX88772_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)) < 0) { dbg("Failed to read MAC address: %d", ret); goto out2; } memcpy(dev->net->dev_addr, buf, ETH_ALEN); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, - 0, 0, 0, buf)) < 0) { - dbg("Enabling software MII failed: %d", ret); + if ((ret = asix_set_sw_mii(dev)) < 0) goto out2; - } - if (((ret = ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, + if (((ret = asix_read_cmd(dev, AX_CMD_READ_MII_REG, 0x0010, 2, 2, buf)) < 0) || (*((u16 *)buf) != 0x003b)) { dbg("Read PHY register 2 must be 0x3b00: %d", ret); @@ -605,74 +630,49 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) /* Initialize MII structure */ dev->mii.dev = dev->net; - dev->mii.mdio_read = ax8817x_mdio_read; - dev->mii.mdio_write = ax8817x_mdio_write; + dev->mii.mdio_read = asix_mdio_read; + dev->mii.mdio_write = asix_mdio_write; dev->mii.phy_id_mask = 0xff; dev->mii.reg_num_mask = 0xff; - dev->net->do_ioctl = ax8817x_ioctl; + dev->net->do_ioctl = asix_ioctl; + dev->mii.phy_id = asix_get_phyid(dev); - /* Get the PHY id */ - if ((ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, - 0, 0, 2, buf)) < 0) { - dbg("Error reading PHY ID: %02x", ret); + if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0) goto out2; - } else if (ret < 2) { - /* this should always return 2 bytes */ - dbg("AX_CMD_READ_PHY_ID returned less than 2 bytes: ret=%02x", - ret); - ret = -EIO; - goto out2; - } - dev->mii.phy_id = *((u8 *)buf + 1); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, - 0, 0, buf)) < 0) { - dbg("Set external PHY reset pin level: %d", ret); - goto out2; - } - msleep(150); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, - AX_SWRESET_IPRL | AX_SWRESET_PRL, - 0, 0, buf)) < 0) { - dbg("Set Internal/External PHY reset control: %d", ret); - goto out2; - } msleep(150); + if ((ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL)) < 0) + goto out2; - dev->net->set_multicast_list = ax8817x_set_multicast; + msleep(150); + + dev->net->set_multicast_list = asix_set_multicast; dev->net->ethtool_ops = &ax88772_ethtool_ops; - ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); - ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, + asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA); mii_nway_restart(&dev->mii); - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, + if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) { dbg("Write medium mode register: %d", ret); goto out2; } - if ((ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, + if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, AX88772_IPG2_DEFAULT, 0, buf)) < 0) { dbg("Write IPG,IPG1,IPG2 failed: %d", ret); goto out2; } - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, &buf)) < 0) { - dbg("Failed to set hardware MII: %02x", ret); + if ((ret = asix_set_hw_mii(dev)) < 0) goto out2; - } /* Set RX_CTL to default values with 2k buffer, and enable cactus */ - if ((ret = - ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, - buf)) < 0) { - dbg("Reset RX_CTL failed: %d", ret); + if ((ret = asix_write_rx_ctl(dev, 0x0088)) < 0) goto out2; - } kfree(buf); @@ -794,23 +794,23 @@ static int ax88772_link_reset(struct usbnet *dev) u16 mode; mode = AX88772_MEDIUM_DEFAULT; - lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); - adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); + lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); + adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); res = mii_nway_result(lpa|adv); if ((res & LPA_DUPLEX) == 0) mode &= ~AX88772_MEDIUM_FULL_DUPLEX; if ((res & LPA_100) == 0) mode &= ~AX88772_MEDIUM_100MB; - ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); return 0; } static const struct driver_info ax8817x_info = { .description = "ASIX AX8817x USB 2.0 Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, + .bind = ax88172_bind, + .status = asix_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, @@ -819,8 +819,8 @@ static const struct driver_info ax8817x_info = { static const struct driver_info dlink_dub_e100_info = { .description = "DLink DUB-E100 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, + .bind = ax88172_bind, + .status = asix_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, @@ -829,8 +829,8 @@ static const struct driver_info dlink_dub_e100_info = { static const struct driver_info netgear_fa120_info = { .description = "Netgear FA-120 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, + .bind = ax88172_bind, + .status = asix_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, @@ -839,8 +839,8 @@ static const struct driver_info netgear_fa120_info = { static const struct driver_info hawking_uf200_info = { .description = "Hawking UF200 USB Ethernet", - .bind = ax8817x_bind, - .status = ax8817x_status, + .bind = ax88172_bind, + .status = asix_status, .link_reset = ax88172_link_reset, .reset = ax88172_link_reset, .flags = FLAG_ETHER, @@ -850,13 +850,12 @@ static const struct driver_info hawking_uf200_info = { static const struct driver_info ax88772_info = { .description = "ASIX AX88772 USB 2.0 Ethernet", .bind = ax88772_bind, - .status = ax8817x_status, + .status = asix_status, .link_reset = ax88772_link_reset, .reset = ax88772_link_reset, .flags = FLAG_ETHER | FLAG_FRAMING_AX, .rx_fixup = ax88772_rx_fixup, .tx_fixup = ax88772_tx_fixup, - .data = 0x00130103, }; static const struct usb_device_id products [] = { diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 5b6675684567..2deb4c01539e 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -262,7 +262,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data) usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), (char *) &pegasus->dr, - &tmp, 1, ctrl_callback, pegasus); + tmp, 1, ctrl_callback, pegasus); add_wait_queue(&pegasus->ctrl_wait, &wait); set_current_state(TASK_UNINTERRUPTIBLE); diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index 49991ac1bf3b..94ddfe16fdda 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -39,6 +39,20 @@ * RNDIS is NDIS remoted over USB. It's a MSFT variant of CDC ACM ... of * course ACM was intended for modems, not Ethernet links! USB's standard * for Ethernet links is "CDC Ethernet", which is significantly simpler. + * + * NOTE that Microsoft's "RNDIS 1.0" specification is incomplete. Issues + * include: + * - Power management in particular relies on information that's scattered + * through other documentation, and which is incomplete or incorrect even + * there. + * - There are various undocumented protocol requirements, such as the + * need to send unused garbage in control-OUT messages. + * - In some cases, MS-Windows will emit undocumented requests; this + * matters more to peripheral implementations than host ones. + * + * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in + * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and + * currently rare) "Ethernet Emulation Model" (EEM). */ /* @@ -72,17 +86,17 @@ struct rndis_msg_hdr { */ #define RNDIS_MSG_PACKET ccpu2(0x00000001) /* 1-N packets */ #define RNDIS_MSG_INIT ccpu2(0x00000002) -#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_INIT_C (RNDIS_MSG_INIT|RNDIS_MSG_COMPLETION) #define RNDIS_MSG_HALT ccpu2(0x00000003) #define RNDIS_MSG_QUERY ccpu2(0x00000004) -#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_QUERY_C (RNDIS_MSG_QUERY|RNDIS_MSG_COMPLETION) #define RNDIS_MSG_SET ccpu2(0x00000005) -#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_SET_C (RNDIS_MSG_SET|RNDIS_MSG_COMPLETION) #define RNDIS_MSG_RESET ccpu2(0x00000006) -#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_RESET_C (RNDIS_MSG_RESET|RNDIS_MSG_COMPLETION) #define RNDIS_MSG_INDICATE ccpu2(0x00000007) #define RNDIS_MSG_KEEPALIVE ccpu2(0x00000008) -#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION) +#define RNDIS_MSG_KEEPALIVE_C (RNDIS_MSG_KEEPALIVE|RNDIS_MSG_COMPLETION) /* codes for "status" field of completion messages */ #define RNDIS_STATUS_SUCCESS ccpu2(0x00000000) @@ -596,13 +610,13 @@ static struct usb_driver rndis_driver = { static int __init rndis_init(void) { - return usb_register(&rndis_driver); + return usb_register(&rndis_driver); } module_init(rndis_init); static void __exit rndis_exit(void) { - usb_deregister(&rndis_driver); + usb_deregister(&rndis_driver); } module_exit(rndis_exit); diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c index fe9b60cd8d95..9b1e4ed1d07e 100644 --- a/drivers/usb/net/zd1201.c +++ b/drivers/usb/net/zd1201.c @@ -1736,6 +1736,7 @@ static const struct iw_handler_def zd1201_iw_handlers = { .standard = (iw_handler *)zd1201_iw_handler, .private = (iw_handler *)zd1201_private_handler, .private_args = (struct iw_priv_args *) zd1201_private_args, + .get_wireless_stats = zd1201_get_wireless_stats, }; static int zd1201_probe(struct usb_interface *interface, @@ -1796,7 +1797,6 @@ static int zd1201_probe(struct usb_interface *interface, zd->dev->open = zd1201_net_open; zd->dev->stop = zd1201_net_stop; zd->dev->get_stats = zd1201_get_stats; - zd->dev->get_wireless_stats = zd1201_get_wireless_stats; zd->dev->wireless_handlers = (struct iw_handler_def *)&zd1201_iw_handlers; zd->dev->hard_start_xmit = zd1201_hard_start_xmit; diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 5a8a2c91c2b2..f96b73f54bf1 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -158,6 +158,15 @@ config USB_SERIAL_FTDI_SIO To compile this driver as a module, choose M here: the module will be called ftdi_sio. +config USB_SERIAL_FUNSOFT + tristate "USB Fundamental Software Dongle Driver" + depends on USB_SERIAL + ---help--- + Say Y here if you want to use the Fundamental Software dongle. + + To compile this driver as a module, choose M here: the + module will be called funsoft. + config USB_SERIAL_VISOR tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver" depends on USB_SERIAL diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index f7fe4172efed..93c21245b1af 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o +obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 167f8ec56131..8023bb7279b1 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -54,7 +54,7 @@ static struct console usbcons; * serial.c code, except that the specifier is "ttyUSB" instead * of "ttyS". */ -static int __init usb_console_setup(struct console *co, char *options) +static int usb_console_setup(struct console *co, char *options) { struct usbcons_info *info = &usbcons_info; int baud = 9600; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f3af81b4dd29..f5851db67f5b 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -489,10 +489,12 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) }, { USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TTUSB_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ECLO_COM_1WIRE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_777_PID) }, { USB_DEVICE(FTDI_VID, FTDI_WESTREX_MODEL_8900F_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PCDJ_DAC2_PID) }, { USB_DEVICE(ICOM_ID1_VID, ICOM_ID1_PID) }, + { USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 8da773c2744d..2155f0e4a378 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -399,6 +399,21 @@ #define FTDI_WESTREX_MODEL_777_PID 0xDC00 /* Model 777 */ #define FTDI_WESTREX_MODEL_8900F_PID 0xDC01 /* Model 8900F */ +/* + * Eclo (http://www.eclo.pt/) product IDs. + * PID 0xEA90 submitted by Martin Grill. + */ +#define FTDI_ECLO_COM_1WIRE_PID 0xEA90 /* COM to 1-Wire USB adaptor */ + +/* + * Papouch products (http://www.papouch.com/) + * Submitted by Folkert van Heusden + */ + +#define PAPOUCH_VID 0x5050 /* Vendor ID */ +#define PAPOUCH_TMU_PID 0x0400 /* TMU USB Thermometer */ + + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c new file mode 100644 index 000000000000..803721b97e2e --- /dev/null +++ b/drivers/usb/serial/funsoft.c @@ -0,0 +1,65 @@ +/* + * Funsoft Serial USB driver + * + * Copyright (C) 2006 Greg Kroah-Hartman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include "usb-serial.h" + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x1404, 0xcddc) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver funsoft_driver = { + .name = "funsoft", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static struct usb_serial_driver funsoft_device = { + .driver = { + .owner = THIS_MODULE, + .name = "funsoft", + }, + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1, +}; + +static int __init funsoft_init(void) +{ + int retval; + + retval = usb_serial_register(&funsoft_device); + if (retval) + return retval; + retval = usb_register(&funsoft_driver); + if (retval) + usb_serial_deregister(&funsoft_device); + return retval; +} + +static void __exit funsoft_exit(void) +{ + usb_deregister(&funsoft_driver); + usb_serial_deregister(&funsoft_device); +} + +module_init(funsoft_init); +module_exit(funsoft_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 495db5755df9..5cf2b80add7a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -28,6 +28,7 @@ 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes wants to send >2000 bytes. + 2006-04-10 v0.4.2 fixed two array overrun errors :-/ Work sponsored by: Sigos GmbH, Germany @@ -582,14 +583,14 @@ static void option_setup_urbs(struct usb_serial *serial) portdata = usb_get_serial_port_data(port); /* Do indat endpoints first */ - for (j = 0; j <= N_IN_URB; ++j) { + for (j = 0; j < N_IN_URB; ++j) { portdata->in_urbs[j] = option_setup_urb (serial, port->bulk_in_endpointAddress, USB_DIR_IN, port, portdata->in_buffer[j], IN_BUFLEN, option_indat_callback); } /* outdat endpoints */ - for (j = 0; j <= N_OUT_URB; ++j) { + for (j = 0; j < N_OUT_URB; ++j) { portdata->out_urbs[j] = option_setup_urb (serial, port->bulk_out_endpointAddress, USB_DIR_OUT, port, portdata->out_buffer[j], OUT_BUFLEN, option_outdat_callback); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index b3014fda645c..ccf746b27d4e 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -78,6 +78,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) }, { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) }, { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) }, + { USB_DEVICE(OTI_VENDOR_ID, OTI_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 77901d143979..09f379b19e98 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -79,3 +79,7 @@ /* USB GSM cable from Speed Dragon Multimedia, Ltd */ #define SPEEDDRAGON_VENDOR_ID 0x0e55 #define SPEEDDRAGON_PRODUCT_ID 0x110b + +/* Ours Technology Inc DKU-5 clone, chipset: Prolific Technology Inc */ +#define OTI_VENDOR_ID 0x0ea0 +#define OTI_PRODUCT_ID 0x6858 diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 097f4e8488fe..071f86a59c08 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -27,10 +27,10 @@ #include #include #include +#include #include #include #include -#include #include #include "usb-serial.h" #include "pl2303.h" @@ -192,7 +192,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) if (!port) return -ENODEV; - if (down_interruptible(&port->sem)) + if (mutex_lock_interruptible(&port->mutex)) return -ERESTARTSYS; ++port->open_count; @@ -219,7 +219,7 @@ static int serial_open (struct tty_struct *tty, struct file * filp) goto bailout_module_put; } - up(&port->sem); + mutex_unlock(&port->mutex); return 0; bailout_module_put: @@ -227,7 +227,7 @@ bailout_module_put: bailout_kref_put: kref_put(&serial->kref, destroy_serial); port->open_count = 0; - up(&port->sem); + mutex_unlock(&port->mutex); return retval; } @@ -240,10 +240,10 @@ static void serial_close(struct tty_struct *tty, struct file * filp) dbg("%s - port %d", __FUNCTION__, port->number); - down(&port->sem); + mutex_lock(&port->mutex); if (port->open_count == 0) { - up(&port->sem); + mutex_unlock(&port->mutex); return; } @@ -262,7 +262,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) module_put(port->serial->type->driver.owner); } - up(&port->sem); + mutex_unlock(&port->mutex); kref_put(&port->serial->kref, destroy_serial); } @@ -783,7 +783,7 @@ int usb_serial_probe(struct usb_interface *interface, port->number = i + serial->minor; port->serial = serial; spin_lock_init(&port->lock); - sema_init(&port->sem, 1); + mutex_init(&port->mutex); INIT_WORK(&port->work, usb_serial_port_softint, port); serial->port[i] = port; } diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index d7d27c3385b3..dc89d8710460 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -16,7 +16,7 @@ #include #include -#include +#include #define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ #define SERIAL_TTY_MINORS 255 /* loads of devices :) */ @@ -31,7 +31,7 @@ * @serial: pointer back to the struct usb_serial owner of this port. * @tty: pointer to the corresponding tty for this port. * @lock: spinlock to grab when updating portions of this structure. - * @sem: semaphore used to synchronize serial_open() and serial_close() + * @mutex: mutex used to synchronize serial_open() and serial_close() * access for this port. * @number: the number of the port (the minor number). * @interrupt_in_buffer: pointer to the interrupt in buffer for this port. @@ -63,7 +63,7 @@ struct usb_serial_port { struct usb_serial * serial; struct tty_struct * tty; spinlock_t lock; - struct semaphore sem; + struct mutex mutex; unsigned char number; unsigned char * interrupt_in_buffer; diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 92be101feba7..be9eec225743 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -48,7 +48,8 @@ config USB_STORAGE_FREECOM config USB_STORAGE_ISD200 bool "ISD-200 USB/ATA Bridge support" - depends on USB_STORAGE && BLK_DEV_IDE + depends on USB_STORAGE + depends on BLK_DEV_IDE=y || BLK_DEV_IDE=USB_STORAGE ---help--- Say Y here if you want to use USB Mass Store devices based on the In-Systems Design ISD-200 USB/ATA bridge. diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 22e9d696fdd2..9060e7137441 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -904,18 +904,6 @@ config FB_MATROX_MULTIHEAD There is no need for enabling 'Matrox multihead support' if you have only one Matrox card in the box. -config FB_RADEON_OLD - tristate "ATI Radeon display support (Old driver)" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES if PPC - help - Choose this option if you want to use an ATI Radeon graphics card as - a framebuffer device. There are both PCI and AGP versions. You - don't need to choose this to run the Radeon in plain VGA mode. - config FB_RADEON tristate "ATI Radeon display support" depends on FB && PCI @@ -973,7 +961,7 @@ config FB_ATY128 config FB_ATY tristate "ATI Mach64 display support" if PCI || ATARI - depends on FB + depends on FB && !SPARC32 select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/Makefile b/drivers/video/Makefile index cb90218515ac..23de3b2c7856 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -39,7 +39,6 @@ obj-$(CONFIG_FB_KYRO) += kyro/ obj-$(CONFIG_FB_SAVAGE) += savage/ obj-$(CONFIG_FB_GEODE) += geode/ obj-$(CONFIG_FB_I810) += vgastate.o -obj-$(CONFIG_FB_RADEON_OLD) += radeonfb.o obj-$(CONFIG_FB_NEOMAGIC) += neofb.o vgastate.o obj-$(CONFIG_FB_VIRGE) += virgefb.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 821c6da8e42c..f7bbff4ddc6a 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -67,6 +67,7 @@ #include #ifdef CONFIG_PPC_PMAC +#include #include #include #include @@ -1748,7 +1749,7 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id * var = default_var; #ifdef CONFIG_PPC_PMAC - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { /* Indicate sleep capability */ if (par->chip_gen == rage_M3) { pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, NULL, 0, 1); @@ -2011,7 +2012,7 @@ static int aty128fb_blank(int blank, struct fb_info *fb) return 0; #ifdef CONFIG_PMAC_BACKLIGHT - if ((_machine == _MACH_Pmac) && blank) + if (machine_is(powermac) && blank) set_backlight_enable(0); #endif /* CONFIG_PMAC_BACKLIGHT */ @@ -2029,7 +2030,7 @@ static int aty128fb_blank(int blank, struct fb_info *fb) aty128_set_lcd_enable(par, par->lcd_on && !blank); } #ifdef CONFIG_PMAC_BACKLIGHT - if ((_machine == _MACH_Pmac) && !blank) + if (machine_is(powermac) && !blank) set_backlight_enable(1); #endif /* CONFIG_PMAC_BACKLIGHT */ return 0; diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index e799fcca365a..d9d7d3c4cae2 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -75,6 +75,7 @@ #include "ati_ids.h" #ifdef __powerpc__ +#include #include #include "../macmodes.h" #endif @@ -2518,7 +2519,7 @@ static int __init aty_init(struct fb_info *info, const char *name) memset(&var, 0, sizeof(var)); #ifdef CONFIG_PPC - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { /* * FIXME: The NVRAM stuff should be put in a Mac-specific file, as it * applies to all Mac video cards @@ -2673,7 +2674,7 @@ static int atyfb_blank(int blank, struct fb_info *info) return 0; #ifdef CONFIG_PMAC_BACKLIGHT - if ((_machine == _MACH_Pmac) && blank > FB_BLANK_NORMAL) + if (machine_is(powermac) && blank > FB_BLANK_NORMAL) set_backlight_enable(0); #elif defined(CONFIG_FB_ATY_GENERIC_LCD) if (par->lcd_table && blank > FB_BLANK_NORMAL && @@ -2705,7 +2706,7 @@ static int atyfb_blank(int blank, struct fb_info *info) aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par); #ifdef CONFIG_PMAC_BACKLIGHT - if ((_machine == _MACH_Pmac) && blank <= FB_BLANK_NORMAL) + if (machine_is(powermac) && blank <= FB_BLANK_NORMAL) set_backlight_enable(1); #elif defined(CONFIG_FB_ATY_GENERIC_LCD) if (par->lcd_table && blank <= FB_BLANK_NORMAL && @@ -3399,7 +3400,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi struct atyfb_par *par; int i, rc = -ENOMEM; - for (i = ARRAY_SIZE(aty_chips); i >= 0; i--) + for (i = ARRAY_SIZE(aty_chips) - 1; i >= 0; i--) if (pdev->device == aty_chips[i].pci_id) break; diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c index 5886a2f1323e..c7091761cef4 100644 --- a/drivers/video/aty/radeon_pm.c +++ b/drivers/video/aty/radeon_pm.c @@ -20,7 +20,7 @@ #include #ifdef CONFIG_PPC_PMAC -#include +#include #include #include #endif @@ -2745,7 +2745,7 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk) rinfo->pm_mode |= radeon_pm_off; } #if defined(CONFIG_PPC_PMAC) - if (_machine == _MACH_Pmac && rinfo->of_node) { + if (machine_is(powermac) && rinfo->of_node) { if (rinfo->is_mobility && rinfo->pm_reg && rinfo->family <= CHIP_FAMILY_RV250) rinfo->pm_mode |= radeon_pm_d2; diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 9d996f2c10d5..b895eaaa73fd 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -43,11 +43,11 @@ config LCD_DEVICE default y config BACKLIGHT_CORGI - tristate "Sharp Corgi Backlight Driver (SL-C7xx Series)" + tristate "Sharp Corgi Backlight Driver (SL Series)" depends on BACKLIGHT_DEVICE && PXA_SHARPSL default y help - If you have a Sharp Zaurus SL-C7xx, say y to enable the + If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the backlight driver. config BACKLIGHT_HP680 diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 151fda8dded0..334b1db1bd7c 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -16,14 +16,12 @@ static ssize_t backlight_show_power(struct class_device *cdev, char *buf) { - int rc; + int rc = -ENXIO; struct backlight_device *bd = to_backlight_device(cdev); down(&bd->sem); - if (likely(bd->props && bd->props->get_power)) - rc = sprintf(buf, "%d\n", bd->props->get_power(bd)); - else - rc = -ENXIO; + if (likely(bd->props)) + rc = sprintf(buf, "%d\n", bd->props->power); up(&bd->sem); return rc; @@ -31,7 +29,7 @@ static ssize_t backlight_show_power(struct class_device *cdev, char *buf) static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count) { - int rc, power; + int rc = -ENXIO, power; char *endp; struct backlight_device *bd = to_backlight_device(cdev); @@ -40,12 +38,13 @@ static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, return -EINVAL; down(&bd->sem); - if (likely(bd->props && bd->props->set_power)) { + if (likely(bd->props)) { pr_debug("backlight: set power to %d\n", power); - bd->props->set_power(bd, power); + bd->props->power = power; + if (likely(bd->props->update_status)) + bd->props->update_status(bd); rc = count; - } else - rc = -ENXIO; + } up(&bd->sem); return rc; @@ -53,14 +52,12 @@ static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf) { - int rc; + int rc = -ENXIO; struct backlight_device *bd = to_backlight_device(cdev); down(&bd->sem); - if (likely(bd->props && bd->props->get_brightness)) - rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd)); - else - rc = -ENXIO; + if (likely(bd->props)) + rc = sprintf(buf, "%d\n", bd->props->brightness); up(&bd->sem); return rc; @@ -68,7 +65,7 @@ static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf) static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count) { - int rc, brightness; + int rc = -ENXIO, brightness; char *endp; struct backlight_device *bd = to_backlight_device(cdev); @@ -77,12 +74,18 @@ static ssize_t backlight_store_brightness(struct class_device *cdev, const char return -EINVAL; down(&bd->sem); - if (likely(bd->props && bd->props->set_brightness)) { - pr_debug("backlight: set brightness to %d\n", brightness); - bd->props->set_brightness(bd, brightness); - rc = count; - } else - rc = -ENXIO; + if (likely(bd->props)) { + if (brightness > bd->props->max_brightness) + rc = -EINVAL; + else { + pr_debug("backlight: set brightness to %d\n", + brightness); + bd->props->brightness = brightness; + if (likely(bd->props->update_status)) + bd->props->update_status(bd); + rc = count; + } + } up(&bd->sem); return rc; @@ -90,14 +93,26 @@ static ssize_t backlight_store_brightness(struct class_device *cdev, const char static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf) { - int rc; + int rc = -ENXIO; struct backlight_device *bd = to_backlight_device(cdev); down(&bd->sem); if (likely(bd->props)) rc = sprintf(buf, "%d\n", bd->props->max_brightness); - else - rc = -ENXIO; + up(&bd->sem); + + return rc; +} + +static ssize_t backlight_show_actual_brightness(struct class_device *cdev, + char *buf) +{ + int rc = -ENXIO; + struct backlight_device *bd = to_backlight_device(cdev); + + down(&bd->sem); + if (likely(bd->props && bd->props->get_brightness)) + rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd)); up(&bd->sem); return rc; @@ -123,7 +138,10 @@ static struct class backlight_class = { static struct class_device_attribute bl_class_device_attributes[] = { DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power), - DECLARE_ATTR(brightness, 0644, backlight_show_brightness, backlight_store_brightness), + DECLARE_ATTR(brightness, 0644, backlight_show_brightness, + backlight_store_brightness), + DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness, + NULL), DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), }; @@ -144,8 +162,12 @@ static int fb_notifier_callback(struct notifier_block *self, bd = container_of(self, struct backlight_device, fb_notif); down(&bd->sem); if (bd->props) - if (!bd->props->check_fb || bd->props->check_fb(evdata->info)) - bd->props->set_power(bd, *(int *)evdata->data); + if (!bd->props->check_fb || + bd->props->check_fb(evdata->info)) { + bd->props->fb_blank = *(int *)evdata->data; + if (likely(bd->props && bd->props->update_status)) + bd->props->update_status(bd); + } up(&bd->sem); return 0; } @@ -231,6 +253,12 @@ void backlight_device_unregister(struct backlight_device *bd) &bl_class_device_attributes[i]); down(&bd->sem); + if (likely(bd->props && bd->props->update_status)) { + bd->props->brightness = 0; + bd->props->power = 0; + bd->props->update_status(bd); + } + bd->props = NULL; up(&bd->sem); diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index d0aaf450e8c7..2ebbfd95145f 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -1,7 +1,7 @@ /* - * Backlight Driver for Sharp Corgi + * Backlight Driver for Sharp Zaurus Handhelds (various models) * - * Copyright (c) 2004-2005 Richard Purdie + * Copyright (c) 2004-2006 Richard Purdie * * Based on Sharp's 2.4 Backlight Driver * @@ -15,80 +15,63 @@ #include #include #include -#include +#include #include #include - #include #include -#define CORGI_DEFAULT_INTENSITY 0x1f -#define CORGI_LIMIT_MASK 0x0b - -static int corgibl_powermode = FB_BLANK_UNBLANK; -static int current_intensity = 0; -static int corgibl_limit = 0; -static void (*corgibl_mach_set_intensity)(int intensity); -static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED; +static int corgibl_intensity; +static DEFINE_MUTEX(bl_mutex); static struct backlight_properties corgibl_data; +static struct backlight_device *corgi_backlight_device; +static struct corgibl_machinfo *bl_machinfo; -static void corgibl_send_intensity(int intensity) +static unsigned long corgibl_flags; +#define CORGIBL_SUSPENDED 0x01 +#define CORGIBL_BATTLOW 0x02 + +static int corgibl_send_intensity(struct backlight_device *bd) { - unsigned long flags; void (*corgi_kick_batt)(void); + int intensity = bd->props->brightness; - if (corgibl_powermode != FB_BLANK_UNBLANK) { + if (bd->props->power != FB_BLANK_UNBLANK) intensity = 0; - } else { - if (corgibl_limit) - intensity &= CORGI_LIMIT_MASK; - } + if (bd->props->fb_blank != FB_BLANK_UNBLANK) + intensity = 0; + if (corgibl_flags & CORGIBL_SUSPENDED) + intensity = 0; + if (corgibl_flags & CORGIBL_BATTLOW) + intensity &= bl_machinfo->limit_mask; - spin_lock_irqsave(&bl_lock, flags); + mutex_lock(&bl_mutex); + bl_machinfo->set_bl_intensity(intensity); + mutex_unlock(&bl_mutex); - corgibl_mach_set_intensity(intensity); - - spin_unlock_irqrestore(&bl_lock, flags); + corgibl_intensity = intensity; corgi_kick_batt = symbol_get(sharpsl_battery_kick); if (corgi_kick_batt) { corgi_kick_batt(); symbol_put(sharpsl_battery_kick); } -} -static void corgibl_blank(int blank) -{ - switch(blank) { - - case FB_BLANK_NORMAL: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_POWERDOWN: - if (corgibl_powermode == FB_BLANK_UNBLANK) { - corgibl_send_intensity(0); - corgibl_powermode = blank; - } - break; - case FB_BLANK_UNBLANK: - if (corgibl_powermode != FB_BLANK_UNBLANK) { - corgibl_powermode = blank; - corgibl_send_intensity(current_intensity); - } - break; - } + return 0; } #ifdef CONFIG_PM static int corgibl_suspend(struct platform_device *dev, pm_message_t state) { - corgibl_blank(FB_BLANK_POWERDOWN); + corgibl_flags |= CORGIBL_SUSPENDED; + corgibl_send_intensity(corgi_backlight_device); return 0; } static int corgibl_resume(struct platform_device *dev) { - corgibl_blank(FB_BLANK_UNBLANK); + corgibl_flags &= ~CORGIBL_SUSPENDED; + corgibl_send_intensity(corgi_backlight_device); return 0; } #else @@ -96,30 +79,15 @@ static int corgibl_resume(struct platform_device *dev) #define corgibl_resume NULL #endif - -static int corgibl_set_power(struct backlight_device *bd, int state) -{ - corgibl_blank(state); - return 0; -} - -static int corgibl_get_power(struct backlight_device *bd) -{ - return corgibl_powermode; -} - -static int corgibl_set_intensity(struct backlight_device *bd, int intensity) -{ - if (intensity > corgibl_data.max_brightness) - intensity = corgibl_data.max_brightness; - corgibl_send_intensity(intensity); - current_intensity=intensity; - return 0; -} - static int corgibl_get_intensity(struct backlight_device *bd) { - return current_intensity; + return corgibl_intensity; +} + +static int corgibl_set_intensity(struct backlight_device *bd) +{ + corgibl_send_intensity(corgi_backlight_device); + return 0; } /* @@ -128,36 +96,38 @@ static int corgibl_get_intensity(struct backlight_device *bd) */ void corgibl_limit_intensity(int limit) { - corgibl_limit = (limit ? 1 : 0); - corgibl_send_intensity(current_intensity); + if (limit) + corgibl_flags |= CORGIBL_BATTLOW; + else + corgibl_flags &= ~CORGIBL_BATTLOW; + corgibl_send_intensity(corgi_backlight_device); } EXPORT_SYMBOL(corgibl_limit_intensity); static struct backlight_properties corgibl_data = { - .owner = THIS_MODULE, - .get_power = corgibl_get_power, - .set_power = corgibl_set_power, + .owner = THIS_MODULE, .get_brightness = corgibl_get_intensity, - .set_brightness = corgibl_set_intensity, + .update_status = corgibl_set_intensity, }; -static struct backlight_device *corgi_backlight_device; - static int __init corgibl_probe(struct platform_device *pdev) { struct corgibl_machinfo *machinfo = pdev->dev.platform_data; + bl_machinfo = machinfo; corgibl_data.max_brightness = machinfo->max_intensity; - corgibl_mach_set_intensity = machinfo->set_bl_intensity; + if (!machinfo->limit_mask) + machinfo->limit_mask = -1; corgi_backlight_device = backlight_device_register ("corgi-bl", NULL, &corgibl_data); if (IS_ERR (corgi_backlight_device)) return PTR_ERR (corgi_backlight_device); - corgibl_set_intensity(NULL, CORGI_DEFAULT_INTENSITY); - corgibl_limit_intensity(0); + corgibl_data.power = FB_BLANK_UNBLANK; + corgibl_data.brightness = machinfo->default_intensity; + corgibl_send_intensity(corgi_backlight_device); printk("Corgi Backlight Driver Initialized.\n"); return 0; @@ -167,8 +137,6 @@ static int corgibl_remove(struct platform_device *dev) { backlight_device_unregister(corgi_backlight_device); - corgibl_set_intensity(NULL, 0); - printk("Corgi Backlight Driver Unloaded\n"); return 0; } diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 95da4c9ed1f1..a71e984c93d4 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -25,66 +25,58 @@ #define HP680_MAX_INTENSITY 255 #define HP680_DEFAULT_INTENSITY 10 -static int hp680bl_powermode = FB_BLANK_UNBLANK; +static int hp680bl_suspended; static int current_intensity = 0; static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED; +static struct backlight_device *hp680_backlight_device; -static void hp680bl_send_intensity(int intensity) +static void hp680bl_send_intensity(struct backlight_device *bd) { unsigned long flags; + u16 v; + int intensity = bd->props->brightness; - if (hp680bl_powermode != FB_BLANK_UNBLANK) + if (bd->props->power != FB_BLANK_UNBLANK) + intensity = 0; + if (bd->props->fb_blank != FB_BLANK_UNBLANK) + intensity = 0; + if (hp680bl_suspended) intensity = 0; spin_lock_irqsave(&bl_lock, flags); - sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS); - spin_unlock_irqrestore(&bl_lock, flags); -} - -static void hp680bl_blank(int blank) -{ - u16 v; - - switch(blank) { - - case FB_BLANK_NORMAL: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_POWERDOWN: - if (hp680bl_powermode == FB_BLANK_UNBLANK) { - hp680bl_send_intensity(0); - hp680bl_powermode = blank; - sh_dac_disable(DAC_LCD_BRIGHTNESS); - v = inw(HD64461_GPBDR); - v |= HD64461_GPBDR_LCDOFF; - outw(v, HD64461_GPBDR); - } - break; - case FB_BLANK_UNBLANK: - if (hp680bl_powermode != FB_BLANK_UNBLANK) { - sh_dac_enable(DAC_LCD_BRIGHTNESS); - v = inw(HD64461_GPBDR); - v &= ~HD64461_GPBDR_LCDOFF; - outw(v, HD64461_GPBDR); - hp680bl_powermode = blank; - hp680bl_send_intensity(current_intensity); - } - break; + if (intensity && current_intensity == 0) { + sh_dac_enable(DAC_LCD_BRIGHTNESS); + v = inw(HD64461_GPBDR); + v &= ~HD64461_GPBDR_LCDOFF; + outw(v, HD64461_GPBDR); + sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS); + } else if (intensity == 0 && current_intensity != 0) { + sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS); + sh_dac_disable(DAC_LCD_BRIGHTNESS); + v = inw(HD64461_GPBDR); + v |= HD64461_GPBDR_LCDOFF; + outw(v, HD64461_GPBDR); + } else if (intensity) { + sh_dac_output(255-(u8)intensity, DAC_LCD_BRIGHTNESS); } + spin_unlock_irqrestore(&bl_lock, flags); + + current_intensity = intensity; } + #ifdef CONFIG_PM -static int hp680bl_suspend(struct device *dev, pm_message_t state, u32 level) +static int hp680bl_suspend(struct platform_device *dev, pm_message_t state) { - if (level == SUSPEND_POWER_DOWN) - hp680bl_blank(FB_BLANK_POWERDOWN); + hp680bl_suspended = 1; + hp680bl_send_intensity(hp680_backlight_device); return 0; } -static int hp680bl_resume(struct device *dev, u32 level) +static int hp680bl_resume(struct platform_device *dev) { - if (level == RESUME_POWER_ON) - hp680bl_blank(FB_BLANK_UNBLANK); + hp680bl_suspended = 0; + hp680bl_send_intensity(hp680_backlight_device); return 0; } #else @@ -92,24 +84,9 @@ static int hp680bl_resume(struct device *dev, u32 level) #define hp680bl_resume NULL #endif - -static int hp680bl_set_power(struct backlight_device *bd, int state) +static int hp680bl_set_intensity(struct backlight_device *bd) { - hp680bl_blank(state); - return 0; -} - -static int hp680bl_get_power(struct backlight_device *bd) -{ - return hp680bl_powermode; -} - -static int hp680bl_set_intensity(struct backlight_device *bd, int intensity) -{ - if (intensity > HP680_MAX_INTENSITY) - intensity = HP680_MAX_INTENSITY; - hp680bl_send_intensity(intensity); - current_intensity = intensity; + hp680bl_send_intensity(bd); return 0; } @@ -120,65 +97,67 @@ static int hp680bl_get_intensity(struct backlight_device *bd) static struct backlight_properties hp680bl_data = { .owner = THIS_MODULE, - .get_power = hp680bl_get_power, - .set_power = hp680bl_set_power, .max_brightness = HP680_MAX_INTENSITY, .get_brightness = hp680bl_get_intensity, - .set_brightness = hp680bl_set_intensity, + .update_status = hp680bl_set_intensity, }; -static struct backlight_device *hp680_backlight_device; - -static int __init hp680bl_probe(struct device *dev) +static int __init hp680bl_probe(struct platform_device *dev) { hp680_backlight_device = backlight_device_register ("hp680-bl", NULL, &hp680bl_data); if (IS_ERR (hp680_backlight_device)) return PTR_ERR (hp680_backlight_device); - hp680bl_set_intensity(NULL, HP680_DEFAULT_INTENSITY); + hp680_backlight_device->props->brightness = HP680_DEFAULT_INTENSITY; + hp680bl_send_intensity(hp680_backlight_device); return 0; } -static int hp680bl_remove(struct device *dev) +static int hp680bl_remove(struct platform_device *dev) { backlight_device_unregister(hp680_backlight_device); return 0; } -static struct device_driver hp680bl_driver = { - .name = "hp680-bl", - .bus = &platform_bus_type, +static struct platform_driver hp680bl_driver = { .probe = hp680bl_probe, .remove = hp680bl_remove, .suspend = hp680bl_suspend, .resume = hp680bl_resume, + .driver = { + .name = "hp680-bl", + }, }; -static struct platform_device hp680bl_device = { - .name = "hp680-bl", - .id = -1, -}; +static struct platform_device *hp680bl_device; static int __init hp680bl_init(void) { int ret; - ret=driver_register(&hp680bl_driver); + ret = platform_driver_register(&hp680bl_driver); if (!ret) { - ret = platform_device_register(&hp680bl_device); - if (ret) - driver_unregister(&hp680bl_driver); + hp680bl_device = platform_device_alloc("hp680-bl", -1); + if (!hp680bl_device) + return -ENOMEM; + + ret = platform_device_add(hp680bl_device); + + if (ret) { + platform_device_put(hp680bl_device); + platform_driver_unregister(&hp680bl_driver); + } } return ret; } static void __exit hp680bl_exit(void) { - platform_device_unregister(&hp680bl_device); - driver_unregister(&hp680bl_driver); + platform_device_unregister(hp680bl_device); + platform_driver_unregister(&hp680bl_driver); } module_init(hp680bl_init); diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c index 910e2338a27e..8ba6152db2fd 100644 --- a/drivers/video/cfbimgblt.c +++ b/drivers/video/cfbimgblt.c @@ -169,7 +169,7 @@ static inline void slow_imageblit(const struct fb_image *image, struct fb_info * while (j--) { l--; - color = (*s & 1 << (FB_BIT_NR(l))) ? fgcolor : bgcolor; + color = (*s & (1 << l)) ? fgcolor : bgcolor; val |= FB_SHIFT_HIGH(color, shift); /* Did the bitshift spill bits to the next long? */ diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 66d6f2f0a219..1103010af54a 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -60,8 +60,8 @@ #include #endif #ifdef CONFIG_PPC_PREP -#include -#define isPReP (_machine == _MACH_prep) +#include +#define isPReP (machine_is(prep)) #else #define isPReP 0 #endif diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 041d06987861..ca020719d20b 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -466,7 +466,7 @@ static int __init fb_console_setup(char *this_opt) int i, j; if (!this_opt || !*this_opt) - return 0; + return 1; while ((options = strsep(&this_opt, ",")) != NULL) { if (!strncmp(options, "font:", 5)) @@ -481,10 +481,10 @@ static int __init fb_console_setup(char *this_opt) options++; } if (*options != ',') - return 0; + return 1; options++; } else - return 0; + return 1; } if (!strncmp(options, "map:", 4)) { @@ -496,7 +496,7 @@ static int __init fb_console_setup(char *this_opt) con2fb_map_boot[i] = (options[j++]-'0') % FB_MAX; } - return 0; + return 1; } if (!strncmp(options, "vc:", 3)) { @@ -518,7 +518,7 @@ static int __init fb_console_setup(char *this_opt) rotate = 0; } } - return 0; + return 1; } __setup("fbcon=", fb_console_setup); @@ -1142,6 +1142,7 @@ static void fbcon_init(struct vc_data *vc, int init) set_blitting_type(vc, info); } + ops->p = &fb_display[fg_console]; } static void fbcon_deinit(struct vc_data *vc) diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c index 0339f5640a78..74ac2acaf72c 100644 --- a/drivers/video/console/sticore.c +++ b/drivers/video/console/sticore.c @@ -275,7 +275,7 @@ static int __init sti_setup(char *str) if (str) strlcpy (default_sti_path, str, sizeof (default_sti_path)); - return 0; + return 1; } /* Assuming the machine has multiple STI consoles (=graphic cards) which @@ -321,7 +321,7 @@ static int __init sti_font_setup(char *str) i++; } - return 0; + return 1; } /* The optional linux kernel parameter "sti_font" defines which font @@ -373,7 +373,7 @@ sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request) glob_cfg->save_addr)); /* dump extended cfg */ - cfg = PTR_STI(glob_cfg->ext_ptr); + cfg = PTR_STI((unsigned long)glob_cfg->ext_ptr); DPRINTK(( KERN_INFO "monitor %d\n" "in friendly mode: %d\n" @@ -453,25 +453,11 @@ sti_init_glob_cfg(struct sti_struct *sti, sti->regions_phys[i] = REGION_OFFSET_TO_PHYS(sti->regions[i], newhpa); - /* remap virtually */ - /* FIXME: add BTLB support if btlb==1 */ len = sti->regions[i].region_desc.length * 4096; - -/* XXX: Enabling IOREMAP debugging causes a crash, so we must be passing - * a virtual address to something expecting a physical address that doesn't - * go through a readX macro */ -#if 0 - if (len) - glob_cfg->region_ptrs[i] = (unsigned long) ( - sti->regions[i].region_desc.cache ? - ioremap(sti->regions_phys[i], len) : - ioremap_nocache(sti->regions_phys[i], len) ); -#else if (len) glob_cfg->region_ptrs[i] = sti->regions_phys[i]; -#endif - DPRINTK(("region #%d: phys %08lx, virt %08x, len=%lukB, " + DPRINTK(("region #%d: phys %08lx, region_ptr %08x, len=%lukB, " "btlb=%d, sysonly=%d, cache=%d, last=%d\n", i, sti->regions_phys[i], glob_cfg->region_ptrs[i], len/1024, diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index b1a8dca76430..8d8eadb64853 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -435,6 +435,11 @@ int fb_prepare_logo(struct fb_info *info, int rotate) depth = info->var.green.length; } + if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) { + /* assume console colormap */ + depth = 4; + } + if (depth >= 8) { switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: @@ -1588,7 +1593,7 @@ static int __init video_setup(char *options) } } - return 0; + return 1; } __setup("video=", video_setup); #endif diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 951c9974a1d3..23c1827b2d0b 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -115,6 +115,7 @@ #include #ifdef CONFIG_PPC_PMAC +#include unsigned char nvram_read_byte(int); static int default_vmode = VMODE_NVRAM; static int default_cmode = CMODE_NVRAM; @@ -1833,7 +1834,7 @@ static int initMatrox2(WPMINFO struct board* b){ /* FIXME: Where to move this?! */ #if defined(CONFIG_PPC_PMAC) #ifndef MODULE - if (_machine == _MACH_Pmac) { + if (machine_is(powermac)) { struct fb_var_screeninfo var; if (default_vmode <= 0 || default_vmode > VMODE_MAX) default_vmode = VMODE_640_480_60; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 6d3e4890cb43..093ab9977c7c 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -30,6 +30,7 @@ #include #endif #ifdef CONFIG_PMAC_BACKLIGHT +#include #include #endif @@ -1355,7 +1356,7 @@ static int nvidiafb_blank(int blank, struct fb_info *info) NVWriteCrtc(par, 0x1a, vesa); #ifdef CONFIG_PMAC_BACKLIGHT - if (par->FlatPanel && _machine == _MACH_Pmac) { + if (par->FlatPanel && machine_is(powermac)) { set_backlight_enable(!blank); } #endif @@ -1741,7 +1742,7 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, info->fix.id, par->FbMapSize / (1024 * 1024), info->fix.smem_start); #ifdef CONFIG_PMAC_BACKLIGHT - if (par->FlatPanel && _machine == _MACH_Pmac) + if (par->FlatPanel && machine_is(powermac)) register_backlight_controller(&nvidia_backlight_controller, par, "mnca"); #endif diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 53ad61f1038c..809fc5eefc15 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -232,9 +232,9 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) if (var->yres < MIN_YRES) var->yres = MIN_YRES; if (var->xres > fbi->max_xres) - var->xres = fbi->max_xres; + return -EINVAL; if (var->yres > fbi->max_yres) - var->yres = fbi->max_yres; + return -EINVAL; var->xres_virtual = max(var->xres_virtual, var->xres); var->yres_virtual = @@ -781,7 +781,7 @@ static void pxafb_disable_controller(struct pxafb_info *fbi) LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ - schedule_timeout(20 * HZ / 1000); + schedule_timeout(200 * HZ / 1000); remove_wait_queue(&fbi->ctrlr_wait, &wait); /* disable LCD controller clock */ @@ -1274,7 +1274,7 @@ int __init pxafb_probe(struct platform_device *dev) struct pxafb_mach_info *inf; int ret; - dev_dbg(dev, "pxafb_probe\n"); + dev_dbg(&dev->dev, "pxafb_probe\n"); inf = dev->dev.platform_data; ret = -ENOMEM; diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c deleted file mode 100644 index 24982adb3aa2..000000000000 --- a/drivers/video/radeonfb.c +++ /dev/null @@ -1,3167 +0,0 @@ -/* - * drivers/video/radeonfb.c - * framebuffer driver for ATI Radeon chipset video boards - * - * Copyright 2000 Ani Joshi - * - * - * ChangeLog: - * 2000-08-03 initial version 0.0.1 - * 2000-09-10 more bug fixes, public release 0.0.5 - * 2001-02-19 mode bug fixes, 0.0.7 - * 2001-07-05 fixed scrolling issues, engine initialization, - * and minor mode tweaking, 0.0.9 - * 2001-09-07 Radeon VE support, Nick Kurshev - * blanking, pan_display, and cmap fixes, 0.1.0 - * 2001-10-10 Radeon 7500 and 8500 support, and experimental - * flat panel support, 0.1.1 - * 2001-11-17 Radeon M6 (ppc) support, Daniel Berlin, 0.1.2 - * 2001-11-18 DFP fixes, Kevin Hendricks, 0.1.3 - * 2001-11-29 more cmap, backlight fixes, Benjamin Herrenschmidt - * 2002-01-18 DFP panel detection via BIOS, Michael Clark, 0.1.4 - * 2002-06-02 console switching, mode set fixes, accel fixes - * 2002-06-03 MTRR support, Peter Horton, 0.1.5 - * 2002-09-21 rv250, r300, m9 initial support, - * added mirror option, 0.1.6 - * - * Special thanks to ATI DevRel team for their hardware donations. - * - */ - - -#define RADEON_VERSION "0.1.6" - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#if defined(__powerpc__) -#include -#include -#include "macmodes.h" - -#ifdef CONFIG_NVRAM -#include -#endif - -#ifdef CONFIG_PMAC_BACKLIGHT -#include -#endif - -#ifdef CONFIG_BOOTX_TEXT -#include -#endif - -#ifdef CONFIG_ADB_PMU -#include -#include -#endif - -#endif /* __powerpc__ */ - -#ifdef CONFIG_MTRR -#include -#endif - -#include