S: Sterling Heights, Michigan 48313
S: USA
+N: William Greathouse
+E: wgreathouse@smva.com
+E: wgreathouse@myfavoritei.com
+D: Current Belkin USB Serial Adapter F5U103 hacker
+D: Kernel hacker, embedded systems
+S: 7802 Fitzwater Road
+S: Brecksville, OH 44141-1334
+S: USA
+
N: Tristan Greaves
E: Tristan.Greaves@icl.com
E: tmg296@ecs.soton.ac.uk
# http://www.traduc.org/kernelfr
# - Spanish, by Carlos Perelló MarÃn (fperllo@ehome.encis.es), at
# http://visar.csustan.edu/~carlos/
-# - Italian, by Alessandro Rubini (rubini@linux.it), at
-# ftp://ftp-pavia1.linux.it/pub/linux/Configure.help
# - Polish, by Cezar Cichocki (cezar@cs.net.pl), at
# http://www.cs.net.pl/~cezar/Kernel
# - German, by Jörg Strebel (jstrebel@suse.de) and Karl Eichwalder
#
# LocalWords: CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab
# LocalWords: unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz
-# LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd
+# LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide pavia pl pd
# LocalWords: HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN
# LocalWords: ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt
# LocalWords: BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB
--- /dev/null
+XPRAM
+=====
+
+The S/390 architecture supports more RAM than can be accessed as main memory.
+The LINUX for S/390 main memory is limited to 2 GB. However, additional
+memory can be declared as expanded storage. The S/390 architecture allows
+applications to access up to 16 TB of expanded storage (although the current
+hardware can only be equipped with up to 32 GB memory). Memory in the
+expanded storage range can be copied in 4 KB blocks to, or from, the main
+memory.
+
+An interesting feature of expanded storage is that is persistent with respect
+to IPLs (booting) but volatile with respect to IMLs (power off/on).
+
+The XPRAM device driver is a block device driver that supports LINUX for S/390
+allowing it to access the expanded storage. Thus XPRAM can be used as a basis
+for fast swap devices and/or fast file systems.
+
+Features
+++++++++
+XPRAM automatically detects whether expanded storage is available on the
+system. The expanded storage can be subdivided into up to 32 partitions, the
+default being a single partition. The XPRAM device driver has major number 35.
+The partitions have minor numbers 0 through 31. The hard sector size of XPRAM
+is set to 4096 bytes.
+
+Limitations
++++++++++++
+If expanded storage is not available, XPRAM cannot be used. Its initialization
+fails gracefully with a log message reporting the lack of expanded storage.
+
+Configuration option
+++++++++++++++++++++
+
+CONFIG_XPRAM
+
+Module name
++++++++++++
+
+XPRAM can be used as module. Its moduel name is xpram.o.
+
+Kernel parameter syntax
++++++++++++++++++++++++
+The kernel parameter is optional. The default defines the whole expanded
+storage to be one partition.
+
+xpram_parts=<number_of_partition>[,<partition_size>[,...]]
+
+where <number_of_partitions> defines how many partitions the expanded storage
+is split into. The i-th <partition_size> defines the size of the i-th
+partition.
+
+The syntax for sizes is:
+
+[0x]<non-negative_integer>[k|K|m|M|g|G]
+
+If the 0x prefix is used the subsequent number is interpreted as a hexadecimal
+value, otherwise it is interpreted as a decimal value (default). The
+non-negative_integer value may be followed by a magnitude:
+
+- k or K for kilo (1024) is the default
+- m or M for Mega (1024*1024)
+- g or G for Giga (1024*1024*1024)
+
+The <non-negative_integer> value multiplied by its magnitude defines the
+partition's size in bytes. The default size is 0.
+
+Any partition defined with a non-zero size is allocated the amount of memory
+specified by its non-negative_integer parameter.
+
+You can automatically allocate the remaining memory between a set of partitions
+by specifying zero for the size of each partition in the set. The following
+formula is used to calculate the size for each of these partitions:
+
+ (available exp. storage - sum of all non-zero sizes specified)
+computed size = --------------------------------------------------------------
+ number of partitions with zero sizes
+
+This formula is only a good approximation of the actual size allocated to each
+partition. Because of the requirement to assign blocks in multiples of 4K,
+partitions can be larger or smaller than the estimate produced by the
+calculation. In addition, there might be an amount of memory left as a "guard
+space" between two partitions.
+
+Example
+-------
+
+xpram_parts=4,0x800M,0,0,0x1000M
+
+This allocates the extended storage into four partitions. Partition 1 has 2 GB,
+partition 4 has x 4 GB, and partitions 2 and 3 use equal parts of the remaining
+storage. If the total amount of extended storage was 16 GB, then partitions 3
+and 4 would each have approximately 5 GB.
+
+Module parameter syntax
++++++++++++++++++++++++
+XPRAM may be used as module. The syntax of the module parameters passed to
+insmod differs from the kernel parameter syntax:
+
+[devs=<number_of_devices> [sizes=<size>[,<size>,...]]]
+
+where:
+- number_of_devices is used to define the number of partitions.
+- size is a non-negative integer that defines the partition's size.
+ Only decimal values are allowed and no magnitudes are accepted.
+ The size will be interpretedin KB.
+
+Example
+-------
+
+devs=4 sizes=2097152,8388608,4194304,2097152
+
+This allocates a total of 16 GB of extended storage into four partitions, of
+(respectively) size 2 GB, 8 GB, 4 GB, and 2 GB.
+
+Usage
++++++
+
+XPRAM is a block device driver with major 35.
+Using the standard naming scheme (see devices.txt) the partitions of XPRAM
+can be accessed through /dev/slram0, ... , /dev/slram31.
+
+XPRAM does not require any formatting. Partitioning is only possible during
+device initialization by kernel or module parameters. Note that if both the
+expanded storage and the partitioning parameters are left unchanged between
+two device initializations (even if LINUX was IPLed in the meantime) then
+XPRAM behaves like a persistent storage. This is not true if the system is
+IMLed.
+
+You can make a files system on a XPRAM partition (e.g. mke2fs) with a block
+size that is a multiple of 4096 byte and mount this file system.
+
+Alternativly an XPRAM partition can be used as a swap device (mkswap, swapon).
\ No newline at end of file
driver.
+Belkin USB Serial Adapter F5U103
+
+ Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs.
+
+Current status:
+ The following have been tested and work:
+ Baud rate 300-230400
+ Data bits 5-8
+ Stop bits 1-2
+ Parity N,E,O,M,S
+ Handshake None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)*
+ Break Set and clear
+ Line contrl Input/Output query and control **
+
+ * Hardware input flow control is only enabled for firmware
+ levels above 2.06. Read source code comments describing Belkin
+ firmware errata. Hardware output flow control is working for all
+ firmware versions.
+ ** Queries of inputs (CTS,DSR,CD,RI) show the last
+ reported state. Queries of outputs (DTR,RTS) show the last
+ requested state and may not reflect current state as set by
+ automatic hardware flow control.
+
+TO DO List:
+ -- Add true modem contol line query capability. Currently tracks the
+ states reported by the interrupt and the states requested.
+ -- Add error reporting back to application for UART error conditions.
+ -- Add support for flush ioctls.
+ -- Add everything else that is missing :)
+
+
Generic Serial driver
If your device is not one of the above listed devices, compatible with
VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 18
-EXTRAVERSION = pre20
+EXTRAVERSION = pre21
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
DRIVERS := $(DRIVERS) drivers/net/fc/fc.a
endif
-ifdef CONFIG_PPC
-DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a
+ifdef CONFIG_POWERMAC
+DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.o
endif
ifdef CONFIG_PNP
(struct mpc_config_ioapic *)mpt;
if (m->mpc_flags&MPC_APIC_USABLE)
{
- ioapics++;
- printk("I/O APIC #%d Version %d at 0x%lX.\n",
- m->mpc_apicid,m->mpc_apicver,
- m->mpc_apicaddr);
- mp_apics [mp_apic_entries] = *m;
- if (++mp_apic_entries > MAX_IO_APICS)
- --mp_apic_entries;
+ if(m->mpc_apicaddr == 0)
+ {
+ printk(KERN_ERR "Error - Non MP compliant BIOS. Skipping invalid io-apic!\n");
+ }
+ else
+ {
+ ioapics++;
+ printk("I/O APIC #%d Version %d at 0x%lX.\n",
+ m->mpc_apicid,m->mpc_apicver,
+ m->mpc_apicaddr);
+ mp_apics [mp_apic_entries] = *m;
+ if (++mp_apic_entries > MAX_IO_APICS)
+ --mp_apic_entries;
+ }
}
mpt+=sizeof(*m);
count+=sizeof(*m);
printk("Warning: switching to non APIC mode.\n");
skip_ioapic_setup=1;
}
+ if (ioapics == 0)
+ {
+ printk("Warning: BIOS table gives no I/O APIC.\n");
+ printk("Warning: switching to non APIC mode.\n");
+ skip_ioapic_setup=1;
+ }
return num_processors;
}
# modified by Cort (cort@cs.nmt.edu)
#
.c.s:
- $(CC) $(CFLAGS) -S -o $*.s $<
+ $(CC) $(CFLAGS) -I$(HPATH) -S -o $*.s $<
.s.o:
$(AS) -o $*.o $<
.c.o:
extern char *vidmem;
extern int lines, cols;
/* estimate for delay */
-unsigned long loops_per_sec = 50000000;;
+unsigned long loops_per_jiffy = 50000000/HZ;
/*
* VGA Register
*/
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
-CFLAGS = $(CPPFLAGS) -O -fno-builtin
+CFLAGS = $(CPPFLAGS) -O -fno-builtin -I$(HPATH)
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
-CHRP_LD_ARGS = -Ttext 0x00400000
+CHRP_LD_ARGS = -Ttext 0x01000000
GZ = gzip -9
COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o
MSIZE=
endif
-ifeq ($(CONFIG_ALL_PPC),y)
-# yes, we want to build pmac stuff
-CONFIG_PMAC = y
-endif
-
ifeq ($(CONFIG_SMP),y)
TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE)
else
TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE)
endif
-ifeq ($(CONFIG_PMAC),y)
+ifeq ($(CONFIG_POWERMAC),y)
hack-coff: hack-coff.c
$(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
#define get_16be(x) (*(unsigned short *)(x))
#define get_32be(x) (*(unsigned *)(x))
-#define RAM_START 0x00000000
-#define RAM_END (8<<20)
+#define RAM_END (16 << 20)
#define PROG_START 0x00010000
+#define PROG_SIZE 0x003f0000
+
+#define SCRATCH_SIZE (128 << 10)
char *avail_ram;
-char *end_avail;
+char *begin_avail, *end_avail;
+char *avail_high;
+unsigned int heap_use;
+unsigned int heap_max;
extern char _end[];
extern char image_data[];
im = image_data;
len = image_len;
/* claim 3MB starting at PROG_START */
- claim(PROG_START, 3 << 20, 0);
+ claim(PROG_START, PROG_SIZE, 0);
dst = (void *) PROG_START;
if (im[0] == 0x1f && im[1] == 0x8b) {
- /* claim 512kB for scratch space */
- avail_ram = (char *) claim(0, 512 << 10, 0x10);
- end_avail = avail_ram + (512 << 10);
- printf("avail_ram = %x\n", avail_ram);
+ /* claim some memory for scratch space */
+ avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10);
+ begin_avail = avail_high = avail_ram;
+ end_avail = avail_ram + SCRATCH_SIZE;
+ printf("heap at 0x%x\n", avail_ram);
printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
- gunzip(dst, 3 << 20, im, &len);
+ gunzip(dst, PROG_SIZE, im, &len);
printf("done %u bytes\n", len);
+ printf("%u bytes of heap consumed, max in use %u\n",
+ avail_high - begin_avail, heap_max);
} else {
memmove(dst, im, len);
}
flush_cache(dst, len);
+#if 0
stop_imac_ethernet();
stop_imac_usb();
+#endif
sa = (unsigned long)PROG_START;
printf("start address = 0x%x\n", sa);
pause();
}
+#if 0
#define eieio() asm volatile("eieio");
void stop_imac_ethernet(void)
*usb_ctrl = 0x01000000; /* cpu_to_le32(1) */
eieio();
}
+#endif
+
+struct memchunk {
+ unsigned int size;
+ struct memchunk *next;
+};
+
+static struct memchunk *freechunks;
void *zalloc(void *x, unsigned items, unsigned size)
{
- void *p = avail_ram;
+ void *p;
+ struct memchunk **mpp, *mp;
size *= items;
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");
pause();
void zfree(void *x, void *addr, unsigned nb)
{
+ struct memchunk *mp = addr;
+
+ nb = (nb + 7) & -8;
+ heap_use -= nb;
+ if (avail_ram == addr + nb) {
+ avail_ram = addr;
+ return;
+ }
+ mp->size = nb;
+ mp->next = freechunks;
+ freechunks = mp;
}
#define HEAD_CRC 2
bool 'Altivec (G4) support' CONFIG_ALTIVEC
fi
-if [ "$CONFIG_ALL_PPC" != "y" ];then
+if [ "$CONFIG_ALL_PPC" != "y" ]; then
define_bool CONFIG_MACH_SPECIFIC y
fi
-if [ "$CONFIG_PPC64" != "y" ];then
- define_bool CONFIG_6xx y
+if [ "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" ]; then
+ define_bool CONFIG_POWERMAC y
fi
endmenu
bool 'Support for VGA Console' CONFIG_VGA_CONSOLE
bool 'Support for frame buffer devices' CONFIG_FB
-
bool 'Power management support for Apple PowerBooks' CONFIG_PMAC_PBOOK
-bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
-bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
-tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
-if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
- bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE
-fi
-tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
-bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE
bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
source drivers/char/Config.in
source drivers/usb/Config.in
-source fs/Config.in
+
+mainmenu_option next_comment
+comment 'Mac device drivers'
+if [ "$CONFIG_INPUT_KEYBDEV" = "y" -o "$CONFIG_INPUT_MOUSEDEV" = "y" ]; then
+ bool 'Use input layer for ADB keyboard and mouse' CONFIG_INPUT_ADBHID
+fi
+if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then
+ define_bool CONFIG_MAC_HID y
+ bool ' Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES
+ bool ' Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
+else
+ bool 'Support for ADB keyboard (old driver)' CONFIG_MAC_KEYBOARD
+ bool 'Support for ADB mouse (old driver)' CONFIG_ADBMOUSE
+fi
+tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
+bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
+tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
+if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
+ bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE
+fi
+endmenu
mainmenu_option next_comment
comment 'Sound'
endmenu
+source fs/Config.in
+
mainmenu_option next_comment
comment 'Kernel hacking'
ifeq ($(CONFIG_MBX),y)
O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o
-else
+endif
ifeq ($(CONFIG_APUS),y)
O_OBJS += apus_setup.o prom.o openpic.o
-else
-ifneq ($(CONFIG_MBX),y)
-O_OBJS += prep_time.o pmac_time.o chrp_time.o \
- pmac_setup.o pmac_support.o \
- prep_pci.o pmac_pci.o chrp_pci.o \
- residual.o prom.o openpic.o feature.o \
- prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o \
- gemini_pci.o gemini_prom.o gemini_setup.o
-OX_OBJS += chrp_setup.o prep_setup.o
endif
+
+PMAC_OBJS = pmac_time.o pmac_setup.o pmac_support.o pmac_pci.o pmac_pic.o \
+ feature.o openpic.o open_pic.o prom.o
+CHRP_OBJS = $(PMAC_OBJS) chrp_time.o chrp_pci.o i8259.o indirect_pci.o
+CHRPX_OBJS = chrp_setup.o
+PREP_OBJS = prep_time.o prep_pci.o residual.o prep_nvram.o i8259.o \
+ indirect_pci.o openpic.o open_pic.o prom.o
+PREPX_OBJS = prep_setup.o
+
+ifeq ($(CONFIG_ALL_PPC),y)
+O_OBJS += $(sort $(PMAC_OBJS) $(PREP_OBJS) $(CHRP_OBJS))
+OX_OBJS += $(PMACX_OBJS) $(PREPX_OBJS) $(CHRPX_OBJS)
+endif
+ifeq ($(CONFIG_PMAC),y)
+O_OBJS += $(PMAC_OBJS)
+OX_OBJS += $(PMACX_OBJS)
endif
+ifeq ($(CONFIG_PREP),y)
+O_OBJS += $(PREP_OBJS)
+OX_OBJS += $(PREPX_OBJS)
+endif
+ifeq ($(CONFIG_CHRP),y)
+O_OBJS += $(CHRP_OBJS)
+OX_OBJS += $(CHRPX_OBJS)
+endif
+
+GEMINI_OBJS = $(PREP_OBJS) gemini_pci.o gemini_prom.o gemini_setup.o
+ifeq ($(CONFIG_GEMINI),y)
+O_OBJS += $(GEMINI_OBJS)
+OX_OBJS += $(PREPX_OBJS)
endif
ifdef CONFIG_SMP
$(HOSTCC) -o find_name find_name.c
checks: checks.c
- $(HOSTCC) ${CFLAGS} -D__KERNEL__ -o checks checks.c
+ $(HOSTCC) ${CFLAGS} -D__KERNEL__ -I../../../include -o checks checks.c
./checks
include $(TOPDIR)/Rules.make
ppc_md.kbd_unexpected_up = NULL;
ppc_md.kbd_leds = NULL;
ppc_md.kbd_init_hw = NULL;
- ppc_md.kbd_sysrq_xlate = NULL;
+ ppc_md.sysrq_xlate = NULL;
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
ppc_ide_md.insw = apus_ide_insw;
#include <asm/machdep.h>
#include "pci.h"
+#include "open_pic.h"
/* LongTrail */
#define pci_config_addr(bus, dev, offset) \
for( dev=pci_devices ; dev; dev=dev->next )
{
if ( dev->irq )
- dev->irq = openpic_to_irq( dev->irq );
+ dev->irq = dev->irq + open_pic.irq_offset;
/* these need to be absolute addrs for OF and Matrox FB -- Cort */
if ( dev->vendor == PCI_VENDOR_ID_MATROX )
{
#include <asm/irq.h>
#include <asm/adb.h>
#include <asm/hydra.h>
+#include <asm/keyboard.h>
#include <asm/time.h>
#include "local_irq.h"
int chrp_set_rtc_time(unsigned long nowtime);
unsigned long rtas_event_scan_rate = 0, rtas_event_scan_ct = 0;
void chrp_calibrate_decr(void);
-void chrp_time_init(void);
+long chrp_time_init(void);
void chrp_setup_pci_ptrs(void);
extern PTE *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
extern int probingmem;
+extern unsigned long loops_per_jiffy;
unsigned long empty_zero_page[1024];
}
}
-void
-chrp_do_IRQ(struct pt_regs *regs,
- int cpu,
- int isfake)
-{
- int irq;
- unsigned long bits = 0;
- int openpic_eoi_done = 0;
-
-#ifdef __SMP__
- {
- unsigned int loops = 1000000;
- while (test_bit(0, &global_irq_lock)) {
- if (smp_processor_id() == global_irq_holder) {
- printk("uh oh, interrupt while we hold global irq lock!\n");
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- break;
- }
- if (loops-- == 0) {
- printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
-#ifdef CONFIG_XMON
- xmon(0);
-#endif
- }
- }
- }
-#endif /* __SMP__ */
-
- irq = openpic_irq(smp_processor_id());
- if (irq == IRQ_8259_CASCADE)
- {
- /*
- * This magic address generates a PCI IACK cycle.
- *
- * This should go in the above mask/ack code soon. -- Cort
- */
- if ( chrp_int_ack_special )
- irq = *chrp_int_ack_special;
- else
- irq = i8259_irq(0);
- /*
- * Acknowledge as soon as possible to allow i8259
- * interrupt nesting */
- openpic_eoi(smp_processor_id());
- openpic_eoi_done = 1;
- }
- if (irq == OPENPIC_VEC_SPURIOUS)
- {
- /*
- * Spurious interrupts should never be
- * acknowledged
- */
- ppc_spurious_interrupts++;
- openpic_eoi_done = 1;
- goto out;
- }
- bits = 1UL << irq;
-
- if (irq < 0)
- {
- printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
- irq, regs->nip);
- ppc_spurious_interrupts++;
- }
- else
- {
- ppc_irq_dispatch_handler( regs, irq );
- }
-out:
- if (!openpic_eoi_done)
- openpic_eoi(smp_processor_id());
-}
-
__initfunc(void
chrp_init_IRQ(void))
{
(*(unsigned long *)get_property(np,
"8259-interrupt-acknowledge", NULL));
}
- open_pic.irq_offset = 16;
+ open_pic.irq_offset = NUM_8259_INTERRUPTS;
for ( i = 16 ; i < NR_IRQS ; i++ )
irq_desc[i].ctl = &open_pic;
openpic_init(1);
irq_desc[i].ctl = &i8259_pic;
i8259_init();
#ifdef CONFIG_XMON
- request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
+ request_irq(HYDRA_INT_ADB_NMI+open_pic.irq_offset,
xmon_irq, 0, "NMI", 0);
#endif /* CONFIG_XMON */
#ifdef __SMP__
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
- ppc_md.SYSRQ_KEY = 0x54;
+ ppc_md.sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
#endif
}
else
ppc_md.kbd_leds = mackbd_leds;
ppc_md.kbd_init_hw = mackbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate;
- ppc_md.SYSRQ_KEY = 0x69;
+ ppc_md.sysrq_xlate = mackbd_sysrq_xlate;
+ SYSRQ_KEY = 0x69;
#endif
}
#else
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
- ppc_md.SYSRQ_KEY = 0x54;
+ ppc_md.sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
#endif
#endif
#endif
ppc_md.get_cpuinfo = chrp_get_cpuinfo;
ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
ppc_md.init_IRQ = chrp_init_IRQ;
- ppc_md.do_IRQ = chrp_do_IRQ;
+ ppc_md.do_IRQ = open_pic_do_IRQ;
ppc_md.init = chrp_init2;
static int nvram_as0 = NVRAM_AS0;
static int nvram_data = NVRAM_DATA;
-__initfunc(void chrp_time_init(void))
+__initfunc(long chrp_time_init(void))
{
struct device_node *rtcs;
int base;
rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
if (rtcs == NULL || rtcs->addrs == NULL)
- return;
+ 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)
* arch/ppc/kernel/feature.c
*
* Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ * Ben. Herrenschmidt (bh40@calva.net)
*
* 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.
*
- * BenH: Changed implementation to work on multiple registers
- * polarity is also taken into account. Removed delay (now
- * responsibility of the caller). Added spinlocks.
- *
*/
#include <linux/types.h>
#include <linux/init.h>
#include <asm/errno.h>
#include <asm/ohare.h>
#include <asm/heathrow.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/feature.h>
#undef DEBUG_FEATURE
#define MAX_FEATURE_CONTROLLERS 2
-#define MAX_FEATURE_OFFSET 0x50
+#define MAX_FEATURE_OFFSET 0x100
#define FREG(c,r) (&(((c)->reg)[(r)>>2]))
+/* Keylargo reg. access. */
+#define KL_FCR(r) (keylargo_base + ((r) >> 2))
+#define KL_IN(r) (in_le32(KL_FCR(r)))
+#define KL_OUT(r,v) (out_le32(KL_FCR(r), (v)))
+#define KL_BIS(r,v) (KL_OUT((r), KL_IN(r) | (v)))
+#define KL_BIC(r,v) (KL_OUT((r), KL_IN(r) & ~(v)))
+
+/* Uni-N reg. access. Note that Uni-N regs are big endian */
+#define UN_REG(r) (uninorth_base + ((r) >> 2))
+#define UN_IN(r) (in_be32(UN_REG(r)))
+#define UN_OUT(r,v) (out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v)))
+
typedef struct feature_bit {
int reg; /* reg. offset from mac-io base */
unsigned int polarity; /* 0 = normal, 1 = inverse */
unsigned int mask; /* bit mask */
} fbit;
-/* I don't have an OHare machine to test with, so I left those as they
- * were. Someone with such a machine chould check out what OF says and
- * try too see if they match the heathrow ones and should be changed too
+/* Those features concern for OHare-based PowerBooks (2400, 3400, 3500)
*/
static fbit feature_bits_ohare_pbook[] = {
{0x38,0,0}, /* FEATURE_null */
{0x38,0,0}, /* FEATURE_IDE2_reset */
{0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
{0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
};
-/* Those bits are from a PowerBook. It's possible that desktop machines
- * based on heathrow need a different definition or some bits removed
+/* Those bits concern heathrow-based desktop machines (Beige G3s). We have removed
+ * the SCC related bits and init them once. They have proven to occasionally cause
+ * problems with the desktop units.
*/
static fbit feature_bits_heathrow[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,0}, /* FEATURE_Serial_reset */
+ {0x38,0,0}, /* FEATURE_Serial_enable */
+ {0x38,0,0}, /* FEATURE_Serial_IO_A */
+ {0x38,0,0}, /* FEATURE_Serial_IO_B */
+ {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */
+ {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */
+ {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */
+ {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */
+ {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */
+ {0x38,1,0}, /* FEATURE_Mediabay_reset */
+ {0x38,1,0}, /* FEATURE_Mediabay_power */
+ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */
+ {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */
+ {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */
+ {0x38,1,0}, /* FEATURE_Modem_power */
+ {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,1,0}, /* FEATURE_Sound_Power */
+ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x38,0,0}, /* FEATURE_IDE2_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
+ {0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
+};
+
+/* Those bits concern heathrow-based PowerBooks (wallstreet/mainstreet).
+ * Heathrow-based desktop macs (Beige G3s) are _not_ handled here
+ */
+static fbit feature_bits_wallstreet[] = {
{0x38,0,0}, /* FEATURE_null */
{0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */
{0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */
{0x38,0,0}, /* FEATURE_IDE2_reset */
{0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
{0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
};
/*
* Those bits are from a 1999 G3 PowerBook, with a paddington chip.
- * Mostly the same as the heathrow.
+ * Mostly the same as the heathrow. They are used on both PowerBooks
+ * and desktop machines using the paddington chip
*/
static fbit feature_bits_paddington[] = {
{0x38,0,0}, /* FEATURE_null */
- {0x38,0,0}, /* FEATURE_Serial_reset */
+ {0x38,0,PADD_RESET_SCC}, /* FEATURE_Serial_reset */
{0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */
{0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */
{0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */
{0x38,0,0}, /* FEATURE_IDE2_reset */
{0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */
{0x38,0,0}, /* FEATURE_Mediabay_content */
+ {0x38,0,0}, /* FEATURE_Airport_reset */
};
/* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...).
+ * Note: Different sets may be needed for iBook, especially for sound
*/
static fbit feature_bits_keylargo[] = {
{0x38,0,0}, /* FEATURE_null */
- {0x38,0,0}, /* FEATURE_Serial_reset */
- {0x38,0,0x00000054}, /* FEATURE_Serial_enable */
- {0x38,0,0}, /* FEATURE_Serial_IO_A */
- {0x38,0,0}, /* FEATURE_Serial_IO_B */
+ {0x38,0,KL0_SCC_RESET}, /* FEATURE_Serial_reset */
+ {0x38,0,KL0_SERIAL_ENABLE}, /* FEATURE_Serial_enable */
+ {0x38,0,KL0_SCC_A_INTF_ENABLE}, /* FEATURE_Serial_IO_A */
+ {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */
{0x38,0,0}, /* FEATURE_SWIM3_enable */
{0x38,0,0}, /* FEATURE_MESH_enable */
{0x3c,0,0}, /* FEATURE_IDE0_enable */
- {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */
+ {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */
{0x38,0,0}, /* FEATURE_IOBUS_enable */
{0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */
{0x34,1,0x00000400}, /* FEATURE_Mediabay_power */
{0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */
{0x3c,0,0x0}, /* FEATURE_IDE1_enable */
- {0x3c,1,0x08000000}, /* FEATURE_IDE1_reset */
+ {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */
{0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */
{0x38,0,0}, /* FEATURE_BMac_reset */
{0x38,0,0}, /* FEATURE_BMac_IO_enable */
- {0x40,1,0x02000000}, /* FEATURE_Modem_power */
+ {0x40,1,KL2_MODEM_POWER_N}, /* FEATURE_Modem_power */
{0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */
{0x38,0,0}, /* FEATURE_Sound_Power */
{0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
{0x38,0,0}, /* FEATURE_IDE2_enable */
- {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */
- {0x34,0,0x00001000}, /* FEATURE_Mediabay_IDE_switch */
+ {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */
+ {0x34,0,KL_MBCR_MBDEV_ENABLE}, /* FEATURE_Mediabay_IDE_switch */
{0x34,0,0x00000100}, /* FEATURE_Mediabay_content */
+ {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */
};
/* definition of a feature controller object */
};
/* static functions */
-static void
+static struct feature_controller*
feature_add_controller(struct device_node *controller_device, fbit* bits);
static struct feature_controller*
feature_lookup_controller(struct device_node *device);
-/* static varialbles */
+static void uninorth_init(void);
+static void keylargo_init(void);
+#ifdef CONFIG_PMAC_PBOOK
+static void heathrow_prepare_for_sleep(struct feature_controller* ctrler);
+static void heathrow_wakeup(struct feature_controller* ctrler);
+static void core99_prepare_for_sleep(struct feature_controller* ctrler);
+static void core99_wake_up(struct feature_controller* ctrler);
+#endif /* CONFIG_PMAC_PBOOK */
+
+/* static variables */
static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS];
static int controller_count = 0;
+/* Core99 stuffs */
+static volatile u32* uninorth_base;
+static volatile u32* keylargo_base;
+static struct feature_controller* keylargo;
+static int uninorth_rev;
+static int keylargo_rev;
+static u32 board_features;
+
+#define FTR_NEED_OPENPIC_TWEAK 0x00000001
+
+static struct board_features_t {
+ char* compatible;
+ u32 features;
+} board_features_datas[] __init =
+{
+ { "PowerMac2,1", 0 }, /* iMac ? */
+ { "PowerMac2,2", 0 }, /* iMac ? */
+ { "PowerMac3,1", FTR_NEED_OPENPIC_TWEAK }, /* Sawtooth (G4) */
+ { "PowerMac3,3", 0 }, /* Dual G4 or Cube ? */
+ { "PowerMac5,1", 0 }, /* Dual G4 or Cube ? */
+ { "PowerBook2,1", 0 }, /* iBook */
+ { "PowerBook2,2", 0 }, /* iBook FireWire ? */
+ { "PowerBook3,1", 0 }, /* PowerBook 2000 (Pismo) */
+ { NULL, 0 }
+};
void
feature_init(void)
{
struct device_node *np;
+ u32* rev;
+ int i;
+
+ /* Figure out motherboard type & options */
+ for(i=0;board_features_datas[i].compatible;i++)
+ if (machine_is_compatible(board_features_datas[i].compatible)) {
+ board_features = board_features_datas[i].features;
+ break;
+ }
+ /* Track those poor mac-io's */
+
np = find_devices("mac-io");
while (np != NULL) {
/* KeyLargo contains several (5 ?) FCR registers in mac-io,
* plus some gpio's which could eventually be handled here.
*/
if (device_is_compatible(np, "Keylargo")) {
- feature_add_controller(np, feature_bits_keylargo);
+ struct feature_controller* ctrler =
+ feature_add_controller(np, feature_bits_keylargo);
+ if (ctrler) {
+ keylargo = ctrler;
+ keylargo_base = ctrler->reg;
+ rev = (u32 *)get_property(ctrler->device, "revision-id", NULL);
+ if (rev)
+ keylargo_rev = *rev;
+ }
} else if (device_is_compatible(np, "paddington")) {
feature_add_controller(np, feature_bits_paddington);
+ } else if (machine_is_compatible("AAPL,PowerBook1998")) {
+ feature_add_controller(np, feature_bits_wallstreet);
} else {
- feature_add_controller(np, feature_bits_heathrow);
+ struct feature_controller* ctrler =
+ feature_add_controller(np, feature_bits_heathrow);
+ if (ctrler)
+ out_le32(FREG(ctrler,HEATHROW_FEATURE_REG),
+ in_le32(FREG(ctrler,HEATHROW_FEATURE_REG)) | HRW_DEFAULTS);
+
}
np = np->next;
}
}
}
+ /* Locate core99 Uni-N */
+ np = find_devices("uni-n");
+ if (np && np->n_addrs > 0) {
+ uninorth_base = ioremap(np->addrs[0].address, 0x1000);
+ uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+ }
+ if (uninorth_base && keylargo_base)
+ printk("Uni-N revision: %d, KeyLargo revision: %d\n",
+ uninorth_rev, keylargo_rev);
+ if (uninorth_base)
+ uninorth_init();
+ if (keylargo_base)
+ keylargo_init();
+
if (controller_count)
printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
#endif
}
-static void
+static struct feature_controller*
feature_add_controller(struct device_node *controller_device, fbit* bits)
{
struct feature_controller* controller;
if (controller_count >= MAX_FEATURE_CONTROLLERS) {
printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
controller_device->full_name, MAX_FEATURE_CONTROLLERS);
- return;
+ return NULL;
}
controller = &controllers[controller_count];
if (controller_device->n_addrs == 0) {
printk(KERN_ERR "No addresses for %s\n",
controller_device->full_name);
- return;
+ return NULL;
}
+ /* We remap the entire mac-io here. Normally, this will just
+ * give us back our already existing BAT mapping
+ */
controller->reg = (volatile u32 *)ioremap(
- controller_device->addrs[0].address, MAX_FEATURE_OFFSET);
+ controller_device->addrs[0].address,
+ controller_device->addrs[0].size);
if (bits == NULL) {
printk(KERN_INFO "Twiddling the magic ohare bits\n");
out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES);
- return;
+ return NULL;
}
spin_lock_init(&controller->lock);
controller_count++;
+
+ return controller;
}
static struct feature_controller*
return bit->polarity ? (value == 0) : (value == bit->mask);
}
+/*
+ * Core99 functions
+ *
+ * Note: We currently assume there is _one_ UniN chip and _one_ KeyLargo
+ * chip, which is the case on all Core99 machines so far
+ */
+
+/* Only one GMAC is assumed */
+void
+feature_set_gmac_power(struct device_node* device, int power)
+{
+ unsigned long flags;
+
+ if (!uninorth_base || !keylargo)
+ return;
+
+ spin_lock_irqsave(&keylargo->lock, flags);
+ if (power)
+ UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+ else
+ UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
+ spin_unlock_irqrestore(&keylargo->lock, flags);
+ udelay(20);
+}
+
+void
+feature_set_gmac_phy_reset(struct device_node* device, int reset)
+{
+ unsigned long flags;
+
+ if (!keylargo_base || !keylargo)
+ return;
+
+ spin_lock_irqsave(&keylargo->lock, flags);
+ out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset);
+ (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET));
+ spin_unlock_irqrestore(&keylargo->lock, flags);
+}
+
+/* Pass the node of the correct controller, please */
+void
+feature_set_usb_power(struct device_node* device, int power)
+{
+ char* prop;
+ int number;
+ u32 reg;
+
+ unsigned long flags;
+
+ if (!keylargo_base || !keylargo)
+ return;
+
+ prop = (char *)get_property(device, "AAPL,clock-id", NULL);
+ if (!prop)
+ return;
+ if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0)
+ number = 0;
+ else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0)
+ number = 2;
+ else
+ return;
+
+ spin_lock_irqsave(&keylargo->lock, flags);
+ if (power) {
+ /* Turn ON */
+
+ if (number == 0) {
+ KL_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+ mdelay(1);
+ KL_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+ } else {
+ KL_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+ mdelay(1);
+ KL_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+ }
+ reg = KL_IN(KEYLARGO_FCR4);
+ reg &= ~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) |
+ KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number));
+ reg &= ~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) |
+ KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1));
+ KL_OUT(KEYLARGO_FCR4, reg);
+ (void)KL_IN(KEYLARGO_FCR4);
+ udelay(10);
+ } else {
+ /* Turn OFF */
+
+ reg = KL_IN(KEYLARGO_FCR4);
+ reg |= KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) |
+ KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number);
+ reg |= KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) |
+ KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1);
+ KL_OUT(KEYLARGO_FCR4, reg);
+ (void)KL_IN(KEYLARGO_FCR4);
+ udelay(1);
+ if (number == 0) {
+ KL_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
+ (void)KL_IN(KEYLARGO_FCR0);
+ udelay(1);
+ KL_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+ (void)KL_IN(KEYLARGO_FCR0);
+ } else {
+ KL_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+ (void)KL_IN(KEYLARGO_FCR0);
+ udelay(1);
+ KL_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+ (void)KL_IN(KEYLARGO_FCR0);
+ }
+ udelay(1);
+ }
+ spin_unlock_irqrestore(&keylargo->lock, flags);
+}
+
+/* Not yet implemented */
+void
+feature_set_firewire_power(struct device_node* device, int power)
+{
+}
+
+#ifdef CONFIG_SMP
+void
+feature_core99_kick_cpu1(void)
+{
+ out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_ASSERT);
+ udelay(1);
+ out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_RELEASE);
+}
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_PMAC_PBOOK
+void
+feature_prepare_for_sleep(void)
+{
+ /* We assume gatwick is second */
+ struct feature_controller* ctrler = &controllers[0];
+
+ if (!ctrler)
+ return;
+ if (controller_count > 1 &&
+ device_is_compatible(ctrler->device, "gatwick"))
+ ctrler = &controllers[1];
+
+ if (ctrler->bits == feature_bits_heathrow ||
+ ctrler->bits == feature_bits_paddington) {
+ heathrow_prepare_for_sleep(ctrler);
+ return;
+ }
+ if (ctrler->bits == feature_bits_keylargo) {
+ core99_prepare_for_sleep(ctrler);
+ return;
+ }
+}
+
+
+void
+feature_wake_up(void)
+{
+ struct feature_controller* ctrler = &controllers[0];
+
+ if (!ctrler)
+ return;
+ if (controller_count > 1 &&
+ device_is_compatible(ctrler->device, "gatwick"))
+ ctrler = &controllers[1];
+
+ if (ctrler->bits == feature_bits_heathrow ||
+ ctrler->bits == feature_bits_paddington) {
+ heathrow_wakeup(ctrler);
+ return;
+ }
+ if (ctrler->bits == feature_bits_keylargo) {
+ core99_wake_up(ctrler);
+ return;
+ }
+}
+
+static u32 save_fcr[5];
+static u32 save_mbcr;
+static u32 save_gpio_levels[2];
+static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT];
+static u8 save_gpio_normal[KEYLARGO_GPIO_CNT];
+
+static void
+heathrow_prepare_for_sleep(struct feature_controller* ctrler)
+{
+ save_mbcr = in_le32(FREG(ctrler, 0x34));
+ save_fcr[0] = in_le32(FREG(ctrler, 0x38));
+ save_fcr[1] = in_le32(FREG(ctrler, 0x3c));
+
+ out_le32(FREG(ctrler, 0x38), save_fcr[0] & ~HRW_IOBUS_ENABLE);
+}
+
+static void
+heathrow_wakeup(struct feature_controller* ctrler)
+{
+ out_le32(FREG(ctrler, 0x38), save_fcr[0]);
+ out_le32(FREG(ctrler, 0x3c), save_fcr[1]);
+ out_le32(FREG(ctrler, 0x34), save_mbcr);
+ mdelay(1);
+ out_le32(FREG(ctrler, 0x38), save_fcr[0] | HRW_IOBUS_ENABLE);
+ mdelay(1);
+}
+
+
+static void
+core99_prepare_for_sleep(struct feature_controller* ctrler)
+{
+ u32 temp;
+ int i;
+ u8* base8;
+
+ /*
+ * Save various bits of KeyLargo
+ */
+
+ save_gpio_levels[0] = KL_IN(KEYLARGO_GPIO_LEVELS0);
+ save_gpio_levels[1] = KL_IN(KEYLARGO_GPIO_LEVELS1);
+ base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0);
+ for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+ save_gpio_extint[i] = in_8(base8+i);
+ base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_0);
+ for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+ save_gpio_normal[i] = in_8(base8+i);
+ save_mbcr = KL_IN(KEYLARGO_MBCR);
+ save_fcr[0] = KL_IN(KEYLARGO_FCR0);
+ save_fcr[1] = KL_IN(KEYLARGO_FCR1);
+ save_fcr[2] = KL_IN(KEYLARGO_FCR2);
+ save_fcr[3] = KL_IN(KEYLARGO_FCR3);
+ save_fcr[4] = KL_IN(KEYLARGO_FCR4);
+
+ /*
+ * Turn off as much as we can
+ */
+
+ KL_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
+ mdelay(1);
+ KL_BIC(KEYLARGO_FCR0, KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | KL0_SCC_CELL_ENABLE);
+ KL_BIC(KEYLARGO_FCR0, KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);
+
+ KL_BIS(KEYLARGO_MBCR, KL_MBCR_MBDEV_ENABLE);
+
+ KL_BIC(KEYLARGO_FCR1,
+ KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |
+ KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |
+ KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |
+ KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |
+ KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |
+ KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |
+ KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |
+ KL1_UIDE_ENABLE);
+
+ KL_BIS(KEYLARGO_FCR2, KL2_MODEM_POWER_N);
+ KL_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);
+
+ temp = KL_IN(KEYLARGO_FCR3);
+ if (keylargo_rev >= 2)
+ temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL);
+
+ temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |
+ KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12;
+ temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE
+ | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE
+ | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);
+ KL_OUT(KEYLARGO_FCR3, temp);
+
+ /*
+ * Put the host bridge to sleep
+ */
+
+ UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);
+ UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);
+
+ /*
+ * FIXME: A bit of black magic with OpenPIC (don't ask me why)
+ */
+ if (board_features & FTR_NEED_OPENPIC_TWEAK) {
+ KL_BIS(0x506e0, 0x00400000);
+ KL_BIS(0x506e0, 0x80000000);
+ }
+}
+
+static void
+core99_wake_up(struct feature_controller* ctrler)
+{
+ int i;
+ u8* base8;
+
+ /*
+ * Wakeup the host bridge
+ */
+ UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);
+ UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);
+
+ /*
+ * Restore KeyLargo
+ */
+
+ KL_OUT(KEYLARGO_MBCR, save_mbcr);
+ KL_OUT(KEYLARGO_FCR0, save_fcr[0]);
+ KL_OUT(KEYLARGO_FCR1, save_fcr[1]);
+ KL_OUT(KEYLARGO_FCR2, save_fcr[2]);
+ KL_OUT(KEYLARGO_FCR3, save_fcr[3]);
+ KL_OUT(KEYLARGO_FCR4, save_fcr[4]);
+ mdelay(1);
+ KL_OUT(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
+ KL_OUT(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
+ base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0);
+ for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
+ out_8(base8+i, save_gpio_extint[i]);
+ base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_0);
+ for (i=0; i<KEYLARGO_GPIO_CNT; i++)
+ out_8(base8+i, save_gpio_normal[i]);
+
+ /* FIXME more black magic with OpenPIC ... */
+ if (board_features & FTR_NEED_OPENPIC_TWEAK) {
+ KL_BIC(0x506e0, 0x00400000);
+ KL_BIC(0x506e0, 0x80000000);
+ }
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+/* Initialize the Core99 UniNorth host bridge and memory controller
+ */
+static void
+uninorth_init(void)
+{
+ struct device_node* gmac;
+ unsigned long actrl;
+
+ /* Set the arbitrer QAck delay according to what Apple does
+ */
+ actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;
+ actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY)
+ << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;
+ UN_OUT(UNI_N_ARB_CTRL, actrl);
+
+ /*
+ * Turns OFF the gmac clock. The gmac driver will turn
+ * it back ON when the interface is enabled. This save
+ * power on portables.
+ *
+ * Note: We could also try to turn OFF the PHY. Since this
+ * has to be done by both the gmac driver and this code,
+ * I'll probably end-up moving some of this out of the
+ * modular gmac driver into a non-modular stub containing
+ * some basic PHY management and power management stuffs
+ */
+ gmac = find_devices("ethernet");
+
+ while(gmac) {
+ if (device_is_compatible(gmac, "gmac"))
+ break;
+ gmac = gmac->next;
+ }
+ if (gmac)
+ feature_set_gmac_power(gmac, 0);
+}
+
+/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure
+ * OpenPIC is enabled
+ */
+static void
+keylargo_init(void)
+{
+ KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE);
+}
+
#include <asm/io.h>
#include <asm/m48t35.h>
#include <asm/gemini.h>
+#include <asm/processor.h>
#include <asm/time.h>
#include "local_irq.h"
return clock;
}
-
-#define L2CR_PIPE_LATEWR (0x01800000) /* late-write SRAM */
-#define L2CR_L2CTL (0x00100000) /* RAM control */
-#define L2CR_INST_DISABLE (0x00400000) /* disable for insn's */
-#define L2CR_L2I (0x00200000) /* global invalidate */
-#define L2CR_L2E (0x80000000) /* enable */
-#define L2CR_L2WT (0x00080000) /* write-through */
-
void __init gemini_init_l2(void)
{
unsigned char reg;
cache |= L2CR_L2WT;
#endif
cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE;
- _set_L2CR(0);
- _set_L2CR(cache|L2CR_L2I|L2CR_L2E);
+ _set_L2CR(cache|L2CR_L2E);
}
}
#define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x))))
/* ensure that the RTC is up and running */
-void __init gemini_time_init(void)
+long __init gemini_time_init(void)
{
unsigned char reg;
gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL);
gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL);
}
+ return 0;
}
#undef DEBUG_RTC
ppc_md.kbd_leds = NULL;
ppc_md.kbd_init_hw = NULL;
#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.kbd_sysrq_xlate = NULL;
+ ppc_md.sysrq_xlate = NULL;
#endif
}
* 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.
+ *
+ * 2000-04-10.
+ * Add sys_rt_sigreturn in DoSyscall Handler.
+ * Giovanna Ambrosini (ambrosini@lightning.ch).
*
*/
__secondary_start:
/* Switch MMU off, clear BATs and flush TLB */
bl mmu_off
+mmu_off_return:
bl clear_bats
bl flush_tlbs
-
-/* Use the first pair of BAT registers to map the 1st 16MB
- * of RAM to KERNELBASE. From this point on we can't safely
- * call OF any more.
- */
- lis r11,KERNELBASE@h
- mfspr r9,PVR
- rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
- cmpi 0,r9,1
- bne 4f
- ori r11,r11,4 /* set up BAT registers for 601 */
- li r8,0x7f /* valid, block length = 8MB */
- oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */
- oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */
- mtspr IBAT0U,r11 /* N.B. 601 has valid bit in */
- mtspr IBAT0L,r8 /* lower BAT register */
- mtspr IBAT1U,r9
- mtspr IBAT1L,r10
- b 5f
-4:
-#ifdef CONFIG_APUS
- ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */
- ori r11,r11,0xfe /* set up an 8MB mapping */
- lis r8,CYBERBASEp@h
- lwz r8,0(r8)
- addis r8,r8,KERNELBASE@h
- addi r8,r8,2
-#else
- ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */
- li r8,2 /* R/W access */
- /*
- * If the MMU is off clear the bats. See clear_bat() -- Cort
- */
-#ifndef CONFIG_GEMINI
- /*
- * allow secondary cpus to get at all of ram in early bootup
- * since their init_task may be up there -- Cort
- */
- oris r18,r8,0x10000000@h
- oris r21,r11,(KERNELBASE+0x10000000)@h
- mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */
- mtspr DBAT1U,r21 /* bit in upper BAT register */
- mtspr IBAT1L,r18
- mtspr IBAT1U,r21
-
- oris r18,r8,0x20000000@h
- oris r21,r11,(KERNELBASE+0x20000000)@h
- mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */
- mtspr DBAT2U,r21 /* bit in upper BAT register */
- mtspr IBAT2L,r18
- mtspr IBAT2U,r21
-#endif /* ndef CONFIG_GEMINI */
+ bl setup_init_bats
+#ifndef CONFIG_APUS
+#ifdef CONFIG_BOOTX_TEXT
+ bl setup_disp_bat
+#endif
#endif
- mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */
- mtspr DBAT0U,r11 /* bit in upper BAT register */
- mtspr IBAT0L,r8
- mtspr IBAT0U,r11
-5: isync
#ifdef CONFIG_APUS
/* Unfortunately the APUS specific instructions bloat the
* code so it cannot fit in the 0x100 bytes available. We have
#endif /* CONFIG_8xx */
b turn_on_mmu
+/* Hack for sleep on Core99 machines
+ */
+#ifdef CONFIG_POWERMAC
+ . = 0x80
+SleepVector:
+ .long 0
+ .long 0
+#endif /* CONFIG_POWERMAC */
+
/*
* GCC sometimes accesses words at negative offsets from the stack
* pointer, although the SysV ABI says it shouldn't. To cope with
#endif /* CONFIG_GEMINI */
#else
STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif
+#endif
/* Machine check */
STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
/* Construct the high word of the PPC-style PTE */
mfsrin r5,r3 /* get segment reg for segment */
rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */
-
-#ifndef __SMP__ /* do this later for SMP */
oris r5,r5,0x8000 /* set V (valid) bit */
-#endif
-
rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */
/* Get the address of the primary PTE group in the hash table */
.globl hash_page_patch_A
*/
found_empty:
found_slot:
+ clrlwi r5,r5,1 /* clear valid bit (0x80000000) */
stw r5,0(r3) /* clear V (valid) bit in PTE */
sync
tlbsync
blr
#endif /* CONFIG_ALTIVEC */
-#else /* CONFIG_8xx */
- .globl giveup_fpu
-giveup_fpu:
- blr
-#endif /* CONFIG_8xx */
-
mmu_off:
- addi r4, r3, __secondary_start - _start
+ addi r4, r3, mmu_off_return - _start
mfmsr r3
andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */
beqlr
. = 0x4000
#endif
+#else /* CONFIG_8xx */
+ .globl giveup_fpu
+giveup_fpu:
+ blr
+#endif /* CONFIG_8xx */
+
turn_on_mmu:
mfmsr r0
ori r1,r0,MSR_DR|MSR_IR
cror 14,14,18
bne 3,6f
ori r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC|HID0_ABE /* for g3/g4, enable */
+ rlwinm r11,r11,0,23,21 /* clear HID0_SPD */
li r3,0
mtspr ICTC,r3
5: mtspr HID0,r11 /* superscalar exec & br history tbl */
1:
#endif /* SHOW_SYSCALLS */
cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
+ cmpi 1,r0,0x6666 /* Special case for 'sys_rt_sigreturn' */
beq- 10f
+ beq- cr1,16f
lwz r10,TASK_FLAGS(r2)
andi. r10,r10,PF_TRACESYS
bne- 50f
/* sys_sigreturn */
10: addi r3,r1,STACK_FRAME_OVERHEAD
bl sys_sigreturn
+ cmpi 0,r3,0 /* Check for restarted system call */
+ bge int_return
+ b 20b
+/* sys_rt_sigreturn */
+16: addi r3,r1,STACK_FRAME_OVERHEAD
+ bl sys_rt_sigreturn
cmpi 0,r3,0 /* Check for restarted system call */
bge int_return
b 20b
mtlr r4
blr
#endif /* CONFIG_8xx */
-
-/*
- * We put a few things here that have to be page-aligned.
- * This stuff goes at the beginning of the data segment,
- * which is page-aligned.
- */
- .data
- .globl sdata
-sdata:
- .globl empty_zero_page
-empty_zero_page:
- .space 4096
-
- .globl swapper_pg_dir
-swapper_pg_dir:
- .space 4096
-
-/*
- * This space gets a copy of optional info passed to us by the bootstrap
- * Used to pass parameters into the kernel like root=/dev/sda1, etc.
- */
- .globl cmd_line
-cmd_line:
- .space 512
/*
* An undocumented "feature" of 604e requires that the v bit
blt 1b
sync
blr
+
+/* Use the first pair of BAT registers to map the 1st 16MB
+ * of RAM to KERNELBASE. From this point on we can't safely
+ * call OF any more.
+ */
+setup_init_bats:
+ lis r11,KERNELBASE@h
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpi 0,r9,1
+ bne 4f
+ ori r11,r11,4 /* set up BAT registers for 601 */
+ li r8,0x7f /* valid, block length = 8MB */
+ oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */
+ oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */
+ mtspr IBAT0U,r11 /* N.B. 601 has valid bit in */
+ mtspr IBAT0L,r8 /* lower BAT register */
+ mtspr IBAT1U,r9
+ mtspr IBAT1L,r10
+ b 5f
+4:
+#ifdef CONFIG_APUS
+ ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */
+ ori r11,r11,0xfe /* set up an 8MB mapping */
+ lis r8,CYBERBASEp@h
+ lwz r8,0(r8)
+ addis r8,r8,KERNELBASE@h
+ addi r8,r8,2
+#else
+ ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */
+ li r8,2 /* R/W access */
+ /*
+ * If the MMU is off clear the bats. See clear_bat() -- Cort
+ */
+#ifndef CONFIG_GEMINI
+ /*
+ * allow secondary cpus to get at all of ram in early bootup
+ * since their init_task may be up there -- Cort
+ */
+ oris r18,r8,0x10000000@h
+ oris r21,r11,(KERNELBASE+0x10000000)@h
+ mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */
+ mtspr DBAT1U,r21 /* bit in upper BAT register */
+ mtspr IBAT1L,r18
+ mtspr IBAT1U,r21
+ oris r18,r8,0x20000000@h
+ oris r21,r11,(KERNELBASE+0x20000000)@h
+ mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */
+ mtspr DBAT2U,r21 /* bit in upper BAT register */
+ mtspr IBAT2L,r18
+ mtspr IBAT2U,r21
+#endif /* ndef CONFIG_GEMINI */
+#endif
+ mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */
+ mtspr DBAT0U,r11 /* bit in upper BAT register */
+ mtspr IBAT0L,r8
+ mtspr IBAT0U,r11
+5: isync
+ blr
+
+#ifdef CONFIG_BOOTX_TEXT
+setup_disp_bat:
+ /*
+ * setup the display bat prepared for us in prom.c
+ */
+ mflr r8
+ bl reloc_offset
+ mtlr r8
+ lis r8, disp_BATL@h
+ ori r8, r8, disp_BATL@l
+ add r8, r3, r8
+ lwz r8, 0(r8)
+ lis r11, disp_BATU@h
+ ori r11, r11, disp_BATU@l
+ add r11, r3, r11
+ lwz r11, 0(r11)
+ mtspr IBAT3L,r8
+ mtspr IBAT3U,r11
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpi 0,r9,1
+ beq 1f
+ mtspr DBAT3L,r8
+ mtspr DBAT3U,r11
+1:
+ blr
+#endif
+
+/*
+ * We put a few things here that have to be page-aligned.
+ * This stuff goes at the beginning of the data segment,
+ * which is page-aligned.
+ */
+ .data
+ .globl sdata
+sdata:
+ .globl empty_zero_page
+empty_zero_page:
+ .space 4096
+
+ .globl swapper_pg_dir
+swapper_pg_dir:
+ .space 4096
+
+/*
+ * This space gets a copy of optional info passed to us by the bootstrap
+ * Used to pass parameters into the kernel like root=/dev/sda1, etc.
+ */
+ .globl cmd_line
+cmd_line:
+ .space 512
+
+
#include "local_irq.h"
-extern volatile unsigned long ipi_count;
+extern atomic_t ipi_recv;
+extern atomic_t ipi_sent;
+void enable_irq(unsigned int irq_nr);
void enable_irq(unsigned int irq_nr);
void disable_irq(unsigned int irq_nr);
if (!handler)
{
/* Free */
- for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next)
- {
- if (action->dev_id == dev_id)
- {
- /* Found it - now free it */
- save_flags(flags);
- cli();
- *p = action->next;
- restore_flags(flags);
- irq_kfree(action);
- return 0;
- }
- }
- return -ENOENT;
+ p = &irq_desc[irq].action;
+ while ((action = *p) != NULL && action->dev_id != dev_id)
+ p = &action->next;
+ if (action == NULL)
+ return -ENOENT;
+
+ /* Found it - now free it */
+ save_flags(flags);
+ cli();
+ *p = action->next;
+ if (irq_desc[irq].action == NULL)
+ disable_irq(irq);
+ restore_flags(flags);
+ irq_kfree(action);
+ return 0;
}
action = (struct irqaction *)
}
#ifdef __SMP__
/* should this be per processor send/receive? */
- len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
-#endif
+ /* should this be per processor send/receive? */
+ len += sprintf(buf+len, "IPI: (recv/sent) %10lu/%lu\n",
+ atomic_read(&ipi_recv), atomic_read(&ipi_sent));
+#endif /* __SMP__ */
len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
return len;
}
atomic_t global_bh_count;
atomic_t global_bh_lock;
+extern unsigned long *_get_SP(void);
+
static void show(char * str)
{
+#if 0
int i;
unsigned long *stack;
+#endif
int cpu = smp_processor_id();
printk("\n%s, CPU %d:\n", str, cpu);
atomic_read(&global_bh_count),
ppc_local_bh_count[0],
ppc_local_bh_count[1]);
+#if 1
+ printk(" CPU: %d last CPU: %d\n", current->processor,current->last_processor);
+ print_backtrace (_get_SP());
+#else
stack = (unsigned long *) &str;
for (i = 40; i ; i--) {
unsigned long x = *++stack;
printk("<[%08lx]> ", x);
}
}
+#endif
}
static inline void wait_on_bh(void)
#include <asm/io.h>
#include <asm/mbx.h>
+#include <asm/machdep.h>
+#include "pci.h"
/*
* This blows......The MBX uses the Tundra QSpan PCI bridge. When
#include <asm/ide.h>
#include <asm/mbx.h>
#include <asm/machdep.h>
-
+#include <asm/keyboard.h>
+#include <asm/8xx_immap.h>
#include <asm/time.h>
+
#include "local_irq.h"
static int mbx_set_rtc_time(unsigned long time);
unsigned long mbx_get_rtc_time(void);
void mbx_calibrate_decr(void);
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
+
extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int mackbd_getkeycode(unsigned int scancode);
extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
- ppc_md.SYSRQ_KEY = 0x54;
+ ppc_md.sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
#endif
#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
* Flush MMU TLB
*/
_GLOBAL(_tlbia)
+#if defined(CONFIG_SMP)
+ mfmsr r10
+ sync
+ rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
+ mtmsr r0
+ SYNC
+ lis r9,hash_table_lock@h
+ ori r9,r9,hash_table_lock@l
+ lwz r8,PROCESSOR(r2)
+ oris r8,r8,10
+10: lwarx r7,0,r9
+ cmpi 0,r7,0
+ bne- 10b
+ stwcx. r8,0,r9
+ bne- 10b
+ eieio
+#endif /* CONFIG_SMP */
sync
tlbia
sync
#ifdef __SMP__
tlbsync
sync
+ li r0,0
+ stw r0,0(r9) /* clear hash_table_lock */
+ mtmsr r10
+ SYNC
#endif
blr
* Flush MMU TLB for a particular address
*/
_GLOBAL(_tlbie)
+#if defined(CONFIG_SMP)
+ mfmsr r10
+ sync
+ rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
+ mtmsr r0
+ SYNC
+ lis r9,hash_table_lock@h
+ ori r9,r9,hash_table_lock@l
+ lwz r8,PROCESSOR(r2)
+ oris r8,r8,11
+10: lwarx r7,0,r9
+ cmpi 0,r7,0
+ bne- 10b
+ stwcx. r8,0,r9
+ bne- 10b
+ eieio
+#endif /* CONFIG_SMP */
tlbie r3
sync
-#ifdef __SMP__
+#ifdef CONFIG_SMP
tlbsync
sync
+ li r0,0
+ stw r0,0(r9) /* clear hash_table_lock */
+ mtmsr r10
+ SYNC
#endif
blr
* The *_ns versions don't do byte-swapping.
*/
_GLOBAL(_insb)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,1
+ blelr-
00: lbz r5,0(r3)
eieio
stbu r5,1(r4)
blr
_GLOBAL(_outsb)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,1
+ blelr-
00: lbzu r5,1(r4)
stb r5,0(r3)
eieio
blr
_GLOBAL(_insw)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,2
+ blelr-
00: lhbrx r5,0,r3
eieio
sthu r5,2(r4)
blr
_GLOBAL(_outsw)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,2
+ blelr-
00: lhzu r5,2(r4)
eieio
sthbrx r5,0,r3
blr
_GLOBAL(_insl)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,4
+ blelr-
00: lwbrx r5,0,r3
eieio
stwu r5,4(r4)
blr
_GLOBAL(_outsl)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,4
+ blelr-
00: lwzu r5,4(r4)
stwbrx r5,0,r3
eieio
_GLOBAL(ide_insw)
_GLOBAL(_insw_ns)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,2
+ blelr-
00: lhz r5,0(r3)
eieio
sthu r5,2(r4)
_GLOBAL(ide_outsw)
_GLOBAL(_outsw_ns)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,2
+ blelr-
00: lhzu r5,2(r4)
sth r5,0(r3)
eieio
blr
_GLOBAL(_insl_ns)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,4
+ blelr-
00: lwz r5,0(r3)
eieio
stwu r5,4(r4)
blr
_GLOBAL(_outsl_ns)
+ cmpwi 0,r5,0
mtctr r5
subi r4,r4,4
+ blelr-
00: lwzu r5,4(r4)
stw r5,0(r3)
eieio
mfspr r3,HID0
blr
-_GLOBAL(_get_ICTC)
- mfspr r3,ICTC
- blr
-
-_GLOBAL(_set_ICTC)
- mtspr ICTC,r3
+_GLOBAL(_set_HID0)
+ sync
+ mtspr HID0, r3
+ sync
+ isync /* Handle erratas in some cases */
blr
-
/*
L2CR functions
Copyright © 1997-1998 by PowerLogix R & D, Inc.
/*
Thur, Dec. 12, 1998.
- First public release, contributed by PowerLogix.
+ ***********
+ Sat, Aug. 7, 1999.
+ - Terry: Made sure code disabled interrupts before running. (Previously
+ it was assumed interrupts were already disabled).
+ - Terry: Updated for tentative G4 support. 4MB of memory is now flushed
+ instead of 2MB. (Prob. only 3 is necessary).
+ - Terry: Updated for workaround to HID0[DPM] processor bug
+ during global invalidates.
+ ***********
+ Thu, July 13, 2000.
+ - Terry: Added isync to correct for an errata.
Author: Terry Greeniaus (tgree@phys.ualberta.ca)
Please e-mail updates to this file to me, thanks!
causes cache pushes from the L1 cache to go to the L2 cache
instead of to main memory.
*/
-
+/*
+ * Summary: this procedure ignores the L2I bit in the value passed in,
+ * flushes the cache if it was already enabled, always invalidates the
+ * cache, then enables the cache if the L2E bit is set in the value
+ * passed in.
+ * -- paulus.
+ */
_GLOBAL(_set_L2CR)
- /* Make sure this is a 750 chip */
+ /* Make sure this is a 750 or 7400 chip */
mfspr r4,PVR
rlwinm r4,r4,16,16,31
- cmplwi r4,0x0008
- beq thisIs750
- cmplwi r4,0x000c
- beq thisIs750
- li r3,-1
- blr
-
-thisIs750:
- /* Get the current enable bit of the L2CR into r4 */
- mfspr r4,L2CR
- mfmsr r7
-
- /* See if we want to perform a global inval this time. */
- rlwinm r6,r3,0,10,10 /* r6 contains the new invalidate bit */
- rlwinm. r5,r3,0,0,0 /* r5 contains the new enable bit */
- rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */
- rlwimi r3,r4,0,0,0 /* Keep the enable bit the same as it was. */
- bne dontDisableCache /* Only disable the cache if L2CRApply
- has the enable bit off */
-
-disableCache:
- /* Disable the cache. First, we turn off interrupts.
- An interrupt while we are flushing the cache could bring
- in data which may not get properly flushed. */
- rlwinm r4,r7,0,17,15 /* Turn off EE bit */
+ cmpwi r4,0x0008
+ cmpwi cr1,r4,0x000c
+ cror 2,2,4*cr1+2
+ bne 99f
+
+ /* Turn off interrupts and data relocation. */
+ mfmsr r7 /* Save MSR in r7 */
+ rlwinm r4,r7,0,17,15
+ rlwinm r4,r4,0,28,26 /* Turn off DR bit */
sync
mtmsr r4
sync
+
+ /* Get the current enable bit of the L2CR into r4 */
+ mfspr r4,L2CR
-/*
- Now, read the first 2MB of memory to put new data in the cache.
- (Actually we only need the size of the L2 cache plus the size
- of the L1 cache, but 2MB will cover everything just to be safe).
-*/
- lis r4,0x0001
+ /* Tweak some bits */
+ rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */
+ rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */
+ rlwinm r3,r3,0,1,31 /* Turn off the enable bit */
+
+ /* Check to see if we need to flush */
+ rlwinm. r4,r4,0,0,0
+ beq 2f
+
+ /* Flush the cache. First, read the first 4MB of memory (physical) to
+ * put new data in the cache. (Actually we only need
+ * the size of the L2 cache plus the size of the L1 cache, but 4MB will
+ * cover everything just to be safe).
+ */
+
+ /**** Might be a good idea to set L2DO here - to prevent instructions
+ from getting into the cache. But since we invalidate
+ the next time we enable the cache it doesn't really matter.
+ ****/
+
+ lis r4,0x0002
mtctr r4
- lis r4,KERNELBASE@h
-1: lwzx r0,r0,r4
- addi r4,r4,0x0020 /* Go to start of next cache line */
+ li r4,0
+1:
+ lwzx r0,r0,r4
+ addi r4,r4,32 /* Go to start of next cache line */
bdnz 1b
- /* Now, flush the first 2MB of memory */
- lis r4,0x0001
+ /* Now, flush the first 4MB of memory */
+ lis r4,0x0002
mtctr r4
- lis r4,KERNELBASE@h
+ li r4,0
sync
-2: dcbf r0,r4
- addi r4,r4,0x0020 /* Go to start of next cache line */
- bdnz 2b
-
- /* Turn off the L2CR enable bit. */
- rlwinm r3,r3,0,1,31
-
-dontDisableCache:
- /* Set up the L2CR configuration bits */
+1:
+ dcbf r0,r4
+ addi r4,r4,32 /* Go to start of next cache line */
+ bdnz 1b
+
+2:
+ /* Set up the L2CR configuration bits (and switch L2 off) */
sync
mtspr L2CR,r3
sync
- /* Reenable interrupts if necessary. */
- mtmsr r7
+ /* Before we perform the global invalidation, we must disable dynamic
+ * power management via HID0[DPM] to work around a processor bug where
+ * DPM can possibly interfere with the state machine in the processor
+ * that invalidates the L2 cache tags.
+ */
+ mfspr r8,HID0 /* Save HID0 in r8 */
+ rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */
sync
-
- cmplwi r6,0
- beq noInval
-
+ mtspr HID0,r4 /* Disable DPM */
+ sync
+
/* Perform a global invalidation */
oris r3,r3,0x0020
sync
mtspr L2CR,r3
sync
+ isync /* For errata */
/* Wait for the invalidation to complete */
3: mfspr r3,L2CR
mtspr L2CR,r3
sync
-noInval:
+ /* Restore HID0[DPM] to whatever it was before */
+ sync
+ mtspr 1008,r8
+ sync
+
/* See if we need to enable the cache */
cmplwi r5,0
- beqlr
+ beq 4f
/* Enable the cache */
oris r3,r3,0x8000
mtspr L2CR,r3
sync
+
+ /* Restore MSR (restores EE and DR bits to original state) */
+4: sync
+ mtmsr r7
+ sync
+ blr
+
+99: li r3,-1
blr
_GLOBAL(_get_L2CR)
/* Make sure this is a 750 chip */
mfspr r3,PVR
- rlwinm r3,r3,16,16,31
- cmplwi r3,0x0008
- beq 1f
- cmplwi r3,0x000c
+ srwi r3,r3,16
+ cmpwi r3,0x0008
+ cmpwi cr1,r3,0x000c
li r3,0
+ cror 2,2,4*cr1+2
bnelr
-1:
/* Return the L2CR contents */
mfspr r3,L2CR
blr
/* --- End of PowerLogix code ---
*/
-/*
-_GLOBAL(_get_L2CR)
- mfspr r3,L2CR
- blr
-
-_GLOBAL(_set_L2CR)
- mtspr L2CR,r3
- blr
-
-*/
/*
* These are used in the alignment trap handler when emulating
.long sys_getresuid /* 165 */
.long sys_query_module
.long sys_poll
-#ifdef CONFIG_NFSD
.long sys_nfsservctl
-#else
- .long sys_ni_syscall
-#endif
.long sys_setresgid
.long sys_getresgid /* 170 */
.long sys_prctl
.long sys_ni_syscall /* streams1 */
.long sys_ni_syscall /* streams2 */
.long sys_vfork
- .space (NR_syscalls-183)*4
+ .long sys_ni_syscall /* 190 */ /* MacOnLinux - old */
+ .long sys_ni_syscall /* 191 */ /* Unused */
+ .long sys_ni_syscall /* 192 - reserved - mmap2 */
+ .long sys_ni_syscall /* 193 - reserved - truncate64 */
+ .long sys_ni_syscall /* 194 - reserved - ftruncate64 */
+ .long sys_ni_syscall /* 195 - reserved - stat64 */
+ .long sys_ni_syscall /* 196 - reserved - lstat64 */
+ .long sys_ni_syscall /* 197 - reserved - fstat64 */
+ .long sys_pciconfig_read /* 198 */
+ .long sys_pciconfig_write /* 199 */
+ .long sys_pciconfig_iobase /* 200 */
+ .long sys_ni_syscall /* 201 - reserved - MacOnLinux - new */
+ .space (NR_syscalls-201)*4
+/*
+ * open_pic.c
+ *
+ * Common support routines for platforms with an OpenPIC interrupt controller
+ *
+ */
+
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/openpic.h>
#include <asm/irq.h>
+#include <asm/processor.h>
#include "open_pic.h"
#include "i8259.h"
-#ifdef __SMP__
-void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
- smp_message_recv(cpl-OPENPIC_VEC_IPI);
-}
-#endif /* __SMP__ */
+extern volatile unsigned char *chrp_int_ack_special;
-void chrp_mask_and_ack_irq(unsigned int irq_nr)
+void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
{
- if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
- i8259_pic.mask_and_ack(irq_nr);
-}
+ int irq;
+ int openpic_eoi_done = 0;
-static void chrp_mask_irq(unsigned int irq_nr)
-{
- if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
- i8259_pic.disable(irq_nr);
+#ifdef __SMP__
+ {
+ unsigned int loops = 1000000;
+ while (test_bit(0, &global_irq_lock)) {
+ if (smp_processor_id() == global_irq_holder) {
+ printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ break;
+ }
+ if (loops-- == 0) {
+ printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+ xmon(0);
+#endif
+ }
+ }
+ }
+#endif /* __SMP__ */
+
+ irq = openpic_irq(smp_processor_id());
+ /* make sure open_pic.irq_offset is set to something!
+ * do we really need the _MACH_Pmac test??
+ */
+ if (!(_machine == _MACH_Pmac) && (irq == open_pic.irq_offset))
+ {
+ /*
+ * This magic address generates a PCI IACK cycle.
+ *
+ * This should go in the above mask/ack code soon. -- Cort
+ */
+ if ( chrp_int_ack_special )
+ irq = *chrp_int_ack_special;
+#ifndef CONFIG_PMAC
+ else
+ irq = i8259_irq(0);
+#endif
+ /*
+ * Acknowledge as soon as possible to allow i8259
+ * interrupt nesting */
+ openpic_eoi(smp_processor_id());
+ openpic_eoi_done = 1;
+ }
+ if (irq == OPENPIC_VEC_SPURIOUS)
+ {
+ /*
+ * Spurious interrupts should never be
+ * acknowledged
+ */
+ ppc_spurious_interrupts++;
+ openpic_eoi_done = 1;
+ goto out;
+ }
+
+ if (irq < 0)
+ {
+ printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+ irq, regs->nip);
+ ppc_spurious_interrupts++;
+ }
else
- openpic_disable_irq(irq_nr-open_pic.irq_offset);
+ {
+ ppc_irq_dispatch_handler( regs, irq );
+ }
+out:
+ if (!openpic_eoi_done)
+ openpic_eoi(smp_processor_id());
}
-static void chrp_unmask_irq(unsigned int irq_nr)
+#ifdef __SMP__
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
{
- if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr))
- i8259_pic.enable(irq_nr);
- else
- openpic_enable_irq(irq_nr-open_pic.irq_offset);
+ smp_message_recv(cpl-OPENPIC_VEC_IPI);
}
+#endif /* __SMP__ */
+
struct hw_interrupt_type open_pic = {
" OpenPIC ",
NULL,
NULL,
NULL,
- chrp_unmask_irq,
- chrp_mask_irq,
- chrp_mask_and_ack_irq,
+ openpic_enable_irq,
+ openpic_disable_irq,
+ /* Theorically, the mask&ack should be NULL for OpenPIC. However, doing
+ * so shows tons of bogus interrupts coming in.
+ * This problem is apparently due to the common code always calling
+ * unmask(). I apparently (need more test) fixed it in the 2.4 new IRQ
+ * management by cleanly implementing the handler's end() function, so
+ * neither mask nor unmask are needed. In the meantime, the fix below will
+ * work for 2.2 -Benh
+ *
+ * Hopefully this will fix my bogus interrups on MTX
+ * I merged everthing together so we don't have the same code in three
+ * places. This might cause stability problems, but I'd rather
+ * get it right once than three different times because someone forgot
+ * to make the same change to PReP or something --Troy
+ */
+ openpic_disable_irq,
0
};
extern struct hw_interrupt_type open_pic;
+void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
void openpic_enable_IPI(u_int ipi);
void do_openpic_setup_cpu(void);
* Note: We might want to adjust priorities too.
*/
-__initfunc(void openpic_init(int main_pic))
+/* Not an init func, called on pbook wakeup --BenH */
+void
+__init
+openpic_init(int main_pic)
{
u_int t, i;
u_int timerfreq;
/* Initialize IPI interrupts */
for (i = 0; i < OPENPIC_NUM_IPI; i++) {
- openpic_initipi(i, 0/*10*/, OPENPIC_VEC_IPI+i);
+ openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i);
}
if (_machine != _MACH_Pmac) {
openpic_initirq( np->intrs[j].line,
pri,
np->intrs[j].line,
- np->intrs[j].sense,
+ 0,
np->intrs[j].sense);
irq_desc[np->intrs[j].line].level = np->intrs[j].sense;
}
{
openpic_setfield(&OpenPIC->Global.Global_Configuration0,
OPENPIC_CONFIG_RESET);
+ /* Wait for reset to complete */
+ while(openpic_readfield(&OpenPIC->Global.Global_Configuration0,
+ OPENPIC_CONFIG_RESET))
+ ;
}
for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
openpic_enable_IPI(i);
-#if 0
+
/* let the openpic know we want intrs */
for ( i = 0; i < NumSources ; i++ )
openpic_mapirq(i, openpic_read(&OpenPIC->Source[i].Destination)
| (1<<smp_processor_id()) );
-#endif
+
openpic_set_priority(smp_processor_id(), 0);
}
*/
void openpic_enable_irq(u_int irq)
{
- check_arg_irq(irq);
+ /* on SMP, we get IPI vector numbers here, we should handle them
+ * or at least ignore them.
+ */
+ if (irq < 0 || irq >= NumSources)
+ return;
openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
/* make sure mask gets to controller before we return to user */
do {
OPENPIC_MASK));
}
+u_int openpic_get_enable(u_int irq)
+{
+ if (irq < 0 || irq >= NumSources)
+ return 0;
+ return !openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_MASK);
+}
+
void openpic_disable_irq(u_int irq)
{
- check_arg_irq(irq);
+ u32 vp;
+
+ /* on SMP, we get IPI vector numbers here, we should handle them
+ * or at least ignore them.
+ */
+ if (irq < 0 || irq >= NumSources)
+ return;
openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK);
/* make sure mask gets to controller before we return to user */
do {
- mb();
- } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
- OPENPIC_MASK));
+ mb(); /* sync is probably useless here */
+ vp = openpic_readfield(&OpenPIC->Source[irq].Vector_Priority,
+ OPENPIC_MASK | OPENPIC_ACTIVITY);
+ } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
}
/*
OPENPIC_SENSE_LEVEL,
(sense ? OPENPIC_SENSE_LEVEL : 0));
}
+
+#ifdef CONFIG_PMAC_PBOOK
+static u32 save_ipi_vp[OPENPIC_NUM_IPI];
+static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
+static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
+static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
+
+__pmac
+void
+openpic_sleep_save_intrs(void)
+{
+ int i;
+
+ for (i=0; i<OPENPIC_NUM_IPI; i++)
+ save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
+ for (i=0; i<NumSources; i++) {
+ save_irq_src_vp[i] = openpic_read(&OpenPIC->Source[i].Vector_Priority);
+ save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination);
+ }
+ for (i=0; i<NumProcessors; i++) {
+ save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
+ openpic_set_priority(i, 0xf);
+ }
+}
+
+__pmac
+void
+openpic_sleep_restore_intrs(void)
+{
+ int i;
+
+ for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
+ openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i);
+ openpic_maptimer(i, 0);
+ }
+ for (i=0; i<OPENPIC_NUM_IPI; i++)
+ openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), save_ipi_vp[i]);
+ for (i=0; i<NumSources; i++) {
+ openpic_write(&OpenPIC->Source[i].Vector_Priority, save_irq_src_vp[i]);
+ openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]);
+ }
+ openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
+ openpic_disable_8259_pass_through();
+ for (i=0; i<NumProcessors; i++)
+ openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, save_cpu_task_pri[i]);
+}
+#endif /* CONFIG_PMAC_PBOOK */
\ No newline at end of file
#include <linux/init.h>
#include <linux/config.h>
#include <linux/openpic.h>
+#include <linux/capability.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
+#include <asm/pci.h>
#include <asm/residual.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/gg2.h>
+#include <asm/uaccess.h>
#include "pci.h"
}
}
#endif
+
+
+void *
+pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical)
+{
+ if (!ppc_md.pci_dev_io_base) {
+ /* Please, someone fix this for non-pmac machines, we
+ * need either the virtual or physical PCI IO base
+ */
+ return 0;
+ }
+ return ppc_md.pci_dev_io_base(bus, devfn, physical);
+}
+
+void *
+pci_dev_mem_base(unsigned char bus, unsigned char devfn)
+{
+ /* Default memory base is 0 (1:1 mapping) */
+ if (!ppc_md.pci_dev_mem_base) {
+ /* Please, someone fix this for non-pmac machines.*/
+ return 0;
+ }
+ return ppc_md.pci_dev_mem_base(bus, devfn);
+}
+
+/* Returns the root-bridge number (Uni-N number) of a device */
+int
+pci_dev_root_bridge(unsigned char bus, unsigned char devfn)
+{
+ /* Defaults to 0 */
+ if (!ppc_md.pci_dev_root_bridge)
+ return 0;
+ return ppc_md.pci_dev_root_bridge(bus, devfn);
+}
+
+/*
+ * Those syscalls are derived from the Alpha versions, they
+ * allow userland apps to retreive the per-device iobase and
+ * mem-base. They also provide wrapper for userland to do
+ * config space accesses.
+ * The "host_number" returns the number of the Uni-N sub bridge
+ */
+
+asmlinkage int
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ long err = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (!pcibios_present())
+ return -ENOSYS;
+
+ switch (len) {
+ case 1:
+ err = pcibios_read_config_byte(bus, dfn, off, &ubyte);
+ put_user(ubyte, buf);
+ break;
+ case 2:
+ err = pcibios_read_config_word(bus, dfn, off, &ushort);
+ put_user(ushort, (unsigned short *)buf);
+ break;
+ case 4:
+ err = pcibios_read_config_dword(bus, dfn, off, &uint);
+ put_user(uint, (unsigned int *)buf);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+asmlinkage int
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+ unsigned long off, unsigned long len,
+ unsigned char *buf)
+{
+ unsigned char ubyte;
+ unsigned short ushort;
+ unsigned int uint;
+ long err = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (!pcibios_present())
+ return -ENOSYS;
+
+ switch (len) {
+ case 1:
+ err = get_user(ubyte, buf);
+ if (err)
+ break;
+ err = pcibios_write_config_byte(bus, dfn, off, ubyte);
+ if (err != PCIBIOS_SUCCESSFUL) {
+ err = -EFAULT;
+ }
+ break;
+ case 2:
+ err = get_user(ushort, (unsigned short *)buf);
+ if (err)
+ break;
+ err = pcibios_write_config_word(bus, dfn, off, ushort);
+ if (err != PCIBIOS_SUCCESSFUL) {
+ err = -EFAULT;
+ }
+ break;
+ case 4:
+ err = get_user(uint, (unsigned int *)buf);
+ if (err)
+ break;
+ err = pcibios_write_config_dword(bus, dfn, off, uint);
+ if (err != PCIBIOS_SUCCESSFUL) {
+ err = -EFAULT;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+/* Provide information on locations of various I/O regions in physical
+ * memory. Do this on a per-card basis so that we choose the right
+ * root bridge.
+ * Note that the returned IO or memory base is a physical address
+ */
+
+asmlinkage long
+sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+{
+ long result = -EOPNOTSUPP;
+
+ switch (which) {
+ case IOBASE_BRIDGE_NUMBER:
+ return (long)pci_dev_root_bridge(bus, devfn);
+ case IOBASE_MEMORY:
+ return (long)pci_dev_mem_base(bus, devfn);
+ case IOBASE_IO:
+ result = (long)pci_dev_io_base(bus, devfn, 1);
+ if (result == 0)
+ result = -EOPNOTSUPP;
+ break;
+ }
+
+ return result;
+}
struct device_node* node;
volatile unsigned int* cfg_addr;
volatile unsigned int* cfg_data;
+ void* iobase;
+ void* iobase_phys;
};
static struct uninorth_data uninorth_bridges[3];
return 0;
}
+/* This routines figures out on which root bridge a given PCI device
+ * is attached.
+ *
+ * WARNING: When passed the address of the bridge itself (11), it must
+ * return the AGP bus. Currently, it returns 0, which is by
+ * chance the AGP one. We may have to improve that however...
+ */
+__pmac
+int
+pmac_pci_dev_root_bridge(unsigned char bus, unsigned char dev_fn)
+{
+ struct device_node *node, *bridge_node;
+ int bridge = uninorth_default;
+
+ if (uninorth_count == 0)
+ return 0;
+ if (bus == 0 && PCI_SLOT(dev_fn) < 11)
+ return 0;
+
+ /* We look for the OF device corresponding to this bus/devfn pair. If we
+ * don't find it, we default to the external PCI */
+ bridge_node = NULL;
+ node = find_pci_device_OFnode(bus, dev_fn & 0xf8);
+ if (node) {
+ /* note: we don't stop on the first occurence since we need to go
+ * up to the root bridge */
+ do {
+ if (node->type && !strcmp(node->type, "pci")
+ && device_is_compatible(node, "uni-north"))
+ bridge_node = node;
+ node=node->parent;
+ } while (node);
+ }
+ if (bridge_node) {
+ int i;
+ for (i=0;i<uninorth_count;i++)
+ if (uninorth_bridges[i].node == bridge_node) {
+ bridge = i;
+ break;
+ }
+ }
+
+ if (bridge == -1) {
+ printk(KERN_WARNING "pmac_pci: no default bridge !\n");
+ return 0;
+ }
+
+ return bridge;
+}
+
+__pmac
+void *
+pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical)
+{
+ int bridge = -1;
+ if (uninorth_count != 0)
+ bridge = pmac_pci_dev_root_bridge(bus, devfn);
+ if (bridge == -1) {
+ struct bridge_data *bp;
+
+ if (bus > max_bus || (bp = bridges[bus]) == 0)
+ return 0;
+ return physical ? bp->io_base_phys : bp->io_base;
+ }
+ return physical ? uninorth_bridges[bridge].iobase_phys
+ : uninorth_bridges[bridge].iobase;
+}
+
+__pmac
+void *
+pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn)
+{
+ return 0;
+}
+
/* This function only works for bus 0, uni-N uses a different mecanism for
* other busses (see below)
*/
|1UL)
-/* We should really use RTAS here, unfortunately, it's not available with BootX.
- * (one more reason for writing a beautiful OF booter). I'll do the RTAS stuff
- * later, once I have something that works enough with BootX.
- */
__pmac static
unsigned int
uni_north_access_data(unsigned char bus, unsigned char dev_fn,
unsigned char offset)
{
- struct device_node *node, *bridge_node;
- int bridge = uninorth_default;
+ int bridge;
unsigned int caddr;
- if (bus == 0) {
- if (PCI_SLOT(dev_fn) < 11) {
- return 0;
- }
- /* We look for the OF device corresponding to this bus/devfn pair. If we
- * don't find it, we default to the external PCI */
- bridge_node = NULL;
- node = find_pci_device_OFnode(bus, dev_fn & 0xf8);
- if (node) {
- /* note: we don't stop on the first occurence since we need to go
- * up to the root bridge */
- do {
- if (!strcmp(node->type, "pci"))
- bridge_node = node;
- node=node->parent;
- } while (node);
- }
- if (bridge_node) {
- int i;
- for (i=0;i<uninorth_count;i++)
- if (uninorth_bridges[i].node == bridge_node) {
- bridge = i;
- break;
- }
- }
+ bridge = pmac_pci_dev_root_bridge(bus, dev_fn);
+ if (bus == 0)
caddr = UNI_N_CFA0(dev_fn, offset);
- } else
+ else
caddr = UNI_N_CFA1(bus, dev_fn, offset);
-
+
if (bridge == -1) {
printk(KERN_WARNING "pmac_pci: no default bridge !\n");
return 0;
out_le32((volatile unsigned int *)bp->cfg_data, val);
}
+static int __init
+fixup_one_level_bus_range(struct device_node *node, int higher)
+{
+ for (; node != 0;node = node->sibling) {
+ int * bus_range;
+ unsigned int *class_code;
+ int len;
+
+ /* For PCI<->PCI bridges or CardBus bridges, we go down */
+ class_code = (unsigned int *) get_property(node, "class-code", 0);
+ if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+ (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+ continue;
+ bus_range = (int *) get_property(node, "bus-range", &len);
+ if (bus_range != NULL && len > 2 * sizeof(int)) {
+ if (bus_range[1] > higher)
+ higher = bus_range[1];
+ }
+ higher = fixup_one_level_bus_range(node->child, higher);
+ }
+ return higher;
+}
+
+/* This routine fixes the "bus-range" property of all bridges in the
+ * system since they tend to have their "last" member wrong on macs
+ *
+ * Note that the bus numbers manipulated here are OF bus numbers, they
+ * are not Linux bus numbers.
+ */
+static void __init
+fixup_bus_range(struct device_node *bridge)
+{
+ int * bus_range;
+ int len;
+
+ /* Lookup the "bus-range" property for the hose */
+ bus_range = (int *) get_property(bridge, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s\n",
+ bridge->full_name);
+ return;
+ }
+ bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+}
__initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end))
{
dev->full_name);
continue;
}
+ fixup_bus_range(dev);
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",
uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000);
uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000);
uninorth_bridges[i].node = dev;
+ uninorth_bridges[i].iobase_phys = (void *)addr->address;
+ /* is 0x10000 enough for io space ? */
+ uninorth_bridges[i].iobase = (void *)ioremap(addr->address, 0x10000);
/* XXX This is the bridge with the PCI expansion bus. This is also the
* address of the bus that will receive type 1 config accesses and io
* accesses. Appears to be correct for iMac DV and G4 Sawtooth too.
if (device_is_compatible(dev, "uni-north")) {
bp->cfg_addr = 0;
bp->cfg_data = 0;
- /* is 0x10000 enough for io space ? */
- bp->io_base = (void *)ioremap(addr->address, 0x10000);
+ bp->io_base = uninorth_bridges[uninorth_count-1].iobase;
+ bp->io_base_phys = uninorth_bridges[uninorth_count-1].iobase_phys;
} else if (strcmp(dev->name, "pci") == 0) {
/* XXX assume this is a mpc106 (grackle) */
bp->cfg_addr = (volatile unsigned int *)
bp->cfg_data = (volatile unsigned char *)
ioremap(0xfee00000, 0x1000);
bp->io_base = (void *) ioremap(0xfe000000, 0x20000);
+ bp->io_base_phys = (void *)0xfe000000;
if (machine_is_compatible("AAPL,PowerBook1998"))
grackle_set_loop_snoop(bp, 1);
#if 0 /* Disabled for now, HW problems ??? */
bp->cfg_data = (volatile unsigned char *)
ioremap(addr->address + 0xc00000, 0x1000);
bp->io_base = (void *) ioremap(addr->address, 0x10000);
+ bp->io_base_phys = (void *)addr->address;
}
if (isa_io_base == 0)
isa_io_base = (unsigned long) bp->io_base;
#include <asm/smp.h>
#include <asm/prom.h>
#include "pmac_pic.h"
+#include "open_pic.h"
struct pmac_irq_hw {
unsigned int flag;
static int max_irqs;
static int max_real_irqs;
-static int has_openpic = 0;
+
+extern u_int openpic_read(volatile u_int *addr);
#define MAXCOUNT 10000000
pmac_set_irq_mask(irq_nr);
}
-static void pmac_openpic_mask_irq(unsigned int irq_nr)
-{
- openpic_disable_irq(irq_nr);
-}
-
-static void pmac_openpic_unmask_irq(unsigned int irq_nr)
-{
- openpic_enable_irq(irq_nr);
-}
-
-
-
struct hw_interrupt_type pmac_pic = {
" PMAC-PIC ",
NULL,
0
};
-struct hw_interrupt_type pmac_open_pic = {
- " OpenPIC ",
- NULL,
- NULL,
- NULL,
- pmac_openpic_unmask_irq,
- pmac_openpic_mask_irq,
- NULL,/*pmac_openpic_mask_irq,*/
- 0
-};
-
static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
{
int irq, bits;
int cpu,
int isfake)
{
+ extern void psurge_smp_message_recv(void);
+
int irq;
unsigned long bits = 0;
if (xmon_2nd)
xmon(regs);
#endif
- pmac_smp_message_recv();
+ psurge_smp_message_recv();
goto out;
}
/* could be here due to a do_fake_interrupt call but we don't
}
#endif /* __SMP__ */
- /* Yeah, I know, this could be a separate do_IRQ function */
- if (has_openpic) {
- irq = openpic_irq(0);
- if (irq == OPENPIC_VEC_SPURIOUS) {
- /* Spurious interrupts should never be ack'ed */
- ppc_spurious_interrupts++;
- } else {
- /* Can this happen ? (comes from CHRP code) */
- if (irq < 0) {
- printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
- irq, regs->nip);
- ppc_spurious_interrupts++;
- } else {
- if (!irq_desc[irq].level)
- openpic_eoi(0);
- ppc_irq_dispatch_handler( regs, irq );
- if (irq_desc[irq].level)
- openpic_eoi(0);
- }
- }
- return;
- }
-
for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
int i = irq >> 5;
bits = ld_le32(&pmac_irq_hw[i]->flag)
struct device_node *irqctrler;
volatile struct pmac_irq_hw *addr;
int second_irq;
+ u_int t;
+ int nr_irq;
/* We first try to detect Apple's new Core99 chipset, since mac-io
* is quite different on those machines and contains an IBM MPIC2.
OpenPIC = (volatile struct OpenPIC *)
ioremap(irqctrler->addrs[0].address,
irqctrler->addrs[0].size);
- for ( i = 0 ; i < NR_IRQS ; i++ ) {
- irq_desc[i].ctl = &pmac_open_pic;
+ /* from openpic.c code... --Troy
+ * dynamically figure out how many interrupts
+ * We should really do something like panic
+ * if nr_irq >= OPENPIC_VEC_IPI
+ */
+ t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
+ nr_irq = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
+ OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
+
+ for ( i = 0 ; i < nr_irq ; i++ ) {
+ irq_desc[i].ctl = &open_pic;
irq_desc[i].level = 0;
}
+ ppc_md.do_IRQ = open_pic_do_IRQ;
+ open_pic.irq_offset = 0;
openpic_init(1);
- has_openpic = 1;
#ifdef CONFIG_XMON
pswitch = find_devices("programmer-switch");
if (pswitch && pswitch->n_intrs)
request_irq(pswitch->intrs[0].line, xmon_irq, 0,
"NMI - XMON", 0);
#endif /* CONFIG_XMON */
+#ifdef __SMP__
+ request_irq(OPENPIC_VEC_IPI, openpic_ipi_action,
+ 0, "IPI0", 0);
+ request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action,
+ 0, "IPI1 (invalidate TLB)", 0);
+ request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action,
+ 0, "IPI2 (stop CPU)", 0);
+ request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action,
+ 0, "IPI3 (reschedule)", 0);
+#endif /* __SMP__ */
return;
}
irqctrler = NULL;
* sleep_save_intrs() saves the states of all interrupt enables
* and disables all interupts except for the nominated one.
* sleep_restore_intrs() restores the states of all interrupt enables.
+ *
+ * TODO: Those should be sleep notifiers with high priority.
*/
unsigned int sleep_save_mask[2];
void
-sleep_save_intrs(int viaint)
+pmac_sleep_save_intrs(int viaint)
{
sleep_save_mask[0] = ppc_cached_irq_mask[0];
sleep_save_mask[1] = ppc_cached_irq_mask[1];
ppc_cached_irq_mask[0] = 0;
ppc_cached_irq_mask[1] = 0;
- set_bit(viaint, ppc_cached_irq_mask);
+ if (viaint > 0)
+ set_bit(viaint, ppc_cached_irq_mask);
out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
if (max_real_irqs > 32)
out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
}
void
-sleep_restore_intrs(void)
+pmac_sleep_restore_intrs(void)
{
int i;
+
out_le32(&pmac_irq_hw[0]->enable, 0);
if (max_real_irqs > 32)
out_le32(&pmac_irq_hw[1]->enable, 0);
#include <asm/feature.h>
#include <asm/ide.h>
#include <asm/machdep.h>
-
+#include <asm/keyboard.h>
#include <asm/time.h>
+
#include "local_irq.h"
#include "pmac_pic.h"
#undef SHOW_GATWICK_IRQS
-void pmac_time_init(void);
-unsigned long pmac_get_rtc_time(void);
-int pmac_set_rtc_time(unsigned long nowtime);
-void pmac_read_rtc_time(void);
-void pmac_calibrate_decr(void);
-void pmac_setup_pci_ptrs(void);
+extern long pmac_time_init(void);
+extern unsigned long pmac_get_rtc_time(void);
+extern int pmac_set_rtc_time(unsigned long nowtime);
+extern void pmac_read_rtc_time(void);
+extern void pmac_calibrate_decr(void);
+extern void pmac_setup_pci_ptrs(void);
extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
extern int mackbd_getkeycode(unsigned int scancode);
extern void mackbd_leds(unsigned char leds);
extern void mackbd_init_hw(void);
#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char mackbd_sysrq_xlate[128];
+extern unsigned char mackbd_sysrq_xlate[128];
+extern unsigned char mac_hid_kbd_sysrq_xlate[128];
+extern unsigned char pckbd_sysrq_xlate[128];
#endif /* CONFIG_MAGIC_SYSRQ */
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
- char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
+extern int keyboard_sends_linux_keycodes;
+extern int mac_hid_kbd_translate(unsigned char scancode,
+ unsigned char *keycode, char raw_mode);
+extern char mac_hid_kbd_unexpected_up(unsigned char keycode);
+extern void mac_hid_init_hw(void);
+
extern void pmac_nvram_update(void);
+extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn);
+extern void *pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn);
+extern int pmac_pci_dev_root_bridge(unsigned char bus, unsigned char devfn);
+
unsigned char drive_info;
int ppc_override_l2cr = 0;
int ppc_override_l2cr_value;
+static int current_root_goodness = -1;
+
extern char saved_command_line[];
extern int pmac_newworld;
extern void zs_kgdb_hook(int tty_num);
static void ohare_init(void);
static void init_p2pbridge(void);
-static void init_uninorth(void);
+
+#ifdef CONFIG_SMP
+volatile static long int core99_l2_cache;
+void core99_init_l2(void)
+{
+ int cpu = smp_processor_id();
+
+ if ( (_get_PVR() >> 16) != 8 && (_get_PVR() >> 16) != 12 )
+ return;
+
+ if (cpu == 0){
+ core99_l2_cache = _get_L2CR();
+ printk("CPU0: L2CR is %lx\n", core99_l2_cache);
+ } else {
+ printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
+ _set_L2CR(core99_l2_cache);
+ printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache);
+ }
+}
+#endif /* CONFIG_SMP */
__pmac
int
struct device_node *cpu;
int *fp;
- /* Set loops_per_sec to a half-way reasonable value,
+ /* Set loops_per_jiffy to a half-way reasonable value,
for use until calibrate_delay gets called. */
cpu = find_type_devices("cpu");
if (cpu != 0) {
case 10: /* mach V (604ev5) */
case 12: /* G4 */
case 20: /* 620 */
- loops_per_jiffy = (*fp)/HZ;
+ loops_per_jiffy = *fp / HZ;
break;
default: /* 601, 603, etc. */
- loops_per_jiffy = (*fp / 2)/HZ;
+ loops_per_jiffy = *fp / (2*HZ);
}
} else
- loops_per_jiffy = 50000000/HZ;
+ loops_per_jiffy = 50000000 / HZ;
}
/* this area has the CPU identification register
*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
init_p2pbridge();
- init_uninorth();
- /* Checks "l2cr-value" property in the registry */
+ /* Checks "l2cr-value" property in the registry
+ * And enable G3/G4 Dynamic Power Management
+ */
if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) {
struct device_node *np = find_devices("cpus");
if (np == 0)
ppc_override_l2cr = 1;
ppc_override_l2cr_value = *l2cr;
_set_L2CR(0);
- _set_L2CR(ppc_override_l2cr_value);
+ if (ppc_override_l2cr_value)
+ _set_L2CR(ppc_override_l2cr_value);
}
}
+ _set_HID0(_get_HID0() | HID0_DPM);
}
if (ppc_override_l2cr)
? "enabled" : "disabled");
feature_init();
+#ifdef CONFIG_SMP
+ core99_init_l2();
+#endif
+
#ifdef CONFIG_KGDB
zs_kgdb_hook(0);
#endif
}
}
-__initfunc(static void init_uninorth(void))
-{
- /*
- * Turns OFF the gmac clock. The gmac driver will turn
- * it back ON when the interface is enabled. This save
- * power on portables.
- *
- * Note: We could also try to turn OFF the PHY. Since this
- * has to be done by both the gmac driver and this code,
- * I'll probably end-up moving some of this out of the
- * modular gmac driver into a non-modular stub containing
- * some basic PHY management and power management stuffs
- */
- struct device_node* uni_n = find_devices("uni-n");
- struct device_node* gmac = find_devices("ethernet");
- unsigned long* addr;
-
- if (!uni_n || uni_n->n_addrs < 1)
- return;
- addr = ioremap(uni_n->addrs[0].address, 0x300);
-
- while(gmac) {
- if (device_is_compatible(gmac, "gmac"))
- break;
- gmac = gmac->next;
- }
- if (gmac) {
- *(addr + 8) &= ~0x00000002UL;
- eieio();
- }
-}
-
extern char *bootpath;
extern char *bootdevice;
void *boot_host;
/* can't be initfunc - can be called whenever a disk is first accessed */
__pmac
-void note_bootable_part(kdev_t dev, int part)
+void note_bootable_part(kdev_t dev, int part, int goodness)
{
static int found_boot = 0;
char *p;
/* Do nothing if the root has been set already. */
- if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))
+ if ((goodness < current_root_goodness) &&
+ (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)))
return;
p = strstr(saved_command_line, "root=");
if (p != NULL && (p == saved_command_line || p[-1] == ' '))
if (boot_dev == 0 || dev == boot_dev) {
ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
boot_dev = NODEV;
- printk(" (root on %d)", part);
+ current_root_goodness = goodness;
}
}
ppc_md.get_rtc_time = pmac_get_rtc_time;
ppc_md.calibrate_decr = pmac_calibrate_decr;
-#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD)
+#ifdef CONFIG_VT
+#ifdef CONFIG_MAC_KEYBOARD
ppc_md.kbd_setkeycode = mackbd_setkeycode;
ppc_md.kbd_getkeycode = mackbd_getkeycode;
ppc_md.kbd_translate = mackbd_translate;
ppc_md.kbd_leds = mackbd_leds;
ppc_md.kbd_init_hw = mackbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate;
- ppc_md.SYSRQ_KEY = 0x69;
+ ppc_md.sysrq_xlate = mackbd_sysrq_xlate;
+ SYSRQ_KEY = 0x69;
#endif
+#elif defined(CONFIG_INPUT_ADBHID)
+ ppc_md.kbd_setkeycode = 0;
+ ppc_md.kbd_getkeycode = 0;
+ ppc_md.kbd_translate = mac_hid_kbd_translate;
+ ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
+ ppc_md.kbd_leds = 0;
+ ppc_md.kbd_init_hw = mac_hid_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+#ifdef CONFIG_MAC_ADBKEYCODES
+ if (!keyboard_sends_linux_keycodes) {
+ ppc_md.sysrq_xlate = mac_hid_kbd_sysrq_xlate;
+ SYSRQ_KEY = 0x69;
+ } else
+#endif /* CONFIG_MAC_ADBKEYCODES */
+ {
+ ppc_md.sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
+ }
#endif
+#endif /* CONFIG_MAC_KEYBOARD */
+#endif /* CONFIG_VT */
#if defined(CONFIG_BLK_DEV_IDE_PMAC)
ppc_ide_md.insw = pmac_ide_insw;
#include <asm/pmu.h>
#include <asm/machdep.h>
#include <asm/nvram.h>
+#include <asm/backlight.h>
#undef DEBUG
static int core99_bank = 0;
static int nvram_partitions[3];
+static struct backlight_controller *backlighter = NULL;
+static void* backlighter_data = NULL;
+static int backlight_autosave = 0;
+static int backlight_level = BACKLIGHT_MAX;
+static int backlight_enabled = 1;
+
/* FIXME: kmalloc fails to allocate the image now that I had to move it
* before time_init(). For now, I allocate a static buffer here
* but it's a waste of space on all but core99 machines
#if 0
static char* nvram_image;
#else
-__pmac static char nvram_image[NVRAM_SIZE];
+static char nvram_image[NVRAM_SIZE];
#endif
extern int pmac_newworld;
-static u8
+static u8 __pmac
chrp_checksum(struct chrp_header* hdr)
{
u8 *ptr;
return sum;
}
-static u32
+static u32 __pmac
core99_calc_adler(u8 *buffer)
{
int cnt;
return (high << 16) | low;
}
-static u32
+static u32 __pmac
core99_check(u8* datas)
{
struct core99_header* hdr99 = (struct core99_header*)datas;
return hdr99->generation;
}
-static int
+static int __pmac
core99_erase_bank(int bank)
{
int stat, i;
return 0;
}
-static int
+static int __pmac
core99_write_bank(int bank, u8* datas)
{
int i, stat = 0;
return 0;
}
-static void
+static void __pmac
lookup_partitions(void)
{
u8 buffer[17];
} else if (nvram_naddrs == 2) {
nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
- } else if (nvram_naddrs == 0 && adb_controller->kind == ADB_VIAPMU) {
+ } else if (nvram_naddrs == 0 && adb_controller &&
+ adb_controller->kind == ADB_VIAPMU) {
nvram_naddrs = -1;
} else {
printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
lookup_partitions();
}
-void
+void __pmac
pmac_nvram_update(void)
{
struct core99_header* hdr99;
printk("nvram: Error writing bank %d\n", core99_bank);
}
-unsigned char
+unsigned char __pmac
nvram_read_byte(int addr)
{
struct adb_request req;
return 0;
}
-void
+void __pmac
nvram_write_byte(unsigned char val, int addr)
{
struct adb_request req;
eieio();
}
-int
+int __pmac
pmac_get_partition(int partition)
{
return nvram_partitions[partition];
}
-u8
+u8 __pmac
pmac_xpram_read(int xpaddr)
{
int offset = nvram_partitions[pmac_nvram_XPRAM];
return nvram_read_byte(xpaddr + offset);
}
-void
+void __pmac
pmac_xpram_write(int xpaddr, u8 data)
{
int offset = nvram_partitions[pmac_nvram_XPRAM];
nvram_write_byte(xpaddr + offset, data);
}
+void __pmac
+register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type)
+{
+ struct device_node* bk_node;
+ char *prop;
+ int valid = 0;
+
+ bk_node = find_devices("backlight");
+
+ /* Special case for the old PowerBooks, they don't yet have
+ * the property we expect
+ */
+ backlight_autosave = machine_is_compatible("AAPL,3400/2400")
+ || machine_is_compatible("AAPL,3500");
+ if ((backlight_autosave
+ || machine_is_compatible("AAPL,PowerBook1998")
+ || machine_is_compatible("PowerBook1,1"))
+ && !strcmp(type, "pmu"))
+ valid = 1;
+ else if (bk_node) {
+ prop = get_property(bk_node, "backlight-control", NULL);
+ if (prop && !strncmp(prop, type, strlen(type)))
+ valid = 1;
+ }
+ if (!valid)
+ return;
+ backlighter = ctrler;
+ backlighter_data = data;
+
+ if (bk_node && !backlight_autosave)
+ prop = get_property(bk_node, "bklt", NULL);
+ else
+ prop = NULL;
+ if (prop) {
+ backlight_level = ((*prop)+1) >> 1;
+ if (backlight_level > BACKLIGHT_MAX)
+ backlight_level = BACKLIGHT_MAX;
+ }
+
+ if (backlight_autosave) {
+ struct adb_request req;
+ pmu_request(&req, NULL, 2, 0xd9, 0);
+ while (!req.complete)
+ pmu_poll();
+ backlight_level = req.reply[1] >> 4;
+ }
+
+ if (!backlighter->set_enable(1, backlight_level, data))
+ backlight_enabled = 1;
+
+ printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
+ type, backlight_level);
+}
+
+void __pmac
+unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
+{
+ /* We keep the current backlight level (for now) */
+ if (ctrler == backlighter && data == backlighter_data)
+ backlighter = NULL;
+}
+
+int __pmac
+set_backlight_enable(int enable)
+{
+ int rc;
+
+ if (!backlighter)
+ return -ENODEV;
+ rc = backlighter->set_enable(enable, backlight_level, backlighter_data);
+ if (!rc)
+ backlight_enabled = enable;
+ return rc;
+}
+
+int __pmac
+get_backlight_enable(void)
+{
+ if (!backlighter)
+ return -ENODEV;
+ return backlight_enabled;
+}
+
+int __pmac
+set_backlight_level(int level)
+{
+ int rc = 0;
+
+ if (!backlighter)
+ return -ENODEV;
+ if (level < BACKLIGHT_MIN)
+ level = BACKLIGHT_OFF;
+ if (level > BACKLIGHT_MAX)
+ level = BACKLIGHT_MAX;
+ if (backlight_enabled)
+ rc = backlighter->set_level(level, backlighter_data);
+ if (!rc)
+ backlight_level = level;
+ if (!rc && !backlight_autosave) {
+ level <<=1;
+ if (level & 0x10)
+ level |= 0x01;
+ // -- todo: save to property "bklt"
+ }
+ return rc;
+}
+
+int __pmac
+get_backlight_level(void)
+{
+ if (!backlighter)
+ return -ENODEV;
+ return backlight_level;
+}
+
extern struct timezone sys_tz;
__init
-void pmac_time_init(void)
+long pmac_time_init(void)
{
s32 delta = 0;
int dst;
dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
dst ? "on" : "off");
- sys_tz.tz_minuteswest = -delta/60;
- /* I _suppose_ this is 0:off, 1:on */
- sys_tz.tz_dsttime = dst;
+ return -delta;
}
__pmac
unsigned long pmac_get_rtc_time(void)
{
struct adb_request req;
- int offset = sys_tz.tz_minuteswest * 60;
/* Get the time from the RTC */
if (adb_controller == 0)
printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
req.reply_len);
return (req.reply[3] << 24) + (req.reply[4] << 16)
- + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET + offset;
+ + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
case ADB_VIAPMU:
if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) {
printk("pmac_read_rtc_time: pmu_request failed\n");
printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
req.reply_len);
return (req.reply[1] << 24) + (req.reply[2] << 16)
- + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET + offset;
+ + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET;
default:
return 0;
}
struct adb_request req;
int dst, delta;
- nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60;
+ nowtime += RTC_OFFSET;
/* Set the time in the RTC */
if (adb_controller == 0)
return 0;
}
- /* write the timezone offset back into the xpram */
- delta = sys_tz.tz_minuteswest * -60;
- pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0x9, delta >> 16);
- pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0xa, delta >> 8);
- pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0xb, delta);
- dst = pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 8);
- dst = sys_tz.tz_dsttime? (dst | 0x80): (dst & ~0x80);
- pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 8, dst);
-
return 1;
}
buffer += len;
left -= len;
_set_L2CR(0);
- _set_L2CR(val);
- while ( _get_L2CR() & 0x1 )
- /* wait for invalidate to finish */;
+ if (val)
+ _set_L2CR(val);
} else {
p = buf;
EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
EXPORT_SYMBOL(DMA_MODE_READ);
EXPORT_SYMBOL(DMA_MODE_WRITE);
+#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC)
EXPORT_SYMBOL(_prep_type);
EXPORT_SYMBOL(ucSystemType);
+#endif
EXPORT_SYMBOL(atomic_add);
EXPORT_SYMBOL(atomic_sub);
EXPORT_SYMBOL(_read_unlock);
EXPORT_SYMBOL(_write_lock);
EXPORT_SYMBOL(_write_unlock);
-#endif
+#endif /* __SMP__ */
EXPORT_SYMBOL(_machine);
EXPORT_SYMBOL(ppc_md);
-
-EXPORT_SYMBOL(adb_request);
-EXPORT_SYMBOL(adb_register);
-EXPORT_SYMBOL(cuda_request);
-EXPORT_SYMBOL(cuda_poll);
-EXPORT_SYMBOL(pmu_request);
-EXPORT_SYMBOL(pmu_poll);
-#ifdef CONFIG_PMAC_PBOOK
-EXPORT_SYMBOL(pmu_register_sleep_notifier);
-EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
-EXPORT_SYMBOL(pmu_enable_irled);
-#endif CONFIG_PMAC_PBOOK
EXPORT_SYMBOL(abort);
+
+#ifndef CONFIG_MBX
EXPORT_SYMBOL(find_devices);
EXPORT_SYMBOL(find_type_devices);
EXPORT_SYMBOL(find_compatible_devices);
EXPORT_SYMBOL(find_pci_device_OFnode);
EXPORT_SYMBOL(find_all_nodes);
EXPORT_SYMBOL(get_property);
+#endif /* CONFIG_MBX */
+#ifdef CONFIG_POWERMAC
+EXPORT_SYMBOL(adb_request);
+EXPORT_SYMBOL(adb_register);
+EXPORT_SYMBOL(cuda_request);
+EXPORT_SYMBOL(cuda_poll);
+EXPORT_SYMBOL(pmu_request);
+EXPORT_SYMBOL(pmu_poll);
+#endif /* CONFIG_POWERMAC */
+#ifdef CONFIG_PMAC_PBOOK
+EXPORT_SYMBOL(pmu_register_sleep_notifier);
+EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
+EXPORT_SYMBOL(pmu_enable_irled);
+#endif /* CONFIG_PMAC_PBOOK */
+#ifdef CONFIG_POWERMAC
EXPORT_SYMBOL(pci_io_base);
+EXPORT_SYMBOL(pci_dev_io_base);
+EXPORT_SYMBOL(pci_dev_mem_base);
EXPORT_SYMBOL(pci_device_loc);
EXPORT_SYMBOL(feature_set);
EXPORT_SYMBOL(feature_clear);
EXPORT_SYMBOL(feature_test);
-#ifdef CONFIG_SCSI
-EXPORT_SYMBOL(note_scsi_host);
-#endif
-EXPORT_SYMBOL(kd_mksound);
-/*#ifdef CONFIG_PMAC */
+EXPORT_SYMBOL(feature_set_gmac_power);
+EXPORT_SYMBOL(feature_set_gmac_phy_reset);
+EXPORT_SYMBOL(feature_set_usb_power);
+EXPORT_SYMBOL(feature_set_firewire_power);
EXPORT_SYMBOL(nvram_read_byte);
EXPORT_SYMBOL(nvram_write_byte);
EXPORT_SYMBOL(pmac_xpram_read);
EXPORT_SYMBOL(pmac_xpram_write);
-/*#endif*/ /* CONFIG_PMAC */
-#ifdef CONFIG_PPC_RTC
+#ifdef CONFIG_SCSI
+EXPORT_SYMBOL(note_scsi_host);
+#endif /* CONFIG_SCSI */
+#endif /* CONFIG_POWERMAC */
+EXPORT_SYMBOL(kd_mksound);
EXPORT_SYMBOL(mktime);
EXPORT_SYMBOL(to_tm);
-#endif
EXPORT_SYMBOL(abs);
#include <asm/machdep.h>
#include "pci.h"
+#include "open_pic.h"
#define MAX_DEVNR 22
/* Used for Motorola to store system config register */
static unsigned long *ProcInfo;
-extern void chrp_do_IRQ(struct pt_regs *,int , int);
-
/* Tables for known hardware */
/* Motorola PowerStackII - Utah */
OpenPIC_InitSenses = mvme2600_openpic_initsenses;
OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses);
- ppc_md.do_IRQ = chrp_do_IRQ;
+ ppc_md.do_IRQ = open_pic_do_IRQ;
/* If raven is present on Motorola store the system config register
* for later use.
if (n & 0xF0) {
return (n & 0x0F);
} else {
- return(openpic_to_irq(n));
+ return(n+open_pic.irq_offset);
}
}
dev->devfn, 0x44, short_reg);
}
}
+ if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+ PCI_DEVICE_ID_WINBOND_82C105, dev))){
+ if (OpenPIC){
+ /* Disable LEGIRQ mode so PCI INTs are routed to
+ the 8259 */
+ pci_write_config_dword(dev, 0x40, 0x10ff00a1);
+ } else {
+ /* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
+ pci_write_config_dword(dev, 0x40, 0x10ff08a1);
+ }
+ }
}
__initfunc(
void
#include <asm/mk48t59.h>
#include <asm/prep_nvram.h>
#include <asm/raven.h>
-
-
+#include <asm/keyboard.h>
#include <asm/time.h>
+#include <asm/vga.h>
+
#include "local_irq.h"
#include "i8259.h"
#include "open_pic.h"
extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
extern int rd_image_start; /* starting block # of image */
#endif
-#ifdef CONFIG_VGA_CONSOLE
-unsigned long vgacon_remap_base;
-#endif
__prep
int
irq_desc[i].ctl = &i8259_pic;
i8259_init();
#ifdef __SMP__
- request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action,
+ request_irq(OPENPIC_VEC_IPI, openpic_ipi_action,
0, "IPI0", 0);
+ request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action,
+ 0, "IPI1 (invalidate TLB)", 0);
+ request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action,
+ 0, "IPI2 (stop CPU)", 0);
+ request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action,
+ 0, "IPI3 (reschedule)", 0);
#endif /* __SMP__ */
}
ppc_md.kbd_leds = pckbd_leds;
ppc_md.kbd_init_hw = pckbd_init_hw;
#ifdef CONFIG_MAGIC_SYSRQ
- ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate;
- ppc_md.SYSRQ_KEY = 0x54;
+ ppc_md.sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
#endif
#endif
}
printk("[");
for (; bits->bit != 0; ++bits) {
if (val & bits->bit) {
- printk("%s", bits->name);
+ printk("%s%s", sep, bits->name);
sep = ", ";
}
}
#include <linux/string.h>
#include <linux/init.h>
#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/console.h>
#include <asm/spinlock.h>
#include <asm/prom.h>
#include <asm/page.h>
#include <asm/system.h>
#include <asm/gemini.h>
#include <asm/linux_logo.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/adb.h>
+#include <asm/pmu.h>
/*
* Properties whose value is longer than this get excluded from our
#ifdef CONFIG_BOOTX_TEXT
+/*
+ * The VGA font is in the _pmac section. Can't this cause problems with CHRP
+ * using some of the prom_xxxx functions ?
+ * All this need to be moved in a separate source file anyway
+ */
+
static void clearscreen(void);
static void flushscreen(void);
void drawstring(const char *c);
void drawhex(unsigned long v);
static void scrollscreen(void);
+static void prepare_disp_BAT(void);
+static void boot_console_write(struct console *co, const char *s,
+ unsigned count);
static void draw_byte(unsigned char c, long locX, long locY);
static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
static long g_max_loc_X = 0;
static long g_max_loc_Y = 0;
+unsigned long disp_BATL = 0;
+unsigned long disp_BATU = 0;
+
#define cmapsz (16*256)
static unsigned char vga_font[cmapsz];
+static struct console boot_cons = {
+ "boot",
+ boot_console_write,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ CON_PRINTBUFFER,
+ 0,
+ 0,
+ NULL
+};
+static int boot_cons_registered = 0;
+
#endif /* CONFIG_BOOTX_TEXT */
return prom_args.args[nargs];
}
-__init
+/*__init*/
void
prom_print(const char *msg)
{
}
#ifdef CONFIG_BOOTX_TEXT
+ prepare_disp_BAT();
prom_print(RELOC("booting...\n"));
flushscreen();
#endif
* is in its holding pattern code.
*
* -- Cort
+ *
+ * This code crashes on some pmacs since the memory at 8M is not
+ * claim'ed and so can be unmapped. -- BenH
*/
+ if (chrp)
{
extern void __secondary_hold(void);
unsigned long i;
}
/* look for cpus */
- for (node = 0; prom_next_node(&node);)
+ for (node = 0; chrp && prom_next_node(&node);)
{
type[0] = 0;
call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
if (!chrp && RELOC(disp_bi)) {
RELOC(prom_stdout) = 0;
clearscreen();
+ prepare_disp_BAT();
prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
}
#endif
drawhex(val);
drawstring("\n");
}
+
+/* Calc BAT values for mapping the display and store them
+ * in disp_BATH and disp_BATL. Those values are then used
+ * from head.S to map the display during identify_machine()
+ * and MMU_Init()
+ *
+ * For now, the display is mapped in place (1:1). This should
+ * be changed if the display physical address overlaps
+ * KERNELBASE, which is fortunately not the case on any machine
+ * I know of. This mapping is temporary and will disappear as
+ * soon as the setup done by MMU_Init() is applied
+ *
+ * For now, we align the BAT and then map 8Mb on 601 and 16Mb
+ * on other PPCs. This may cause trouble if the framebuffer
+ * is really badly aligned, but I didn't encounter this case
+ * yet.
+ */
+__init
+static void
+prepare_disp_BAT(void)
+{
+ unsigned long offset = reloc_offset();
+ boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
+ unsigned long addr = (unsigned long)bi->dispDeviceBase;
+
+ if ((_get_PVR() >> 16) != 1) {
+ /* 603, 604, G3, G4, ... */
+ addr &= 0xFF000000UL;
+ RELOC(disp_BATU) = addr | (BL_16M<<2) | 2;
+ RELOC(disp_BATL) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);
+ } else {
+ /* 601 */
+ addr &= 0xFF800000UL;
+ RELOC(disp_BATU) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
+ RELOC(disp_BATL) = addr | BL_8M | 0x40;
+ }
+ bi->logicalDisplayBase = bi->dispDeviceBase;
+}
+
#endif
-static int prom_set_color(ihandle ih, int i, int r, int g, int b)
+__init
+static int
+prom_set_color(ihandle ih, int i, int r, int g, int b)
{
struct prom_args prom_args;
unsigned long offset = reloc_offset();
ihandle ih;
int i;
unsigned long offset = reloc_offset();
- char type[16], *path;
+ char type[16], *path, name[32];
static unsigned char default_colors[] = {
0x00, 0x00, 0x00,
0x00, 0x00, 0xaa,
type, sizeof(type));
if (strcmp(type, RELOC("display")) != 0)
continue;
+ name[0] = 0;
+ call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"),
+ name, sizeof(name));
+ if (!strcmp(name, RELOC("offscreen-display")))
+ continue;
+
/* It seems OF doesn't null-terminate the path :-( */
path = (char *) mem;
memset(path, 0, 256);
((node->name && !strcmp(node->name, "open-pic")) ||
!node->name)) {
for (i = 0; i < np->n_intrs; ++i)
- np->intrs[i].line = openpic_to_irq(np->intrs[i].line);
+ np->intrs[i].line = np->intrs[i].line + NUM_8259_INTERRUPTS;
}
return mem_start;
}
/* CHRP machines */
np->n_intrs = l / (2 * sizeof(int));
for (i = 0; i < np->n_intrs; ++i) {
- np->intrs[i].line = openpic_to_irq(*ip++);
+ np->intrs[i].line = (*ip++) + NUM_8259_INTERRUPTS;
np->intrs[i].sense = *ip++;
}
}
int l;
for (np = allnodes; np != 0; np = np->allnext) {
- char *pname = np->parent ?
- (char *)get_property(np->parent, "name", &l) : 0;
- if (pname && strcmp(pname, "mac-io") == 0)
+ int in_macio = 0;
+ struct device_node* parent = np->parent;
+ while(parent) {
+ char *pname = (char *)get_property(parent, "name", &l);
+ if (pname && strcmp(pname, "mac-io") == 0) {
+ in_macio = 1;
+ break;
+ }
+ parent = parent->parent;
+ }
+ if (in_macio)
continue;
reg = (unsigned int *) get_property(np, "reg", &l);
if (reg == 0 || l < sizeof(struct reg_property))
struct property *pp;
for (pp = np->properties; pp != 0; pp = pp->next)
- if (strcmp(pp->name, name) == 0) {
+ if (pp->name && strcmp(pp->name, name) == 0) {
if (lenp != 0)
*lenp = pp->length;
return pp->value;
void
map_bootx_text(void)
{
+ unsigned long base, offset, size;
if (disp_bi == 0)
return;
- disp_bi->logicalDisplayBase =
- ioremap((unsigned long) disp_bi->dispDeviceBase,
- disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]);
+ base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL;
+ offset = ((unsigned long) disp_bi->dispDeviceBase) - base;
+ size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset
+ + disp_bi->dispDeviceRect[0];
+ disp_bi->logicalDisplayBase = ioremap(base, size) + offset;
+}
+
+__init
+void
+install_boot_console(void)
+{
+ register_console(&boot_cons);
+ boot_cons_registered = 1;
+}
+
+void
+remove_boot_console(void)
+{
+ if (boot_cons_registered)
+ unregister_console(&boot_cons);
+ boot_cons_registered = 0;
}
/* Calc the base address of a given point (x,y) */
unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
(bi->dispDeviceDepth >> 3)) >> 2;
int i,j;
-
+
+#ifdef CONFIG_POWERMAC
+ pmu_suspend();
+#endif
+
for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
{
unsigned long *src_ptr = src;
*(dst_ptr++) = 0;
dst += (bi->dispDeviceRowBytes >> 2);
}
+
+#ifdef CONFIG_POWERMAC
+ pmu_resume();
+#endif
}
__pmac
drawchar(*c++);
}
+#ifdef CONFIG_BOOTX_TEXT
+__pmac
+static void boot_console_write(struct console *co, const char *s,
+ unsigned count)
+{
+ while(count--)
+ drawchar(*s++);
+}
+#endif
+
__pmac
void
drawhex(unsigned long v)
#endif
#include <asm/bootx.h>
#include <asm/machdep.h>
+#include <asm/uaccess.h>
extern void pmac_init(unsigned long r3,
unsigned long r4,
unsigned long r6,
unsigned long r7);
-#ifdef CONFIG_BOOTX_TEXT
-extern void map_bootx_text(void);
-#endif
#ifdef CONFIG_XMON
extern void xmon_map_scc(void);
#endif
struct machdep_calls ppc_md;
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned long SYSRQ_KEY;
+#endif /* CONFIG_MAGIC_SYSRQ */
+#ifdef CONFIG_VGA_CONSOLE
+unsigned long vgacon_remap_base;
+#endif
/* copy of the residual data */
#ifndef CONFIG_MBX
(GET_PVR & 0xff00) >> 8, GET_PVR & 0xff);
len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
- (CD(loops_per_jiffy*HZ)+2500)/500000,
- (CD(loops_per_jiffy*HZ)+2500)/5000 % 100);
+ (CD(loops_per_jiffy)+2500)/(500000/HZ),
+ (CD(loops_per_jiffy)+2500)/(5000/HZ) % 100);
bogosum += CD(loops_per_jiffy);
}
-#ifdef __SMP__
- if ( i )
- len += sprintf(buffer+len, "\n");
- len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
- (bogosum+2500)/500000,
- (bogosum+2500)/5000 % 100);
-#endif /* __SMP__ */
-
/*
* Ooh's and aah's info about zero'd pages in idle task
*/
switch (_machine)
{
+#ifdef CONFIG_POWERMAC
case _MACH_Pmac:
pmac_init(r3, r4, r5, r6, r7);
break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP)
case _MACH_prep:
prep_init(r3, r4, r5, r6, r7);
break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
case _MACH_chrp:
chrp_init(r3, r4, r5, r6, r7);
break;
+#endif
#ifdef CONFIG_APUS
case _MACH_apus:
apus_init(r3, r4, r5, r6, r7);
unsigned long val = simple_strtoul(str, NULL, 0);
printk(KERN_INFO "l2cr set to %lx\n", val);
_set_L2CR(0);
- _set_L2CR(val);
+ if (val)
+ _set_L2CR(val);
}
}
extern unsigned long find_available_memory(void);
extern unsigned long *end_of_DRAM;
-#ifdef CONFIG_BOOTX_TEXT
- map_bootx_text();
-#endif
#ifdef CONFIG_XMON
{
*memory_end_p = (unsigned long) end_of_DRAM;
ppc_md.setup_arch(memory_start_p, memory_end_p);
+
+ sort_exception_table();
}
+#ifndef CONFIG_POWERMAC
+void note_bootable_part(kdev_t dev, int part, int goodness)
+{
+}
+#endif
+
void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
{
int i;
* 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.
+ *
+ *
+ * 2000-04-7.
+ * Define a real-time signal frame with siginfo and ucontext
+ * structures (setup_rt_frame()).
+ * Stuck up a real-time signal frame when setting the signal
+ * frame with SA_SIGINFO flags.
+ * Add sys_rt_sigreturn() to undo the signal stack.
+ *
+ * Giovanna Ambrosini (ambrosini@lightning.ch)
*/
#include <linux/sched.h>
}
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
-{
- printk("sys_rt_sigreturn(): %s/%d not yet implemented.\n",
- current->comm,current->pid);
- do_exit(SIGSEGV);
-}
-
asmlinkage int
sys_sigaltstack(const stack_t *uss, stack_t *uoss)
{
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
* a sigregs struct
- * one or more sigcontext structs
+ * one or more sigcontext structs with
* a gap of __SIGNAL_FRAMESIZE bytes
*
* Each of these things must be a multiple of 16 bytes in size.
*
- * XXX ultimately we will have to stack up a siginfo and ucontext
- * for each rt signal.
*/
struct sigregs {
elf_gregset_t gp_regs;
int abigap[56];
};
+struct rt_sigframe
+{
+ unsigned long _unused[2];
+ struct siginfo *pinfo;
+ void *puc;
+ struct siginfo info;
+ struct ucontext uc;
+};
+
/*
* Do a signal return; undo the signal stack.
*/
do_exit(SIGSEGV);
}
+
+/*
+ * When we have rt signals to deliver, we set up on the
+ * user stack, going down from the original stack pointer:
+ * a sigregs struct
+ * one rt_sigframe struct (siginfo + ucontext)
+ * a gap of __SIGNAL_FRAMESIZE bytes
+ *
+ * Each of these things must be a multiple of 16 bytes in size.
+ *
+ */
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct rt_sigframe *rt_sf;
+ struct sigcontext_struct sigctx;
+ struct sigregs *sr;
+ int ret;
+ elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */
+ sigset_t set;
+ stack_t st;
+ unsigned long prevsp;
+
+ rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
+ || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
+ || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
+ goto badframe;
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(¤t->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ rt_sf++; /* Look at next rt_sigframe */
+ if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) {
+ /* Last stacked signal - restore registers -
+ * sigctx is initialized to point to the
+ * preamble frame (where registers are stored)
+ * see handle_signal()
+ */
+ sr = (struct sigregs *) sigctx.regs;
+ if (regs->msr & MSR_FP )
+ giveup_fpu(current);
+ if (copy_from_user(saved_regs, &sr->gp_regs,
+ sizeof(sr->gp_regs)))
+ goto badframe;
+ saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+ | (saved_regs[PT_MSR] & MSR_USERCHANGE);
+ memcpy(regs, saved_regs, GP_REGS_SIZE);
+ if (copy_from_user(current->tss.fpr, &sr->fp_regs,
+ sizeof(sr->fp_regs)))
+ goto badframe;
+ /* This function sets back the stack flags into
+ the current task structure. */
+ sys_sigaltstack(&st, NULL);
+
+ ret = regs->result;
+ } else {
+ /* More signals to go */
+ /* Set up registers for next signal handler */
+ regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE;
+ if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)))
+ goto badframe;
+ sr = (struct sigregs *) sigctx.regs;
+ regs->gpr[3] = ret = sigctx.signal;
+ /* Get the siginfo */
+ get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo);
+ /* Get the ucontext */
+ get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc);
+ regs->gpr[6] = (unsigned long) rt_sf;
+
+ regs->link = (unsigned long) &sr->tramp;
+ regs->nip = sigctx.handler;
+ if (get_user(prevsp, &sr->gp_regs[PT_R1])
+ || put_user(prevsp, (unsigned long *) regs->gpr[1]))
+ goto badframe;
+ }
+ return ret;
+
+badframe:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+
/*
* Set up a signal frame.
*/
do_exit(SIGSEGV);
}
+
+static void
+setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
+ signed long newsp)
+{
+ struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp;
+
+ /* Set up preamble frame */
+ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto badframe;
+ if (regs->msr & MSR_FP)
+ giveup_fpu(current);
+ if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
+ || __copy_to_user(&frame->fp_regs, current->tss.fpr,
+ ELF_NFPREG * sizeof(double))
+ /* Set up to return from user space.
+ It calls the sc exception at offset 0x9999
+ for sys_rt_sigreturn().
+ */
+ || __put_user(0x38006666UL, &frame->tramp[0]) /* li r0,0x6666 */
+ || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */
+ goto badframe;
+ flush_icache_range((unsigned long) &frame->tramp[0],
+ (unsigned long) &frame->tramp[2]);
+
+ /* Retrieve rt_sigframe from stack and
+ set up registers for signal handler
+ */
+ newsp -= __SIGNAL_FRAMESIZE;
+ if (put_user(regs->gpr[1], (unsigned long *)newsp)
+ || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler)
+ || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
+ || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
+ || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
+ goto badframe;
+
+ regs->gpr[1] = newsp;
+ regs->gpr[6] = (unsigned long) rt_sf;
+ regs->link = (unsigned long) frame->tramp;
+
+ return;
+
+badframe:
+#if DEBUG_SIG
+ printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
+ regs, frame, newsp);
+#endif
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
/*
* OK, we're invoking a handler
*/
unsigned long *newspp, unsigned long frame)
{
struct sigcontext_struct *sc;
+ struct rt_sigframe *rt_sf;
if (regs->trap == 0x0C00 /* System Call! */
&& ((int)regs->result == -ERESTARTNOHAND ||
!(ka->sa.sa_flags & SA_RESTART))))
regs->result = -EINTR;
- /* Put another sigcontext on the stack */
- *newspp -= sizeof(*sc);
- sc = (struct sigcontext_struct *) *newspp;
- if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
- goto badframe;
-
- if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
- || __put_user(oldset->sig[0], &sc->oldmask)
+ /* Set up Signal Frame */
+ if (ka->sa.sa_flags & SA_SIGINFO) {
+ /* Put a Real Time Context onto stack */
+ *newspp -= sizeof(*rt_sf);
+ rt_sf = (struct rt_sigframe *) *newspp;
+ if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
+ goto badframe;
+
+ if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler)
+ || __put_user(&rt_sf->info, &rt_sf->pinfo)
+ || __put_user(&rt_sf->uc, &rt_sf->puc)
+ /* Put the siginfo */
+ || __copy_to_user(&rt_sf->info, info, sizeof(*info))
+ /* Create the ucontext */
+ || __put_user(0, &rt_sf->uc.uc_flags)
+ || __put_user(0, &rt_sf->uc.uc_link)
+ || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
+ || __put_user(sas_ss_flags(regs->gpr[1]),
+ &rt_sf->uc.uc_stack.ss_flags)
+ || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)
+ || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset))
+ /* mcontext.regs points to preamble register frame */
+ || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
+ || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
+ goto badframe;
+ } else {
+ /* Put another sigcontext on the stack */
+ *newspp -= sizeof(*sc);
+ sc = (struct sigcontext_struct *) *newspp;
+ if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
+ goto badframe;
+
+ if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)
+ || __put_user(oldset->sig[0], &sc->oldmask)
#if _NSIG_WORDS > 1
- || __put_user(oldset->sig[1], &sc->_unused[3])
+ || __put_user(oldset->sig[1], &sc->_unused[3])
#endif
- || __put_user((struct pt_regs *)frame, &sc->regs)
- || __put_user(sig, &sc->signal))
- goto badframe;
+ || __put_user((struct pt_regs *)frame, &sc->regs)
+ || __put_user(sig, &sc->signal))
+ goto badframe;
+ }
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
if (newsp == frame)
return 0; /* no signals delivered */
- setup_frame(regs, (struct sigregs *) frame, newsp);
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(regs, (struct sigregs *) frame, newsp);
+ else
+ setup_frame(regs, (struct sigregs *) frame, newsp);
return 1;
}
stw r4,SL_HID0(r1)
/* Set up stuff at address 0 */
- lis r5,wake_up@ha
- addi r5,r5,wake_up@l
+ lis r5,grackle_wake_up@ha
+ addi r5,r5,grackle_wake_up@l
tophys(r5,r5)
stw r5,SL_PC(r1)
lis r4,KERNELBASE@h
addi r6,r6,MAGIC@l
stw r5,0(r4)
stw r6,4(r4)
+ /* Setup stuffs at 0x80-0x84 for Core99 */
+ lis r3,core99_wake_up@ha
+ addi r3,r3,core99_wake_up@l
+ tophys(r3,r3)
+ stw r3,0x80(r4)
+ stw r5,0x84(r4)
/*
- * Flush the L1 data cache by reading the first 64kB of RAM
+ * Flush the L1 data cache by reading the first 128kB of RAM
* and then flushing the same area with the dcbf instruction.
* The L2 cache has already been disabled.
*/
- li r4,0x0800 /* 64kB / 32B */
+ li r4,0x1000 /* 128kB / 32B */
mtctr r4
lis r4,KERNELBASE@h
1:
lwz r0,0(r4)
- addi r4,r4,0x0020 /* Go to start of next cache line */
+ addi r4,r4,0x0020 /* Go to start of next cache line */
bdnz 1b
sync
- li r4,0x0800 /* 64k */
+ li r4,0x1000 /* 128kB / 32B */
mtctr r4
lis r4,KERNELBASE@h
1:
bdnz 1b
sync
+/* Turn off L1 (necessary ?) */
+ mfspr r3,HID0
+ ori r3,r3, HID0_ICE|HID0_DCE
+ xori r3,r3, HID0_ICE|HID0_DCE
+ mtspr HID0,r3
+ sync
+ isync
+
/*
* Set the HID0 and MSR for sleep.
*/
1: sync
mtmsr r2
isync
- b 1b
+ b 1b
+
/*
* Here is the resume code.
+ * Core99 machines resume here
+ * r4 has the physical address of SL_PC(sp).
+ */
+
+core99_wake_up:
+ mr r1,r4
+ mfspr r3,HID0
+ /* use rlwinm ... */
+ oris r3,r3,HID0_SLEEP@h
+ xoris r3,r3,HID0_SLEEP@h
+ mtspr HID0,r3
+ sync
+ isync
+
+ /* sanitize MSR */
+ mfmsr r3
+ ori r3,r3,MSR_EE|MSR_IP
+ xori r3,r3,MSR_EE|MSR_IP
+ mtmsr r3
+ sync
+ isync
+
+/*
+ * Here is the resume code for older machines.
* r1 has the physical address of SL_PC(sp).
*/
-wake_up:
- /* Flash inval the instruction cache */
+grackle_wake_up:
+ /* Enable and then Flash inval the instruction cache */
mfspr r3,HID0
- ori r3,r3, HID0_ICFI
- mtspr HID0,r3
+ ori r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
+ sync
isync
- /* Restore the HID0 register. This turns on the L1 caches. */
+ mtspr HID0,r3
+ xori r3,r3, HID0_ICFI|HID0_DCI
+ mtspr HID0,r3
+ sync
+
+ /* Restore the remaining bits of the HID0 register. */
subi r1,r1,SL_PC
lwz r3,SL_HID0(r1)
sync
lwz r4,SL_IBAT3+4(r1)
mtibatl 3,r4
+ /* Flush all TLBs */
+ lis r4, 0x1000
+1: addic. r4, r4, -0x1000
+ tlbie r4
+ blt 1b
+ sync
+
/* restore the MSR and turn on the MMU */
lwz r3,SL_MSR(r1)
bl turn_on_mmu
tovirt(r1,r1)
/* Restore TB */
+ lis r3,0
+ mttbl r3
lwz r3,SL_TB(r1)
lwz r4,SL_TB+4(r1)
mttbu r3
mtsrr1 r3
sync
rfi
+ sync
*
* Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
* (troy@blacklablinux.com, hozer@drgw.net)
+ * Support for PReP (Motorola MTX/MVME) and Macintosh G4 SMP
+ * by Troy Benjegerdes (hozer@drgw.net)
*/
#include <linux/kernel.h>
#include <asm/gemini.h>
#include <asm/residual.h>
#include <asm/time.h>
+#include <asm/feature.h>
#include "open_pic.h"
int first_cpu_booted = 0;
struct cpuinfo_PPC cpu_data[NR_CPUS];
struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */
-volatile unsigned long ipi_count;
+atomic_t ipi_recv;
+atomic_t ipi_sent;
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
extern unsigned long *MotSave_SmpIar;
extern unsigned char *MotSave_CpusState[2];
+/* l2 cache stuff for dual G4 macs */
+extern void core99_init_l2(void);
+
/* register for interrupting the secondary processor on the powersurge */
#define PSURGE_INTR ((volatile unsigned *)0xf80000c0)
void smp_message_recv(int msg)
{
- ipi_count++;
+ atomic_inc(&ipi_recv);
switch( msg )
{
}
}
+#ifdef CONFIG_POWERMAC
/*
* As it is now, if we're sending two message at the same time
* we have race conditions on Pmac. The PowerSurge doesn't easily
* rather than this.
* -- Cort
*/
-int pmac_smp_message[NR_CPUS];
-void pmac_smp_message_recv(void)
+int psurge_smp_message[NR_CPUS];
+void psurge_smp_message_recv(void)
{
- int msg = pmac_smp_message[smp_processor_id()];
+ int msg = psurge_smp_message[smp_processor_id()];
/* clear interrupt */
out_be32(PSURGE_INTR, ~0);
smp_message_recv(msg);
/* reset message */
- pmac_smp_message[smp_processor_id()] = -1;
+ psurge_smp_message[smp_processor_id()] = -1;
}
-
+#endif /* powermac */
/*
* 750's don't broadcast tlb invalidates so
smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
}
-void smp_message_pass(int target, int msg, unsigned long data, int wait)
+#ifdef CONFIG_POWERMAC
+static void psurge_message_pass(int target, int msg, unsigned long data, int wait)
{
int i;
+ /*
+ * IPI's on the Pmac are a hack but without reasonable
+ * IPI hardware SMP on Pmac is a hack.
+ *
+ * We assume here that the msg is not -1. If it is,
+ * the recipient won't know the message was destined
+ * for it. -- Cort
+ */
+ for ( i = 0; i <= smp_num_cpus ; i++ )
+ psurge_smp_message[i] = -1;
+ switch( target )
+ {
+ case MSG_ALL:
+ psurge_smp_message[smp_processor_id()] = msg;
+ /* fall through */
+ case MSG_ALL_BUT_SELF:
+ for ( i = 0 ; i < smp_num_cpus ; i++ )
+ if ( i != smp_processor_id () )
+ psurge_smp_message[i] = msg;
+ break;
+ default:
+ psurge_smp_message[target] = msg;
+ break;
+ }
+ /* interrupt secondary processor */
+ out_be32(PSURGE_INTR, ~0);
+ out_be32(PSURGE_INTR, 0);
+ /*
+ * Assume for now that the secondary doesn't send
+ * IPI's -- Cort
+ * Could be fixed with 2.4 code from Paulus -- BenH
+ */
+ /* interrupt primary */
+ /**(volatile unsigned long *)(0xf3019000);*/
+}
+#endif /* powermac */
+
+void smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+ atomic_inc(&ipi_sent);
+
if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) )
return;
switch (_machine) {
+#ifdef CONFIG_POWERMAC
case _MACH_Pmac:
- /*
- * IPI's on the Pmac are a hack but without reasonable
- * IPI hardware SMP on Pmac is a hack.
- *
- * We assume here that the msg is not -1. If it is,
- * the recipient won't know the message was destined
- * for it. -- Cort
- */
- for ( i = 0; i <= smp_num_cpus ; i++ )
- pmac_smp_message[i] = -1;
- switch( target )
- {
- case MSG_ALL:
- pmac_smp_message[smp_processor_id()] = msg;
- /* fall through */
- case MSG_ALL_BUT_SELF:
- for ( i = 0 ; i < smp_num_cpus ; i++ )
- if ( i != smp_processor_id () )
- pmac_smp_message[i] = msg;
- break;
- default:
- pmac_smp_message[target] = msg;
+ /* Hack, 2.4 does it cleanly */
+ if (OpenPIC == NULL) {
+ psurge_message_pass(target, msg, data, wait);
break;
- }
- /* interrupt secondary processor */
- out_be32(PSURGE_INTR, ~0);
- out_be32(PSURGE_INTR, 0);
- /*
- * Assume for now that the secondary doesn't send
- * IPI's -- Cort
- */
- /* interrupt primary */
- /**(volatile unsigned long *)(0xf3019000);*/
- break;
+ }
+ /* else fall through and do something sane --Troy */
+#endif
case _MACH_chrp:
case _MACH_prep:
case _MACH_gemini:
}
}
+#ifdef CONFIG_POWERMAC
+static void pmac_core99_kick_cpu(int nr)
+{
+ extern void __secondary_start_psurge(void);
+
+ unsigned long save_int;
+ unsigned long flags;
+ volatile unsigned long *vector
+ = ((volatile unsigned long *)(KERNELBASE+0x500));
+
+ if (nr != 1)
+ return;
+
+ __save_flags(flags);
+ __cli();
+
+ /* Save EE vector */
+ save_int = *vector;
+
+ /* Setup fake EE vector that does
+ * b __secondary_start_psurge - KERNELBASE
+ */
+ *vector = 0x48000002 +
+ ((unsigned long)__secondary_start_psurge - KERNELBASE);
+
+ /* flush data cache and inval instruction cache */
+ flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+ /* Put some life in our friend */
+ feature_core99_kick_cpu1();
+
+ /* FIXME: We wait a bit for the CPU to take the exception, I should
+ * instead wait for the entry code to set something for me. Well,
+ * ideally, all that crap will be done in prom.c and the CPU left
+ * in a RAM-based wait loop like CHRP.
+ */
+ mdelay(1);
+
+ /* Restore our exception vector */
+ *vector = save_int;
+ flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+
+ __restore_flags(flags);
+}
+#endif /* powermac */
+
void __init smp_boot_cpus(void)
{
extern struct task_struct *current_set[NR_CPUS];
switch ( _machine )
{
+#ifdef CONFIG_POWERMAC
case _MACH_Pmac:
- /* assume powersurge board - 2 processors -- Cort */
+ /* assum e powersurge board - 2 processors -- Cort */
+ /* or a dual G4 -- Troy */
cpu_nr = 2;
break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
case _MACH_chrp:
cpu_nr = ((openpic_read(&OpenPIC->Global.Feature_Reporting0)
& OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1;
break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP)
case _MACH_prep:
/* assume 2 for now == fix later -- Johnnie */
if ( mot_multi )
cpu_nr = 2;
break;
}
+#endif
+#ifdef CONFIG_GEMINI
case _MACH_gemini:
cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2;
cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr;
break;
+#endif
default:
printk("SMP not supported on this machine.\n");
return;
/* wake up cpus */
switch ( _machine )
{
+#ifdef CONFIG_POWERMAC
case _MACH_Pmac:
- /* setup entry point of secondary processor */
- *(volatile unsigned long *)(0xf2800000) =
- (unsigned long)__secondary_start_psurge-KERNELBASE;
- eieio();
- /* interrupt secondary to begin executing code */
- out_be32(PSURGE_INTR, ~0);
- out_be32(PSURGE_INTR, 0);
+ if (OpenPIC == NULL) {
+ /* setup entry point of secondary processor */
+ *(volatile unsigned long *)(0xf2800000) =
+ (unsigned long)__secondary_start_psurge-KERNELBASE;
+ eieio();
+ /* interrupt secondary to begin executing code */
+ out_be32(PSURGE_INTR, ~0);
+ out_be32(PSURGE_INTR, 0);
+ } else
+ pmac_core99_kick_cpu(i);
break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
case _MACH_chrp:
*(unsigned long *)KERNELBASE = i;
asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
break;
+#endif
+#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP)
case _MACH_prep:
*MotSave_SmpIar = (unsigned long)__secondary_start_psurge - KERNELBASE;
*MotSave_CpusState[1] = CPU_GOOD;
printk("CPU1 reset, waiting\n");
break;
+#endif
+#ifdef CONFIG_GEMINI
case _MACH_gemini:
openpic_init_processor( 1<<i );
openpic_init_processor( 0 );
break;
+#endif
}
-
+
/*
* wait to see if the cpu made a callin (is actually up).
* use this value that I found through experimentation.
}
}
- if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+ if (OpenPIC)
do_openpic_setup_cpu();
- if ( _machine == _MACH_Pmac )
+ else if ( _machine == _MACH_Pmac )
{
/* reset the entry point so if we get another intr we won't
* try to startup again */
* place to stick it for now.
* -- Cort
*/
- if ( _machine & (_MACH_gemini|_MACH_chrp|_MACH_prep) )
+ if (OpenPIC) {
do_openpic_setup_cpu();
+#ifdef CONFIG_POWERMAC
+ if ( _machine == _MACH_Pmac )
+ core99_init_l2();
+#endif
+ }
+#ifdef CONFIG_GEMINI
if ( _machine == _MACH_gemini )
gemini_init_l2();
+#endif
while(!smp_commenced)
barrier();
__sti();
return error;
}
+
+#ifndef CONFIG_PCI
+/*
+ * Those are normally defined in arch/ppc/kernel/pci.c. But when CONFIG_PCI is
+ * not defined, this file is not linked at all, so here are the "empty" versions
+ */
+asmlinkage int sys_pciconfig_read() { return -ENOSYS; }
+asmlinkage int sys_pciconfig_write() { return -ENOSYS; }
+asmlinkage long sys_pciconfig_iobase() { return -ENOSYS; }
+#endif
+
{
int dval, d;
unsigned long cpu = smp_processor_id();
-
+
hardirq_enter(cpu);
#ifdef __SMP__
{
__initfunc(void time_init(void))
{
+ long time_offset = 0;
+
if (ppc_md.time_init != NULL)
- {
- ppc_md.time_init();
- }
+ time_offset = ppc_md.time_init();
if ((_get_PVR() >> 16) == 1) {
/* 601 processor: dec counts down by 128 every 128ns */
xtime.tv_sec = ppc_md.get_rtc_time();
xtime.tv_usec = 0;
+ if (time_offset) {
+ struct timezone tz;
+ tz.tz_minuteswest = time_offset/60;
+ tz.tz_dsttime = 0; /* Not handled correctly by the kernel anyway */
+ do_sys_settimeofday(NULL, &tz);
+ }
set_dec(decrementer_count);
/* allow updates right away */
_exception(SIGTRAP, regs);
}
+/* Illegal instruction emulation support. Originally written to
+ * provide the PVR to user applications using the mfspr rd, PVR.
+ * Return non-zero if we can't emulate, or EFAULT if the associated
+ * memory access caused an access fault. Return zero on success.
+ *
+ * There are a couple of ways to do this, either "decode" the instruction
+ * or directly match lots of bits. In this case, matching lots of
+ * bits is faster and easier.
+ *
+ */
+#define INST_MFSPR_PVR 0x7c1f42a6
+#define INST_MFSPR_PVR_MASK 0xfc1fffff
+
+static int
+emulate_instruction(struct pt_regs *regs)
+{
+ uint instword;
+ uint rd;
+ int retval;
+
+ retval = EINVAL;
+ if (!user_mode(regs))
+ return retval;
+
+ retval = EFAULT;
+ if (get_user(instword, (uint *)(regs->nip)))
+ return retval;
+
+ /* Emulate the mfspr rD, PVR.
+ */
+ retval = EINVAL;
+ if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
+ rd = (instword >> 21) & 0x1f;
+ regs->gpr[rd] = _get_PVR();
+ retval = 0;
+ }
+ if (retval == 0)
+ regs->nip += 4;
+ return(retval);
+}
+
void
ProgramCheckException(struct pt_regs *regs)
{
+ int errcode;
+
if (regs->msr & 0x100000) {
/* IEEE FP exception */
_exception(SIGFPE, regs);
#endif
_exception(SIGTRAP, regs);
} else {
- _exception(SIGILL, regs);
+ /* Try to emulate it if we should. */
+ if ((errcode = emulate_instruction(regs))) {
+ if (errcode == EFAULT)
+ _exception(SIGBUS, regs);
+ else
+ _exception(SIGILL, regs);
+ }
}
}
#include <linux/module.h>
#include <asm/uaccess.h>
-extern const struct exception_table_entry __start___ex_table[];
-extern const struct exception_table_entry __stop___ex_table[];
+extern struct exception_table_entry __start___ex_table[];
+extern struct exception_table_entry __stop___ex_table[];
+
+/*
+ * The exception table needs to be sorted because we use the macros
+ * which put things into the exception table in a variety of segments
+ * such as the prep, pmac, chrp, etc. segments as well as the init
+ * segment and the main kernel text segment.
+ */
+static inline void
+sort_ex_table(struct exception_table_entry *start,
+ struct exception_table_entry *finish)
+{
+ struct exception_table_entry el, *p, *q;
+
+ /* insertion sort */
+ for (p = start + 1; p < finish; ++p) {
+ /* start .. p-1 is sorted */
+ if (p[0].insn < p[-1].insn) {
+ /* move element p down to its right place */
+ el = *p;
+ q = p;
+ do {
+ /* el comes before q[-1], move q[-1] up one */
+ q[0] = q[-1];
+ --q;
+ } while (q > start && el.insn < q[-1].insn);
+ *q = el;
+ }
+ }
+}
+
+void
+sort_exception_table(void)
+{
+ sort_ex_table(__start___ex_table, __stop___ex_table);
+}
static inline unsigned long
search_one_table(const struct exception_table_entry *first,
{
unsigned long ret;
-#if 1 /*ndef CONFIG_MODULES*/
+#ifndef CONFIG_MODULES
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
if (ret) return ret;
* still be merged.
* -- Cort
*/
+#ifdef CONFIG_BOOTX_TEXT
+extern boot_infos_t *disp_bi;
+#endif
__initfunc(void MMU_init(void))
{
#ifdef __SMP__
struct device_node *macio = find_devices("mac-io");
if (macio && macio->n_addrs)
base = macio->addrs[0].address;
- setbat(0, base, base, 0x100000, IO_PAGE);
+ /* Hrm... we have it at 0x80000000 on some machines
+ * and this is covered by the userland segment
+ * registers. Isn't that bad ? Well, the BAT takes
+ * precedence, but I don't like it. --BenH
+ */
+ if (base >= 0xf0000000)
+ setbat(0, base, base, 0x100000, IO_PAGE);
ioremap_base = 0xf0000000;
}
break;
ioremap(0x80000000, 0x4000);
ioremap(0x81000000, 0x4000);
#endif /* CONFIG_8xx */
+#ifdef CONFIG_BOOTX_TEXT
+ if (_machine == _MACH_Pmac)
+ map_bootx_text();
+#endif
}
/*
*p = 0;
return str;
}
+
+void
+xmon_enter(void)
+{
+ pmu_suspend();
+}
+
+void
+xmon_leave(void)
+{
+ pmu_resume();
+}
extern int setjmp(u_int *);
extern void longjmp(u_int *, int);
+extern void xmon_enter(void);
+extern void xmon_leave(void);
+
#define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3])
static char *help_string = "\
msr = get_msr();
set_msr(msr & ~0x8000); /* disable interrupts */
remove_bpts();
+ xmon_enter();
excprint(excp);
cmd = cmds(excp);
if (cmd == 's') {
xmon_trace = 0;
insert_bpts();
}
+ xmon_leave();
set_msr(msr); /* restore interrupt enable */
}
# FIXME: should insert zeroes into memory when filling holes
# FIXME: calculate blkpertrack from rdc data and blksize
+# change 09/20/00 removed obsolete store of ipldevice to textesegment
+
# Usage of registers
# r1: ipl subchannel ( general use, dont overload without save/restore !)
# r10:
stsch .Lrdcdata
oi .Lrdcdata+5,0x84 # enable ssch and multipath mode
.Lecs: xi .Lrdcdata+27,0x01 # enable concurrent sense
- msch .Lrdcdata
+ msch .Lrdcdata
xi .Lprgn,6 # restore Wait and d/a bit in PCnew PSW
l %r2,.Lparm
- mvc 0x0(8,%r2),.Lnull # set parmarea to null
+ mvc 0x0(8,%r2),.Lnull # set parmarea to null
lctl %c6,%c6,.Lc6 # enable all interrupts
.Lrdc: # read device characteristics
la %r6,.Lrdcccw
.Lzeroes:
lr %r2,%r3
.L001: slr %r3,%r3
- icm %r3,3,.Lcountarea+6 # get blocksize
+ icm %r3,3,.Lcountarea+6 # get blocksize
slr %r5,%r5 # no bytes to move
.L008: mvcle %r2,%r4,0 # fill zeroes to storage
jo .L008 # until block is filled
mvc 0x600(256,%r3),0x180(%r4)
mvc 0x700(256,%r3),0x280(%r4)
.Lrunkern:
- lhi %r2,17
- sll %r2,12
- st %r1,0xc6c(%r2) # store iplsubchannel to lowcore
- st %r1,0xc6c # store iplsubchannel to lowcore
+# lhi %r2,17
+# sll %r2,12
+# st %r1,0xc6c(%r2) # store iplsubchannel to lowcore
+# st %r1,0xc6c # store iplsubchannel to lowcore
br %r3
# This function does the start IO
# r2: number of first block to read ( input by caller )
lr %r15,%r4 # save number or blocks
slr %r7,%r7
icm %r7,3,.Lrdcdata+14 # load heads to r7
- lhi %r6,9
- clc .Lrdcdata+3(2),.L9345
+ lhi %r6,9
+ clc .Lrdcdata+3(2),.L9345
je .L011
lhi %r6,10
clc .Lrdcdata+3(2),.L3380
lhi %r6,12
clc .Lrdcdata+3(2),.L3390
je .L011
- bras %r14,.Ldisab
+ bras %r14,.Ldisab
.L011:
# loop for nbl times
.Lrdloop:
mainmenu_option next_comment
comment 'Code maturity level options'
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
endmenu
mainmenu_option next_comment
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
+CONFIG_PROCESS_DEBUG=n
#
# Processor type and features
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
# CONFIG_IP_ROUTER is not set
#include <linux/stddef.h>
#include <linux/kernel.h>
-#include <asm/string.h>
+#include <linux/string.h>
#include <asm/ebcdic.h>
void cpcmd(char *cmd, char *response, int rlen)
+/*
+ * arch/s390/kernel/debug.c
+ * S/390 debug facility
+ *
+ * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
+ * IBM Corporation
+ * Author(s): Michael Holzheu (holzheu@de.ibm.com),
+ * Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ *
+ * Bugreports to: <Linux390@de.ibm.com>
+ */
+
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
#include <asm/ebcdic.h>
-#include <asm/debug.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
#ifdef MODULE
#include <linux/module.h>
#endif
-#include <asm/ebcdic.h>
+#include <asm/debug.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#if defined(CONFIG_ARCH_S390)
+#define DEBUG_PROC_HEADER_SIZE 38
+#endif
+
+#define ADD_BUFFER 1000
+
+/* typedefs */
+
+typedef struct file_private_info {
+ loff_t len; /* length of output in byte */
+ int size; /* size of buffer for output */
+ char *data; /* buffer for output */
+ debug_info_t *debug_info; /* the debug information struct */
+ struct debug_view *view; /* used view of debug info */
+} file_private_info_t;
+
+extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
+
+/* internal function prototyes */
+
+static int debug_init(void);
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+ int size, struct debug_view *view);
+static ssize_t debug_output(struct file *file, char *user_buf,
+ size_t user_len, loff_t * offset);
+static ssize_t debug_input(struct file *file, const char *user_buf,
+ size_t user_len, loff_t * offset);
+static int debug_open(struct inode *inode, struct file *file);
+static int debug_close(struct inode *inode, struct file *file);
+static struct proc_dir_entry
+*debug_create_proc_dir_entry(struct proc_dir_entry *root,
+ const char *name, mode_t mode,
+ struct inode_operations *iops,
+ struct file_operations *fops);
+static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
+ struct proc_dir_entry *entry);
+static void debug_info_get(debug_info_t *);
+static void debug_info_put(debug_info_t *);
+static int debug_prolog_level_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf);
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char *user_buf,
+ size_t user_buf_size, loff_t * offset);
+static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf);
+static int debug_ascii_format_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf,
+ const char *in_buf);
+static int debug_ebcdic_format_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf,
+ const char *in_buf);
+
+/* globals */
+
+struct debug_view debug_ascii_view = {
+ "ascii",
+ NULL,
+ &debug_dflt_header_fn,
+ &debug_ascii_format_fn,
+ NULL
+};
+
+struct debug_view debug_ebcdic_view = {
+ "ebcdic",
+ NULL,
+ &debug_dflt_header_fn,
+ &debug_ebcdic_format_fn,
+ NULL
+};
+
+struct debug_view debug_hex_view = {
+ "hex",
+ NULL,
+ &debug_dflt_header_fn,
+ &debug_hex_format_fn,
+ NULL
+};
+
+struct debug_view debug_level_view = {
+ "level",
+ &debug_prolog_level_fn,
+ NULL,
+ NULL,
+ &debug_input_level_fn
+};
+
+/* static globals */
+
+static debug_info_t debug_areas[DEBUG_MAX_AREAS];
+static debug_info_t *free_area = 0;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+static struct semaphore debug_lock = MUTEX;
+#else
+DECLARE_MUTEX(debug_lock);
+#endif
-debug_info_t debug_areas[MAX_DEBUG_AREAS] = { {NULL, },};
-debug_info_t *free_area = 0;
static int initialized = 0;
-static spinlock_t debug_lock = SPIN_LOCK_UNLOCKED;
-
-debug_info_t *
-debug_register (char *name, int page_order, int nr_areas)
-{
- debug_info_t *rc = 0;
- int i;
- long flags;
-
- if ( ! initialized ){
- debug_init();
- initialized = 1;
- }
- if (!free_area)
- {
- printk (KERN_WARNING "No free debug area\n");
- return NULL;
- }
- spin_lock_irqsave (&debug_lock, flags);
- rc = free_area;
- free_area = *((debug_info_t **) rc);
-
- memset(rc, 0, nr_areas * sizeof(debug_info_t));
- rc->areas = (debug_entry_t **) kmalloc (nr_areas *
- sizeof (debug_entry_t *),
- GFP_ATOMIC);
- if (!rc->areas)
- {
- goto noareas;
- }
-
- for (i = 0; i < nr_areas; i++)
- {
- rc->areas[i] = (debug_entry_t *) __get_free_pages (GFP_ATOMIC,
- page_order);
- if (!rc->areas[i])
+static struct file_operations debug_file_ops = {
+ read: debug_output,
+ write: debug_input,
+ open: debug_open,
+ release: debug_close,
+};
+
+static struct inode_operations debug_inode_ops = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ default_file_ops: &debug_file_ops, /* file ops */
+#endif
+};
+
+
+static struct proc_dir_entry *debug_proc_root_entry;
+
+
+/* functions */
+
+/*
+ * debug_info_get
+ * - increments reference count for debug-info
+ */
+
+static void debug_info_get(debug_info_t * db_info)
+{
+ if (db_info)
+ atomic_inc(&db_info->ref_count);
+}
+
+/*
+ * debug_info_put:
+ * - decreases reference count for debug-info and frees it if necessary
+ */
+
+static void debug_info_put(debug_info_t *db_info)
+{
+ int i;
+
+ if (!db_info)
+ return;
+ if (atomic_dec_and_test(&db_info->ref_count)) {
+ printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
+ db_info, db_info->name);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (db_info->views[i] != NULL)
+ debug_delete_proc_dir_entry
+ (db_info->proc_root_entry,
+ db_info->proc_entries[i]);
+ }
+ debug_delete_proc_dir_entry(debug_proc_root_entry,
+ db_info->proc_root_entry);
+ for (i = 0; i < db_info->nr_areas; i++) {
+ free_pages((unsigned long) db_info->areas[i],
+ db_info->page_order);
+ }
+ kfree(db_info->areas);
+ db_info->areas = NULL;
+ *((debug_info_t **) db_info) = free_area;
+ free_area = db_info;
+ }
+}
+
+
+/*
+ * debug_output:
+ * - called for user read()
+ * - copies formated output form private_data of the file
+ * handle to the user buffer
+ */
+
+static ssize_t debug_output(struct file *file, /* file descriptor */
+ char *user_buf, /* user buffer */
+ size_t user_len, /* length of buffer */
+ loff_t *offset /* offset in the file */ )
+{
+ loff_t len;
+ int rc;
+ file_private_info_t *p_info;
+
+ p_info = ((file_private_info_t *) file->private_data);
+ if (*offset >= p_info->len) {
+ return 0; /* EOF */
+ } else {
+ len = MIN(user_len, (p_info->len - *offset));
+ if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len)))
+ return rc;;
+ (*offset) += len;
+ return len; /* number of bytes "read" */
+ }
+}
+
+/*
+ * debug_input:
+ * - called for user write()
+ * - calls input function of view
+ */
+
+static ssize_t debug_input(struct file *file,
+ const char *user_buf, size_t length,
+ loff_t *offset)
+{
+ int rc = 0;
+ file_private_info_t *p_info;
+
+ down(&debug_lock);
+ p_info = ((file_private_info_t *) file->private_data);
+ if (p_info->view->input_proc)
+ rc = p_info->view->input_proc(p_info->debug_info,
+ p_info->view, file, user_buf,
+ length, offset);
+ up(&debug_lock);
+ return rc; /* number of input characters */
+}
+
+/*
+ * debug_format_output:
+ * - calls prolog, header and format functions of view to format output
+ */
+
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+ int size, struct debug_view *view)
+{
+ int len = 0;
+ int i, j;
+ int nr_of_entries;
+ debug_entry_t *act_entry;
+
+ /* print prolog */
+ if (view->prolog_proc)
+ len += view->prolog_proc(debug_area, view, buf);
+ /* print debug records */
+ if (!(view->format_proc) && !(view->header_proc))
+ goto out;
+ nr_of_entries = PAGE_SIZE / debug_area->entry_size
+ << debug_area->page_order;
+ for (i = 0; i < debug_area->nr_areas; i++) {
+ act_entry = debug_area->areas[i];
+ for (j = 0; j < nr_of_entries; j++) {
+ if (act_entry->id.fields.used == 0)
+ break; /* empty entry */
+ if (view->header_proc)
+ len += view->header_proc(debug_area, view, i,
+ act_entry, buf + len);
+ if (view->format_proc)
+ len += view->format_proc(debug_area, view,
+ buf + len,
+ act_entry->data);
+ len += sprintf(buf + len, "\n");
+ if (len > size) {
+ printk(KERN_ERR
+ "debug: error -- memory exceeded for (%s/%s)\n",
+ debug_area->name, view->name);
+ printk(KERN_ERR "debug: fix view %s!!\n",
+ view->name);
+ printk(KERN_ERR
+ "debug: area: %i (0 - %i) entry: %i (0 - %i)\n",
+ i, debug_area->nr_areas - 1, j,
+ nr_of_entries - 1);
+ goto out;
+ }
+ act_entry = (debug_entry_t *) (((char *) act_entry) +
+ debug_area->entry_size);
+ }
+ }
+ out:
+ return len;
+}
+
+
+/*
+ * debug_open:
+ * - called for user open()
+ * - copies formated output to private_data area of the file
+ * handle
+ */
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ int i, j = 0, size = 0, rc = 0, f_entry_size = 0;
+ file_private_info_t *p_info;
+
+#ifdef DEBUG
+ printk("debug_open\n");
+#endif
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ down(&debug_lock);
+
+ /* find debug log and view */
+
+ for (i = 0; i < DEBUG_MAX_AREAS; i++) {
+ if (debug_areas[i].areas == NULL)
+ continue; /* not in use */
+ for (j = 0; j < DEBUG_MAX_VIEWS; j++) {
+ if (debug_areas[i].views[j] == NULL)
+ continue;
+ else if (debug_areas[i].proc_entries[j]->low_ino ==
+ file->f_dentry->d_inode->i_ino) {
+ goto found; /* found view ! */
+ }
+ }
+ }
+ /* no entry found */
+ rc = -EINVAL;
+ goto out;
+ found:
+ if ((file->private_data =
+ kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
+ printk(KERN_ERR "debug_open: kmalloc failed\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ p_info = (file_private_info_t *) file->private_data;
+
+ /*
+ * the size for the formated output is calculated
+ * with the following formula:
+ *
+ * prolog-size
+ * +
+ * (record header size + record data field size)
+ * * number of entries per page
+ * * number of pages per area
+ * * number of areas
+ */
+
+ if (debug_areas[i].views[j]->prolog_proc)
+ size +=
+ debug_areas[i].views[j]->prolog_proc(&debug_areas[i],
+ debug_areas[i].
+ views[j], NULL);
+
+ if (debug_areas[i].views[j]->header_proc)
+ f_entry_size =
+ debug_areas[i].views[j]->header_proc(&debug_areas[i],
+ debug_areas[i].
+ views[j], 0, NULL,
+ NULL);
+ if (debug_areas[i].views[j]->format_proc)
+ f_entry_size +=
+ debug_areas[i].views[j]->format_proc(&debug_areas[i],
+ debug_areas[i].
+ views[j], NULL,
+ NULL);
+ if (f_entry_size)
+ f_entry_size += 1; /* \n in each line */
+
+
+ size += f_entry_size
+ * (PAGE_SIZE / debug_areas[i].entry_size
+ << debug_areas[i].page_order)
+ * debug_areas[i].nr_areas + 1; /* terminating \0 */
+#ifdef DEBUG
+ printk("debug_open: size: %i\n", size);
+#endif
+
+ /* alloc some bytes more to be safe against bad views */
+ if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) {
+ printk(KERN_ERR "debug_open: vmalloc failed\n");
+ vfree(file->private_data);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ p_info->size = size;
+ p_info->debug_info = &debug_areas[i];
+ p_info->view = debug_areas[i].views[j];
+
+ spin_lock_irq(&debug_areas[i].lock);
+
+ p_info->len =
+ debug_format_output(&debug_areas[i], p_info->data, size,
+ debug_areas[i].views[j]);
+#ifdef DEBUG
{
- for (i--; i >= 0; i--)
- {
- free_pages ((unsigned long) rc->areas[i], page_order);
- }
- goto nopages;
+ int ilen = p_info->len;
+ printk("debug_open: len: %i\n", ilen);
+ }
+#endif
+
+ spin_unlock_irq(&debug_areas[i].lock);
+ debug_info_get(&debug_areas[i]);
+
+ out:
+ up(&debug_lock);
+#ifdef MODULE
+ if (rc != 0)
+ MOD_DEC_USE_COUNT;
+#endif
+ return rc;
+}
+
+/*
+ * debug_close:
+ * - called for user close()
+ * - deletes private_data area of the file handle
+ */
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+ file_private_info_t *p_info;
+#ifdef DEBUG
+ printk("debug_close\n");
+#endif
+ down(&debug_lock);
+ p_info = (file_private_info_t *) file->private_data;
+ debug_info_put(p_info->debug_info);
+ if (p_info->data) {
+ vfree(p_info->data);
+ kfree(file->private_data);
+ }
+ up(&debug_lock);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0; /* success */
+}
+
+/*
+ * debug_create_proc_dir_entry:
+ * - initializes proc-dir-entry and registers it
+ */
+
+static struct proc_dir_entry *debug_create_proc_dir_entry
+ (struct proc_dir_entry *root, const char *name, mode_t mode,
+ struct inode_operations *iops, struct file_operations *fops)
+{
+ struct proc_dir_entry *rc = NULL;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ const char *fn = name;
+ int len;
+ len = strlen(fn);
+
+ rc = (struct proc_dir_entry *) kmalloc(sizeof(struct proc_dir_entry)
+ + len + 1, GFP_ATOMIC);
+ if (!rc)
+ goto out;
+
+ memset(rc, 0, sizeof(struct proc_dir_entry));
+ memcpy(((char *) rc) + sizeof(*rc), fn, len + 1);
+ rc->name = ((char *) rc) + sizeof(*rc);
+ rc->namelen = len;
+ rc->low_ino = 0, rc->mode = mode;
+ rc->nlink = 1;
+ rc->uid = 0;
+ rc->gid = 0;
+ rc->size = 0;
+ rc->get_info = NULL;
+ rc->ops = iops;
+
+ proc_register(root, rc);
+#else
+ rc = create_proc_entry(name, mode, root);
+ if (!rc)
+ goto out;
+ if (fops)
+ rc->proc_fops = fops;
+#endif
+
+ out:
+ return rc;
+}
+
+
+/*
+ * delete_proc_dir_entry:
+ */
+
+static void debug_delete_proc_dir_entry
+ (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry)
+{
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ proc_unregister(root, proc_entry->low_ino);
+ kfree(proc_entry);
+#else
+ remove_proc_entry(proc_entry->name, root);
+#endif
+}
+
+/*
+ * debug_register:
+ * - creates and initializes debug area for the caller
+ * - returns handle for debug area
+ */
+
+debug_info_t *debug_register
+ (char *name, int page_order, int nr_areas, int buf_size)
+{
+ debug_info_t *rc = NULL;
+ int i;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ if (!initialized)
+ debug_init();
+ down(&debug_lock);
+ if (!free_area) {
+ printk(KERN_WARNING "debug: no free debug area for %s\n",
+ name);
+ goto out;
+ }
+ rc = free_area;
+ free_area = *((debug_info_t **) rc);
+ rc->areas = (debug_entry_t **) kmalloc(nr_areas *
+ sizeof(debug_entry_t *),
+ GFP_ATOMIC);
+ if (!rc->areas) {
+ free_area = rc;
+ rc = NULL;
+ goto out;
+ }
+ for (i = 0; i < nr_areas; i++) {
+ rc->areas[i] =
+ (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
+ page_order);
+ if (!rc->areas[i]) {
+ for (i--; i >= 0; i--) {
+ free_pages((unsigned long) rc->areas[i],
+ page_order);
+ }
+ free_area = rc;
+ rc = NULL;
+ goto out;
+ } else {
+ memset(rc->areas[i], 0, PAGE_SIZE << page_order);
+ }
}
- }
- rc->page_order = page_order;
- rc->nr_areas = nr_areas;
- rc->name = kmalloc (strlen (name) + 1, GFP_ATOMIC);
- strncpy (rc->name, name, strlen (name));
- ASCEBC(rc->name, strlen (name));
- rc->name[strlen (name)] = 0;
-
- rc->active_entry = kmalloc (nr_areas, GFP_ATOMIC);
- memset(rc->active_entry, 0, nr_areas * sizeof(int));
- rc->level=3;
- printk (KERN_INFO "reserved %d areas of %d pages for debugging %s\n",
- nr_areas, 1 << page_order, name);
- goto exit;
-
-nopages:
-noareas:
- free_area = rc;
-exit:
- spin_unlock_irqrestore (&debug_lock, flags);
- return rc;
-}
-
-void
-debug_unregister (debug_info_t * id, char *name)
-{
- int i = id->nr_areas;
- long flags;
- spin_lock_irqsave (&debug_lock, flags);
- printk (KERN_INFO "freeing debug area %p named '%s'\n", id, name);
- if (strncmp (name, id->name, strlen (name)))
- {
- printk (KERN_ERR "name '%s' does not match against '%s'\n",
- name, id->name);
- }
- for (i--; i >= 0; i--)
- {
- free_pages ((unsigned long) id->areas[i], id->page_order);
- }
- kfree (id->areas);
- kfree (id->name);
- *((debug_info_t **) id) = free_area;
- free_area = id;
- spin_unlock_irqrestore (&debug_lock, flags);
- return;
-}
-
-static inline void
-proceed_active_entry (debug_info_t * id)
-{
- id->active_entry[id->active_area] =
- (id->active_entry[id->active_area]++) %
- ((PAGE_SIZE / sizeof (debug_entry_t)) << (id->page_order));
-}
-
-static inline void
-proceed_active_area (debug_info_t * id)
-{
- id->active_area = (id->active_area++) % id->nr_areas;
-}
-
-static inline debug_entry_t *
-get_active_entry (debug_info_t * id)
-{
- return &id->areas[id->active_area][id->active_entry[id->active_area]];
-}
-
-static inline debug_entry_t *
-debug_common ( debug_info_t * id )
-{
- debug_entry_t * active;
- proceed_active_entry (id);
- active = get_active_entry (id);
- STCK (active->id.stck);
- active->id.stck = active->id.stck >> 4;
- active->id.fields.cpuid = smp_processor_id ();
- active->caller = __builtin_return_address (0);
- return active;
-}
-
-void
-debug_event (debug_info_t * id, int level, unsigned int tag)
-{
- long flags;
- debug_entry_t *active;
- if (!id)
- {
- return;
- }
- if (level < id->level)
- {
- return;
- }
- spin_lock_irqsave (&id->lock, flags);
- active = debug_common(id);
- active->tag.tag = tag;
- spin_unlock_irqrestore (&id->lock, flags);
- return;
-}
-
-void
-debug_text_event (debug_info_t * id, int level, char tag[4])
-{
- long flags;
- debug_entry_t *active;
- if (!id)
- {
- return;
- }
- if (level < id->level)
- {
- return;
- }
- spin_lock_irqsave (&id->lock, flags);
- active = debug_common(id);
- strncpy ( active->tag.text, tag, 4);
- ASCEBC (active->tag.text, 4 );
- spin_unlock_irqrestore (&id->lock, flags);
- return;
-}
-
-void
-debug_exception (debug_info_t * id, int level, unsigned int tag)
-{
- long flags;
- debug_entry_t *active;
- if (!id)
- {
- return;
- }
- if (level < id->level)
- {
- return;
- }
- spin_lock_irqsave (&id->lock, flags);
- active = debug_common(id);
- active->tag.tag = tag;
- proceed_active_area (id);
- spin_unlock_irqrestore (&id->lock, flags);
-
- return;
-}
-
-void
-debug_text_exception (debug_info_t * id, int level, char tag[4])
-{
- long flags;
- debug_entry_t *active;
- if (!id)
- {
- return;
- }
- if (level < id->level)
- {
- return;
- }
- spin_lock_irqsave (&id->lock, flags);
- active = debug_common(id);
- strncpy ( active->tag.text, tag, 4);
- ASCEBC (active->tag.text, 4 );
- proceed_active_area (id);
- spin_unlock_irqrestore (&id->lock, flags);
- return;
-}
-
-int
-debug_init (void)
-{
- int rc = 0;
- int i;
- for (i = 0; i < MAX_DEBUG_AREAS - 1; i++)
- {
- *(debug_info_t **) (&debug_areas[i]) =
- (debug_info_t *) (&debug_areas[i + 1]);
- }
- *(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL;
- free_area = &(debug_areas[0]);
- printk (KERN_INFO "%d areas reserved for debugging information\n",
- MAX_DEBUG_AREAS);
- return rc;
+
+ rc->page_order = page_order;
+ rc->nr_areas = nr_areas;
+ rc->active_area = 0;
+ rc->level = DEBUG_DEFAULT_LEVEL;
+ rc->buf_size = buf_size;
+ rc->entry_size = sizeof(debug_entry_t)
+ + buf_size - 4; /* must subtract data[4] */
+ strncpy(rc->name, name,
+ MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
+ rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
+ memset(rc->active_entry, 0, nr_areas * sizeof(int));
+ memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+ atomic_set(&(rc->ref_count), 0);
+ rc->proc_root_entry =
+ debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
+ S_IFDIR | S_IRUGO | S_IXUGO |
+ S_IWUSR | S_IWGRP, NULL, NULL);
+ debug_register_view(rc, &debug_level_view);
+ debug_info_get(rc);
+ printk(KERN_INFO
+ "debug: reserved %d areas of %d pages for debugging %s\n",
+ nr_areas, 1 << page_order, rc->name);
+ out:
+ if (rc == NULL){
+ printk(KERN_ERR "debug: debug_register failed for %s\n",name);
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ }
+ up(&debug_lock);
+ return rc;
}
+/*
+ * debug_unregister:
+ * - give back debug area
+ */
+
+void debug_unregister(debug_info_t * id)
+{
+ if (!id)
+ goto out;
+ down(&debug_lock);
+ printk(KERN_INFO "debug: unregistering %s\n", id->name);
+ debug_info_put(id);
+ up(&debug_lock);
+
#ifdef MODULE
-int
-init_module (void)
-{
- int rc = 0;
- rc = debug_init ();
- if (rc)
- {
- printk (KERN_INFO "An error occurred with debug_init\n");
- }
-
- { /* test section */
- debug_info_t *a[4];
- printk (KERN_INFO "registering 1, %p\n", a[0] =
- debug_register ("debug1", 1, 1));
- printk (KERN_INFO "registering 2, %p\n", a[1] =
- debug_register ("debug2", 1, 2));
- printk (KERN_INFO "registering 3, %p\n", a[2] =
- debug_register ("debug3", 2, 1));
- printk (KERN_INFO "registering 4, %p\n", a[3] =
- debug_register ("debug4", 2, 2));
- debug_unregister (a[0], "debug1");
- debug_unregister (a[1], "debug3");
- printk (KERN_INFO "registering 1, %p\n", a[0] =
- debug_register ("debug5", 1, 1));
- printk (KERN_INFO "registering 2, %p\n", a[1] =
- debug_register ("debug6", 1, 2));
- debug_unregister (a[2], "debug2");
- debug_unregister (a[3], "debug4");
- debug_unregister (a[0], "debug5");
- debug_unregister (a[1], "debug6");
- }
- return rc;
-}
-
-void
-cleanup_module (void)
-{
-
- return;
-}
-
-#endif /* MODULE */
+ MOD_DEC_USE_COUNT;
+#endif
+ out:
+ return;
+}
+
+
+/*
+ * proceed_active_entry:
+ * - set active entry to next in the ring buffer
+ */
+
+static inline void proceed_active_entry(debug_info_t * id)
+{
+ if ((id->active_entry[id->active_area] += id->entry_size)
+ > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
+ id->active_entry[id->active_area] = 0;
+}
+
+/*
+ * proceed_active_area:
+ * - set active area to next in the ring buffer
+ */
+
+static inline void proceed_active_area(debug_info_t * id)
+{
+ id->active_area++;
+ id->active_area = id->active_area % id->nr_areas;
+}
+
+/*
+ * get_active_entry:
+ */
+
+static inline debug_entry_t *get_active_entry(debug_info_t * id)
+{
+ return (debug_entry_t *) ((char *) id->areas[id->active_area] +
+ id->active_entry[id->active_area]);
+}
+
+/*
+ * debug_common:
+ * - set timestamp, caller address, cpu number etc.
+ */
+
+static inline debug_entry_t *debug_common(debug_info_t * id)
+{
+ debug_entry_t *active;
+
+ active = get_active_entry(id);
+ STCK(active->id.stck);
+ active->id.fields.cpuid = smp_processor_id();
+ active->id.fields.used = 1;
+ active->caller = __builtin_return_address(0);
+ return active;
+}
+
+/*
+ * debug_event:
+ */
+
+debug_entry_t *debug_event(debug_info_t * id, int level, void *buf,
+ int len)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level < id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 0;
+ memset(active->data, 0, id->buf_size);
+ memcpy(active->data, buf, MIN(len, id->buf_size));
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_int_event:
+ */
+
+debug_entry_t *debug_int_event(debug_info_t * id, int level,
+ unsigned int tag)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level < id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 0;
+ memset(active->data, 0, id->buf_size);
+ memcpy(active->data, &tag, MIN(sizeof(unsigned int), id->buf_size));
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_text_event:
+ */
+
+debug_entry_t *debug_text_event(debug_info_t * id, int level,
+ const char *txt)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level < id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ memset(active->data, 0, id->buf_size);
+ strncpy(active->data, txt, MIN(strlen(txt), id->buf_size));
+ ASCEBC(active->data, MIN(strlen(txt), id->buf_size));
+ active->id.fields.exception = 0;
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+
+}
+
+/*
+ * debug_exception:
+ */
+
+debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf,
+ int len)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level < id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 1;
+ memset(active->data, 0, id->buf_size);
+ memcpy(active->data, buf, MIN(len, id->buf_size));
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_int_exception:
+ */
+
+debug_entry_t *debug_int_exception(debug_info_t * id, int level,
+ unsigned int tag)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level < id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 1;
+ memset(active->data, 0, id->buf_size);
+ memcpy(active->data, &tag,
+ MIN(sizeof(unsigned int), id->buf_size));
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_text_exception:
+ */
+
+debug_entry_t *debug_text_exception(debug_info_t * id, int level,
+ const char *txt)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level < id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ memset(active->data, 0, id->buf_size);
+ strncpy(active->data, txt, MIN(strlen(txt), id->buf_size));
+ ASCEBC(active->data, MIN(strlen(txt), id->buf_size));
+ active->id.fields.exception = 1;
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+
+}
+
+/*
+ * debug_init:
+ * - is called exactly once to initialize the debug feature
+ */
+
+int debug_init(void)
+{
+ int rc = 0;
+ int i;
+
+ down(&debug_lock);
+ if (!initialized) {
+ debug_proc_root_entry =
+ debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT,
+ S_IFDIR | S_IRUGO | S_IXUGO
+ | S_IWUSR | S_IWGRP, NULL,
+ NULL);
+ for (i = 0; i < DEBUG_MAX_AREAS - 1; i++) {
+ *(debug_info_t **) (&debug_areas[i]) =
+ (debug_info_t *) (&debug_areas[i + 1]);
+ }
+ *(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL;
+ free_area = &(debug_areas[0]);
+ printk(KERN_INFO
+ "debug: %d areas reserved for debugging information\n",
+ DEBUG_MAX_AREAS);
+ initialized = 1;
+ }
+ up(&debug_lock);
+
+ return rc;
+}
+
+/*
+ * debug_register_view:
+ */
+
+int debug_register_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ long flags;
+ mode_t mode = S_IFREG;
+
+ if (!id)
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (id->views[i] == NULL)
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS) {
+ printk(KERN_WARNING "debug: cannot register view %s/%s\n",
+ id->name,view->name);
+ printk(KERN_WARNING
+ "debug: maximum number of views reached (%i)!\n", i);
+ rc = -1;
+ }
+ else {
+ id->views[i] = view;
+ if (view->prolog_proc || view->format_proc || view->header_proc)
+ mode |= S_IRUSR;
+ if (view->input_proc)
+ mode |= S_IWUSR;
+ id->proc_entries[i] =
+ debug_create_proc_dir_entry(id->proc_root_entry,
+ view->name, mode,
+ &debug_inode_ops,
+ &debug_file_ops);
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return rc;
+}
+
+/*
+ * debug_unregister_view:
+ */
+
+int debug_unregister_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ long flags;
+
+ if (!id)
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (id->views[i] == view)
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS)
+ rc = -1;
+ else {
+ debug_delete_proc_dir_entry(id->proc_root_entry,
+ id->proc_entries[i]);
+ id->views[i] = NULL;
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return rc;
+}
+
+/*
+ * functions for debug-views
+ ***********************************
+*/
+
+/*
+ * prints out actual debug level
+ */
+
+static int debug_prolog_level_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf)
+{
+ int rc = 0;
+
+ if (out_buf == NULL) {
+ rc = 2;
+ goto out;
+ }
+ rc = sprintf(out_buf, "%i\n", id->level);
+ out:
+ return rc;
+}
+
+/*
+ * reads new debug level
+ */
+
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char *user_buf,
+ size_t in_buf_size, loff_t * offset)
+{
+ char input_buf[1];
+ int rc = in_buf_size;
+
+ if (*offset != 0)
+ goto out;
+ if ((rc = copy_from_user(input_buf, user_buf, 1)))
+ goto out;
+ if (isdigit(input_buf[0])) {
+ int new_level = ((int) input_buf[0] - (int) '0');
+ if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
+ printk(KERN_INFO
+ "debug: level %i is out of range (%i - %i)\n",
+ new_level, 0, DEBUG_MAX_LEVEL);
+ } else {
+ id->level = new_level;
+ printk(KERN_INFO
+ "debug: set new level %i for %s\n",
+ id->level, id->name);
+ }
+ } else {
+ printk(KERN_INFO "debug: level `%c` is not valid\n",
+ input_buf[0]);
+ }
+ out:
+ *offset += in_buf_size;
+ return rc; /* number of input characters */
+}
+
+/*
+ * prints debug data in hex format
+ */
+
+static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int i, rc = 0;
+
+ if (out_buf == NULL || in_buf == NULL) {
+ rc = id->buf_size * 3;
+ goto out;
+ }
+ for (i = 0; i < id->buf_size; i++) {
+ rc += sprintf(out_buf + rc, "%02x ",
+ ((unsigned char *) in_buf)[i]);
+ }
+ out:
+ return rc;
+}
+
+/*
+ * prints debug data in ascii format
+ */
+
+static int debug_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int i, rc = 0;
+
+ if (out_buf == NULL || in_buf == NULL) {
+ rc = id->buf_size;
+ goto out;
+ }
+ for (i = 0; i < id->buf_size; i++) {
+ unsigned char c = in_buf[i];
+ if (!isprint(c))
+ rc += sprintf(out_buf + rc, ".");
+ else
+ rc += sprintf(out_buf + rc, "%c", c);
+ }
+ out:
+ return rc;
+}
+
+/*
+ * prints debug data in ebcdic format
+ */
+
+static int debug_ebcdic_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int i, rc = 0;
+
+ if (out_buf == NULL || in_buf == NULL) {
+ rc = id->buf_size;
+ goto out;
+ }
+ for (i = 0; i < id->buf_size; i++) {
+ unsigned char c = in_buf[i];
+ EBCASC(&c, 1);
+ if (!isprint(c))
+ rc += sprintf(out_buf + rc, ".");
+ else
+ rc += sprintf(out_buf + rc, "%c", c);
+ }
+ out:
+ return rc;
+}
+
+/*
+ * prints header for debug entry
+ */
+
+int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
+{
+ struct timeval time_val;
+ unsigned long long time;
+ char *except_str;
+ unsigned long caller;
+ int rc = 0;
+
+ if (out_buf == NULL) {
+ rc = DEBUG_PROC_HEADER_SIZE;
+ goto out;
+ }
+
+ time = entry->id.stck;
+ /* adjust todclock to 1970 */
+ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
+ tod_to_timeval(time, &time_val);
+
+ if (entry->id.fields.exception)
+ except_str = "*";
+ else
+ except_str = "-";
+ caller = (unsigned long) entry->caller;
+#if defined(CONFIG_ARCH_S390)
+ caller &= 0x7fffffff;
+ rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ",
+ area, time_val.tv_sec,
+ time_val.tv_usec, except_str,
+ entry->id.fields.cpuid, caller);
+#endif
+ out:
+ return rc;
+}
+
+/*
+ * init_module:
+ */
+
+#ifdef MODULE
+int init_module(void)
+{
+ int rc = 0;
+#ifdef DEBUG
+ printk("debug_module_init: \n");
+#endif
+ rc = debug_init();
+ if (rc)
+ printk(KERN_INFO "debug: an error occurred with debug_init\n");
+ return rc;
+}
+
+/*
+ * cleanup_module:
+ */
+
+void cleanup_module(void)
+{
+#ifdef DEBUG
+ printk("debug_cleanup_module: \n");
+#endif
+ debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry);
+ return;
+}
+
+#endif /* MODULE */
/*
* stack layout for the system_call stack entry
- * Martin please don't modify these back to hard coded values
- * You know how bad I'm at mental arithmetic DJB & it gives
+ * Martin please don't modify these back to hard coded values
+ * You know how bad I'm at mental arithmetic DJB & it gives
* me grief when I modify the pt_regs
*/
-SP_PTREGS = STACK_FRAME_OVERHEAD
+SP_PTREGS = STACK_FRAME_OVERHEAD
SP_PSW = SP_PTREGS
SP_R0 = (SP_PSW+PSW_MASK_SIZE+PSW_ADDR_SIZE)
SP_R1 = (SP_R0+GPR_SIZE)
/* fpu registers are saved & restored by the gdb stub itself */
SP_FPC = (SP_CRREGS+(NUM_CRS*CR_SIZE))
SP_FPRS = (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
-/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not
+/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not
defined in ptrace.h but space is needed for this too */
SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE))
#else
SP_PGM_OLD_ILC= (SP_TRAP+4)
#endif
-SP_SVC_STEP = (SP_PGM_OLD_ILC+4)
+SP_SVC_STEP = (SP_PGM_OLD_ILC+4)
SP_SIZE = (SP_SVC_STEP+4)
/*
* these defines are offsets into the thread_struct
stm %r0,%r12,SP_R0(%r15) ; /* store gprs 0-12 to kernel stack */ \
st %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \
mvc SP_RD(12,%r15),__LC_SAVE_AREA ; /* move R13-R15 to stack */ \
- stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \
+ stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */\
mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 ; /* store ac. regs */ \
mvc SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \
la %r0,psworg ; /* store trap indication */ \
#define RESTORE_ALL \
mvc __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
- lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \
+ lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \
ni __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \
lpsw __LC_RETURN_PSW /* back to caller */
-
+
#define GET_CURRENT /* load pointer to task_struct to R9 */ \
lr %r9,%r15 ; \
n %r9,BASED(.Lc0xffffe000)
basr %r1,0 # setup base pointer
resume_base:
l %r4,_TSS_PTREGS(%r3)
- tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
+ tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
bz resume_noper-resume_base(%r1) # if not we're fine
- stctl %r9,%r11,24(%r15) # We are using per stuff
+ stctl %r9,%r11,24(%r15) # We are using per stuff
clc _TSS_PER(12,%r3),24(%r15)
be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's
- lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't
+ lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't
resume_noper:
stm %r6,%r15,24(%r15) # store resume registers of prev task
st %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
#
# call do_signal before return
#
-sysc_signal_return:
+sysc_signal_return:
la %r2,SP_PTREGS(%r15) # load pt_regs
sr %r3,%r3 # clear *oldset
l %r1,BASED(.Ldo_signal)
# call do_bottom_half and return from syscall, if interrupt-level
# is zero
#
-sysc_handle_bottom_half:
+sysc_handle_bottom_half:
l %r1,BASED(.Ldo_bottom_half)
la %r14,BASED(sysc_return_bh)
br %r1 # call do_bottom_half
#
# call schedule with sysc_return as return-address
#
-sysc_reschedule:
+sysc_reschedule:
l %r1,BASED(.Lschedule)
la %r14,BASED(sysc_return)
br %r1 # call scheduler, return to sysc_return
# a new process exits the kernel with ret_from_fork
#
.globl ret_from_fork
-ret_from_fork:
+ret_from_fork:
basr %r13,0
l %r13,.Lentry_base-.(%r13) # setup base pointer to &entry_base
GET_CURRENT # load pointer to task_struct to R9
# but are called with different parameter.
# return-address is set up above
#
-sys_clone_glue:
+sys_clone_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
l %r1,BASED(.Lclone)
br %r1 # branch to sys_clone
-sys_fork_glue:
+sys_fork_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
l %r1,BASED(.Lfork)
br %r1 # branch to sys_fork
-sys_vfork_glue:
+sys_vfork_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
l %r1,BASED(.Lvfork)
br %r1 # branch to sys_vfork
-sys_execve_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
+sys_execve_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
l %r1,BASED(.Lexecve)
lr %r12,%r14 # save return address
basr %r14,%r1 # call sys_execve
b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8
# in system_call/sysc_tracesys
-sys_sigreturn_glue:
+sys_sigreturn_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
l %r1,BASED(.Lsigreturn)
br %r1 # branch to sys_sigreturn
-sys_rt_sigreturn_glue:
+sys_rt_sigreturn_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
l %r1,BASED(.Lrt_sigreturn)
br %r1 # branch to sys_sigreturn
#
# sigsuspend and rt_sigsuspend need pt_regs as an additional
# parameter and they have to skip the store of %r2 into the
-# user register %r2 because the return value was set in
+# user register %r2 because the return value was set in
# sigsuspend and rt_sigsuspend already and must not be overwritten!
#
-sys_sigsuspend_glue:
+sys_sigsuspend_glue:
lr %r5,%r4 # move mask back
lr %r4,%r3 # move history1 parameter
lr %r3,%r2 # move history0 parameter
la %r14,4(%r14) # skip store of return value
br %r1 # branch to sys_sigsuspend
-sys_rt_sigsuspend_glue:
+sys_rt_sigsuspend_glue:
lr %r4,%r3 # move sigsetsize parameter
lr %r3,%r2 # move unewset parameter
la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
la %r14,4(%r14) # skip store of return value
br %r1 # branch to sys_rt_sigsuspend
+sys_sigaltstack_glue:
+ la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
+ l %r1,BASED(.Lsigaltstack)
+ br %r1 # branch to sys_sigreturn
+
+
.globl sys_call_table
sys_call_table:
.long sys_ni_syscall /* 0 */
.long sys_getcwd
.long sys_capget
.long sys_capset /* 185 */
- .long sys_sigaltstack
+ .long sys_sigaltstack_glue
.long sys_sendfile
.long sys_ni_syscall /* streams1 */
.long sys_ni_syscall /* streams2 */
.long sys_vfork_glue /* 190 */
.rept 255-190
- .long sys_ni_syscall
+ .long sys_ni_syscall
.endr
/*
be BASED(pgm_svcper)
# no interesting special case, ignore PER event
lm %r13,%r15,__LC_SAVE_AREA
- lpsw 0x28
+ lpsw 0x28
# it was a single stepped SVC that is causing all the trouble
pgm_svcper:
tm 0x21,0x01 # test problem state bit
la %r0,0x20 # store trap indication
st %r0,SP_TRAP(%r15)
xc 0(4,%r15),0(%r15) # clear back chain
- mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero
+ mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero
mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
b BASED(pgm_system_call) # now do the svc
pgm_svcret:
# call do_bottom_half and return from syscall, if interrupt-level
# is zero
#
-io_handle_bottom_half:
+io_handle_bottom_half:
l %r1,BASED(.Ldo_bottom_half)
la %r14,BASED(io_return_bh)
br %r1 # call do_bottom_half
#
# call schedule with io_return as return-address
#
-io_reschedule:
+io_reschedule:
l %r1,BASED(.Lschedule)
la %r14,BASED(io_return)
br %r1 # call scheduler, return to io_return
#
# call do_signal before return
#
-io_signal_return:
+io_signal_return:
la %r2,SP_PTREGS(%r15) # load pt_regs
sr %r3,%r3 # clear *oldset
l %r1,BASED(.Ldo_signal)
SAVE_ALL(0x18)
la %r2,SP_PTREGS(%r15) # address of register-save area
lh %r3,__LC_EXT_INT_CODE # error code
- lr %r1,%r3 # calculate index
- srl %r1,8 # = (code + (code >> 8)) & 0xff
- alr %r1,%r3
+ lr %r1,%r3 # calculate index = code & 0xff
n %r1,BASED(.Lc0xff)
sll %r1,2
l %r9,BASED(.Lext_hash)
ext_int_found:
l %r9,4(%r9) # get handler address
la %r14,BASED(io_return)
- br %r9 # branch to ext call handler
+ br %r9 # branch to ext call handler
/*
* Machine check handler routines
.Lrt_sigreturn:.long sys_rt_sigreturn
.Lrt_sigsuspend:
.long sys_rt_sigsuspend
+.Lsigaltstack: .long sys_sigaltstack
.Lsigreturn: .long sys_sigreturn
.Lsigsuspend: .long sys_sigsuspend
.Ltrace: .long syscall_trace
lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
# virtual and never return ...
.align 8
-.Lentry:.long 0x04080000,0x80000000 + _stext
+.Lentry:.long 0x00080000,0x80000000 + _stext
.Lctl: .long 0x04b50002 # cr0: various things
- .long .Lpgd+0x7f # cr1: primary space segment table
+ .long 0 # cr1: primary space segment table
.long 0 # cr2: access register translation
.long 0 # cr3: instruction authorization
.long 0 # cr4: instruction authorization
.long 0 # cr5: various things
.long 0 # cr6: I/O interrupts
- .long .Lpgd+0x7f # cr7: secondary space segment table
+ .long 0 # cr7: secondary space segment table
.long 0 # cr8: access registers translation
.long 0 # cr9: tracing off
.long 0 # cr10: tracing off
.long 0 # cr11: tracing off
.long 0 # cr12: tracing off
- .long .Lpgd+0x7f # cr13: home space segment table
+ .long 0 # cr13: home space segment table
.long 0xc0000000 # cr14: machine check handling off
.long 0 # cr15: linkage stack operations
.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem
.align 8
.Ldw: .long 0x000a0000,0x00000000
-#
-# tempory segment-table at 0x11000
-#
- .org 0x11000
-.Lpgd: .long .Lpt0+0x1f # 00000000-000fffff
- .long .Lpt1+0x1f # 00100000-001fffff
- .long .Lpt2+0x1f # 00200000-002fffff
- .long .Lpt3+0x1f # 00300000-003fffff
- .fill 2044,4,0x20 # 00400000-7fffffff
-
-#
-# tempory page-tables at 0x12000-0x15fff
-#
- .macro mktable from,to
- .long \from*0x10000
- .long \from*0x10000+0x1000
- .long \from*0x10000+0x2000
- .long \from*0x10000+0x3000
- .long \from*0x10000+0x4000
- .long \from*0x10000+0x5000
- .long \from*0x10000+0x6000
- .long \from*0x10000+0x7000
- .long \from*0x10000+0x8000
- .long \from*0x10000+0x9000
- .long \from*0x10000+0xa000
- .long \from*0x10000+0xb000
- .long \from*0x10000+0xc000
- .long \from*0x10000+0xd000
- .long \from*0x10000+0xe000
- .long \from*0x10000+0xf000
- .if \to-\from
- mktable "(\from+1)",\to
- .endif
- .endm
-
-.Lpt0: mktable 0,15
-.Lpt1: mktable 16,31
-.Lpt2: mktable 32,47
-.Lpt3: mktable 48,63
#include <asm/delay.h>
#include <asm/lowcore.h>
-unsigned long s390_init_IRQ(unsigned long);
-void s390_free_irq(unsigned int irq, void *dev_id);
-int s390_request_irq( unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags,
- const char *devname,
- void *dev_id);
+unsigned long s390_init_IRQ ( unsigned long);
+void s390_free_irq ( unsigned int irq, void *dev_id);
+int s390_request_irq( unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id);
atomic_t nmi_counter;
action = ioinfo[i]->irq_desc.action;
- if (!action)
+ if (!action)
continue;
p += sprintf(p, "%3d: ",i);
p += sprintf(p, "%10u ", kstat_irqs(i));
#else
for (j=0; j<smp_num_cpus; j++)
- p += sprintf(p, "%10u ",
- kstat.irqs[cpu_logical_map(j)][i]);
+ p += sprintf( p, "%10u ",
+ kstat.irqs[cpu_logical_map(j)][i]);
#endif
p += sprintf(p, " %14s", ioinfo[i]->irq_desc.handler->typename);
p += sprintf(p, " %s", action->name);
__initfunc(unsigned long init_IRQ( unsigned long memory))
{
- return s390_init_IRQ( memory);
+ int result;
+
+ result=s390_init_IRQ(memory);
+ return result;
}
void free_irq(unsigned int irq, void *dev_id)
{
- s390_free_irq( irq, dev_id);
+ s390_free_irq( irq, dev_id);
}
const char *devname,
void *dev_id)
{
- return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
+ return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
}
#include <asm/uaccess.h>
#include <asm/mathemu.h>
+#include <linux/config.h>
-static void display_emulation_not_implemented(char *instr)
-{
- struct pt_regs *regs=current->tss.regs;
- printk("%s not implemented\n",instr);
- printk("Process with %s instruction %s (pid: %d, stackpage=%08X)\n",
- instr,
- current->comm, current->pid, 4096+(addr_t)current);
- printk("%s's PSW: %08lx %08lx\n",instr,
- (unsigned long) regs->psw.mask,
- (unsigned long) regs->psw.addr);
+#ifdef CONFIG_SYSCTL
+int sysctl_ieee_emulation_warnings=1;
+#endif
+
+#define mathemu_put_user(x, ptr) \
+{ \
+ if(put_user((x),(ptr))) \
+ return 1; \
+}
+
+#define mathemu_get_user(x, ptr) \
+{ \
+ if(get_user((x),(ptr))) \
+ return 1; \
+}
+
+
+#define mathemu_copy_from_user(to,from,n) \
+{ \
+ if(copy_from_user((to),(from),(n))==-EFAULT) \
+ return 1; \
+}
+
+
+#define mathemu_copy_to_user(to, from, n) \
+{ \
+ if(copy_to_user((to),(from),(n))==-EFAULT) \
+ return 1; \
}
-static void set_CC_df(__u64 val1,__u64 val2) {
+
+
+static void display_emulation_not_implemented(char *instr)
+{
+ struct pt_regs *regs;
+ __u16 *location;
+
+#if CONFIG_SYSCTL
+ if(sysctl_ieee_emulation_warnings)
+#endif
+ {
+ regs=current->tss.regs;
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n",
+ instr,
+ current->comm, current->pid);
+ printk("%s's PSW: %08lx %08lx\n",instr,
+ (unsigned long) regs->psw.mask,
+ (unsigned long) location);
+ }
+}
+
+static int set_CC_df(__u64 val1,__u64 val2) {
int rc;
rc = __cmpdf2(val1,val2);
current->tss.regs->psw.mask &= 0xFFFFCFFF;
current->tss.regs->psw.mask |= 0x00002000;
break;
}
+ return 0;
}
-static void set_CC_sf(__u32 val1,__u32 val2) {
+static int set_CC_sf(__u32 val1,__u32 val2) {
int rc;
rc = __cmpsf2(val1,val2);
current->tss.regs->psw.mask &= 0xFFFFCFFF;
current->tss.regs->psw.mask |= 0x00002000;
break;
}
+ return 0;
}
-static void emu_adb (int rx, __u64 val) {
+static int emu_adb (int rx, __u64 val) {
current->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d,val);
set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_adbr (int rx, int ry) {
+static int emu_adbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d,
current->tss.fp_regs.fprs[ry].d);
set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_aeb (int rx, __u32 val) {
+static int emu_aeb (int rx, __u32 val) {
current->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f,val);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_aebr (int rx, int ry) {
+static int emu_aebr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f,
current->tss.fp_regs.fprs[ry].f);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_axbr (int rx, int ry) {
+static int emu_axbr (int rx, int ry) {
display_emulation_not_implemented("axbr");
+ return 0;
}
-static void emu_cdb (int rx, __u64 val) {
+static int emu_cdb (int rx, __u64 val) {
set_CC_df(current->tss.fp_regs.fprs[rx].d,val);
+ return 0;
}
-static void emu_cdbr (int rx, int ry) {
+static int emu_cdbr (int rx, int ry) {
set_CC_df(current->tss.fp_regs.fprs[rx].d,current->tss.fp_regs.fprs[ry].d);
+ return 0;
}
-static void emu_cdfbr (int rx, int ry) {
+static int emu_cdfbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].d =
__floatsidf(current->tss.regs->gprs[ry]);
+ return 0;
}
-static void emu_ceb (int rx, __u32 val) {
+static int emu_ceb (int rx, __u32 val) {
set_CC_sf(current->tss.fp_regs.fprs[rx].f,val);
+ return 0;
}
-static void emu_cebr (int rx, int ry) {
+static int emu_cebr (int rx, int ry) {
set_CC_sf(current->tss.fp_regs.fprs[rx].f,current->tss.fp_regs.fprs[ry].f);
+ return 0;
}
-static void emu_cefbr (int rx, int ry) {
+static int emu_cefbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].f =
__floatsisf(current->tss.regs->gprs[ry]);
+ return 0;
}
-static void emu_cfdbr (int rx, int ry, int mask) {
+static int emu_cfdbr (int rx, int ry, int mask) {
current->tss.regs->gprs[rx] =
__fixdfsi(current->tss.fp_regs.fprs[ry].d);
+ return 0;
}
-static void emu_cfebr (int rx, int ry, int mask) {
+static int emu_cfebr (int rx, int ry, int mask) {
current->tss.regs->gprs[rx] =
__fixsfsi(current->tss.fp_regs.fprs[ry].f);
+ return 0;
}
-static void emu_cfxbr (int rx, int ry, int mask) {
+static int emu_cfxbr (int rx, int ry, int mask) {
display_emulation_not_implemented("cfxbr");
+ return 0;
}
-static void emu_cxbr (int rx, int ry) {
+static int emu_cxbr (int rx, int ry) {
display_emulation_not_implemented("cxbr");
+ return 0;
}
-static void emu_cxfbr (int rx, int ry) {
+static int emu_cxfbr (int rx, int ry) {
display_emulation_not_implemented("cxfbr");
+ return 0;
}
-static void emu_ddb (int rx, __u64 val) {
+static int emu_ddb (int rx, __u64 val) {
current->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d,val);
set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_ddbr (int rx, int ry) {
+static int emu_ddbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d,
current->tss.fp_regs.fprs[ry].d);
set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_deb (int rx, __u32 val) {
+static int emu_deb (int rx, __u32 val) {
current->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f,val);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_debr (int rx, int ry) {
+static int emu_debr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f,
current->tss.fp_regs.fprs[ry].f);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_didbr (int rx, int ry, int mask) {
+static int emu_didbr (int rx, int ry, int mask) {
display_emulation_not_implemented("didbr");
+ return 0;
}
-static void emu_diebr (int rx, int ry, int mask) {
+static int emu_diebr (int rx, int ry, int mask) {
display_emulation_not_implemented("diebr");
+ return 0;
}
-static void emu_dxbr (int rx, int ry) {
+static int emu_dxbr (int rx, int ry) {
display_emulation_not_implemented("dxbr");
+ return 0;
}
-static void emu_efpc (int rx, int ry) {
- display_emulation_not_implemented("efpc");
+static int emu_efpc (int rx, int ry) {
+ current->tss.regs->gprs[rx]=current->tss.fp_regs.fpc;
+ return 0;
}
-static void emu_fidbr (int rx, int ry, int mask) {
+static int emu_fidbr (int rx, int ry, int mask) {
display_emulation_not_implemented("fidbr");
+ return 0;
}
-static void emu_fiebr (int rx, int ry, int mask) {
+static int emu_fiebr (int rx, int ry, int mask) {
display_emulation_not_implemented("fiebr");
+ return 0;
}
-static void emu_fixbr (int rx, int ry, int mask) {
+static int emu_fixbr (int rx, int ry, int mask) {
display_emulation_not_implemented("fixbr");
+ return 0;
}
-static void emu_kdb (int rx, __u64 val) {
+static int emu_kdb (int rx, __u64 val) {
display_emulation_not_implemented("kdb");
+ return 0;
}
-static void emu_kdbr (int rx, int ry) {
+static int emu_kdbr (int rx, int ry) {
display_emulation_not_implemented("kdbr");
+ return 0;
}
-static void emu_keb (int rx, __u32 val) {
+static int emu_keb (int rx, __u32 val) {
display_emulation_not_implemented("keb");
+ return 0;
}
-static void emu_kebr (int rx, int ry) {
+static int emu_kebr (int rx, int ry) {
display_emulation_not_implemented("kebr");
+ return 0;
}
-static void emu_kxbr (int rx, int ry) {
+static int emu_kxbr (int rx, int ry) {
display_emulation_not_implemented("kxbr");
+ return 0;
}
-static void emu_lcdbr (int rx, int ry) {
+static int emu_lcdbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].d =
__negdf2(current->tss.fp_regs.fprs[ry].d);
set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_lcebr (int rx, int ry) {
+static int emu_lcebr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].f =
__negsf2(current->tss.fp_regs.fprs[ry].f);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_lcxbr (int rx, int ry) {
+static int emu_lcxbr (int rx, int ry) {
display_emulation_not_implemented("lcxbr");
+ return 0;
}
-static void emu_ldeb (int rx, __u32 val) {
+static int emu_ldeb (int rx, __u32 val) {
current->tss.fp_regs.fprs[rx].d = __extendsfdf2(val);
+ return 0;
}
-static void emu_ldebr (int rx, int ry) {
+static int emu_ldebr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].d =
__extendsfdf2(current->tss.fp_regs.fprs[ry].f);
+ return 0;
}
-static void emu_ldxbr (int rx, int ry) {
+static int emu_ldxbr (int rx, int ry) {
display_emulation_not_implemented("ldxbr");
+ return 0;
}
-static void emu_ledbr (int rx, int ry) {
+static int emu_ledbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].f = __truncdfsf2(current->tss.fp_regs.fprs[ry].d);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_lexbr (int rx, int ry) {
+static int emu_lexbr (int rx, int ry) {
display_emulation_not_implemented("lexbr");
+ return 0;
}
-static void emu_lndbr (int rx, int ry) {
+static int emu_lndbr (int rx, int ry) {
display_emulation_not_implemented("lndbr");
+ return 0;
}
-static void emu_lnebr (int rx, int ry) {
+static int emu_lnebr (int rx, int ry) {
display_emulation_not_implemented("lnebr");
+ return 0;
}
-static void emu_lnxbr (int rx, int ry) {
+static int emu_lnxbr (int rx, int ry) {
display_emulation_not_implemented("lnxbr");
+ return 0;
}
-static void emu_lpdbr (int rx, int ry) {
+static int emu_lpdbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].d = __absdf2(current->tss.fp_regs.fprs[ry].d);
set_CC_df(current->tss.fp_regs.fprs[rx].d,0);
+ return 0;
}
-static void emu_lpebr (int rx, int ry) {
+static int emu_lpebr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].f = __abssf2(current->tss.fp_regs.fprs[ry].f);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_lpxbr (int rx, int ry) {
+static int emu_lpxbr (int rx, int ry) {
display_emulation_not_implemented("lpxbr");
+ return 0;
}
-static void emu_ltdbr (int rx, int ry) {
+static int emu_ltdbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].d = current->tss.fp_regs.fprs[ry].d;
set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_ltebr (int rx, int ry) {
+static int emu_ltebr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].f = current->tss.fp_regs.fprs[ry].f;
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_ltxbr (int rx, int ry) {
+static int emu_ltxbr (int rx, int ry) {
display_emulation_not_implemented("ltxbr");
+ return 0;
}
-static void emu_lxdb (int rx, __u64 val) {
+static int emu_lxdb (int rx, __u64 val) {
display_emulation_not_implemented("lxdb");
+ return 0;
}
-static void emu_lxdbr (int rx, int ry) {
+static int emu_lxdbr (int rx, int ry) {
display_emulation_not_implemented("lxdbr");
+ return 0;
}
-static void emu_lxeb (int rx, __u32 val) {
+static int emu_lxeb (int rx, __u32 val) {
display_emulation_not_implemented("lxeb");
+ return 0;
}
-static void emu_lxebr (int rx, int ry) {
+static int emu_lxebr (int rx, int ry) {
display_emulation_not_implemented("lxebr");
+ return 0;
}
-static void emu_madb (int rx, __u64 val, int mask) {
+static int emu_madb (int rx, __u64 val, int mask) {
display_emulation_not_implemented("madb");
+ return 0;
}
-static void emu_madbr (int rx, int ry, int mask) {
+static int emu_madbr (int rx, int ry, int mask) {
display_emulation_not_implemented("madbr");
+ return 0;
}
-static void emu_maeb (int rx, __u32 val, int mask) {
+static int emu_maeb (int rx, __u32 val, int mask) {
display_emulation_not_implemented("maeb");
+ return 0;
}
-static void emu_maebr (int rx, int ry, int mask) {
+static int emu_maebr (int rx, int ry, int mask) {
display_emulation_not_implemented("maebr");
+ return 0;
}
-static void emu_mdb (int rx, __u64 val) {
+static int emu_mdb (int rx, __u64 val) {
current->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d,val);
set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_mdbr (int rx, int ry) {
+static int emu_mdbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d,
current->tss.fp_regs.fprs[ry].d);
set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_mdeb (int rx, __u32 val) {
+static int emu_mdeb (int rx, __u32 val) {
display_emulation_not_implemented("mdeb");
+ return 0;
}
-static void emu_mdebr (int rx, int ry) {
+static int emu_mdebr (int rx, int ry) {
display_emulation_not_implemented("mdebr");
+ return 0;
}
-static void emu_meeb (int rx, __u32 val) {
+static int emu_meeb (int rx, __u32 val) {
current->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f,
val);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_meebr (int rx, int ry) {
+static int emu_meebr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f,
current->tss.fp_regs.fprs[ry].f);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_msdb (int rx, __u64 val, int mask) {
+static int emu_msdb (int rx, __u64 val, int mask) {
display_emulation_not_implemented("msdb");
+ return 0;
}
-static void emu_msdbr (int rx, int ry, int mask) {
+static int emu_msdbr (int rx, int ry, int mask) {
display_emulation_not_implemented("msdbr");
+ return 0;
}
-static void emu_mseb (int rx, __u32 val, int mask) {
+static int emu_mseb (int rx, __u32 val, int mask) {
display_emulation_not_implemented("mseb");
+ return 0;
}
-static void emu_msebr (int rx, int ry, int mask) {
+static int emu_msebr (int rx, int ry, int mask) {
display_emulation_not_implemented("msebr");
+ return 0;
}
-static void emu_mxbr (int rx, int ry) {
+static int emu_mxbr (int rx, int ry) {
display_emulation_not_implemented("mxbr");
+ return 0;
}
-static void emu_mxdb (int rx, __u64 val) {
+static int emu_mxdb (int rx, __u64 val) {
display_emulation_not_implemented("mxdb");
+ return 0;
}
-static void emu_mxdbr (int rx, int ry) {
+static int emu_mxdbr (int rx, int ry) {
display_emulation_not_implemented("mxdbr");
+ return 0;
}
-static void emu_sdb (int rx, __u64 val) {
+static int emu_sdb (int rx, __u64 val) {
current->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d,
val);
set_CC_sf(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_sdbr (int rx, int ry) {
+static int emu_sdbr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d,
current->tss.fp_regs.fprs[ry].d);
set_CC_sf(current->tss.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_seb (int rx, __u32 val) {
+static int emu_seb (int rx, __u32 val) {
current->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f,
val);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_sebr (int rx, int ry) {
+static int emu_sebr (int rx, int ry) {
current->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f,
current->tss.fp_regs.fprs[ry].f);
set_CC_sf(current->tss.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_sfpc (int rx, int ry) {
- display_emulation_not_implemented("sfpc");
+static int emu_sfpc (int rx, int ry) {
+ __u32 val=current->tss.regs->gprs[rx];
+ if(val==0)
+ current->tss.fp_regs.fpc=val;
+ else
+ display_emulation_not_implemented("sfpc");
+ return 0;
}
-static void emu_sqdb (int rx, __u64 val) {
+static int emu_sqdb (int rx, __u64 val) {
display_emulation_not_implemented("sqdb");
+ return 0;
}
-static void emu_sqdbr (int rx, int ry) {
+static int emu_sqdbr (int rx, int ry) {
display_emulation_not_implemented("sqdbr");
+ return 0;
}
-static void emu_sqeb (int rx, __u32 val) {
+static int emu_sqeb (int rx, __u32 val) {
display_emulation_not_implemented("sqeb");
+ return 0;
}
-static void emu_sqebr (int rx, int ry) {
+static int emu_sqebr (int rx, int ry) {
display_emulation_not_implemented("sqebr");
+ return 0;
}
-static void emu_sqxbr (int rx, int ry) {
+static int emu_sqxbr (int rx, int ry) {
display_emulation_not_implemented("sqxbr");
+ return 0;
}
-static void emu_sxbr (int rx, int ry) {
+static int emu_sxbr (int rx, int ry) {
display_emulation_not_implemented("sxbr");
+ return 0;
}
-static void emu_tcdb (int rx, __u64 val) {
+static int emu_tcdb (int rx, __u64 val) {
display_emulation_not_implemented("tcdb");
+ return 0;
}
-static void emu_tceb (int rx, __u32 val) {
+static int emu_tceb (int rx, __u32 val) {
display_emulation_not_implemented("tceb");
+ return 0;
}
-static void emu_tcxb (int rx, __u64 val) {
+static int emu_tcxb (int rx, __u64 val) {
display_emulation_not_implemented("tcxb");
+ return 0;
}
}
int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
+ int rc=0;
static const __u8 format_table[] = {
2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4,
1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3,
emu_store_regd((opcode[3]>>4)&15);
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_regd((opcode[3]>>4)&15);
- emu_load_regd(opcode[3]&15);
- return 0;
+ emu_load_regd((opcode[3]>>4)&15);
+ emu_load_regd(opcode[3]&15);
+ return rc;
case 2: /* RRE format, float operation */
emu_store_rege((opcode[3]>>4)&15);
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_rege((opcode[3]>>4)&15);
- emu_load_rege(opcode[3]&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ emu_load_rege(opcode[3]&15);
+ return rc;
case 3: /* RRF format, double operation */
emu_store_regd((opcode[3]>>4)&15);
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- emu_load_regd((opcode[3]>>4)&15);
- emu_load_regd(opcode[3]&15);
- return 0;
+ emu_load_regd((opcode[3]>>4)&15);
+ emu_load_regd(opcode[3]&15);
+ return rc;
case 4: /* RRF format, float operation */
emu_store_rege((opcode[3]>>4)&15);
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- emu_load_rege((opcode[3]>>4)&15);
- emu_load_rege(opcode[3]&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ emu_load_rege(opcode[3]&15);
+ return rc;
case 5: /* RRE format, cefbr instruction */
emu_store_rege((opcode[3]>>4)&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_rege((opcode[3]>>4)&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ return rc;
case 6: /* RRE format, cdfbr & cxfbr instruction */
emu_store_regd((opcode[3]>>4)&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_regd((opcode[3]>>4)&15);
- return 0;
- /* FIXME !! */
- return 0;
- case 7: /* RRF format, cfebr instruction */
+ emu_load_regd((opcode[3]>>4)&15);
+ return rc;
+ case 7: /* RRF format, cfebr instruction */
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- return 0;
+ return rc;
case 8: /* RRF format, cfdbr & cfxbr instruction */
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- return 0;
+ return rc;
case 9: /* RRE format, ldebr & mdebr instruction */
/* float store but double load */
emu_store_rege((opcode[3]>>4)&15);
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_regd((opcode[3]>>4)&15);
- return 0;
+ emu_load_regd((opcode[3]>>4)&15);
+ return rc;
case 10: /* RRE format, ledbr instruction */
/* double store but float load */
emu_store_regd((opcode[3]>>4)&15);
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_rege((opcode[3]>>4)&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ return rc;
default:
return 1;
}
}
int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
+ int rc=0;
+
static const __u8 format_table[] = {
0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4,
2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3,
emu_store_regd((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_from_user fails ? */
- copy_from_user(&temp, dxb, 8);
+ mathemu_copy_from_user(&temp, dxb, 8);
/* call the emulation function */
- ((void (*)(int, __u64))jump_table[opcode[5]])
+ rc=((int (*)(int, __u64))jump_table[opcode[5]])
(opcode[1]>>4,temp);
- emu_load_regd((opcode[1]>>4)&15);
- return 0;
+ emu_load_regd((opcode[1]>>4)&15);
+ return rc;
}
case 2: /* RXE format, __u32 constant */ {
__u32 *dxb, temp;
emu_store_rege((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
- get_user(temp, dxb);
+ mathemu_get_user(temp, dxb);
/* call the emulation function */
- ((void (*)(int, __u32))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32))jump_table[opcode[5]])
(opcode[1]>>4,temp);
- emu_load_rege((opcode[1]>>4)&15);
- return 0;
+ emu_load_rege((opcode[1]>>4)&15);
+ return rc;
}
case 3: /* RXF format, __u64 constant */ {
__u32 *dxb, temp;
emu_store_regd((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_from_user fails ? */
- copy_from_user(&temp, dxb, 8);
+ mathemu_copy_from_user(&temp, dxb, 8);
/* call the emulation function */
- ((void (*)(int, __u32, int))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
(opcode[1]>>4,temp,opcode[4]>>4);
- emu_load_regd((opcode[1]>>4)&15);
- return 0;
+ emu_load_regd((opcode[1]>>4)&15);
+ return rc;
}
case 4: /* RXF format, __u32 constant */ {
__u32 *dxb, temp;
emu_store_rege((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
- get_user(temp, dxb);
+ mathemu_get_user(temp, dxb);
/* call the emulation function */
- ((void (*)(int, __u32, int))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
(opcode[1]>>4,temp,opcode[4]>>4);
emu_load_rege((opcode[1]>>4)&15);
- return 0;
+ return rc;
}
case 5: /* RXE format, __u32 constant */
/* store_rege and load_regd */
- {
+ {
__u32 *dxb, temp;
__u32 opc;
emu_store_rege((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
- get_user(temp, dxb);
+ mathemu_get_user(temp, dxb);
/* call the emulation function */
- ((void (*)(int, __u32))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32))jump_table[opcode[5]])
(opcode[1]>>4,temp);
emu_load_regd((opcode[1]>>4)&15);
- return 0;
+ return rc;
}
default:
return 1;
/*
* Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
*/
-void math_emu_ldr(__u8 *opcode) {
+int math_emu_ldr(__u8 *opcode) {
__u16 opc = *((__u16 *) opcode);
if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */
current->tss.fp_regs.fprs[(opc&0x00f0)>>4] =
current->tss.fp_regs.fprs[opc&0x000f];
}
+ return 0;
}
/*
* Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
*/
-void math_emu_ler(__u8 *opcode) {
+int math_emu_ler(__u8 *opcode) {
__u16 opc = *((__u16 *) opcode);
if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */
current->tss.fp_regs.fprs[(opc&0x00f0)>>4] =
current->tss.fp_regs.fprs[opc&0x000f];
}
+ return 0;
}
/*
* Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u64 *dxb;
dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_from_user fails ? */
- copy_from_user(¤t->tss.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+ mathemu_copy_from_user(¤t->tss.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+ return 0;
}
/*
* Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_le(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_le(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u32 *mem, *dxb;
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
mem = (__u32 *) (¤t->tss.fp_regs.fprs[(opc>>20)&15].f);
- get_user(mem[0], dxb);
+ mathemu_get_user(mem[0], dxb);
+ return 0;
}
/*
* Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_std(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_std(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u64 *dxb;
dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_to_user fails ? */
- copy_to_user(dxb, ¤t->tss.fp_regs.fprs[(opc>>20)&15].d, 8);
+ mathemu_copy_to_user(dxb, ¤t->tss.fp_regs.fprs[(opc>>20)&15].d, 8);
+ return 0;
}
/*
* Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u32 *mem, *dxb;
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if put_user fails ? */
+ /* FIXME: how to react if mathemu_put_user fails ? */
mem = (__u32 *) (¤t->tss.fp_regs.fprs[(opc>>20)&15].f);
- put_user(mem[0], dxb);
+ mathemu_put_user(mem[0], dxb);
+ return 0;
}
/*
* Emulate LFPC D(B)
*/
int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
- /* FIXME: how to do that ?!? */
+ __u32 *dxb,temp;
+ __u32 opc = *((__u32 *) opcode);
+ dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
+ mathemu_get_user(temp, dxb);
+ if(temp!=0)
+ display_emulation_not_implemented("lfpc");
return 0;
}
* Emulate STFPC D(B)
*/
int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
- /* FIXME: how to do that ?!? */
+ __u32 *dxb;
+ __u32 opc = *((__u32 *) opcode);
+ dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
+ mathemu_put_user(current->tss.fp_regs.fpc, dxb);
return 0;
}
*/
int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
/* FIXME: how to do that ?!? */
+ display_emulation_not_implemented("srnm");
return 0;
}
if (bh_mask & bh_active) {
#endif
do_bottom_half();
- continue;
+ __sti();
+ if (!current->need_resched)
+ continue;
}
if (current->need_resched) {
schedule();
0 returned you know you've got all the lines
*/
-int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_struct *tss,struct pt_regs * regs)
-{
+static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs)
+{
int linelen=0;
int regno,chaincnt;
u32 backchain,prev_backchain,endchain;
+ u32 ksp = 0;
+ char *mode = "???";
enum
{
sp_kern_backchain1
};
- if(task)
- tss=&task->tss;
- if(tss)
- regs=tss->regs;
+ if (task)
+ ksp = task->tss.ksp;
+ if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE))
+ ksp = regs->gprs[15];
+
+ if (regs)
+ mode = (regs->psw.mask & PSW_PROBLEM_STATE)?
+ "User" : "Kernel";
+
switch(line)
{
- case sp_linefeed: linelen=sprintf(buff,"\n");
+ case sp_linefeed:
+ linelen=sprintf(buff,"\n");
break;
case sp_psw:
if(regs)
- linelen=sprintf(buff,"User PSW: %08lx %08lx\n",
+ linelen=sprintf(buff, "%s PSW: %08lx %08lx\n", mode,
(unsigned long) regs->psw.mask,
(unsigned long) regs->psw.addr);
else
linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
break;
case sp_ksp:
- if(task)
- linelen+=sprintf(&buff[linelen],"task: %08x ",(addr_t)task);
- if(tss)
- linelen+=sprintf(&buff[linelen],"tss: %08x ksp: %08x ",
- (addr_t)tss,(addr_t)tss->ksp);
- if(regs)
- linelen+=sprintf(&buff[linelen],"pt_regs: %08x\n",(addr_t)regs);
+ linelen=sprintf(&buff[linelen],
+ "task: %08x ksp: %08x pt_regs: %08x\n",
+ (addr_t)task, (addr_t)ksp, (addr_t)regs);
break;
case sp_gprs:
if(regs)
- linelen=sprintf(buff,"User GPRS:\n");
+ linelen=sprintf(buff, "%s GPRS:\n", mode);
break;
case sp_gprs1 ... sp_gprs4:
if(regs)
break;
case sp_acrs:
if(regs)
- linelen=sprintf(buff,"User ACRS:\n");
+ linelen=sprintf(buff, "%s ACRS:\n", mode);
break;
case sp_acrs1 ... sp_acrs4:
if(regs)
}
break;
case sp_kern_backchain:
- if(tss&&tss->ksp&®s)
- linelen=sprintf(buff,"Kernel BackChain CallChain BackChain CallChain\n");
+ if (ksp)
+ linelen=sprintf(buff, "Kernel BackChain CallChain\n");
break;
default:
- if(tss&&tss->ksp&®s)
+ if (ksp)
{
- backchain=(tss->ksp&PSW_ADDR_MASK);
+ backchain=ksp&PSW_ADDR_MASK;
endchain=((backchain&(-8192))+8192);
prev_backchain=backchain-1;
line-=sp_kern_backchain1;
if((backchain==0)||(backchain>=endchain)
||(chaincnt>=8)||(prev_backchain>=backchain))
break;
- if((chaincnt>>1)==line)
+ if(chaincnt==line)
{
- linelen+=sprintf(&buff[linelen],"%s%08x %08x ",
- (chaincnt&1) ? "":" ",
- backchain,*(u32 *)(backchain+56));
- }
- if((chaincnt>>1)>line)
+ linelen+=sprintf(&buff[linelen]," %08x [<%08x>]\n",
+ backchain,
+ *(u32 *)(backchain+56)&PSW_ADDR_MASK);
break;
+ }
prev_backchain=backchain;
backchain=(*((u32 *)backchain))&PSW_ADDR_MASK;
}
- if(linelen)
- linelen+=sprintf(&buff[linelen],"\n");
}
}
return(linelen);
}
-void show_regs(struct task_struct * task,struct thread_struct *tss,struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
{
char buff[80];
int line;
+
+ printk("CPU: %d\n",smp_processor_id());
+ printk("Process %s (pid: %d, stackpage=%08X)\n",
+ current->comm, current->pid, 4096+(addr_t)current);
- for(line=0;sprintf_regs(line,buff,task,tss,regs);line++)
+ for (line = 0; sprintf_regs(line, buff, current, regs); line++)
printk(buff);
}
+char *task_show_regs(struct task_struct *task, char *buffer)
+{
+ int line, len;
+
+ for (line = 0; ; line++)
+ {
+ len = sprintf_regs(line, buffer, task, task->tss.regs);
+ if (!len) break;
+ buffer += len;
+ }
+ return buffer;
+}
+
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
int clone_arg = flags | CLONE_VM;
struct task_struct * p, struct pt_regs * regs)
{
struct stack_frame
- {
- unsigned long back_chain;
- unsigned long eos;
- unsigned long glue1;
- unsigned long glue2;
- unsigned long scratch[2];
- unsigned long gprs[10]; /* gprs 6 -15 */
- unsigned long fprs[4]; /* fpr 4 and 6 */
- unsigned long empty[4];
+ {
+ unsigned long back_chain;
+ unsigned long eos;
+ unsigned long glue1;
+ unsigned long glue2;
+ unsigned long scratch[2];
+ unsigned long gprs[10]; /* gprs 6 -15 */
+ unsigned long fprs[4]; /* fpr 4 and 6 */
+ unsigned long empty[4];
#if CONFIG_REMOTE_DEBUG
gdb_pt_regs childregs;
#else
lock_kernel();
clone_flags = regs.gprs[3];
- newsp = regs.gprs[2];
+ newsp = regs.orig_gpr2;
if (!newsp)
newsp = regs.gprs[15];
ret = do_fork(clone_flags, newsp, ®s);
goto out;
error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], ®s);
if (error == 0)
+ {
current->flags &= ~PF_DTRACE;
+ current->tss.fp_regs.fpc=0;
+ if(MACHINE_HAS_IEEE)
+ {
+ __asm__ __volatile__
+ ("sr 0,0\n\t"
+ "sfpc 0,0\n\t"
+ :
+ :
+ :"0");
+ }
+ }
putname(filename);
out:
unlock_kernel();
struct vm_area_struct * vma;
addr=ADDR_BITS_REMOVE(addr);
vma= find_extend_vma(tsk, addr);
-
+
if (!vma)
return -EIO;
if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
/* ieee_instruction_pointer from the user structure DJB */
if(child!=current)
{
- if (!(child->flags & PF_PTRACED))
- goto out;
- if (child->state != TASK_STOPPED)
- {
- if (request != PTRACE_KILL)
+ if (!(child->flags & PF_PTRACED))
+ goto out;
+ if (child->state != TASK_STOPPED)
+ {
+ if (request != PTRACE_KILL)
+ goto out;
+ }
+ if (child->p_pptr != current)
goto out;
- }
- if (child->p_pptr != current)
- goto out;
}
switch (request)
{
#include <asm/s390_ext.h>
/*
- * Simple hash strategy: index = ((code >> 8) + code) & 0xff;
+ * Simple hash strategy: index = code & 0xff;
* ext_int_hash[index] is the start of the list for all external interrupts
* that hash to this index. With the current set of external interrupts
* (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
ext_int_info_t *p;
int index;
- index = (code + (code >> 8)) & 0xff;
+ index = code & 0xff;
p = ext_int_hash[index];
while (p != NULL) {
if (p->code == code)
ext_int_info_t *p, *q;
int index;
- index = (code + (code >> 8)) & 0xff;
+ index = code & 0xff;
q = NULL;
p = ext_int_hash[index];
while (p != NULL) {
*/
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/interrupt.h>
#include <asm/debug.h>
#include <linux/genhd.h>
#include <asm/ccwcache.h>
#include <asm/irq.h>
#include <asm/string.h>
-#include <asm/checksum.h>\r
+#include <asm/checksum.h>
#include <asm/s390_ext.h>
#include <asm/s390dyn.h>
#include <asm/ebcdic.h>
#include <asm/timex.h>
#include <asm/delay.h>
-#if CONFIG_CHANDEV
-#include <asm/chandev.h>
-#endif
#if CONFIG_IP_MULTICAST
#include <net/arp.h>
#endif
* I/O subsystem
*/
EXPORT_SYMBOL(halt_IO);
+EXPORT_SYMBOL(clear_IO);
EXPORT_SYMBOL(do_IO);
EXPORT_SYMBOL(resume_IO);
EXPORT_SYMBOL(ioinfo);
EXPORT_SYMBOL(s390_device_register);
EXPORT_SYMBOL(s390_device_unregister);
+EXPORT_SYMBOL(s390_bh_lock);
+
EXPORT_SYMBOL(ccw_alloc_request);
EXPORT_SYMBOL(ccw_free_request);
EXPORT_SYMBOL(register_external_interrupt);
EXPORT_SYMBOL(unregister_external_interrupt);
-/*
+/*
* debug feature
*/
EXPORT_SYMBOL(debug_register);
EXPORT_SYMBOL(debug_unregister);
+EXPORT_SYMBOL(debug_register_view);
+EXPORT_SYMBOL(debug_unregister_view);
EXPORT_SYMBOL(debug_event);
+EXPORT_SYMBOL(debug_int_event);
EXPORT_SYMBOL(debug_text_event);
EXPORT_SYMBOL(debug_exception);
+EXPORT_SYMBOL(debug_int_exception);
EXPORT_SYMBOL(debug_text_exception);
+EXPORT_SYMBOL(debug_hex_view);
+EXPORT_SYMBOL(debug_ascii_view);
+EXPORT_SYMBOL(debug_ebcdic_view);
+EXPORT_SYMBOL(debug_dflt_header_fn);
/*
* memory management
EXPORT_SYMBOL_NOVERS(strrchr);
EXPORT_SYMBOL_NOVERS(strtok);
EXPORT_SYMBOL_NOVERS(strpbrk);
+EXPORT_SYMBOL_NOVERS(strstr);
EXPORT_SYMBOL_NOVERS(_ascebc_500);
EXPORT_SYMBOL_NOVERS(_ebcasc_500);
/*
* misc.
*/
+EXPORT_SYMBOL(__copy_from_user_fixup);
+EXPORT_SYMBOL(__copy_to_user_fixup);
EXPORT_SYMBOL(__udelay);
#ifdef CONFIG_SMP
#include <asm/smplock.h>
EXPORT_SYMBOL(kernel_flag);
EXPORT_SYMBOL(smp_ctl_set_bit);
EXPORT_SYMBOL(smp_ctl_clear_bit);
+EXPORT_SYMBOL(smp_do_callback_all);
#endif
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(csum_fold);
EXPORT_SYMBOL(genhd_dasd_name);
-#if CONFIG_IP_MULTICAST
+#ifdef CONFIG_IP_MULTICAST
/* Required for lcs gigibit ethernet multicast support */
EXPORT_SYMBOL(arp_mc_map);
#endif
* S/390 dynamic device attachment
*
* S390 version
- * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
*/
{
int has_ieee=MACHINE_HAS_IEEE;
+ /* If we don't mask with the FPC_VALID_MASK here
+ * we've got a very quick shutdown -h now command
+ * via a kernel specification exception.
+ */
+ fpregs->fpc&=FPC_VALID_MASK;
asm volatile ("LD 0,8(%0)\n\t"
"LD 2,24(%0)\n\t"
"LD 4,40(%0)\n\t"
#include <asm/s390dyn.h>
#include <asm/s390mach.h>
-#undef CONFIG_DEBUG_IO
+#undef CONFIG_DEBUG_IO
#define CONFIG_DEBUG_CRW
#define REIPL_DEVID_MAGIC 0x87654321
struct s390_irqaction init_IRQ_action;
-unsigned int highest_subchannel;
-ioinfo_t *ioinfo_head = NULL;
-ioinfo_t *ioinfo_tail = NULL;
-ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = {
+unsigned int highest_subchannel;
+ioinfo_t *ioinfo_head = NULL;
+ioinfo_t *ioinfo_tail = NULL;
+ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = {
[0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA
};
int s390_DevicePathVerification( int irq, __u8 domask );
-extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs);
-extern int enable_none(unsigned int irq);
-extern int disable_none(unsigned int irq);
+extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs);
+extern int enable_none(unsigned int irq);
+extern int disable_none(unsigned int irq);
extern void tod_wait(unsigned long usecs);
asmlinkage void do_IRQ( struct pt_regs regs,
int s390_request_irq_special( int irq,
io_handler_func_t io_handler,
not_oper_handler_func_t not_oper_handler,
- unsigned long irqflags,
- const char *devname,
- void *dev_id)
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id)
{
int retval;
struct s390_irqaction *action;
if ( !io_handler || !dev_id )
return -EINVAL;
- /*
- * during init_IRQ() processing we don't have memory
- * management yet, thus need to use a statically
- * allocated irqaction control block
- */
- if ( init_IRQ_complete )
- {
+ /*
+ * during init_IRQ() processing we don't have memory
+ * management yet, thus need to use a statically
+ * allocated irqaction control block
+ */
+ if ( init_IRQ_complete )
+ {
action = (struct s390_irqaction *)
kmalloc( sizeof(struct s390_irqaction),
GFP_KERNEL);
- }
- else
- {
- action = &init_IRQ_action;
+ }
+ else
+ {
+ action = &init_IRQ_action;
- } /* endif */
+ } /* endif */
if (!action)
- {
+ {
return -ENOMEM;
- } /* endif */
+ } /* endif */
action->handler = io_handler;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;
- retval = s390_setup_irq(irq, action);
+ retval = s390_setup_irq( irq, action);
if ( init_IRQ_complete )
{
s390_DevicePathVerification( irq, 0 );
}
else
- {
- kfree(action);
+ {
+ kfree(action);
- } /* endif */
+ } /* endif */
} /* endif */
} /* endif */
- s390irq_spin_lock_irqsave(irq,flags);
+ s390irq_spin_lock_irqsave( irq, flags);
#ifdef CONFIG_KERNEL_DEBUG
if ( irq != cons_dev )
ioinfo[irq]->ui.flags.unready = 1;
do
- {
+ {
ret = disable_subchannel( irq);
count++;
disable_subchannel( irq);
if ( ioinfo[irq]->ui.flags.busy )
- {
- printk( KERN_CRIT"free_irq(%04X) "
- "- device %04X busy, retry "
- "count exceeded\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- } /* endif */
-
+ {
+ printk( KERN_CRIT"free_irq(%04X) "
+ "- device %04X busy, retry "
+ "count exceeded\n",
+ irq,
+ ioinfo[irq]->devstat.devno);
+
+ } /* endif */
+
break; /* sigh, let's give up ... */
} /* endif */
if ( init_IRQ_complete )
kfree( ioinfo[irq]->irq_desc.action );
- ioinfo[irq]->irq_desc.action = NULL;
- ioinfo[irq]->ui.flags.ready = 0;
+ ioinfo[irq]->irq_desc.action = NULL;
+ ioinfo[irq]->ui.flags.ready = 0;
ioinfo[irq]->irq_desc.handler->enable = enable_none;
ioinfo[irq]->irq_desc.handler->disable = disable_none;
- ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
+ ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
ioinfo[irq]->nopfunc = NULL;
*/
static int enable_subchannel( unsigned int irq)
{
- int ret;
- int ccode;
- int retry = 5;
+ int ret;
+ int ccode;
+ int retry = 5;
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
+ if ( irq > highest_subchannel || irq < 0 )
+ {
+ return( -ENODEV );
- } /* endif */
+ } /* endif */
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
return( -ENODEV);
if ( ioinfo[irq]->ui.flags.d_disable )
{
ioinfo[irq]->ui.flags.d_disable = 0;
- ret = 0;
+ ret = 0;
}
else
{
ccode = stsch(irq, &(ioinfo[irq]->schib) );
- if ( ccode )
- {
- ret = -ENODEV;
- }
- else
- {
+ if ( ccode )
+ {
+ ret = -ENODEV;
+ }
+ else
+ {
ioinfo[irq]->schib.pmcw.ena = 1;
if ( irq == cons_dev )
}
else
{
- ioinfo[irq]->schib.pmcw.isc = 3;
+ ioinfo[irq]->schib.pmcw.isc = 3;
} /* endif */
- do
- {
+ do
+ {
ccode = msch( irq, &(ioinfo[irq]->schib) );
- switch (ccode) {
- case 0:
- ret = 0;
- break;
+ switch (ccode) {
+ case 0:
+ ret = 0;
+ break;
- case 1:
- /*
+ case 1:
+ /*
* very bad, requires interrupt alike
* processing, where "rbh" is a dummy
* parameter for interface compatibility
* only. Bottom-half handling cannot be
* required as this must be an
* unsolicited interrupt (!busy).
- */
+ */
ioinfo[irq]->ui.flags.s_pend = 1;
s390_process_IRQ( irq );
ret = -EIO; /* might be overwritten */
/* ... on re-driving */
/* ... the msch() */
- retry--;
- break;
+ retry--;
+ break;
case 2:
tod_wait(100); /* allow for recovery */
retry--;
break;
- case 3:
+ case 3:
ioinfo[irq]->ui.flags.oper = 0;
- ret = -ENODEV;
- break;
+ ret = -ENODEV;
+ break;
- default:
+ default:
printk( KERN_CRIT"enable_subchannel(%04X) "
" : ccode 2 on msch() for device "
"%04X received !\n",
irq,
ioinfo[irq]->devstat.devno);
- ret = -ENODEV; // never reached
- }
+ ret = -ENODEV; // never reached
+ }
- } while ( (ccode == 1) && retry );
+ } while ( (ccode == 1) && retry );
- } /* endif */
+ } /* endif */
} /* endif */
*/
static int disable_subchannel( unsigned int irq)
{
- int cc; /* condition code */
- int ret; /* function return value */
- int retry = 5;
+ int cc; /* condition code */
+ int ret; /* function return value */
+ int retry = 5;
if ( irq > highest_subchannel )
{
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
return( -ENODEV);
- }
+ }
else if ( ioinfo[irq]->ui.flags.busy )
{
/*
{
ioinfo[irq]->schib.pmcw.ena = 0;
- do
- {
+ do
+ {
cc = msch( irq, &(ioinfo[irq]->schib) );
- switch (cc) {
- case 0 :
- ret = 0; /* done */
- break;
+ switch (cc) {
+ case 0 :
+ ret = 0; /* done */
+ break;
- case 1 :
- /*
+ case 1 :
+ /*
* very bad, requires interrupt alike
* processing, where "rbh" is a dummy
* parm for interface compatibility
ioinfo[irq]->ui.flags.s_pend = 0;
ret = -EIO; /* might be overwritten */
- /* ... on re-driving the */
- /* ... msch() call */
- retry--;
- break;
-
- case 2 :
- /*
- * *** must not occur ! ***
- * *** ***
+ /* ... on re-driving the */
+ /* ... msch() call */
+ retry--;
+ break;
+
+ case 2 :
+ /*
+ * *** must not occur ! ***
+ * *** ***
* *** indicates our internal ***
* *** interrupt accounting is out ***
- * *** of sync ===> panic() ***
- */
+ * *** of sync ===> panic() ***
+ */
printk( KERN_CRIT"disable_subchannel(%04X) "
"- unexpected busy condition for "
"device %04X received !\n",
irq,
ioinfo[irq]->devstat.devno);
ret = -EBUSY;
- break;
+ break;
- case 3 :
- /*
+ case 3 :
+ /*
* should hardly occur ?!
- */
+ */
ioinfo[irq]->ui.flags.oper = 0;
ioinfo[irq]->ui.flags.d_disable = 1;
ret = 0; /* if the device has gone we */
/* ... don't need to disable */
/* ... it anymore ! */
- break;
+ break;
- default :
- ret = -ENODEV; // never reached ...
- break;
+ default :
+ ret = -ENODEV; // never reached ...
+ break;
- } /* endswitch */
+ } /* endswitch */
- } while ( (cc == 1) && retry );
+ } while ( (cc == 1) && retry );
} /* endif */
* As we don't know about the calling environment
* we assure running disabled. Before leaving the
* function we resestablish the old environment.
- *
- * Note : as we don't need a system wide lock, therefore
- * we shouldn't use cli(), but __cli() as this
- * affects the current CPU only.
+ *
+ * Note : as we don't need a system wide lock, therefore
+ * we shouldn't use cli(), but __cli() as this
+ * affects the current CPU only.
*/
__save_flags(flags);
__cli();
cr6 = 0;
asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
- s390_process_subchannels();
+ s390_process_subchannels();
/*
* enable default I/O-interrupt sublass 3
s390_device_recognition_all();
- init_IRQ_complete = 1;
+ init_IRQ_complete = 1;
__restore_flags(flags);
ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE);
ioinfo[irq]->orb.ssic = ( (flag & DOIO_ALLOW_SUSPEND )
- && (flag & DOIO_SUPPRESS_INTER) );
+ && (flag & DOIO_SUPPRESS_INTER) );
if ( flag & DOIO_VALID_LPM )
{
} /* endif */
- ioinfo[irq]->orb.cpa = (ccw1_t *)virt_to_phys( cpa);
+ ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);
/*
* If sync processing was requested we lock the sync ISC, modify the
case 0:
if ( !ioinfo[irq]->ui.flags.w4sense )
- {
+ {
/*
* init the device driver specific devstat irb area
*
} /* endif */
ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;
-
+
/*
* If synchronous I/O processing is requested, we have
* to wait for the corresponding interrupt to occur by
*/
if ( flag & DOIO_WAIT_FOR_INTERRUPT )
{
- int io_sub = -1;
- psw_t io_new_psw;
- int ccode;
+ psw_t io_new_psw;
+ int ccode;
uint64_t time_start;
uint64_t time_curr;
- int ready = 0;
- struct _lowcore *lc = NULL;
+ int ready = 0;
+ int io_sub = -1;
+ struct _lowcore *lc = NULL;
int do_retry = 1;
- /*
+ /*
* We shouldn't perform a TPI loop, waiting for an
* interrupt to occur, but should load a WAIT PSW
* instead. Otherwise we may keep the channel subsystem
* busy, not able to present the interrupt. When our
* sync. interrupt arrived we reset the I/O old PSW to
* its original value.
- */
- memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
+ */
+ memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
ccode = iac();
switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "start_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
+ case 0: // primary-space
+ io_sync_wait.mask = _IO_PSW_MASK
+ | _PSW_PRIM_SPACE_MODE
+ | _PSW_IO_WAIT;
+ break;
+ case 1: // secondary-space
+ io_sync_wait.mask = _IO_PSW_MASK
+ | _PSW_SEC_SPACE_MODE
+ | _PSW_IO_WAIT;
+ break;
+ case 2: // access-register
+ io_sync_wait.mask = _IO_PSW_MASK
+ | _PSW_ACC_REG_MODE
+ | _PSW_IO_WAIT;
+ break;
+ case 3: // home-space
+ io_sync_wait.mask = _IO_PSW_MASK
+ | _PSW_HOME_SPACE_MODE
+ | _PSW_IO_WAIT;
+ break;
+ default:
+ panic( "start_IO() : unexpected "
+ "address-space-control %d\n",
+ ccode);
+ break;
} /* endswitch */
io_sync_wait.addr = FIX_PSW(&&io_wakeup);
{
tpi_info_t tpi_info;
- do
- {
+ do
+ {
if ( tpi(&tpi_info) == 1 )
{
io_sub = tpi_info.irq;
do_retry = 0;
} /* endif */
-
+
} while ( do_retry );
}
else
{
- asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
+ asm volatile ("lpsw %0" : : "m" (io_sync_wait));
io_wakeup:
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
+ io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
} /* endif */
if ( do_retry )
- ready = s390_process_IRQ( io_sub );
+ ready = s390_process_IRQ( io_sub );
/*
* surrender when retry count's exceeded ...
memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
'\0', sizeof( irb_t) );
- /*
- * Let the common interrupt handler process the pending status.
- * However, we must avoid calling the user action handler, as
+ /*
+ * Let the common interrupt handler process the pending status.
+ * However, we must avoid calling the user action handler, as
* it won't be prepared to handle a pending status during
* do_IO() processing inline. This also implies that process_IRQ
* must terminate synchronously - especially if device sensing
if ( ioinfo[irq]->opm == 0 )
{
- ret = -ENODEV;
- ioinfo[irq]->ui.flags.oper = 0;
+ ret = -ENODEV;
+ ioinfo[irq]->ui.flags.oper = 0;
}
else
{
ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
#ifdef CONFIG_DEBUG_IO
- {
- char buffer[80];
+ {
+ char buffer[80];
stsch(irq, &(ioinfo[irq]->schib) );
- sprintf( buffer, "s390_start_IO(%04X) - irb for "
+ sprintf( buffer, "s390_start_IO(%04X) - irb for "
"device %04X, after status pending\n",
irq,
ioinfo[irq]->devstat.devno );
&(ioinfo[irq]->devstat.ii.irb) ,
sizeof(irb_t));
- sprintf( buffer, "s390_start_IO(%04X) - schib for "
+ sprintf( buffer, "s390_start_IO(%04X) - schib for "
"device %04X, after status pending\n",
irq,
ioinfo[irq]->devstat.devno );
if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL)
- {
+ {
sprintf( buffer, "s390_start_IO(%04X) - sense "
"data for "
"device %04X, after status pending\n",
((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt);
} /* endif */
- }
+ }
#endif
}
else
{
- ret = -EIO;
+ ret = -EIO;
ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
ioinfo[irq]->ui.flags.oper = 1;
break;
default: /* device/path not operational */
-
+
if ( flag & DOIO_VALID_LPM )
{
ioinfo[irq]->opm &= ~lpm;
ioinfo[irq]->opm = 0;
} /* endif */
-
+
if ( ioinfo[irq]->opm == 0 )
{
ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+ ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
} /* endif */
ret = -ENODEV;
memcpy( ioinfo[irq]->irq_desc.action->dev_id,
- &(ioinfo[irq]->devstat),
- sizeof( devstat_t) );
+ &(ioinfo[irq]->devstat),
+ sizeof( devstat_t) );
#ifdef CONFIG_DEBUG_IO
- {
- char buffer[80];
+ {
+ char buffer[80];
stsch(irq, &(ioinfo[irq]->schib) );
- sprintf( buffer, "s390_start_IO(%04X) - schib for "
+ sprintf( buffer, "s390_start_IO(%04X) - schib for "
"device %04X, after 'not oper' status\n",
irq,
ioinfo[irq]->devstat.devno );
} while ( retry && (iret == -EBUSY ) );
- sync_isc_locked = 0; // local setting
+ sync_isc_locked = 0; // local setting
ioinfo[irq]->ui.flags.syncio = 0; // global setting
spin_unlock_irqrestore( &sync_isc, psw_flags);
{
ioinfo[irq]->ui.flags.repnone = 0;
- } /* endif */
+ } /* endif */
return( ret);
}
ccode = rsch( irq);
switch (ccode) {
- case 0 :
- break;
+ case 0 :
+ break;
- case 1 :
+ case 1 :
s390_process_IRQ( irq );
- ret = -EBUSY;
- break;
+ ret = -EBUSY;
+ break;
- case 2 :
- ret = -EINVAL;
- break;
+ case 2 :
+ ret = -EINVAL;
+ break;
- case 3 :
- /*
- * useless to wait for request completion
- * as device is no longer operational !
- */
+ case 3 :
+ /*
+ * useless to wait for request completion
+ * as device is no longer operational !
+ */
ioinfo[irq]->ui.flags.oper = 0;
ioinfo[irq]->ui.flags.busy = 0;
- ret = -ENODEV;
- break;
+ ret = -ENODEV;
+ break;
} /* endswitch */
* it allows the device interrupt handler to associate the upcoming
* interrupt with the halt_IO() request.
*/
-int halt_IO( int irq,
+int halt_IO( int irq,
unsigned long user_intparm,
unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */
{
{
int io_sub;
__u32 io_parm;
- psw_t io_new_psw;
- int ccode;
+ psw_t io_new_psw;
+ int ccode;
int ready = 0;
- struct _lowcore *lc = NULL;
+ struct _lowcore *lc = NULL;
- /*
+ /*
* We shouldn't perform a TPI loop, waiting for
* an interrupt to occur, but should load a
* WAIT PSW instead. Otherwise we may keep the
ccode = iac();
switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "halt_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
+ case 0: // primary-space
+ io_sync_wait.mask = _IO_PSW_MASK
+ | _PSW_PRIM_SPACE_MODE
+ | _PSW_IO_WAIT;
+ break;
+ case 1: // secondary-space
+ io_sync_wait.mask = _IO_PSW_MASK
+ | _PSW_SEC_SPACE_MODE
+ | _PSW_IO_WAIT;
+ break;
+ case 2: // access-register
+ io_sync_wait.mask = _IO_PSW_MASK
+ | _PSW_ACC_REG_MODE
+ | _PSW_IO_WAIT;
+ break;
+ case 3: // home-space
+ io_sync_wait.mask = _IO_PSW_MASK
+ | _PSW_HOME_SPACE_MODE
+ | _PSW_IO_WAIT;
+ break;
+ default:
+ panic( "halt_IO() : unexpected "
+ "address-space-control %d\n",
+ ccode);
+ break;
} /* endswitch */
io_sync_wait.addr = FIX_PSW(&&hio_wakeup);
memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
'\0', sizeof( irb_t) );
- /*
+ /*
* Let the common interrupt handler process the pending
* status. However, we must avoid calling the user
* action handler, as it won't be prepared to handle
*/
if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
{
- ret = -ENODEV;
+ ret = -ENODEV;
ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
ioinfo[irq]->ui.flags.oper = 0;
}
else
{
- ret = -EIO;
+ ret = -EIO;
ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
ioinfo[irq]->ui.flags.oper = 1;
{
disable_cpu_sync_isc( irq );
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
+ sync_isc_locked = 0; // local setting
+ ioinfo[irq]->ui.flags.syncio = 0; // global setting
spin_unlock_irqrestore( &sync_isc, psw_flags);
unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */
{
int ret;
- int ccode;
+ int ccode;
unsigned long psw_flags;
int sync_isc_locked = 0;
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
return( -ENODEV);
- }
+ }
/*
* we only allow for halt_IO if the device has an I/O handler associated
{
ret = -ENODEV;
}
- /*
+ /*
* we ignore the halt_io() request if ending_status was received but
* a SENSE operation is waiting for completion.
- */
+ */
else if ( ioinfo[irq]->ui.flags.w4sense )
{
ret = 0;
}
- /*
+ /*
* We don't allow for halt_io with a sync do_IO() requests pending.
* Concurrent I/O is possible in SMP environments only, but the
* sync. I/O request can be gated to one CPU at a time only.
- */
+ */
else if ( ioinfo[irq]->ui.flags.syncio )
- {
+ {
ret = -EBUSY;
-}
+ }
else
{
-/*
+ /*
* If sync processing was requested we lock the sync ISC,
* modify the device to present interrupts for this ISC only
* and switch the CPU to handle this ISC + the console ISC
* exclusively.
- */
+ */
if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-{
+ {
//
// check whether we run recursively (sense processing)
//
if ( !ioinfo[irq]->ui.flags.syncio )
{
spin_lock_irqsave( &sync_isc, psw_flags);
-
+
ret = enable_cpu_sync_isc( irq);
if ( ret )
- {
+ {
spin_unlock_irqrestore( &sync_isc,
psw_flags);
return( ret);
}
else
- {
+ {
sync_isc_locked = 1; // local
ioinfo[irq]->ui.flags.syncio = 1; // global
} /* endif */
+
+ } /* endif */
} /* endif */
- } /* endif */
-
- /*
+ /*
* Issue "Halt subchannel" and process condition code
- */
+ */
ccode = csch( irq );
switch ( ccode ) {
ioinfo[irq]->ui.flags.haltio = 1;
if ( !ioinfo[irq]->ui.flags.doio )
- {
+ {
ioinfo[irq]->ui.flags.busy = 1;
ioinfo[irq]->u_intparm = user_intparm;
ioinfo[irq]->devstat.cstat = 0;
ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION;
ioinfo[irq]->devstat.scnt = 0;
- }
- else
- {
+ }
+ else
+ {
ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION;
- } /* endif */
+ } /* endif */
/*
* If synchronous I/O processing is requested, we have
* pops up.
*/
if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
+ {
int io_sub;
__u32 io_parm;
psw_t io_new_psw;
int ccode;
-
+
int ready = 0;
struct _lowcore *lc = NULL;
- /*
+ /*
* We shouldn't perform a TPI loop, waiting for
* an interrupt to occur, but should load a
* WAIT PSW instead. Otherwise we may keep the
* the interrupt. When our sync. interrupt
* arrived we reset the I/O old PSW to its
* original value.
- */
+ */
memcpy( &io_new_psw,
&lc->io_new_psw,
sizeof(psw_t));
io_sync_wait.addr = FIX_PSW(&&cio_wakeup);
- /*
+ /*
* Martin didn't like modifying the new PSW, now we take
* a fast exit in do_IRQ() instead
- */
+ */
*(__u32 *)__LC_SYNC_IO_WORD = 1;
do
- {
+ {
asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
cio_wakeup:
*(__u32 *)__LC_SYNC_IO_WORD = 0;
- } /* endif */
+ } /* endif */
ret = 0;
break;
-
- case 1 : /* status pending */
+ case 1 : /* status pending */
+
ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
/*
ret = -ENODEV;
ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
+ }
+ else
+ {
ret = -EIO;
ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
ioinfo[irq]->ui.flags.oper = 1;
- } /* endif */
+ } /* endif */
break;
if ( sync_isc_locked )
{
disable_cpu_sync_isc( irq );
-
+
sync_isc_locked = 0; // local setting
ioinfo[irq]->ui.flags.syncio = 0; // global setting
spin_unlock_irqrestore( &sync_isc, psw_flags);
-
+
} /* endif */
-
+
} /* endif */
return( ret );
}
- /*
+/*
* do_IRQ() handles all normal I/O device IRQ's (the special
* SMP cross-CPU interrupts have their own specific
* handlers).
- *
+ *
* Returns: 0 - no ending status received, no further action taken
* 1 - interrupt handler was called with ending status
- */
+ */
asmlinkage void do_IRQ( struct pt_regs regs,
unsigned int irq,
__u32 s390_intparm )
- {
+{
#ifdef CONFIG_FAST_IRQ
int ccode;
tpi_info_t tpi_info;
return; /* this keeps the device boxed ... */
}
- /*
+ /*
* take fast exit if CPU is in sync. I/O state
- *
+ *
* Note: we have to turn off the WAIT bit and re-disable
* interrupts prior to return as this was the initial
* entry condition to synchronous I/O.
- */
+ */
if ( *(__u32 *)__LC_SYNC_IO_WORD )
- {
+ {
regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
return;
#ifdef CONFIG_FAST_IRQ
- /*
+ /*
* more interrupts pending ?
- */
+ */
ccode = tpi( &tpi_info );
if ( ! ccode )
new_irq = tpi_info.irq;
- /*
+ /*
* if the interrupt is for a different irq we
* release the current irq lock and obtain
* a new one ...
- */
+ */
if ( new_irq != use_irq )
- {
+ {
s390irq_spin_unlock(use_irq);
use_irq = new_irq;
s390irq_spin_lock(use_irq);
- } /* endif */
+ } /* endif */
} while ( 1 );
#endif /* CONFIG_FAST_IRQ */
s390irq_spin_unlock(use_irq);
-
+
return;
- }
+}
- /*
+/*
* s390_process_IRQ() handles status pending situations and interrupts
*
* Called by : do_IRQ() - for "real" interrupts
*
* Returns: 0 - no ending status received, no further action taken
* 1 - interrupt handler was called with ending status
- */
+ */
int s390_process_IRQ( unsigned int irq )
{
int ccode; /* cond code from tsch() operation */
else
{
action = ioinfo[irq]->irq_desc.action;
-
- } /* endif */
+
+ } /* endif */
#ifdef CONFIG_DEBUG_IO
- /*
+ /*
* It might be possible that a device was not-oper. at the time
* of free_irq() processing. This means the handler is no longer
* available when the device possibly becomes ready again. In
* this case we perform delayed disable_subchannel() processing.
- */
+ */
if ( action == NULL )
- {
+ {
if ( !ioinfo[irq]->ui.flags.d_disable )
{
printk( KERN_CRIT"s390_process_IRQ(%04X) "
ioinfo[irq]->devstat.devno);
} /* endif */
+
} /* endif */
#endif
- /*
+ /*
* retrieve the i/o interrupt information (irb),
* update the device specific status information
* and possibly call the interrupt handler.
- *
+ *
* Note 1: At this time we don't process the resulting
* condition code (ccode) from tsch(), although
* we probably should.
* parameter relates to it. If a halt function was
* issued for an idle device, the intparm must not
* be taken from lowcore, but from the devstat area.
- */
+ */
ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
//
// We must only accumulate the status if the device is busy already
//
if ( ioinfo[irq]->ui.flags.busy )
- {
- ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat;
- ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat;
- }
- else
- {
- ioinfo[irq]->devstat.dstat = ioinfo[irq]->devstat.ii.irb.scsw.dstat;
- ioinfo[irq]->devstat.cstat = ioinfo[irq]->devstat.ii.irb.scsw.cstat;
-
- ioinfo[irq]->devstat.flag = 0; // reset status flags
-
- } /* endif */
-
- ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum;
-
- if ( ioinfo[irq]->ui.flags.busy)
{
- ioinfo[irq]->devstat.intparm = ioinfo[irq]->u_intparm;
+ ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat;
+ ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat;
+ ioinfo[irq]->devstat.intparm = ioinfo[irq]->u_intparm;
+
+ }
+ else
+ {
+ ioinfo[irq]->devstat.dstat = ioinfo[irq]->devstat.ii.irb.scsw.dstat;
+ ioinfo[irq]->devstat.cstat = ioinfo[irq]->devstat.ii.irb.scsw.cstat;
+ ioinfo[irq]->devstat.flag = 0; // reset status flags
+ ioinfo[irq]->devstat.intparm = 0;
+
} /* endif */
- /*
+ ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum;
+
+ /*
* reset device-busy bit if no longer set in irb
- */
+ */
if ( (ioinfo[irq]->devstat.dstat & DEV_STAT_BUSY )
&& ((ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))
- {
+ {
ioinfo[irq]->devstat.dstat &= ~DEV_STAT_BUSY;
} /* endif */
- /*
+ /*
* Save residual count and CCW information in case primary and
* secondary status are presented with different interrupts.
- */
+ */
if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl
& ( SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) )
- {
+ {
ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count;
ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa;
#ifdef CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "residual count from irb after tsch() %d\n",
- irq, ioinfo[irq]->devstat.rescnt );
+ if ( irq != cons_dev )
+ printk( "s390_process_IRQ( %04X ) : "
+ "residual count from irb after tsch() %d\n",
+ irq, ioinfo[irq]->devstat.rescnt );
#endif
} /* endif */
irb_cc = ioinfo[irq]->devstat.ii.irb.scsw.cc;
- //
+ //
// check for any kind of channel or interface control check but don't
// issue the message for the console device
- //
+ //
if ( (ioinfo[irq]->devstat.ii.irb.scsw.cstat
& ( SCHN_STAT_CHN_DATA_CHK
| SCHN_STAT_CHN_CTRL_CHK
| SCHN_STAT_INTF_CTRL_CHK ) )
&& (irq != cons_dev ) )
- {
+ {
printk( "Channel-Check or Interface-Control-Check "
"received\n"
" ... device %04X on subchannel %04X, dev_stat "
ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt;
ioinfo[irq]->devstat.flag |=
DEVSTAT_FLAG_SENSE_AVAIL;
-
+
sdevstat = sizeof( devstat_t);
#ifdef CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "concurrent sense bytes avail %d\n",
- irq, ioinfo[irq]->devstat.scnt );
+ if ( irq != cons_dev )
+ printk( "s390_process_IRQ( %04X ) : "
+ "concurrent sense bytes avail %d\n",
+ irq, ioinfo[irq]->devstat.scnt );
#endif
- }
- else
- {
+ }
+ else
+ {
/* don't copy the sense data area ! */
sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;
- } /* endif */
+ } /* endif */
switch ( irb_cc ) {
case 1: /* status pending */
sizeof( devstat_t) );
s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
- s_ccw->cda = (char *)virt_to_phys( ioinfo[irq]->sense_data);
+ s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->sense_data );
s_ccw->count = SENSE_MAX_COUNT;
s_ccw->flags = CCW_FLAG_SLI;
//
// Output : none
//
-void VM_virtual_device_info( unsigned int devno,
- senseid_t *ps )
+void VM_virtual_device_info( unsigned int devno,
+ senseid_t *ps )
{
diag210_t diag_data;
int ccode;
error = 1;
- break;
+ break;
} /* endswitch */
}
if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
+ {
return( -ENODEV );
} /* endif */
- /*
+ /*
* Before playing around with irq locks we should assure
* running disabled on (just) our CPU. Sync. I/O requests
* also require to run disabled.
*
* Note : as no global lock is required, we must not use
* cli(), but __cli() instead.
- */
+ */
__save_flags(flags);
__cli();
if ( !ret )
{
if ( ! *buffer )
- {
+ {
rdc_buf = kmalloc( length, GFP_KERNEL);
- }
- else
- {
+ }
+ else
+ {
rdc_buf = *buffer;
} /* endif */
do
{
rdc_ccw->cmd_code = CCW_CMD_RDC;
- rdc_ccw->cda = (char *)virt_to_phys( rdc_buf );
+ rdc_ccw->cda = (__u32)virt_to_phys( rdc_buf );
rdc_ccw->count = length;
rdc_ccw->flags = CCW_FLAG_SLI;
} /* endif */
if ( !retry )
- {
+ {
ret = -EBUSY;
} /* endif */
__restore_flags(flags);
- /*
+ /*
* on success we update the user input parms
- */
+ */
if ( !ret )
{
*buffer = rdc_buf;
- } /* endif */
+ } /* endif */
if ( emulated )
{
return( ret );
}
- /*
+/*
* Read Configuration data
- */
+ */
int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
- {
+{
unsigned long flags;
int ciw_cnt;
if ( (irq > highest_subchannel) || (irq < 0 ) )
{
return( -ENODEV );
- }
+ }
else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
return( -ENODEV);
{
return( -EOPNOTSUPP );
- } /* endif */
+ } /* endif */
- /*
+ /*
* scan for RCD command in extended SenseID data
- */
-
+ */
+
for ( ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
{
if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD )
{
found = 1;
- } /* endif */
+ } /* endif */
break;
+
} /* endif */
} /* endfor */
if ( found )
-{
+ {
devstat_t devstat; /* inline device status area */
devstat_t *pdevstat;
int ioflags;
emulated = 1;
} /* endif */
- }
+ }
else
- {
+ {
pdevstat = ioinfo[irq]->irq_desc.action->dev_id;
} /* endif */
{
rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count,
GFP_KERNEL);
- }
+ }
else
- {
+ {
rcd_buf = alloc_bootmem( ioinfo[irq]->senseid.ciw[ciw_cnt].count);
} /* endif */
{
ret = -ENOMEM;
- } /* endif */
+ } /* endif */
if ( !ret )
{
memset( rcd_buf,
'\0',
ioinfo[irq]->senseid.ciw[ciw_cnt].count);
-
+
do
- {
+ {
rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd;
- rcd_ccw->cda = (char *)virt_to_phys( rcd_buf );
+ rcd_ccw->cda = (__u32)virt_to_phys( rcd_buf );
rcd_ccw->count = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
rcd_ccw->flags = CCW_FLAG_SLI;
ioflags = DOIO_WAIT_FOR_INTERRUPT
| DOIO_VALID_LPM
| DOIO_DONT_CALL_INTHDLR;
- }
- else
- {
+ }
+ else
+ {
ioflags = DOIO_WAIT_FOR_INTERRUPT
| DOIO_DONT_CALL_INTHDLR;
-
- } /* endif */
+
+ } /* endif */
ret = s390_start_IO( irq,
rcd_ccw,
| DEVSTAT_FLAG_SENSE_AVAIL ) ) )
{
retry = 0; // we got it ...
- }
- else
- {
+ }
+ else
+ {
retry--; // try again ...
- } /* endif */
+ } /* endif */
break;
if ( init_IRQ_complete )
{
kfree( rcd_buf );
- }
- else
- {
+ }
+ else
+ {
free_bootmem( (unsigned long)rcd_buf,
ioinfo[irq]->senseid.ciw[ciw_cnt].count);
*buffer = NULL;
*length = 0;
-
+
} /* endif */
if ( emulated )
return( get_dev_info_by_irq( irq, pdi));
}
-
static int __inline__ get_next_available_irq( ioinfo_t *pi)
{
int ret_val;
if ( pi == NULL )
{
ret_val = -ENODEV;
- break;
+ break;
}
} /* endif */
else
{
ret_irq = -ENODEV;
-
+
} /* endif */
}
else
&& ioinfo[i]->schib.pmcw.dev == devno )
{
- pdi->irq = i;
- pdi->devno = devno;
+ pdi->irq = i;
+ pdi->devno = devno;
if ( ioinfo[i]->ui.flags.oper
&& !ioinfo[i]->ui.flags.unknown )
else
{
pdi->status = DEVSTAT_NOT_OPER;
-
+
memset( &(pdi->sid_data),
'\0',
sizeof( senseid_t));
pdi->status |= DEVSTAT_DEVICE_OWNED;
rc = 0; /* found */
- break;
+ break;
} /* endif */
} /* endif */
} /* endfor */
-
+
} /* endif */
return( rc);
|| ( ioinfo[irq] == INVALID_STORAGE_AREA ) )
{
return -1;
-
+
} /* endif */
/*
* single I/O during boot (IPL) processing.
*/
spin_lock_irqsave( &sync_isc, psw_flags);
-
+
ret = enable_cpu_sync_isc( irq);
if ( ret )
}
else
{
- ioinfo[irq]->ui.flags.syncio = 1; // global
+ ioinfo[irq]->ui.flags.syncio = 1; // global
ioinfo[irq]->ui.flags.unknown = 0;
memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t));
free_irq( irq, &devstat );
} /* endif */
-
+
} /* endif */
}
{
ret = s390_validate_subchannel( irq, 0);
- irq++;
-
+ if ( ret != -ENXIO)
+ irq++;
+
} while ( (ret != -ENXIO) && (irq < __MAX_SUBCHANNELS) );
- highest_subchannel = --irq;
+ highest_subchannel = (--irq);
- printk( "\nHighest subchannel number detected: %u\n",
+ printk( "Highest subchannel number detected (hex) : %04X\n",
highest_subchannel);
}
{
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
-
if ( !init_IRQ_complete )
{
ioinfo[irq] =
sizeof( schib_t));
ioinfo[irq]->irq_desc.status = IRQ_DISABLED;
ioinfo[irq]->irq_desc.handler = &no_irq_type;
-
+
/*
* We have to insert the new ioinfo element
* into the linked list, either at its head,
ioinfo[irq]->prev = pi;
pi->next->prev = ioinfo[irq];
pi->next = ioinfo[irq];
- break;
-
+ break;
+
} /* endif */
pi = pi->next;
} while ( 1 );
-
+
} /* endif */
} /* endif */
ioinfo[irq]->schib.pmcw.pam,
ioinfo[irq]->schib.pmcw.pom);
-/*
+ /*
* initialize ioinfo structure
*/
ioinfo[irq]->irq = irq;
/*
* We should have at least one CHPID ...
- */
+ */
if ( ioinfo[irq]->opm )
-{
+ {
/*
* We now have to initially ...
* ... set "interruption sublass"
&& ( ioinfo[irq]->opm != 0x04 )
&& ( ioinfo[irq]->opm != 0x02 )
&& ( ioinfo[irq]->opm != 0x01 ) )
- {
+ {
ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
- } /* endif */
+ } /* endif */
retry = 5;
do
- {
+ {
ccode2 = msch_err( irq, &ioinfo[irq]->schib);
switch (ccode2) {
ioinfo[irq]->ui.flags.consns = 1;
ret = 0;
break;
-
+
case 1: // status pending
//
// How can we have a pending status as
retry--;
ret = -EIO;
break;
-
+
case 2: // busy
- /*
+ /*
* we mark it not-oper as we can't
* properly operate it !
- */
+ */
ioinfo[irq]->ui.flags.oper = 0;
tod_wait( 100); /* allow for recovery */
retry--;
#define PGMCHK_OPERAND_EXC 0x15
if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC )
- {
+ {
/*
* re-issue the modify subchannel without trying to
* enable the concurrent sense facility
*/
ioinfo[irq]->schib.pmcw.csense = 0;
-
+
ccode2 = msch_err( irq, &ioinfo[irq]->schib);
if ( ccode2 != 0 )
- {
+ {
printk( " ... msch() (2) failed with CC = %X\n",
ccode2 );
ioinfo[irq]->ui.flags.oper = 0;
ret = -EIO;
- }
- else
- {
+ }
+ else
+ {
ioinfo[irq]->ui.flags.oper = 1;
ioinfo[irq]->ui.flags.consns = 0;
ret = 0;
- } /* endif */
- }
- else
- {
+ } /* endif */
+ }
+ else
+ {
printk( " ... msch() (1) failed with CC = %X\n",
ccode2);
ioinfo[irq]->ui.flags.oper = 0;
ret = -EIO;
- } /* endif */
-
+ } /* endif */
+
retry = 0;
break;
} while ( ccode2 && retry );
if ( (ccode2 != 0) && (ccode2 != 3) && (!retry) )
- {
+ {
printk( " ... msch() retry count for "
"subchannel %04X exceeded, CC = %d\n",
irq,
ccode2);
- } /* endif */
+ } /* endif */
}
else
{
} /* endif */
}
else
- {
+ {
ret = -ENODEV;
- } /* endif */
+ } /* endif */
}
else
{
-
ret = -ENXIO;
- } /* endif */
+ } /* endif */
- return( ret );
+ return( ret );
}
/*
senseid_t *psid = sid;/* start with the external buffer */
int sbuffer = 0; /* switch SID data buffer */
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
+ if ( (irq > highest_subchannel) || (irq < 0 ) )
+ {
+ return( -ENODEV );
- }
+ }
else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
return( -ENODEV);
- } /* endif */
+ } /* endif */
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
+ if ( ioinfo[irq]->ui.flags.oper == 0 )
+ {
+ return( -ENODEV );
- } /* endif */
+ } /* endif */
- if ( !ioinfo[irq]->ui.flags.ready )
- {
+ if ( !ioinfo[irq]->ui.flags.ready )
+ {
pdevstat = &devstat;
- /*
+ /*
* Perform SENSE ID command processing. We have to request device
* ownership and provide a dummy I/O handler. We issue sync. I/O
* requests and evaluate the devstat area on return therefore
* we don't need a real I/O handler in place.
- */
+ */
irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat);
if ( irq_ret == 0 )
inlreq = 1;
- }
- else
- {
+ }
+ else
+ {
inlreq = 0;
irq_ret = 0;
pdevstat = ioinfo[irq]->irq_desc.action->dev_id;
- } /* endif */
+ } /* endif */
if ( irq_ret == 0 )
-{
+ {
int i;
s390irq_spin_lock( irq);
// more than one path installed ?
if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-{
+ {
sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
sense_ccw[0].cda = 0;
sense_ccw[0].count = 0;
sense_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID;
- sense_ccw[1].cda = (char *)virt_to_phys( psid );
+ sense_ccw[1].cda = (__u32)virt_to_phys( sid );
sense_ccw[1].count = sizeof( senseid_t);
sense_ccw[1].flags = CCW_FLAG_SLI;
}
else
{
sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID;
- sense_ccw[0].cda = (char *)virt_to_phys( psid );
+ sense_ccw[0].cda = (__u32)virt_to_phys( sid );
sense_ccw[0].count = sizeof( senseid_t);
sense_ccw[0].flags = CCW_FLAG_SLI;
domask &= lpm;
if ( domask )
- {
+ {
psid->cu_type = 0xFFFF; /* initialize fields ... */
psid->cu_model = 0;
psid->dev_type = 0;
retry = 5; /* retry count */
io_retry = 1; /* enable retries */
-
+
/*
* We now issue a SenseID request. In case of BUSY,
* STATUS PENDING or non-CMD_REJECT error conditions
* we run simple retries.
*/
do
- {
+ {
memset( pdevstat, '\0', sizeof( devstat_t) );
irq_ret = s390_start_IO( irq,
//
if ( psid->cu_type == 0xFFFF )
- {
+ {
if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
- {
+ {
#ifdef CONFIG_DEBUG_IO
printk( "SenseID : device %04X on "
"Subchannel %04X "
} /* endif */
if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
+ {
/*
* if the device doesn't support the SenseID
* command further retries wouldn't help ...
*/
if ( pdevstat->ii.sense.data[0]
& (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ) )
- {
+ {
#ifdef CONFIG_DEBUG_IO
printk( "SenseID : device %04X on "
"Subchannel %04X "
irq);
#endif
io_retry = 1;
- }
+ }
#ifdef CONFIG_DEBUG_IO
- else
- {
+ else
+ {
printk( "SenseID : UC on "
"dev %04X, "
"retry %d, "
pdevstat->ii.sense.data[6],
pdevstat->ii.sense.data[7]);
- } /* endif */
+ } /* endif */
#endif
- }
+ }
else if ( ( pdevstat->flag & DEVSTAT_NOT_OPER )
|| ( irq_ret == -ENODEV ) )
- {
+ {
#ifdef CONFIG_DEBUG_IO
printk( "SenseID : path %02X for "
"device %04X on "
io_retry = 0;
ioinfo[irq]->opm &= ~domask;
-
-}
+
+ }
#ifdef CONFIG_DEBUG_IO
else if ( (pdevstat->flag !=
( DEVSTAT_START_FUNCTION
} /* endif */
#endif
- }
+ }
else // we got it ...
- {
+ {
if ( !sbuffer ) // switch buffers
- {
+ {
/*
* we report back the
* first hit only
psid = &isid;
if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
- {
- sense_ccw[1].cda = (char *)virt_to_phys( psid );
- }
- else
- {
- sense_ccw[0].cda = (char *)virt_to_phys( psid );
+ {
+ sense_ccw[1].cda = (__u32)virt_to_phys( psid );
+ }
+ else
+ {
+ sense_ccw[0].cda = (__u32)virt_to_phys( psid );
- } /* endif */
+ } /* endif */
/*
* if just the very first
sbuffer = 1;
- } /* endif */
+ } /* endif */
if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) )
-{
+ {
ioinfo[irq]->ui.flags.esid = 1;
-
+
} /* endif */
io_retry = 0;
-
+
} /* endif */
if ( io_retry )
- {
+ {
retry--;
-
+
if ( retry == 0 )
{
io_retry = 0;
- } /* endif */
-
+ } /* endif */
+
} /* endif */
-
+
} while ( (io_retry) );
} /* endif - domask */
- } /* endfor */
+ } /* endfor */
s390irq_spin_unlock( irq);
} /* endif */
if ( sid->cu_type == 0xFFFF )
-{
+ {
/*
* SenseID CU-type of 0xffff indicates that no device
* information could be retrieved (pre-init value).
/*
* Issue device info message if unit was operational .
*/
- if ( ioinfo[irq]->ui.flags.unknown )
- {
+ if ( !ioinfo[irq]->ui.flags.unknown )
+ {
if ( sid->dev_type != 0 )
- {
+ {
printk( "SenseID : device %04X reports: CU Type/Mod = %04X/%02X,"
" Dev Type/Mod = %04X/%02X\n",
ioinfo[irq]->schib.pmcw.dev,
sid->dev_model);
}
else
- {
+ {
printk( "SenseID : device %04X reports:"
" Dev Type/Mod = %04X/%02X\n",
ioinfo[irq]->schib.pmcw.dev,
sid->cu_type,
sid->cu_model);
- } /* endif */
+ } /* endif */
- } /* endif */
+ } /* endif */
- if ( ioinfo[irq]->ui.flags.unknown )
+ if ( !ioinfo[irq]->ui.flags.unknown )
irq_ret = 0;
else
irq_ret = -ENODEV;
cc = stsch( irq, &ioinfo[irq]->schib );
if ( !cc )
- {
+ {
ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
cc = msch( irq, &ioinfo[irq]->schib );
if ( ccode )
{
ret = -ENODEV;
-}
+ }
else if ( ioinfo[irq]->schib.pmcw.pim == 0x80 )
{
-/*
+ /*
* no error, just not required for single path only devices
- */
+ */
ioinfo[irq]->ui.flags.pgid_supp = 0;
ret = 0;
}
else
-{
+ {
int i;
pgid_t pgid;
__u8 dev_path;
& ioinfo[irq]->schib.pmcw.pom;
if ( usermask )
- {
+ {
dev_path = usermask;
- }
- else
- {
+ }
+ else
+ {
dev_path = ioinfo[irq]->opm;
- } /* endif */
+ } /* endif */
- /*
+ /*
* let's build a path group ID if we don't have one yet
*/
if ( ioinfo[irq]->ui.flags.pgid == 0)
ioinfo[irq]->ui.flags.pgid = 1;
- } /* endif */
+ } /* endif */
memcpy( &pgid, &ioinfo[irq]->pgid, sizeof(pgid_t));
domask = dev_path & pathmask;
if ( domask )
- {
+ {
ret = s390_SetPGID( irq, domask, &pgid );
/*
if ( ret == -EOPNOTSUPP && first )
{
*(int *)&pgid = 0;
-
+
ret = s390_SensePGID( irq, domask, &pgid);
first = 0;
-
+
if ( ret == 0 )
{
- /*
+ /*
* Check whether we retrieved
* a reasonable PGID ...
- */
+ */
if ( pgid.inf.ps.state1 == SNID_STATE1_GROUPED )
- {
+ {
memcpy( &(ioinfo[irq]->pgid),
&pgid,
sizeof(pgid_t) );
- }
+ }
else // ungrouped or garbage ...
- {
+ {
ret = -EOPNOTSUPP;
} /* endif */
- }
+ }
else
- {
+ {
ioinfo[irq]->ui.flags.pgid_supp = 0;
#ifdef CONFIG_DEBUG_IO
" support path grouping\n",
irq,
ioinfo[irq]->schib.pmcw.dev);
-
+
#endif
ioinfo[irq]->ui.flags.pgid_supp = 0;
} /* endif */
-
- } /* endif */
+
+ } /* endif */
} /* endfor */
- } /* endif */
+ } /* endif */
return ret;
#else
#endif
}
- /*
+/*
* s390_SetPGID
*
* Set Path Group ID
- *
- */
+ *
+ */
int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
- {
+{
ccw1_t spid_ccw[2]; /* ccw area for SPID command */
devstat_t devstat; /* required by request_irq() */
devstat_t *pdevstat = &devstat;
}
else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
+ {
return( -ENODEV);
} /* endif */
} /* endif */
if ( irq_ret == 0 )
- {
+ {
s390irq_spin_lock( irq);
spid_ccw[0].cmd_code = 0x5B; /* suspend multipath reconnect */
spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
- spid_ccw[1].cda = (char *)virt_to_phys( pgid );
+ spid_ccw[1].cda = (__u32)virt_to_phys( pgid );
spid_ccw[1].count = sizeof( pgid_t);
spid_ccw[1].flags = CCW_FLAG_SLI;
pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
- /*
+ /*
* We now issue a SenseID request. In case of BUSY
* or STATUS PENDING conditions we retry 5 times.
- */
+ */
do
{
memset( pdevstat, '\0', sizeof( devstat_t) );
if ( pdevstat->flag == ( DEVSTAT_START_FUNCTION
| DEVSTAT_FINAL_STATUS ) )
- {
+ {
retry = 0; // successfully set ...
}
else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
ioinfo[irq]->schib.pmcw.dev,
irq);
- retry = 0;
+ retry = 0;
} /* endif */
}
else if ( irq_ret != -ENODEV )
- {
+ {
retry--;
}
else
{
retry = 0;
- } /* endif */
+ } /* endif */
} while ( retry > 0 );
s390irq_spin_unlock( irq);
- /*
+ /*
* If we installed the irq action handler we have to
* release it too.
- */
+ */
if ( inlreq )
free_irq( irq, pdevstat);
int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
{
ccw1_t snid_ccw; /* ccw area for SNID command */
- devstat_t devstat; /* required by request_irq() */
+ devstat_t devstat; /* required by request_irq() */
devstat_t *pdevstat = &devstat;
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
+ int irq_ret = 0; /* return code */
+ int retry = 5; /* retry count */
+ int inlreq = 0; /* inline request_irq() */
if ( (irq > highest_subchannel) || (irq < 0 ) )
{
/*
* Perform SENSE ID command processing. We have to request device
* ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
+ * requests and evaluate the devstat area on return therefore
+ * we don't need a real I/O handler in place.
+ */
irq_ret = request_irq( irq,
init_IRQ_handler,
0,
} /* endif */
if ( irq_ret == 0 )
- {
+ {
s390irq_spin_lock( irq);
snid_ccw.cmd_code = CCW_CMD_SENSE_PGID;
- snid_ccw.cda = (char *)virt_to_phys( pgid );
+ snid_ccw.cda = (__u32)virt_to_phys( pgid );
snid_ccw.count = sizeof( pgid_t);
snid_ccw.flags = CCW_FLAG_SLI;
| DOIO_DONT_CALL_INTHDLR );
if ( irq_ret == 0 )
- {
+ {
if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
{
/*
*/
if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
{
- retry = 0;
+ retry = 0;
irq_ret = -EOPNOTSUPP;
}
else
retry = 0;
- }
+ }
else
- {
+ {
retry = 0; // success ...
- } /* endif */
+ } /* endif */
}
else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
{
" start_io() reports rc : %d, retrying ...\n",
ioinfo[irq]->schib.pmcw.dev,
irq_ret);
- retry--;
+ retry--;
}
else // -ENODEV ...
{
return( irq_ret );
}
- /*
+/*
* s390_do_crw_pending
*
* Called by the machine check handler to process CRW pending
* conditions. It may be a single CRW, or CRWs may be chained.
*
* Note : we currently process CRWs for subchannel source only
- */
+ */
void s390_do_crw_pending( crwe_t *pcrwe )
- {
+{
int irq;
int dev_oper = 0;
int dev_no = -1;
#endif
while ( pcrwe != NULL )
- {
+ {
switch ( pcrwe->crw.rsc ) {
case CRW_RSC_SCH :
if ( ioinfo[irq]->ui.flags.dval )
dev_no = ioinfo[irq]->devno;
- } /* endif */
+ } /* endif */
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : subchannel validation - start ...\n");
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : subchannel validation - done\n");
#endif
- /*
+ /*
* After the validate processing
* the ioinfo control block
* should be allocated ...
- */
+ */
if ( lock )
- {
+ {
s390irq_spin_unlock( irq );
} /* endif */
#ifdef CONFIG_DEBUG_CRW
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
+ if ( ioinfo[irq] != INVALID_STORAGE_AREA )
{
printk( "do_crw_pending : ioinfo at %08X\n",
(unsigned)ioinfo[irq]);
} /* endif */
#endif
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
+ if ( ioinfo[irq] != INVALID_STORAGE_AREA )
{
if ( ioinfo[irq]->ui.flags.oper == 0 )
{
if ( ( dev_oper == 1 )
&& ( ioinfo[irq]->nopfunc != NULL ) )
{
- free_irq( irq,
- ioinfo[irq]->irq_desc.action->dev_id );
- ioinfo[irq]->nopfunc( irq,
- DEVSTAT_DEVICE_GONE );
+ free_irq( irq,
+ ioinfo[irq]->irq_desc.action->dev_id );
+ ioinfo[irq]->nopfunc( irq,
+ DEVSTAT_DEVICE_GONE );
} /* endif */
- }
- else
- {
+ }
+ else
+ {
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : device "
"recognition - start ...\n");
if ( pdevreg->oper_func != NULL )
pdevreg->oper_func( irq, pdevreg );
- } /* endif */
+ } /* endif */
}
/*
* ... it is and was operational, but
ioinfo[irq]->nopfunc( irq,
DEVSTAT_REVALIDATE );
- } /* endif */
+ } /* endif */
} /* endif */
- } /* endif */
+ } /* endif */
break;
/* added by Holger Smolinski for reipl support in reipl.S */
extern void do_reipl (int);
-void
+void
reipl ( int sch )
{
- int i;
+ int i;
for ( i = 0; i < highest_subchannel; i ++ ) {
- free_irq ( i, (void*)REIPL_DEVID_MAGIC );
+ free_irq ( i, (void*)REIPL_DEVID_MAGIC );
}
do_reipl( 0x10000 | sch );
}
* currently only channel-reports are supported
*
* S390 version
- * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
*/
#include <asm/s390dyn.h>
#include <asm/s390mach.h>
-#define S390_MACHCHK_DEBUG
+#undef S390_MACHCHK_DEBUG
-static int __init s390_machine_check_handler( void * parm );
+static int s390_machine_check_handler( void * parm );
static void s390_enqueue_mchchk( mache_t *mchchk );
static mache_t *s390_dequeue_mchchk( void );
static void s390_enqueue_free_mchchk( mache_t *mchchk );
static mache_t *s390_dequeue_free_mchchk( void );
static int s390_collect_crw_info( void );
-static struct semaphore s_sem[2];
+static struct semaphore s_sem;
static mache_t *mchchk_queue_head = NULL;
static mache_t *mchchk_queue_tail = NULL;
crwe_t *pcrwe; /* CRW buffer element pointer */
mache_t *pmache; /* machine check element pointer */
- init_MUTEX_LOCKED( &s_sem[0] );
- init_MUTEX_LOCKED( &s_sem[1] );
+ init_MUTEX_LOCKED( &s_sem );
pcrwe = kmalloc( MAX_CRW_PENDING * sizeof( crwe_t), GFP_KERNEL);
crw_buffer_anchor = pcrwe;
- for ( i=0; i < MAX_CRW_PENDING; i++)
+ for ( i=0; i < MAX_CRW_PENDING-1; i++)
{
pcrwe->crwe_next = (crwe_t *)((unsigned long)pcrwe + sizeof(crwe_t));
pcrwe = pcrwe->crwe_next;
printk( "init_mach : starting machine check handler\n");
#endif
- kernel_thread( s390_machine_check_handler, s_sem, 0);
-
- /*
- * wait for the machine check handler to be ready
- */
-#ifdef S390_MACHCHK_DEBUG
- printk( "init_mach : waiting for machine check handler coming up ... \n");
-#endif
-
- down( &s_sem[0]);
+ kernel_thread( s390_machine_check_handler, &s_sem, 0);
ctl_clear_bit( 14, 25 ); // disable damage MCH
#if 1
* mchine check pre-processor, collecting the machine check info,
* queueing it and posting the machine check handler for processing.
*/
-void __init s390_do_machine_check( void )
+void s390_do_machine_check( void )
{
int crw_count;
- mcic_t mcic;
+ mcic_t mcic;
#ifdef S390_MACHCHK_DEBUG
printk( "s390_do_machine_check : starting ...\n");
if ( crw_count )
{
- up( &s_sem[1] );
+ up( &s_sem );
} /* endif */
* machine check handler, dequeueing machine check entries
* and processing them
*/
-static int __init s390_machine_check_handler( void *parm)
+static int s390_machine_check_handler( void *parm)
{
struct semaphore *sem = parm;
int flags;
int found = 0;
-#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : up\n");
-#endif
+ /* set name to something sensible */
+ strncpy(current->comm,"kmcheck",15);
+ current->comm[15]=0;
- up( &sem[0] );
+ /* block all signals */
+ sigfillset(¤t->blocked);
#ifdef S390_MACHCHK_DEBUG
printk( "mach_handler : ready\n");
printk( "mach_handler : waiting for wakeup\n");
#endif
- down_interruptible( &sem[1] );
+ down_interruptible( sem );
#ifdef S390_MACHCHK_DEBUG
printk( "\nmach_handler : wakeup ... \n");
#endif
+ found = 0; /* init ... */
__save_flags( flags );
__cli();
+ do {
+
pmache = s390_dequeue_mchchk();
if ( pmache )
}
else
{
- found = 0;
// unconditional surrender ...
#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : terminated \n");
+ printk( "mach_handler : nothing to do, sleeping\n");
#endif
} /* endif */
+ } while ( pmache );
+
__restore_flags( flags );
- } while ( found );
+ } while ( 1 );
return( 0);
}
#ifndef CONFIG_SMP
void machine_restart(char * __unused)
{
- reipl(S390_lowcore.ipl_device);
+ reipl(S390_lowcore.ipl_device);
}
void machine_halt(void)
if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
cpcmd(vmhalt_cmd, NULL, 0);
signal_processor(smp_processor_id(), sigp_stop_and_store_status);
- }
+}
void machine_power_off(void)
{
if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
cpcmd(vmpoff_cmd, NULL, 0);
signal_processor(smp_processor_id(), sigp_stop_and_store_status);
- }
+}
#endif
/*
__initfunc(void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p))
{
- static unsigned int smptrap=0;
+ static unsigned int smptrap = 0;
unsigned long memory_start, memory_end;
char c, cn, *to, *from;
#define SIGFRAME_COMMON \
__u8 callee_used_stack[__SIGNAL_FRAMESIZE]; \
struct sigcontext sc; \
-sigregs sregs; \
+_sigregs sregs; \
__u8 retcode[S390_SYSCALL_SIZE];
typedef struct
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
- }
+ }
}
asmlinkage int
current->blocked = newset;
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
- regs->gprs[2] = -EINTR;
+ regs->gprs[2] = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
- }
+ }
}
-asmlinkage int
+asmlinkage int
sys_sigaction(int sig, const struct old_sigaction *act,
struct old_sigaction *oact)
{
__get_user(new_ka.sa.sa_flags, &act->sa_flags);
__get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
- }
+ }
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
return -EFAULT;
__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
- }
+ }
return ret;
}
asmlinkage int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)
{
- struct pt_regs *regs = (struct pt_regs *) &uss;
return do_sigaltstack(uss, uoss, regs->gprs[15]);
}
-static int save_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int save_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
}
-static int restore_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
static int
restore_sigcontext(struct sigcontext *sc, pt_regs *regs,
- sigregs *sregs,sigset_t *set)
+ _sigregs *sregs,sigset_t *set)
{
unsigned int err;
err=restore_sigregs(regs,sregs);
if(!err)
- err=__copy_from_user(&set->sig,&sc->oldmask,SIGMASK_COPY_SIZE);
+ err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE);
return(err);
}
{
if (sigreturn_common(regs,sizeof(sigframe)))
- goto badframe;
+ goto badframe;
return regs->gprs[2];
-
+
badframe:
force_sig(SIGSEGV, current);
return 0;
- }
+}
asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
if (sigreturn_common(regs,sizeof(rt_sigframe)))
- goto badframe;
+ goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
static void *setup_frame_common(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs * regs,
int frame_size,u16 retcode)
- {
+{
sigframe *frame;
int err;
err=__put_user(&frame->sregs,&frame->sc.sregs);
if(!err)
- err=__copy_to_user(&frame->sc.oldmask,&set->sig,SIGMASK_COPY_SIZE);
+ err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE);
if(!err)
{
regs->gprs[2]=(current->exec_domain
/*
* OK, we're invoking a handler
- */
+ */
static void
handle_signal(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
- {
+{
/* Are we from a system call? */
if (regs->orig_gpr2 >= 0) {
/* If so, check system call restarting.. */
switch (regs->gprs[2]) {
- case -ERESTARTNOHAND:
+ case -ERESTARTNOHAND:
regs->gprs[2] = -EINTR;
break;
- case -ERESTARTSYS:
+ case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
- regs->gprs[2] = -EINTR;
- break;
- }
+ regs->gprs[2] = -EINTR;
+ break;
+ }
/* fallthrough */
- case -ERESTARTNOINTR:
- regs->gprs[2] = regs->orig_gpr2;
- regs->psw.addr -= 2;
+ case -ERESTARTNOINTR:
+ regs->gprs[2] = regs->orig_gpr2;
+ regs->psw.addr -= 2;
}
}
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-int do_signal(struct pt_regs *regs,sigset_t *oldset)
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
{
siginfo_t info;
struct k_sigaction *ka;
if (regs->gprs[2] == -ERESTARTNOHAND ||
regs->gprs[2] == -ERESTARTSYS ||
regs->gprs[2] == -ERESTARTNOINTR) {
- regs->gprs[2] = regs->orig_gpr2;
+ regs->gprs[2] = regs->orig_gpr2;
regs->psw.addr -= 2;
+ }
}
-}
return 0;
}
if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
cpcmd(vmhalt_cmd, NULL, 0);
signal_processor(smp_processor_id(), sigp_stop_and_store_status);
- }
+}
void machine_halt(void)
{
if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
cpcmd(vmpoff_cmd, NULL, 0);
signal_processor(smp_processor_id(), sigp_stop_and_store_status);
- }
+}
void machine_power_off(void)
{
__flush_tlb();
atomic_set(&ec->status, ec_done);
return;
+ case ec_callback: {
+ ec_callback_parms *cbp;
+ cbp = (ec_callback_parms *) ec->parms;
+ atomic_set(&ec->status,ec_executing);
+ (cbp->callback)(cbp->data);
+ atomic_set(&ec->status,ec_done);
+ return;
+ }
default:
}
ec = ec->next;
__ctl_clear_bit(cr, bit);
}
+/*
+ * Execute a callback function on all cpus
+ */
+void smp_do_callback_all(void (*callback)(void *), void *data) {
+ ec_callback_parms parms;
+
+ if (atomic_read(&smp_commenced) != 0) {
+ parms.callback = callback;
+ parms.data = data;
+ smp_ext_call_sync_others(ec_callback, &parms);
+ }
+ (callback)(data);
+}
/*
* Lets check how many CPUs we have.
sigp_ccode ccode;
int curr_cpu;
int i;
-
+
/* request the 0x1202 external interrupt */
if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
panic("Couldn't request external interrupt 0x1202");
typedef void pgm_check_handler_t(struct pt_regs *, long);
pgm_check_handler_t *pgm_check_table[128];
-extern pgm_check_handler_t default_trap_handler;
extern pgm_check_handler_t do_page_fault;
-asmlinkage int system_call(void);
-
static inline void console_verbose(void)
{
extern int console_loglevel;
console_loglevel = 15;
}
-#define DO_ERROR(trapnr, signr, str, name, tsk) \
-asmlinkage void name(struct pt_regs * regs, long error_code) \
-{ \
- if (check_for_fixup(regs) == 0) { \
- tsk->tss.error_code = error_code; \
- tsk->tss.trap_no = trapnr; \
- force_sig(signr, tsk); \
- die(str,regs,error_code); \
- } \
-}
-
-
-void page_exception(void);
-
-/* TODO: define these as 'pgm_check_handler_t xxx;'
-asmlinkage void divide_error(void);
-asmlinkage void debug(void);
-asmlinkage void nmi(void);
-asmlinkage void int3(void);
-asmlinkage void overflow(void);
-asmlinkage void bounds(void);
-asmlinkage void invalid_op(void);
-asmlinkage void device_not_available(void);
-asmlinkage void double_fault(void);
-asmlinkage void coprocessor_segment_overrun(void);
-asmlinkage void invalid_TSS(void);
-asmlinkage void segment_not_present(void);
-asmlinkage void stack_segment(void);
-asmlinkage void general_protection(void);
-asmlinkage void coprocessor_error(void);
-asmlinkage void reserved(void);
-asmlinkage void alignment_check(void);
-asmlinkage void spurious_interrupt_bug(void);
-*/
-
-int kstack_depth_to_print = 24;
-
-/*
- * These constants are for searching for possible module text
- * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-#define MODULE_RANGE (8*1024*1024)
-
-void show_crashed_task_info(void)
-{
- printk("CPU: %d\n",smp_processor_id());
- printk("Process %s (pid: %d, stackpage=%08X)\n",
- current->comm, current->pid, 4096+(addr_t)current);
- show_regs(current,NULL,NULL);
-}
-#if 0
-static void show_registers(struct pt_regs *regs)
-{
- printk("CPU: %d\nPSW: %08lx %08lx\n",
- smp_processor_id(), (unsigned long) regs->psw.mask,
- (unsigned long) regs->psw.addr);
- printk("GPRS:\n");
-
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[0], regs->gprs[1],
- regs->gprs[2], regs->gprs[3]);
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[4], regs->gprs[5],
- regs->gprs[6], regs->gprs[7]);
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[8], regs->gprs[9],
- regs->gprs[10], regs->gprs[11]);
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[12], regs->gprs[13],
- regs->gprs[14], regs->gprs[15]);
- printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 4096+(unsigned long)current);
-/*
- stack = (unsigned long *) esp;
- for(i=0; i < kstack_depth_to_print; i++) {
- if (((long) stack & 4095) == 0)
- break;
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("%08lx ", get_seg_long(ss,stack++));
- }
- printk("\nCall Trace: ");
- stack = (unsigned long *) esp;
- i = 1;
- module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT);
- module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
- module_end = module_start + MODULE_RANGE;
- while (((long) stack & 4095) != 0) {
- addr = get_seg_long(ss, stack++); */
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
-/* if (((addr >= (unsigned long) &_stext) &&
- (addr <= (unsigned long) &_etext)) ||
- ((addr >= module_start) && (addr <= module_end))) {
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("[<%08lx>] ", addr);
- i++;
- }
- }
- printk("\nCode: ");
- for(i=0;i<20;i++)
- printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip)));
- printk("\n");
-*/
-}
-#endif
-
-
spinlock_t die_lock;
void die(const char * str, struct pt_regs * regs, long err)
console_verbose();
spin_lock_irq(&die_lock);
printk("%s: %04lx\n", str, err & 0xffff);
- show_crashed_task_info();
+ show_regs(regs);
spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
-int check_for_fixup(struct pt_regs * regs)
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+ do_trap(interruption_code, signr, str, regs); \
+}
+
+static void inline do_trap(long interruption_code, int signr, char *str,
+ struct pt_regs *regs)
{
- if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
- unsigned long fixup;
- fixup = search_exception_table(regs->psw.addr);
- if (fixup) {
+ if (regs->psw.mask & PSW_PROBLEM_STATE) {
+ struct task_struct *tsk = current;
+ tsk->tss.trap_no = interruption_code;
+ force_sig(signr, tsk);
+#ifdef CONFIG_PROCESS_DEBUG
+ printk("User process fault: interruption code 0x%lX\n",
+ interruption_code);
+ show_regs(regs);
+#endif
+ } else {
+ unsigned long fixup = search_exception_table(regs->psw.addr);
+ if (fixup)
regs->psw.addr = fixup;
- return 1;
- }
+ else
+ die(str, regs, interruption_code);
}
- return 0;
}
int do_debugger_trap(struct pt_regs *regs,int signal)
return(FALSE);
}
-asmlinkage void default_trap_handler(struct pt_regs * regs, long error_code)
-{
- if (check_for_fixup(regs) == 0) {
- current->tss.error_code = error_code;
- current->tss.trap_no = error_code;
- force_sig(SIGSEGV, current);
- die("Unknown program exception",regs,error_code);
- }
-}
-
-DO_ERROR(2, SIGILL, "privileged operation", privileged_op, current)
-DO_ERROR(3, SIGILL, "execute exception", execute_exception, current)
-DO_ERROR(5, SIGSEGV, "addressing exception", addressing_exception, current)
-DO_ERROR(9, SIGFPE, "fixpoint divide exception", divide_exception, current)
-DO_ERROR(0x12, SIGILL, "translation exception", translation_exception, current)
-DO_ERROR(0x13, SIGILL, "special operand exception", special_op_exception, current)
-DO_ERROR(0x15, SIGILL, "operand exception", operand_exception, current)
-
-/* need to define
-DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current)
-DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current)
-DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current)
-DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current)
-DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
-DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
-DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
-*/
-
-#ifdef CONFIG_IEEEFPU_EMULATION
+DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler);
+DO_ERROR(SIGILL, "privileged operation", privileged_op)
+DO_ERROR(SIGILL, "execute exception", execute_exception)
+DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
+DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception)
+DO_ERROR(SIGILL, "translation exception", translation_exception)
+DO_ERROR(SIGILL, "special operand exception", special_op_exception)
+DO_ERROR(SIGILL, "operand exception", operand_exception)
-asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
+asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
__u16 *location;
if(do_debugger_trap(regs,SIGTRAP))
do_sig=1;
}
+#ifdef CONFIG_IEEEFPU_EMULATION
else if (problem_state )
{
if (opcode[0] == 0xb3) {
do_sig = math_emu_lfpc(opcode, regs);
} else
do_sig = 1;
- } else
- do_sig = 1;
- if (do_sig) {
- if (check_for_fixup(regs) == 0) {
- current->tss.error_code = error_code;
- current->tss.trap_no = 1;
- force_sig(SIGILL, current);
- die("illegal operation", regs, error_code);
- }
}
+#endif
+ else
+ do_sig = 1;
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "illegal operation", regs);
unlock_kernel();
}
-asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
+
+
+#ifdef CONFIG_IEEEFPU_EMULATION
+asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
__u16 *location;
get_user(*((__u16 *) opcode), location);
switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */
- math_emu_ldr(opcode);
+ do_sig=math_emu_ldr(opcode);
break;
case 0x38: /* LER Rx,Ry */
- math_emu_ler(opcode);
+ do_sig=math_emu_ler(opcode);
break;
case 0x60: /* STD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_std(opcode, regs);
+ do_sig=math_emu_std(opcode, regs);
break;
case 0x68: /* LD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ld(opcode, regs);
+ do_sig=math_emu_ld(opcode, regs);
break;
case 0x70: /* STE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ste(opcode, regs);
+ do_sig=math_emu_ste(opcode, regs);
break;
case 0x78: /* LE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_le(opcode, regs);
+ do_sig=math_emu_le(opcode, regs);
break;
default:
do_sig = 1;
}
} else
do_sig = 1;
- if (do_sig) {
- if (check_for_fixup(regs) == 0) {
- current->tss.error_code = error_code;
- current->tss.trap_no = 1;
- force_sig(SIGILL, current);
- die("illegal operation", regs, error_code);
- }
- }
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "specification exception", regs);
unlock_kernel();
}
+#else
+DO_ERROR(SIGILL, "specification exception", specification_exception)
+#endif
-asmlinkage void data_exception(struct pt_regs * regs, long error_code)
+asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
__u16 *location;
int do_sig = 0;
lock_kernel();
- location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
if(MACHINE_HAS_IEEE)
{
__asm__ volatile ("stfpc %0\n\t"
(addr_t)ADDR_BITS_REMOVE((addr_t)location);
force_sig(SIGFPE, current);
}
+#ifdef CONFIG_IEEEFPU_EMULATION
else if ((regs->psw.mask & 0x00010000L))
{
get_user(*((__u16 *) opcode), location);
switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */
- math_emu_ldr(opcode);
+ do_sig=math_emu_ldr(opcode);
break;
case 0x38: /* LER Rx,Ry */
- math_emu_ler(opcode);
+ do_sig=math_emu_ler(opcode);
break;
case 0x60: /* STD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_std(opcode, regs);
+ do_sig=math_emu_std(opcode, regs);
break;
case 0x68: /* LD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ld(opcode, regs);
+ do_sig=math_emu_ld(opcode, regs);
break;
case 0x70: /* STE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ste(opcode, regs);
+ do_sig=math_emu_ste(opcode, regs);
break;
case 0x78: /* LE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_le(opcode, regs);
+ do_sig=math_emu_le(opcode, regs);
break;
case 0xb3:
get_user(*((__u16 *) (opcode+2)), location+1);
break;
}
}
+#endif
else
do_sig = 1;
- if (do_sig) {
- if (check_for_fixup(regs) == 0) {
- current->tss.error_code = error_code;
- current->tss.trap_no = 7;
- force_sig(SIGILL, current);
- die("data exception", regs, error_code);
- }
- }
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "data exception", regs);
unlock_kernel();
}
-#else
-DO_ERROR(1, SIGILL, "illegal operation", illegal_op, current)
-DO_ERROR(6, SIGILL, "specification exception", specification_exception, current)
-DO_ERROR(7, SIGILL, "data exception", data_exception, current)
-#endif /* CONFIG_IEEEFPU_EMULATION */
/* init is done in lowcore.S and head.S */
/* I've seen this possibly a task structure being reused ? */
printk("Spurious per exception detected\n");
printk("switching off per tracing for this task.\n");
- show_crashed_task_info();
+ show_regs(regs);
/* Hopefully switching off per tracing will help us survive */
regs->psw.mask &= ~PSW_PER_MASK;
}
endif
L_TARGET = lib.a
-L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o
+L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o
include $(TOPDIR)/Rules.make
* yield the megahertz number of the cpu. The important function
* is udelay and that is done using the tod clock. -- martin.
*/
- __asm__ __volatile__(
+ __asm__ __volatile__(
"0: brct %0,0b"
: /* no outputs */ : "r" (loops/2) );
}
--- /dev/null
+/*
+ * arch/s390/lib/uaccess.S
+ * fixup routines for copy_{from|to}_user functions.
+ *
+ * s390
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * These functions have a non-standard call interface
+ */
+
+#include <asm/lowcore.h>
+
+ .text
+ .align 4
+ .globl __copy_from_user_fixup
+__copy_from_user_fixup:
+ l 1,__LC_PGM_OLD_PSW+4
+ sll 4,1
+ srl 4,1
+0: lhi 3,-4096
+ sll 3,1
+ srl 3,1
+ n 3,__LC_TRANS_EXC_ADDR
+ sr 3,4
+ bm 4(1)
+1: mvcle 2,4,0
+ b 4(1)
+ .section __ex_table,"a"
+ .long 1b,0b
+ .previous
+
+ .align 4
+ .text
+ .globl __copy_to_user_fixup
+__copy_to_user_fixup:
+ l 1,__LC_PGM_OLD_PSW+4
+ sll 4,1
+ srl 4,1
+0: lhi 5,-4096
+ sll 5,1
+ srl 5,1
+ n 5,__LC_TRANS_EXC_ADDR
+ sr 5,4
+ bm 4(1)
+1: mvcle 4,2,0
+ b 4(1)
+ .section __ex_table,"a"
+ .long 1b,0b
+ .previous
+
int write;
unsigned long psw_mask;
unsigned long psw_addr;
+ int kernel_address = 0;
/*
* get psw mask of Program old psw to find out,
if (atomic_read(&S390_lowcore.local_irq_count))
die("page fault from irq handler",regs,error_code);
+ /*
+ * Check which address space the address belongs to
+ */
+ switch (S390_lowcore.trans_exc_code & 3)
+ {
+ case 0: /* Primary Segment Table Descriptor */
+ kernel_address = 1;
+ goto no_context;
+
+ case 1: /* STD determined via access register */
+ if (S390_lowcore.exc_access_id == 0)
+ {
+ kernel_address = 1;
+ goto no_context;
+ }
+ if (regs && S390_lowcore.exc_access_id < NUM_ACRS)
+ {
+ if (regs->acrs[S390_lowcore.exc_access_id] == 0)
+ {
+ kernel_address = 1;
+ goto no_context;
+ }
+ if (regs->acrs[S390_lowcore.exc_access_id] == 1)
+ {
+ /* user space address */
+ break;
+ }
+ }
+ die("page fault via unknown access register", regs, error_code);
+ break;
+
+ case 2: /* Secondary Segment Table Descriptor */
+ case 3: /* Home Segment Table Descriptor */
+ /* user space address */
+ break;
+ }
+
+
+ /*
+ * When we get here, the fault happened in the current
+ * task's user address space, so we search the VMAs
+ */
+
down(&mm->mmap_sem);
vma = find_vma(mm, address);
/* User mode accesses just cause a SIGSEGV */
if (psw_mask & PSW_PROBLEM_STATE) {
tsk->tss.prot_addr = address;
- tsk->tss.error_code = error_code;
- tsk->tss.trap_no = 14;
-
+ tsk->tss.trap_no = error_code;
+#ifdef CONFIG_PROCESS_DEBUG
printk("User process fault: interruption code 0x%lX\n",error_code);
printk("failing address: %lX\n",address);
- show_crashed_task_info();
+ show_regs(regs);
+#endif
force_sig(SIGSEGV, tsk);
return;
}
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
- *
- * First we check if it was the bootup rw-test, though..
*/
- if (address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+ if (kernel_address)
+ printk(KERN_ALERT "Unable to handle kernel pointer dereference"
+ " at virtual kernel address %08lx\n", address);
else
- printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at virtual address %08lx\n",address);
+ printk(KERN_ALERT "Unable to handle kernel paging request"
+ " at virtual user address %08lx\n", address);
/*
* need to define, which information is useful here
*/
*/
out_of_memory:
if (tsk->pid == 1)
- {
+ {
tsk->policy |= SCHED_YIELD;
schedule();
goto survive;
- }
+ }
up(&mm->mmap_sem);
if (psw_mask & PSW_PROBLEM_STATE)
{
printk("VM: killing process %s\n", tsk->comm);
do_exit(SIGKILL);
- }
+ }
goto no_context;
do_sigbus:
* or user mode.
*/
tsk->tss.prot_addr = address;
- tsk->tss.error_code = error_code;
- tsk->tss.trap_no = 14;
+ tsk->tss.trap_no = error_code;
force_sig(SIGBUS, tsk);
/* Kernel mode? Handle exceptions or die */
unsigned long tmp;
unsigned long address=0;
unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
+ static const int ssm_mask = 0x04000000L;
/* unmap whole virtual address space */
/* enable virtual mapping in kernel mode */
__asm__ __volatile__(" LCTL 1,1,%0\n"
" LCTL 7,7,%0\n"
- " LCTL 13,13,%0" : :"m" (pgdir_k));
+ " LCTL 13,13,%0\n"
+ " SSM %1"
+ : : "m" (pgdir_k), "m" (ssm_mask));
local_flush_tlb();
-.TH DASDFMT 8 "Tue Jan 25 2000"
-.UC 4
-.SH NAME
-dasdfmt \- formatting of DSAD (ECKD) disk drives.
-.SH SYNOPSIS
+.TH DASDFMT 8 "Tue Jan 25 2000"\r
+.UC 4\r
+.SH NAME\r
+dasdfmt \- formatting of DSAD (ECKD) disk drives.\r
+.SH SYNOPSIS\r
\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR\r
-.SH DESCRIPTION
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
-for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
-\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
-
-.SH OPTIONS
-.TP
-\fB-t\fR
-Disables any modification of the disk drive. \fBdasdfmt\fR just prints
-out, what it \fBwould\fR do.
-
-.TP
-\fB-v\fR
-Increases verbosity.
-
-.TP
-\fB-y\fR
-Start formatting without further user-confirmation.
-
-.TP
+.SH DESCRIPTION\r
+\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it\r
+for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of\r
+\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.\r
+\r
+.SH OPTIONS\r
+.TP\r
+\fB-t\fR\r
+Disables any modification of the disk drive. \fBdasdfmt\fR just prints\r
+out, what it \fBwould\fR do.\r
+\r
+.TP\r
+\fB-v\fR\r
+Increases verbosity.\r
+\r
+.TP\r
+\fB-y\fR \r
+Start formatting without further user-confirmation.\r
+\r
+.TP\r
\fB-L\fR \r
Omit the writing of a disk label after formatting.\r
\r
.TP\r
-\fB-V\fR
-Print version number and exit.
-
-.TP
-\fB-b\fR \fIblockSize\fR
-Specify blocksize to be used. \fIblocksize\fR must be a positive integer
-and always be a power of two. Due due some limitations in the driver,
-it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
-
-.TP
+\fB-V\fR \r
+Print version number and exit.\r
+\r
+.TP\r
+\fB-b\fR \fIblockSize\fR\r
+Specify blocksize to be used. \fIblocksize\fR must be a positive integer\r
+and always be a power of two. Due due some limitations in the driver,\r
+it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.\r
+\r
+.TP\r
\fB-l\fR \fIdiskLabel\fR\r
Specify the label to be written to disk after formatting. If no label is\r
specified, a sensible default is used. \fIdiskLabel\fR is interpreted as\r
ASCII string and is automatically converted to EBCDIC.\r
-
-.TP
-\fIdiskSpec\fR
-This parameter specified the device to be formatted. It also can be
-given in two variants:
-.sp
+\r
+.TP\r
+\fIdiskSpec\fR\r
+This parameter specified the device to be formatted. It also can be\r
+given in two variants:\r
+.sp\r
\fB-f\fR \fB/dev/dasd\fR\fIX\fR\r
-.br
-or
-.br
- \fB-n\fR \fIdevnum\fR
-.sp
-The first form uses the commonly used
-.SM UNIX
-device notation where \fIX\fR is a single lowercase letter.
+.br\r
+or\r
+.br\r
+ \fB-n\fR \fIdevnum\fR\r
+.sp\r
+The first form uses the commonly used\r
+.SM UNIX\r
+device notation where \fIX\fR is a single lowercase letter.\r
The second form uses simply the device number.\r
-
-.SH BUGS
-None so far ;-)
-
-.SH AUTHOR
-.nf
-This man-page was written by Fritz Elfert <felfert@to.com>
-.fi
+\r
+.SH BUGS\r
+None so far ;-)\r
+\r
+.SH AUTHOR\r
+.nf\r
+This man-page was written by Fritz Elfert <felfert@to.com>\r
+.fi\r
void
do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
int verbosity,int writenolabel,int labelspec,
- char *label,int withoutprompt)
+ char *label,int withoutprompt,int devno)
{
int fd,rc;
struct stat stat_buf;
kdev_t minor_no,major_no;
- int devno;
int new_blksize;
unsigned int label_position;
struct hd_geometry new_geometry;
minor_no=MINOR(stat_buf.st_rdev);
}
check_mounted(major_no, minor_no);
-
+
if ((!writenolabel) && (!labelspec)) {
sprintf(label,"LNX1 x%04x",devno);
}
endptr=NULL;
/* set default values */
- format_params.start_unit=0;
- format_params.stop_unit=-1;
- format_params.blksize=4096;
+ format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
+ format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
+ format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
+ format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
testmode=0;
verbosity=0;
withoutprompt=0;
/******* issue the real command and reread part table *******/
do_format_dasd(dev_name,format_params,testmode,verbosity,
- writenolabel,labelspec,label,withoutprompt);
+ writenolabel,labelspec,label,withoutprompt,devno);
/*************** cleanup ********************************/
if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
--- /dev/null
+CROSS_COMPILE = s390-
+
+hwc_measure: hwc_measure.c
+ $(CROSS_COMPILE)gcc -o $@ $^
+
+hwc_cntl_key: hwc_cntl_key.c
+ $(CROSS_COMPILE)gcc -o $@ $^
+
+clean:
+ rm -f hwc_measure
+ rm -f hwc_cntl_key
+
--- /dev/null
+/*
+ * small application to set string that will be used as CNTL-C
+ * employing a HWC terminal ioctl command
+ *
+ * returns: number of written or read characters
+ *
+ * Copyright (C) 2000 IBM Corporation
+ * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+/* everything about the HWC terminal driver ioctl-commands */
+#include "../../../../drivers/s390/char/hwc_tty.h"
+
+/* standard input, should be our HWC tty */
+#define DESCRIPTOR 0
+
+int main(int argc, char *argv[], char *env[])
+{
+ unsigned char buf[HWC_TTY_MAX_CNTL_SIZE];
+
+ if (argc >= 2) {
+ if (strcmp(argv[1], "c") == 0 ||
+ strcmp(argv[1], "C") == 0 ||
+ strcmp(argv[1], "INTR_CHAR") == 0) {
+ if (argc == 2) {
+ ioctl(DESCRIPTOR, TIOCHWCTTYGINTRC, buf);
+ printf("%s\n", buf);
+ return strlen(buf);
+ } else return ioctl(DESCRIPTOR, TIOCHWCTTYSINTRC, argv[2]);
+// currently not yet implemented in HWC terminal driver
+#if 0
+ } else if (strcmp(argv[1], "d") == 0 ||
+ strcmp(argv[1], "D") == 0 ||
+ strcmp(argv[1], "EOF_CHAR") == 0) {
+ if (argc == 2) {
+ ioctl(DESCRIPTOR, TIOCHWCTTYGEOFC, buf);
+ printf("%s\n", buf);
+ return strlen(buf);
+ } else return ioctl(DESCRIPTOR, TIOCHWCTTYSEOFC, argv[2]);
+ } else if (strcmp(argv[1], "z") == 0 ||
+ strcmp(argv[1], "Z") == 0 ||
+ strcmp(argv[1], "SUSP_CHAR") == 0) {
+ if (argc == 2) {
+ ioctl(DESCRIPTOR, TIOCHWCTTYGSUSPC, buf);
+ printf("%s\n", buf);
+ return strlen(buf);
+ } else return ioctl(DESCRIPTOR, TIOCHWCTTYSSUSPC, argv[2]);
+ } else if (strcmp(argv[1], "n") == 0 ||
+ strcmp(argv[1], "N") == 0 ||
+ strcmp(argv[1], "NEW_LINE") == 0) {
+ if (argc == 2) {
+ ioctl(DESCRIPTOR, TIOCHWCTTYGNL, buf);
+ printf("%s\n", buf);
+ return strlen(buf);
+ } else return ioctl(DESCRIPTOR, TIOCHWCTTYSNL, argv[2]);
+#endif
+ }
+ }
+
+ printf("usage: hwc_cntl_key <control-key> [<new string>]\n");
+ printf(" <control-key> ::= \"c\" | \"C\" | \"INTR_CHAR\" |\n");
+ printf(" \"d\" | \"D\" | \"EOF_CHAR\" |\n");
+ printf(" \"z\" | \"Z\" | \"SUSP_CHAR\" |\n");
+ printf(" \"n\" | \"N\" | \"NEW_LINE\"\n");
+ return -1;
+}
--- /dev/null
+/*
+ * small application for HWC measurement
+ *
+ * Copyright (C) 2000 IBM Corporation
+ * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+/* everything about the HWC low level driver ioctl-commands */
+#include "../../../../drivers/s390/char/hwc_rw.h"
+
+/* standard input, should be our HWC tty */
+#define DESCRIPTOR 0
+
+int main(int argc, char *argv[], char *env[])
+{
+ ioctl_meas_t measured = 0;
+ signed int retval = 0;
+
+ if (argc = 2) {
+
+ if (strcmp(argv[1], "lines") == 0) {
+ retval = ioctl(DESCRIPTOR, TIOCHWCGMEASL,
+ &measured);
+ if (retval < 0)
+ return errno;
+ else {
+ printf("%ld\n", measured);
+ return retval;
+ }
+ }
+
+ if (strcmp(argv[1], "chars") == 0) {
+ retval = ioctl(DESCRIPTOR, TIOCHWCGMEASC,
+ &measured);
+ if (retval < 0)
+ return errno;
+ else {
+ printf("%ld\n", measured);
+ return retval;
+ }
+ }
+
+ if (strcmp(argv[1], "wcalls") == 0) {
+ retval = ioctl(DESCRIPTOR, TIOCHWCGMEASS,
+ &measured);
+ if (retval < 0)
+ return errno;
+ else {
+ printf("%ld\n", measured);
+ return retval;
+ }
+ }
+
+ if (strcmp(argv[1], "reset") == 0) {
+ retval = ioctl(DESCRIPTOR, TIOCHWCSMEAS);
+ if (retval < 0)
+ return errno;
+ else return retval;
+ }
+ }
+
+ printf("usage:\n");
+ printf(" hwc_measure lines "
+ "(prints # of measured lines) or\n");
+ printf(" hwc_measure_chars "
+ "(prints # of measured characters) or\n");
+ printf(" hwc_measure wcalls "
+ "(prints # of measured write calls to HWC interface) or\n");
+ printf(" hwc_measure reset "
+ "(resets measurement counters)\n");
+
+ return -1;
+}
+
+++ /dev/null
-CROSS_COMPILE = s390-
-
-all: hwc_cntl_key
-
-hwc_cntl_key: hwc_cntl_key.c
- $(CROSS_COMPILE)gcc -o $@ $^
- $(STRIP) $@
-
-clean:
- rm -f hwc_cntl_key.c
-
+++ /dev/null
-/*
- * small application to set string that will be used as CNTL-C
- * employing a HWC terminal ioctl command
- *
- * returns: number of written or read characters
- *
- * Copyright (C) 2000 IBM Corporation
- * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
- */
-
-#include <string.h>
-#include <stdio.h>
-
-/* everything about the HWC terminal driver ioctl-commands */
-#include "../../../../drivers/s390/char/hwc_tty.h"
-
-/* standard input, should be our HWC tty */
-#define DESCRIPTOR 0
-
-int main(int argc, char *argv[], char *env[])
-{
- unsigned char buf[HWC_TTY_MAX_CNTL_SIZE];
-
- if (argc >= 2) {
- if (strcmp(argv[1], "c") == 0 ||
- strcmp(argv[1], "C") == 0 ||
- strcmp(argv[1], "INTR_CHAR") == 0) {
- if (argc == 2) {
- ioctl(DESCRIPTOR, TIOCHWCTTYGINTRC, buf);
- printf("%s\n", buf);
- return strlen(buf);
- } else return ioctl(DESCRIPTOR, TIOCHWCTTYSINTRC, argv[2]);
-// currently not yet implemented in HWC terminal driver
-#if 0
- } else if (strcmp(argv[1], "d") == 0 ||
- strcmp(argv[1], "D") == 0 ||
- strcmp(argv[1], "EOF_CHAR") == 0) {
- if (argc == 2) {
- ioctl(DESCRIPTOR, TIOCHWCTTYGEOFC, buf);
- printf("%s\n", buf);
- return strlen(buf);
- } else return ioctl(DESCRIPTOR, TIOCHWCTTYSEOFC, argv[2]);
- } else if (strcmp(argv[1], "z") == 0 ||
- strcmp(argv[1], "Z") == 0 ||
- strcmp(argv[1], "SUSP_CHAR") == 0) {
- if (argc == 2) {
- ioctl(DESCRIPTOR, TIOCHWCTTYGSUSPC, buf);
- printf("%s\n", buf);
- return strlen(buf);
- } else return ioctl(DESCRIPTOR, TIOCHWCTTYSSUSPC, argv[2]);
- } else if (strcmp(argv[1], "n") == 0 ||
- strcmp(argv[1], "N") == 0 ||
- strcmp(argv[1], "NEW_LINE") == 0) {
- if (argc == 2) {
- ioctl(DESCRIPTOR, TIOCHWCTTYGNL, buf);
- printf("%s\n", buf);
- return strlen(buf);
- } else return ioctl(DESCRIPTOR, TIOCHWCTTYSNL, argv[2]);
-#endif
- }
- }
-
- printf("usage: hwc_cntl_key <control-key> [<new string>]\n");
- printf(" <control-key> ::= \"c\" | \"C\" | \"INTR_CHAR\" |\n");
- printf(" \"d\" | \"D\" | \"EOF_CHAR\" |\n");
- printf(" \"z\" | \"Z\" | \"SUSP_CHAR\" |\n");
- printf(" \"n\" | \"N\" | \"NEW_LINE\"\n");
- return -1;
-}
if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp)
o->parmfile = tmp;
if ( ! o -> ramdisk )
- o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
+ o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
tmp = cfg_get_strg(cf_options, "bootsect");
if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp)
o->bootsect = tmp;
return pfile;
of = fopen(pfile, "r");
if ( of ) {
- NTRY( fn = tempnam(NULL,"parm."));
+ NTRY( fn = tempnam(NULL,"parm."));
} else {
fn = pfile;
}
}
}
if (root)
- fprintf(f, "root=%s ", root);
+ fprintf(f, " root=%s", root);
if (ro)
- fprintf(f, "ro ");
+ fprintf(f, " ro");
if (append)
- fprintf(f, "%s", append);
+ fprintf(f, " %s", append);
fprintf(f, "\n");
fclose(f);
fclose(of);
int bs = 1024;
int l;
- ITRY (stat (name, &dst));
+ ITRY(stat ( name, &dst ));
if (S_ISREG (dst.st_mode))
{
if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
PRINT_LEVEL (1, "...ok...");
o->parmfile = gen_tmpparm(o->parmfile);
PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile);
- ITRY (verify_file (o->parmfile, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
+ ITRY (verify_file (o->parmfile, dev));
+ PRINT_LEVEL (1, "...ok...");
+ PRINT_LEVEL (0, "\n");
if (o->ramdisk)
{
int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
if ( o->testlevel <= 1 ) {
- NTRY (write (s_fd, &offset, sizeof (int)));
- NTRY (write (s_fd, &addrct, sizeof (int)));
- }
+ NTRY (write (s_fd, &offset, sizeof (int)));
+ NTRY (write (s_fd, &addrct, sizeof (int)));
+ }
}
ITRY (ioctl (s_fd,FIGETBSZ, &bs));
ITRY (stat (o->bootmap, &s_st));
NTRY ( tmpdev = tmpnam(NULL) );
ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
ITRY (bd_fd = open (tmpdev, O_RDONLY));
- ITRY ( ioctl(s_fd,FIBMAP,&boots));
+ ITRY (ioctl(s_fd,FIBMAP,&boots));
ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
close (bd_fd);
-/* $Id: ioctl32.c,v 1.62.2.16 2000/09/05 00:10:54 davem Exp $
+/* $Id: ioctl32.c,v 1.62.2.17 2000/11/08 09:43:04 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
case ENVCTRL_RD_ETHERNET_TEMPERATURE:
case ENVCTRL_RD_MTHRBD_TEMPERATURE:
case ENVCTRL_RD_CPU_VOLTAGE:
+ case ENVCTRL_RD_GLOBALADDRESS:
case D7SIOCWR:
/* case D7SIOCRD: Same value as ENVCTRL_RD_VOLTAGE_STATUS */
case D7SIOCTM:
MOD_SUB_DIRS += video
endif
-ifdef CONFIG_PPC
+ifdef CONFIG_POWERMAC
SUB_DIRS += macintosh
MOD_SUB_DIRS += macintosh
endif
bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
fi
fi
- if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+ if [ "$CONFIG_POWERMAC" = "y" ]; then
bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
#include <linux/blk.h>
#include <linux/init.h>
+#ifdef CONFIG_ARCH_S390
+#include <asm/dasd.h>
+#endif /* CONFIG_ARCH_S390 */
+
#include <asm/system.h>
#include <asm/byteorder.h>
extern int net_dev_init(void);
#ifdef CONFIG_PPC
-extern void note_bootable_part(kdev_t dev, int part);
+extern void note_bootable_part(kdev_t dev, int part, int goodness);
#endif
static char *raid_name (struct gendisk *hd, int minor, int major_base,
return buf;
}
+#ifdef CONFIG_ARCH_S390
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+#endif
+
/*
* disk_name() is used by genhd.c and md.c.
* It formats the devicename of the indicated disk
const char *maj = hd->major_name;
int unit = (minor >> hd->minor_shift) + 'a';
+#ifdef CONFIG_ARCH_S390
+ if ( strncmp ( hd->major_name,"dasd",4) == 0 ){
+ part = minor & ((1 << hd->minor_shift) - 1);
+ if ( genhd_dasd_name )
+ genhd_dasd_name(buf,minor>>hd->minor_shift,part,hd);
+ return buf;
+ }
+#endif
/*
* IDE devices use multiple major numbers, but the drives
* are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
goodness++;
if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0
- || strcasecmp(part->type, "Linux_PPC") == 0) {
+ || (strnicmp(part->type, "Linux", 5) == 0
+ && strcasecmp(part->type, "Linux_swap") != 0)) {
int i, l;
goodness++;
}
#ifdef CONFIG_PPC
if (found_root_goodness)
- note_bootable_part(dev, found_root);
+ note_bootable_part(dev, found_root, found_root_goodness);
#endif
brelse(bh);
printk("\n");
#endif /* CONFIG_ULTRIX_PARTITION */
#ifdef CONFIG_ARCH_S390
+#include <linux/malloc.h>
+#include <linux/hdreg.h>
+#include <linux/ioctl.h>
#include <asm/ebcdic.h>
-#include "../s390/block/dasd_types.h"
-
-dasd_information_t **dasd_information = NULL;
+#include <asm/uaccess.h>
typedef enum {
ibm_partition_none = 0,
ibm_partition_t partition_type;
char type[5] = {0,};
char name[7] = {0,};
- int di = MINOR(dev) >> hd->minor_shift;
- if ( ! get_ptable_blocksize(dev) )
+ struct hd_geometry geo;
+ mm_segment_t old_fs;
+ int blocksize;
+ struct file *filp = NULL;
+ struct inode *inode = NULL;
+ int offset, size;
+ int rc;
+
+ blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
+ if ( blocksize <= 0 ) {
return 0;
- if ( ! dasd_information )
+ }
+ set_blocksize(dev, blocksize); /* OUCH !! */
+
+ /* find out offset of volume label (partn table) */
+ filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
+ if ( filp == NULL ) {
+ printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed for filp\n");
+ return 0;
+ }
+ memset(filp,0,sizeof(struct file));
+ filp ->f_mode = 1; /* read only */
+ inode = get_empty_inode();
+ inode -> i_rdev = dev;
+ rc = blkdev_open(inode,filp);
+ if ( rc ) {
+ return 0;
+ }
+ old_fs=get_fs();
+ set_fs(KERNEL_DS);
+ rc = filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo));
+ set_fs(old_fs);
+ if ( rc ) {
return 0;
- if ( ( bh = bread( dev,
- dasd_information[di]->sizes.label_block,
- dasd_information[di]->sizes.bp_sector ) ) != NULL ) {
+ }
+ blkdev_release(inode);
+
+ size = hd -> sizes[MINOR(dev)]<<1;
+ if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) {
strncpy ( type,bh -> b_data, 4);
strncpy ( name,bh -> b_data + 4, 6);
} else {
EBCASC(name,6);
}
switch ( partition_type = get_partition_type(type) ) {
- case ibm_partition_lnx1:
+ case ibm_partition_lnx1:
+ offset = (geo.start + 1);
printk ( "(LNX1)/%6s:",name);
- add_partition( hd, MINOR(dev) + 1,
- (dasd_information[di]->sizes.label_block + 1) <<
- dasd_information[di]->sizes.s2b_shift,
- (dasd_information [di]->sizes.blocks -
- dasd_information[di]->sizes.label_block - 1) <<
- dasd_information[di]->sizes.s2b_shift,0 );
break;
case ibm_partition_vol1:
+ offset = 0;
+ size = 0;
printk ( "(VOL1)/%6s:",name);
break;
case ibm_partition_cms1:
printk ( "(CMS1)/%6s:",name);
if (* (((long *)bh->b_data) + 13) == 0) {
/* disk holds a CMS filesystem */
- add_partition( hd, MINOR(dev) + 1,
- (dasd_information [di]->sizes.label_block + 1) <<
- dasd_information [di]->sizes.s2b_shift,
- (dasd_information [di]->sizes.blocks -
- dasd_information [di]->sizes.label_block) <<
- dasd_information [di]->sizes.s2b_shift,0 );
+ offset = (geo.start + 1);
printk ("(CMS)");
} else {
- /* disk is reserved minidisk */
- long *label=(long*)bh->b_data;
- int offset = label[13];
- int size = (label[7]-1-label[13])*(label[3]>>9);
- add_partition( hd, MINOR(dev) + 1,
- offset << dasd_information [di]->sizes.s2b_shift,
- size<<dasd_information [di]->sizes.s2b_shift,0 );
+ /* disk is reserved minidisk */
+ // mdisk_setup_data.size[i] =
+ // (label[7] - 1 - label[13]) *
+ // (label[3] >> 9) >> 1;
+ long *label=(long*)bh->b_data;
+ blocksize = label[3];
+ offset = label[13];
+ size = (label[7]-1)*(blocksize>>9);
printk ("(MDSK)");
}
break;
case ibm_partition_none:
printk ( "(nonl)/ :");
- add_partition( hd, MINOR(dev) + 1,
- (dasd_information [di]->sizes.label_block + 1) <<
- dasd_information [di]->sizes.s2b_shift,
- (dasd_information [di]->sizes.blocks -
- dasd_information [di]->sizes.label_block - 1) <<
- dasd_information [di]->sizes.s2b_shift,0 );
+ offset = (geo.start+1);
break;
+ default:
+ offset = 0;
+ size = 0;
+
}
+ add_partition( hd, MINOR(dev), 0,size,0);
+ add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9),
+ size-offset*(blocksize>>9) ,0 );
printk ( "\n" );
bforget(bh);
return 1;
dev->part[i].start_sect = 0;
dev->part[i].nr_sects = 0;
}
- dev->init(dev);
+ if ( dev->init != NULL )
+ dev->init(dev);
for (drive = 0 ; drive < dev->nr_real ; drive++) {
int first_minor = drive << dev->minor_shift;
current_minor = 1 + first_minor;
- check_partition(dev, MKDEV(dev->major, first_minor));
+ /* If we really have a device check partition table */
+ if ( blksize_size[dev->major] == NULL ||
+ blksize_size[dev->major][current_minor])
+ check_partition(dev, MKDEV(dev->major, first_minor));
}
if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */
- for (i = 0; i < end_minor; i++)
+ for (i = 0; i < end_minor; i++)
dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9);
blk_size[dev->major] = dev->sizes;
}
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/cdrom.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/dbdma.h>
/* allow up to 256 DBDMA commands per xfer */
#define MAX_DCMDS 256
-/* Wait 1.5s for disk to answer on IDE bus after
+/* Wait 2s for disk to answer on IDE bus after
* enable operation.
* NOTE: There is at least one case I know of a disk that needs about 10sec
* before anwering on the bus. I beleive we could add a kernel command
* line arg to override this delay for such cases.
*/
-#define IDE_WAKEUP_DELAY_MS 1500
-#define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */
+#define IDE_WAKEUP_DELAY_MS 2000
+#define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */
static void pmac_ide_setup_dma(struct device_node *np, int ix);
static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive);
*/
feature_set(np, FEATURE_IDE0_enable);
feature_set(np, FEATURE_IOBUS_enable);
+ big_delay = 1; /* Poor old machines with crappy disks */
} else {
/* This is necessary to enable IDE when net-booting */
printk("pmac_ide: enabling IDE bus ID %d\n", pmac_ide[i].aapl_bus_id);
static __inline__ int
wait_for_ready(ide_drive_t *drive)
{
- /* Timeout bumped for some powerbooks */
- int timeout = 2000;
+ /* Timeout bumped (again) for some powerbooks with old disks */
+ int timeout = 10000;
byte stat;
while(--timeout) {
stat = GET_STAT();
- if(!(stat & BUSY_STAT)) {
+ if (!(stat & BUSY_STAT)) {
if (drive->ready_stat == 0)
break;
else if((stat & drive->ready_stat) || (stat & ERR_STAT))
old_select = IN_BYTE(IDE_SELECT_REG);
OUT_BYTE(drive->select.all, IDE_SELECT_REG);
udelay(10);
- OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);
- OUT_BYTE(command, IDE_NSECTOR_REG);
if(wait_for_ready(drive)) {
printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n");
goto out;
}
+ OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG);
+#if 0
+ /* That one cause the wallstreet to freeze, I don't know why yet. We'll have to leave with
+ * the bogus interrupt until I figure out what's up
+ */
+ /* Better not leave a dangling interrupt */
+ OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);
+#endif
+ OUT_BYTE(command, IDE_NSECTOR_REG);
OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG);
+ udelay(10);
result = wait_for_ready(drive);
if (result)
printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n");
+ /* May help kill the bogus interrupt */
+ mdelay(1);
+ (void)GET_STAT();
out:
OUT_BYTE(old_select, IDE_SELECT_REG);
restore_flags(flags);
-
+
return result;
}
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
#ifdef CONFIG_PMAC_PBOOK
-static void idepmac_sleep_disk(int i, unsigned long base)
+static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base)
{
- struct device_node* np = pmac_ide[i].node;
int j;
-
- /* FIXME: We only handle the master IDE */
- if (ide_hwifs[i].drives[0].media == ide_disk) {
+
+ /* FIXME: We only handle the master IDE disk, we shoud
+ * try to fix CD-ROMs here
+ */
+ switch (drive->media) {
+ case ide_disk:
/* Spin down the drive */
outb(0xa0, base+0x60);
outb(0x0, base+0x30);
if (!(status & BUSY_STAT) && (status & DRQ_STAT))
break;
}
- }
- feature_set(np, FEATURE_IDE0_reset);
- feature_clear(np, FEATURE_IDE0_enable);
- switch(pmac_ide[i].aapl_bus_id) {
- case 0:
- feature_set(np, FEATURE_IDE0_reset);
- feature_clear(np, FEATURE_IDE0_enable);
break;
- case 1:
- feature_set(np, FEATURE_IDE1_reset);
- feature_clear(np, FEATURE_IDE1_enable);
+ case ide_cdrom:
+ // todo
break;
- case 2:
- feature_set(np, FEATURE_IDE2_reset);
+ case ide_floppy:
+ // todo
break;
}
- pmac_ide[i].timings[0] = 0;
- pmac_ide[i].timings[1] = 0;
}
-static void idepmac_wake_disk(int i, unsigned long base)
+static void idepmac_wake_device(ide_drive_t *drive, int used_dma)
+ {
+ unsigned long flags;
+
+ /* We force the IDE subdriver to check for a media change
+ * This must be done first or we may lost the condition
+ *
+ * Problem: This can schedule. I moved the block device
+ * wakeup almost late by priority because of that.
+ */
+ DRIVER(drive)->media_change(drive);
+
+ /* We kick the VFS too (see fix in ide.c revalidate) */
+ check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
+
+#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+ /* We re-enable DMA on the drive if it was active. */
+ /* This doesn't work with the CD-ROM in the media-bay, probably
+ * because of a pending unit attention. The problem if that if I
+ * clear the error, the filesystem dies.
+ */
+ if (used_dma && !ide_spin_wait_hwgroup(drive, &flags)) {
+ /* Lock HW group */
+ HWGROUP(drive)->busy = 1;
+ pmac_ide_dma_onoff(drive, 1);
+ HWGROUP(drive)->busy = 0;
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
+#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
+}
+
+static void idepmac_sleep_interface(int i, unsigned base, int mediabay)
{
struct device_node* np = pmac_ide[i].node;
- int j;
- /* Revive IDE disk and controller */
+ /* We clear the timings */
+ pmac_ide[i].timings[0] = 0;
+ pmac_ide[i].timings[1] = 0;
+
+ /* The media bay will handle itself just fine */
+ if (mediabay)
+ return;
+
+ /* Disable and reset the bus */
+ feature_set(np, FEATURE_IDE0_reset);
+ feature_clear(np, FEATURE_IDE0_enable);
switch(pmac_ide[i].aapl_bus_id) {
case 0:
feature_set(np, FEATURE_IDE0_reset);
- feature_set(np, FEATURE_IOBUS_enable);
- mdelay(10);
- feature_set(np, FEATURE_IDE0_enable);
- mdelay(10);
- feature_clear(np, FEATURE_IDE0_reset);
+ feature_clear(np, FEATURE_IDE0_enable);
break;
case 1:
feature_set(np, FEATURE_IDE1_reset);
- feature_set(np, FEATURE_IOBUS_enable);
- mdelay(10);
- feature_set(np, FEATURE_IDE1_enable);
- mdelay(10);
- feature_clear(np, FEATURE_IDE1_reset);
+ feature_clear(np, FEATURE_IDE1_enable);
break;
case 2:
- /* This one exists only for KL, I don't know
- about any enable bit */
feature_set(np, FEATURE_IDE2_reset);
- mdelay(10);
- feature_clear(np, FEATURE_IDE2_reset);
break;
}
- mdelay(IDE_WAKEUP_DELAY_MS);
-
- /* Reset timings */
- pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
- mdelay(10);
-
- /* Wait up to 10 seconds (enough for recent drives) */
- for (j = 0; j < 100; j++) {
- int status;
- mdelay(100);
- status = inb(base + 0x70);
- if (!(status & BUSY_STAT))
- break;
- }
}
-/* Here we handle media bay devices */
-static void
-idepmac_wake_bay(int i, unsigned long base)
+static void idepmac_wake_interface(int i, unsigned long base, int mediabay)
{
- int timeout;
+ struct device_node* np = pmac_ide[i].node;
+ if (!mediabay) {
+ /* Revive IDE disk and controller */
+ switch(pmac_ide[i].aapl_bus_id) {
+ case 0:
+ feature_set(np, FEATURE_IDE0_reset);
+ feature_set(np, FEATURE_IOBUS_enable);
+ mdelay(10);
+ feature_set(np, FEATURE_IDE0_enable);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE0_reset);
+ break;
+ case 1:
+ feature_set(np, FEATURE_IDE1_reset);
+ feature_set(np, FEATURE_IOBUS_enable);
+ mdelay(10);
+ feature_set(np, FEATURE_IDE1_enable);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE1_reset);
+ break;
+ case 2:
+ /* This one exists only for KL, I don't know
+ about any enable bit */
+ feature_set(np, FEATURE_IDE2_reset);
+ mdelay(10);
+ feature_clear(np, FEATURE_IDE2_reset);
+ break;
+ }
+ }
+
/* Reset timings */
pmac_ide_selectproc(&ide_hwifs[i].drives[0]);
mdelay(10);
-
- timeout = 10000;
- while ((inb(base + 0x70) & BUSY_STAT) && timeout) {
- mdelay(1);
- --timeout;
- }
}
/* Note: We support only master drives for now. This will have to be
* improved if we want to handle sleep on the iMacDV where the CD-ROM
* is a slave
*/
+
static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when)
{
int i, ret;
unsigned long base;
-
+ unsigned long flags;
+ int big_delay;
+
switch (when) {
case PBOOK_SLEEP_REQUEST:
break;
break;
case PBOOK_SLEEP_NOW:
for (i = 0; i < pmac_ide_count; ++i) {
+ ide_hwif_t *hwif;
+ ide_drive_t *drive;
+ int unlock = 0;
+
if ((base = pmac_ide[i].regbase) == 0)
- continue;
+ continue;
+
+ hwif = &ide_hwifs[i];
+ drive = &hwif->drives[0];
+
+ if (drive->present) {
+ /* Wait for HW group to complete operations */
+ if (ide_spin_wait_hwgroup(drive, &flags)) {
+ // What can we do here ? Wake drive we had already
+ // put to sleep and return an error ?
+ } else {
+ unlock = 1;
+ /* Lock HW group */
+ HWGROUP(drive)->busy = 1;
+
+ /* Stop the device */
+ idepmac_sleep_device(drive, i, base);
+
+ }
+ }
/* Disable irq during sleep */
- disable_irq(pmac_ide[i].irq);
+ disable_irq(pmac_ide[i].irq);
+ if (unlock)
+ spin_unlock_irqrestore(&io_request_lock, flags);
+
+ /* Check if this is a media bay with an IDE device or not
+ * a media bay.
+ */
ret = check_media_bay_by_base(base, MB_CD);
- if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
- /* not media bay - put the disk to sleep */
- idepmac_sleep_disk(i, base);
+ if ((ret == 0) || (ret == -ENODEV))
+ idepmac_sleep_interface(i, base, (ret == 0));
}
break;
case PBOOK_WAKE:
+ big_delay = 0;
+ for (i = 0; i < pmac_ide_count; ++i) {
+
+ if ((base = pmac_ide[i].regbase) == 0)
+ continue;
+
+ /* Check if this is a media bay with an IDE device or not
+ * a media bay
+ */
+ ret = check_media_bay_by_base(base, MB_CD);
+ if ((ret == 0) || (ret == -ENODEV)) {
+ idepmac_wake_interface(i, base, (ret == 0));
+ big_delay = 1;
+ }
+
+ }
+ /* Let hardware get up to speed */
+ if (big_delay)
+ mdelay(IDE_WAKEUP_DELAY_MS);
+
for (i = 0; i < pmac_ide_count; ++i) {
ide_hwif_t *hwif;
+ ide_drive_t *drive;
+ int j, used_dma;
+
if ((base = pmac_ide[i].regbase) == 0)
continue;
+
hwif = &ide_hwifs[i];
- /* We don't handle media bay devices this way */
- ret = check_media_bay_by_base(base, MB_CD);
- if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present)
- idepmac_wake_disk(i, base);
- else if (ret == 0)
- idepmac_wake_bay(i, base);
- enable_irq(pmac_ide[i].irq);
+ drive = &hwif->drives[0];
+
+ /* Wait for the drive to come up and set it's DMA */
+ if (drive->present) {
+ /* Wait up to 20 seconds */
+ for (j = 0; j < 200; j++) {
+ int status;
+ mdelay(100);
+ status = inb(base + 0x70);
+ if (!(status & BUSY_STAT))
+ break;
+ }
+ }
+
+ /* We don't have re-configured DMA yet */
+ used_dma = drive->using_dma;
+ drive->using_dma = 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
- if (hwif->drives[0].present && hwif->drives[0].using_dma)
- pmac_ide_dma_onoff(&hwif->drives[0], 1);
-#endif
+ /* We resume processing on the HW group */
+ spin_lock_irqsave(&io_request_lock, flags);
+ enable_irq(pmac_ide[i].irq);
+ if (drive->present)
+ HWGROUP(drive)->busy = 0;
+ spin_unlock_irqrestore(&io_request_lock, flags);
+
+ /* Wake the device
+ * We could handle the slave here
+ */
+ if (drive->present)
+ idepmac_wake_device(drive, used_dma);
}
break;
}
return PBOOK_SLEEP_OK;
}
+
#endif /* CONFIG_PMAC_PBOOK */
#ifdef CONFIG_MAC_FLOPPY
if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR)
swim3_fd_eject(MINOR(ROOT_DEV));
+#ifdef CONFIG_BLK_DEV_INITRD
else if(MAJOR(real_root_dev) == FLOPPY_MAJOR)
swim3_fd_eject(MINOR(real_root_dev));
+#endif
#endif
printk(KERN_NOTICE
"VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n");
fi
fi
dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
- if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+ if [ "$CONFIG_POWERMAC" = "y" ]; then
dep_tristate 'PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
fi
dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
case VIDIOCSCHAN:
{
struct video_channel v;
- int input;
+ int input, norm;
int on, res;
if (copy_from_user(&v, arg, sizeof(v))) {
if (on)
zr36057_overlay(zr, 0);
+ norm = zr->params.norm;
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
- i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
- i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+ i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
+ i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm);
if (on)
zr36057_overlay(zr, 1);
case BUZIOC_S_PARAMS:
{
struct zoran_params bp;
- int input, on;
+ int input, on, norm;
if (zr->codec_mode != BUZ_MODE_IDLE) {
return -EINVAL;
zr36057_overlay(zr, 0);
input = zr->params.input == 0 ? 3 : 7;
+ norm = zr->params.norm;
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
- i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
- i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+ i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
+ i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm);
if (on)
zr36057_overlay(zr, 1);
/* restore previous input and norm */
input = zr->params.input == 0 ? 3 : 7;
+ norm = zr->params.norm;
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input);
- i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
+ i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm);
if (copy_to_user(arg, &bs, sizeof(bs))) {
return -EFAULT;
j = zr->params.input == 0 ? 3 : 7;
i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j);
- i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm);
- i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm);
+ j = zr->params.norm;
+ i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &j);
+ i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &j);
/* set individual interrupt enables (without GIRQ0)
but don't global enable until zoran_open() */
}
if (redraw) {
+ int update;
+
set_origin(currcons);
+ update = sw->con_switch(vc_cons[currcons].d);
set_palette(currcons);
- if (sw->con_switch(vc_cons[currcons].d) && vcmode != KD_GRAPHICS)
- /* Update the screen contents */
+ if (update && vcmode != KD_GRAPHICS)
do_update_region(currcons, origin, screenbuf_size/2);
}
set_cursor(currcons);
#if 1 /* how? two almost equivalent choices follow */
compute_shiftstate();
#else
- keysym = U(plain_map[keycode]);
+ keysym = U(key_maps[0][keycode]);
type = KTYP(keysym);
if (type == KT_SHIFT)
(*key_handler[type])(keysym & 0xff, up_flag);
k = i*BITS_PER_LONG;
for(j=0; j<BITS_PER_LONG; j++,k++)
if(test_bit(k, key_down)) {
- sym = U(plain_map[k]);
+ sym = U(key_maps[0][k]);
if(KTYP(sym) == KT_SHIFT) {
val = KVAL(sym);
if (val == KVAL(K_CAPSSHIFT))
#ifdef CONFIG_MDA_CONSOLE
extern void mda_console_init(void);
#endif
-#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
-extern void adbdev_init(void);
-#endif
-#ifdef CONFIG_USB
-int usb_init(void);
-#endif
static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
const char * buf, size_t count, loff_t *ppos)
if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
rand_initialize();
-#ifdef CONFIG_USB
- usb_init();
-#endif
#if defined (CONFIG_FB)
fbmem_init();
#endif
#ifdef CONFIG_VIDEO_BT848
i2c_init();
#endif
-#if defined(CONFIG_PPC) || defined(CONFIG_MAC)
- adbdev_init();
-#endif
#ifdef CONFIG_VIDEO_DEV
videodev_init();
#endif
#ifdef CONFIG_BVME6000
rtc_DP8570A_init();
#endif
-#if defined(CONFIG_RTC) || defined(CONFIG_SUN_MOSTEK_RTC)
+#if defined(CONFIG_RTC) || defined(CONFIG_PPC_RTC) || defined(CONFIG_SUN_MOSTEK_RTC)
rtc_init();
#endif
#ifdef CONFIG_ATARI_DSP56K
extern long console_8xx_init(long, long);
extern int rs_8xx_init(void);
#endif /* CONFIG_8xx */
+#ifdef CONFIG_MAC_SERIAL
+extern long mac_scc_console_init(long, long);
+#endif
#ifdef CONFIG_3215
extern long con3215_init(long, long);
#endif /* CONFIG_3215 */
#ifdef CONFIG_SERIAL_CONSOLE
#ifdef CONFIG_8xx
kmem_start = console_8xx_init(kmem_start, kmem_end);
+#elif defined(CONFIG_MAC_SERIAL)
+ kmem_start = mac_scc_console_init(kmem_start, kmem_end);
#else
kmem_start = serial_console_init(kmem_start, kmem_end);
#endif /* CONFIG_8xx */
SUB_DIRS :=
MOD_SUB_DIRS := $(SUB_DIRS)
-L_TARGET := macintosh.a
+O_TARGET := macintosh.o
M_OBJS :=
ifndef CONFIG_MBX
-L_OBJS := via-cuda.o macio-adb.o via-pmu.o mediabay.o
-LX_OBJS := adb.o
+O_OBJS := via-cuda.o macio-adb.o via-pmu.o mediabay.o
+OX_OBJS := adb.o
endif
ifeq ($(CONFIG_MAC_SERIAL),y)
- L_OBJS += macserial.o
+ O_OBJS += macserial.o
else
ifeq ($(CONFIG_MAC_SERIAL),m)
M_OBJS += macserial.o
endif
ifeq ($(CONFIG_NVRAM),y)
- L_OBJS += nvram.o
+ O_OBJS += nvram.o
else
ifeq ($(CONFIG_NVRAM),m)
M_OBJS += nvram.o
endif
ifeq ($(CONFIG_PPC_RTC),y)
- L_OBJS += rtc.o
+ O_OBJS += rtc.o
else
ifeq ($(CONFIG_PPC_RTC),m)
M_OBJS += rtc.o
endif
ifdef CONFIG_MAC_KEYBOARD
-L_OBJS += mac_keyb.o
+ O_OBJS += mac_keyb.o
+endif
+ifdef CONFIG_INPUT_ADBHID
+ O_OBJS += adbhid.o
+endif
+ifdef CONFIG_MAC_HID
+ O_OBJS += mac_hid.o
endif
include $(TOPDIR)/Rules.make
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/notifier.h>
+#include <linux/init.h>
#include <asm/prom.h>
#include <asm/adb.h>
#include <asm/cuda.h>
#include <asm/pmu.h>
#include <asm/uaccess.h>
#include <asm/hydra.h>
-#include <asm/init.h>
EXPORT_SYMBOL(adb_controller);
EXPORT_SYMBOL(adb_client_list);
#define ADB_MAJOR 56 /* major number for /dev/adb */
-extern void adbdev_init(void);
+extern int adbdev_init(void);
struct adbdev_state {
spinlock_t lock;
adb_release
};
-void adbdev_init()
+static int __init adbdev_init(void)
{
- if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
- return;
+ if (adb_controller == NULL)
+ return 0;
if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
+ return 0;
}
+
+static void adbdev_cleanup(void)
+{
+ unregister_chrdev(ADB_MAJOR, "adb");
+}
+
+module_init(adbdev_init);
+module_exit(adbdev_cleanup);
--- /dev/null
+/*
+ * drivers/input/adbhid.c
+ *
+ * ADB HID driver for Power Macintosh computers.
+ *
+ * Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl
+ * (see that file for its authors and contributors).
+ *
+ * Copyright (C) 2000 Franz Sirl.
+ *
+ * Adapted to ADB changes and support for more devices by
+ * Benjamin Herrenschmidt. Adapted from code in MkLinux
+ * and reworked.
+ *
+ * Supported devices:
+ *
+ * - Standard 1 button mouse
+ * - All standard Apple Extended protocol (handler ID 4)
+ * - mouseman and trackman mice & trackballs
+ * - PowerBook Trackpad (default setup: enable tapping)
+ * - MicroSpeed mouse & trackball (needs testing)
+ * - CH Products Trackball Pro (needs testing)
+ * - Contour Design (Contour Mouse)
+ * - Hunter digital (NoHandsMouse)
+ * - Kensignton TurboMouse 5 (needs testing)
+ * - Mouse Systems A3 mice and trackballs <aidan@kublai.com>
+ * - MacAlly 2-buttons mouse (needs testing) <pochini@denise.shiny.it>
+ *
+ * To do:
+ *
+ * Improve Kensington support.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/input.h>
+#include <linux/kbd_ll.h>
+
+#include <asm/adb.h>
+#include <asm/cuda.h>
+#include <asm/pmu.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
+
+#define KEYB_KEYREG 0 /* register # for key up/down data */
+#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */
+#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
+
+static int adb_message_handler(struct notifier_block *, unsigned long, void *);
+static struct notifier_block adbhid_adb_notifier = {
+ notifier_call: adb_message_handler,
+};
+
+unsigned char adb_to_linux_keycodes[128] = {
+ 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19,
+ 21, 20, 2, 3, 4, 5, 7, 6, 13, 10, 8, 12, 9, 11, 27, 24,
+ 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52,
+ 15, 57, 41, 14, 96, 1, 29,125, 42, 58, 56,105,106,108,103, 0,
+ 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0,
+ 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,183,181,124,
+ 63, 64, 65, 61, 66, 67,191, 87,190, 99, 0, 70, 0, 68,101, 88,
+ 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116
+};
+
+struct adbhid {
+ struct input_dev input;
+ int id;
+ int default_id;
+ int original_handler_id;
+ int current_handler_id;
+ int mouse_kind;
+ unsigned char *keycode;
+ char name[64];
+};
+
+static struct adbhid *adbhid[16] = { 0 };
+
+static void adbhid_probe(void);
+
+static void adbhid_input_keycode(int, int, int);
+static void leds_done(struct adb_request *);
+
+static void init_trackpad(int id);
+static void init_trackball(int id);
+static void init_turbomouse(int id);
+static void init_microspeed(int id);
+static void init_ms_a3(int id);
+
+static struct adb_ids keyboard_ids;
+static struct adb_ids mouse_ids;
+static struct adb_ids buttons_ids;
+
+/* Kind of keyboard, see Apple technote 1152 */
+#define ADB_KEYBOARD_UNKNOWN 0
+#define ADB_KEYBOARD_ANSI 0x0100
+#define ADB_KEYBOARD_ISO 0x0200
+#define ADB_KEYBOARD_JIS 0x0300
+
+/* Kind of mouse */
+#define ADBMOUSE_STANDARD_100 0 /* Standard 100cpi mouse (handler 1) */
+#define ADBMOUSE_STANDARD_200 1 /* Standard 200cpi mouse (handler 2) */
+#define ADBMOUSE_EXTENDED 2 /* Apple Extended mouse (handler 4) */
+#define ADBMOUSE_TRACKBALL 3 /* TrackBall (handler 4) */
+#define ADBMOUSE_TRACKPAD 4 /* Apple's PowerBook trackpad (handler 4) */
+#define ADBMOUSE_TURBOMOUSE5 5 /* Turbomouse 5 (previously req. mousehack) */
+#define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */
+#define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */
+#define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */
+#define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */
+
+static void
+adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll)
+{
+ int id = (data[0] >> 4) & 0x0f;
+
+ if (!adbhid[id]) {
+ printk(KERN_ERR "ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n",
+ id, data[0], data[1], data[2], data[3]);
+ return;
+ }
+
+ /* first check this is from register 0 */
+ if (nb != 3 || (data[0] & 3) != KEYB_KEYREG)
+ return; /* ignore it */
+ kbd_pt_regs = regs;
+ adbhid_input_keycode(id, data[1], 0);
+ if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f)))
+ adbhid_input_keycode(id, data[2], 0);
+}
+
+static void
+adbhid_input_keycode(int id, int keycode, int repeat)
+{
+ int up_flag;
+
+ up_flag = (keycode & 0x80);
+ keycode &= 0x7f;
+
+ switch (keycode) {
+ case 0x39: /* Generate down/up events for CapsLock everytime. */
+ input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 1);
+ input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 0);
+ return;
+ case 0x3f: /* ignore Powerbook Fn key */
+ return;
+ }
+
+ if (adbhid[id]->keycode[keycode])
+ input_report_key(&adbhid[id]->input,
+ adbhid[id]->keycode[keycode], !up_flag);
+ else
+ printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode,
+ up_flag ? "released" : "pressed");
+}
+
+static void
+adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+{
+ int id = (data[0] >> 4) & 0x0f;
+
+ if (!adbhid[id]) {
+ printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id);
+ return;
+ }
+
+ /*
+ Handler 1 -- 100cpi original Apple mouse protocol.
+ Handler 2 -- 200cpi original Apple mouse protocol.
+
+ For Apple's standard one-button mouse protocol the data array will
+ contain the following values:
+
+ BITS COMMENTS
+ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+ data[1] = bxxx xxxx First button and x-axis motion.
+ data[2] = byyy yyyy Second button and y-axis motion.
+
+ Handler 4 -- Apple Extended mouse protocol.
+
+ For Apple's 3-button mouse protocol the data array will contain the
+ following values:
+
+ BITS COMMENTS
+ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+ data[1] = bxxx xxxx Left button and x-axis motion.
+ data[2] = byyy yyyy Second button and y-axis motion.
+ data[3] = byyy bxxx Third button and fourth button. Y is additional
+ high bits of y-axis motion. XY is additional
+ high bits of x-axis motion.
+
+ MacAlly 2-button mouse protocol.
+
+ For MacAlly 2-button mouse protocol the data array will contain the
+ following values:
+
+ BITS COMMENTS
+ data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
+ data[1] = bxxx xxxx Left button and x-axis motion.
+ data[2] = byyy yyyy Right button and y-axis motion.
+ data[3] = ???? ???? unknown
+ data[4] = ???? ???? unknown
+
+ */
+
+ /* If it's a trackpad, we alias the second button to the first.
+ NOTE: Apple sends an ADB flush command to the trackpad when
+ the first (the real) button is released. We could do
+ this here using async flush requests.
+ */
+ switch (adbhid[id]->mouse_kind)
+ {
+ case ADBMOUSE_TRACKPAD:
+ data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80);
+ data[2] = data[2] | 0x80;
+ break;
+ case ADBMOUSE_MICROSPEED:
+ data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
+ data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
+ data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5)
+ | (data[3] & 0x08);
+ break;
+ case ADBMOUSE_TRACKBALLPRO:
+ data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5)
+ & ((data[3] & 0x08) << 4));
+ data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7);
+ data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6);
+ break;
+ case ADBMOUSE_MS_A3:
+ data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
+ data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
+ data[3] = ((data[3] & 0x04) << 5);
+ break;
+ case ADBMOUSE_MACALLY2:
+ data[3] = (data[2] & 0x80) ? 0x80 : 0x00;
+ data[2] |= 0x80; /* Right button is mapped as button 3 */
+ nb=4;
+ break;
+ }
+
+ input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1));
+ input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1));
+
+ if (nb >= 4)
+ input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1));
+
+ input_report_rel(&adbhid[id]->input, REL_X,
+ ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 ));
+ input_report_rel(&adbhid[id]->input, REL_Y,
+ ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 ));
+}
+
+static void
+adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+{
+ int id = (data[0] >> 4) & 0x0f;
+
+ if (!adbhid[id]) {
+ printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id);
+ return;
+ }
+
+ switch (adbhid[id]->original_handler_id) {
+ default:
+ case 0x02: /* Adjustable keyboard button device */
+ printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
+ data[0], data[1], data[2], data[3]);
+ break;
+ case 0x1f: /* Powerbook button device */
+ {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ int backlight = get_backlight_level();
+
+ /*
+ * XXX: Where is the contrast control for the passive?
+ * -- Cort
+ */
+
+ switch (data[1]) {
+ case 0x8: /* mute */
+ break;
+
+ case 0x7: /* contrast decrease */
+ break;
+
+ case 0x6: /* contrast increase */
+ break;
+
+ case 0xa: /* brightness decrease */
+ if (backlight < 0)
+ break;
+ if (backlight > BACKLIGHT_OFF)
+ set_backlight_level(backlight-1);
+ else
+ set_backlight_level(BACKLIGHT_OFF);
+ break;
+
+ case 0x9: /* brightness increase */
+ if (backlight < 0)
+ break;
+ if (backlight < BACKLIGHT_MAX)
+ set_backlight_level(backlight+1);
+ else
+ set_backlight_level(BACKLIGHT_MAX);
+ break;
+ }
+#endif /* CONFIG_PMAC_BACKLIGHT */
+ }
+ break;
+ }
+}
+
+static struct adb_request led_request;
+static int leds_pending[16];
+static int pending_devs[16];
+static int pending_led_start=0;
+static int pending_led_end=0;
+
+static void real_leds(unsigned char leds, int device)
+{
+ if (led_request.complete) {
+ adb_request(&led_request, leds_done, 0, 3,
+ ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
+ ~leds);
+ } else {
+ if (!(leds_pending[device] & 0x100)) {
+ pending_devs[pending_led_end] = device;
+ pending_led_end++;
+ pending_led_end = (pending_led_end < 16) ? pending_led_end : 0;
+ }
+ leds_pending[device] = leds | 0x100;
+ }
+}
+
+/*
+ * Event callback from the input module. Events that change the state of
+ * the hardware are processed here.
+ */
+static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ struct adbhid *adbhid = dev->private;
+ unsigned char leds;
+
+ switch (type) {
+ case EV_LED:
+ leds = (test_bit(LED_SCROLLL, dev->led) ? 4 : 0)
+ | (test_bit(LED_NUML, dev->led) ? 1 : 0)
+ | (test_bit(LED_CAPSL, dev->led) ? 2 : 0);
+ real_leds(leds, adbhid->id);
+ return 0;
+ }
+
+ return -1;
+}
+
+static void leds_done(struct adb_request *req)
+{
+ int leds,device;
+
+ if (pending_led_start != pending_led_end) {
+ device = pending_devs[pending_led_start];
+ leds = leds_pending[device] & 0xff;
+ leds_pending[device] = 0;
+ pending_led_start++;
+ pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
+ real_leds(leds,device);
+ }
+
+}
+
+static int
+adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
+{
+ unsigned long flags;
+
+ switch (code) {
+ case ADB_MSG_PRE_RESET:
+ case ADB_MSG_POWERDOWN:
+ /* Stop the repeat timer. Autopoll is already off at this point */
+ save_flags(flags);
+ cli();
+ {
+ int i;
+ for (i = 1; i < 16; i++) {
+ if (adbhid[i])
+ del_timer(&adbhid[i]->input.timer);
+ }
+ }
+ restore_flags(flags);
+
+ /* Stop pending led requests */
+ while(!led_request.complete)
+ adb_poll();
+ break;
+
+ case ADB_MSG_POST_RESET:
+ adbhid_probe();
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static void
+adbhid_input_register(int id, int default_id, int original_handler_id,
+ int current_handler_id, int mouse_kind)
+{
+ int i;
+
+ if (adbhid[id]) {
+ printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id);
+ return;
+ }
+
+ if (!(adbhid[id] = kmalloc(sizeof(struct adbhid), GFP_KERNEL)))
+ return;
+
+ memset(adbhid[id], 0, sizeof(struct adbhid));
+
+ adbhid[id]->id = default_id;
+ adbhid[id]->original_handler_id = original_handler_id;
+ adbhid[id]->current_handler_id = current_handler_id;
+ adbhid[id]->mouse_kind = mouse_kind;
+ adbhid[id]->input.private = adbhid[id];
+ adbhid[id]->input.name = adbhid[id]->name;
+ adbhid[id]->input.idbus = BUS_ADB;
+ adbhid[id]->input.idvendor = 0x0001;
+ adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id;
+ adbhid[id]->input.idversion = 0x0100;
+
+ switch (default_id) {
+ case ADB_KEYBOARD:
+ if (!(adbhid[id]->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL))) {
+ kfree(adbhid[id]);
+ return;
+ }
+
+ sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x",
+ id, default_id, original_handler_id);
+
+ memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes));
+
+ printk(KERN_INFO "Detected ADB keyboard, type ");
+ switch (original_handler_id) {
+ default:
+ printk("<unknown>.\n");
+ adbhid[id]->input.idversion = ADB_KEYBOARD_UNKNOWN;
+ break;
+
+ case 0x01: case 0x02: case 0x03: case 0x06: case 0x08:
+ case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C:
+ case 0xC0: case 0xC3: case 0xC6:
+ printk("ANSI.\n");
+ adbhid[id]->input.idversion = ADB_KEYBOARD_ANSI;
+ break;
+
+ case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
+ case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
+ case 0xC4: case 0xC7:
+ printk("ISO, swapping keys.\n");
+ adbhid[id]->input.idversion = ADB_KEYBOARD_ISO;
+ i = adbhid[id]->keycode[10];
+ adbhid[id]->keycode[10] = adbhid[id]->keycode[50];
+ adbhid[id]->keycode[50] = i;
+ break;
+
+ case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A:
+ case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9:
+ printk("JIS.\n");
+ adbhid[id]->input.idversion = ADB_KEYBOARD_JIS;
+ break;
+ }
+
+ for (i = 0; i < 128; i++)
+ if (adbhid[id]->keycode[i])
+ set_bit(adbhid[id]->keycode[i], adbhid[id]->input.keybit);
+
+ adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
+ adbhid[id]->input.ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML);
+ adbhid[id]->input.event = adbhid_kbd_event;
+ adbhid[id]->input.keycodemax = 127;
+ adbhid[id]->input.keycodesize = 1;
+ break;
+
+ case ADB_MOUSE:
+ sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x",
+ id, default_id, original_handler_id);
+
+ adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ adbhid[id]->input.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ break;
+
+ case ADB_MISC:
+ switch (original_handler_id) {
+ case 0x02: /* Adjustable keyboard button device */
+ sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x",
+ id, default_id, original_handler_id);
+ break;
+ case 0x1f: /* Powerbook button device */
+ sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x",
+ id, default_id, original_handler_id);
+ break;
+ }
+ if (adbhid[id]->name[0])
+ break;
+ /* else fall through */
+
+ default:
+ printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n");
+ kfree(adbhid[id]);
+ return;
+ }
+
+ adbhid[id]->input.keycode = adbhid[id]->keycode;
+
+ input_register_device(&adbhid[id]->input);
+
+ printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n",
+ adbhid[id]->input.number, id, default_id, original_handler_id);
+
+ if (default_id == ADB_KEYBOARD) {
+ /* HACK WARNING!! This should go away as soon there is an utility
+ * to control that for event devices.
+ */
+ adbhid[id]->input.rep[REP_DELAY] = HZ/2; /* input layer default: HZ/4 */
+ adbhid[id]->input.rep[REP_PERIOD] = HZ/15; /* input layer default: HZ/33 */
+ }
+}
+
+static void adbhid_input_unregister(int id)
+{
+ input_unregister_device(&adbhid[id]->input);
+ if (adbhid[id]->keycode)
+ kfree(adbhid[id]->keycode);
+ kfree(adbhid[id]);
+ adbhid[id] = 0;
+}
+
+
+static void
+adbhid_probe(void)
+{
+ struct adb_request req;
+ int i, default_id, org_handler_id, cur_handler_id;
+
+ for (i = 1; i < 16; i++) {
+ if (adbhid[i])
+ adbhid_input_unregister(i);
+ }
+
+ adb_register(ADB_MOUSE, 0, &mouse_ids, adbhid_mouse_input);
+ adb_register(ADB_KEYBOARD, 0, &keyboard_ids, adbhid_keyboard_input);
+ adb_register(ADB_MISC, 0, &buttons_ids, adbhid_buttons_input);
+
+ for (i = 0; i < keyboard_ids.nids; i++) {
+ int id = keyboard_ids.id[i];
+
+ adb_get_infos(id, &default_id, &org_handler_id);
+
+ /* turn off all leds */
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff);
+
+ /* Enable full feature set of the keyboard
+ ->get it to send separate codes for left and right shift,
+ control, option keys */
+#if 0 /* handler 5 doesn't send separate codes for R modifiers */
+ if (adb_try_handler_change(id, 5))
+ printk("ADB keyboard at %d, handler set to 5\n", id);
+ else
+#endif
+ if (adb_try_handler_change(id, 3))
+ printk("ADB keyboard at %d, handler set to 3\n", id);
+ else
+ printk("ADB keyboard at %d, handler 1\n", id);
+
+ adb_get_infos(id, &default_id, &cur_handler_id);
+ adbhid_input_register(id, default_id, org_handler_id, cur_handler_id, 0);
+ }
+
+ for (i = 0; i < buttons_ids.nids; i++) {
+ int id = buttons_ids.id[i];
+
+ adb_get_infos(id, &default_id, &org_handler_id);
+ adbhid_input_register(id, default_id, org_handler_id, org_handler_id, 0);
+ }
+
+ /* Try to switch all mice to handler 4, or 2 for three-button
+ mode and full resolution. */
+ for (i = 0; i < mouse_ids.nids; i++) {
+ int id = mouse_ids.id[i];
+ int mouse_kind;
+
+ adb_get_infos(id, &default_id, &org_handler_id);
+
+ if (adb_try_handler_change(id, 4)) {
+ printk("ADB mouse at %d, handler set to 4", id);
+ mouse_kind = ADBMOUSE_EXTENDED;
+ }
+ else if (adb_try_handler_change(id, 0x2F)) {
+ printk("ADB mouse at %d, handler set to 0x2F", id);
+ mouse_kind = ADBMOUSE_MICROSPEED;
+ }
+ else if (adb_try_handler_change(id, 0x42)) {
+ printk("ADB mouse at %d, handler set to 0x42", id);
+ mouse_kind = ADBMOUSE_TRACKBALLPRO;
+ }
+ else if (adb_try_handler_change(id, 0x66)) {
+ printk("ADB mouse at %d, handler set to 0x66", id);
+ mouse_kind = ADBMOUSE_MICROSPEED;
+ }
+ else if (adb_try_handler_change(id, 0x5F)) {
+ printk("ADB mouse at %d, handler set to 0x5F", id);
+ mouse_kind = ADBMOUSE_MICROSPEED;
+ }
+ else if (adb_try_handler_change(id, 3)) {
+ printk("ADB mouse at %d, handler set to 3", id);
+ mouse_kind = ADBMOUSE_MS_A3;
+ }
+ else if (adb_try_handler_change(id, 2)) {
+ printk("ADB mouse at %d, handler set to 2", id);
+ mouse_kind = ADBMOUSE_STANDARD_200;
+ }
+ else {
+ printk("ADB mouse at %d, handler 1", id);
+ mouse_kind = ADBMOUSE_STANDARD_100;
+ }
+
+ if ((mouse_kind == ADBMOUSE_TRACKBALLPRO)
+ || (mouse_kind == ADBMOUSE_MICROSPEED)) {
+ init_microspeed(id);
+ } else if (mouse_kind == ADBMOUSE_MS_A3) {
+ init_ms_a3(id);
+ } else if (mouse_kind == ADBMOUSE_EXTENDED) {
+ /*
+ * Register 1 is usually used for device
+ * identification. Here, we try to identify
+ * a known device and call the appropriate
+ * init function.
+ */
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ ADB_READREG(id, 1));
+
+ if ((req.reply_len) &&
+ (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21)
+ || (req.reply[2] == 0x20))) {
+ mouse_kind = ADBMOUSE_TRACKBALL;
+ init_trackball(id);
+ }
+ else if ((req.reply_len >= 4) &&
+ (req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
+ (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) {
+ mouse_kind = ADBMOUSE_TRACKPAD;
+ init_trackpad(id);
+ }
+ else if ((req.reply_len >= 4) &&
+ (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
+ (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) {
+ mouse_kind = ADBMOUSE_TURBOMOUSE5;
+ init_turbomouse(id);
+ }
+ else if ((req.reply_len == 9) &&
+ (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) &&
+ (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) {
+ if (adb_try_handler_change(id, 0x42)) {
+ printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id);
+ mouse_kind = ADBMOUSE_MACALLY2;
+ }
+ }
+ }
+ printk("\n");
+
+ adb_get_infos(id, &default_id, &cur_handler_id);
+ adbhid_input_register(id, default_id, org_handler_id,
+ cur_handler_id, mouse_kind);
+ }
+}
+
+static void
+init_trackpad(int id)
+{
+ struct adb_request req;
+ unsigned char r1_buffer[8];
+
+ printk(" (trackpad)");
+
+ adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+ ADB_READREG(id,1));
+ if (req.reply_len < 8)
+ printk("bad length for reg. 1\n");
+ else
+ {
+ memcpy(r1_buffer, &req.reply[1], 8);
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(id,1),
+ r1_buffer[0],
+ r1_buffer[1],
+ r1_buffer[2],
+ r1_buffer[3],
+ r1_buffer[4],
+ r1_buffer[5],
+ 0x0d, /*r1_buffer[6],*/
+ r1_buffer[7]);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(id,2),
+ 0x99,
+ 0x94,
+ 0x19,
+ 0xff,
+ 0xb2,
+ 0x8a,
+ 0x1b,
+ 0x50);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(id,1),
+ r1_buffer[0],
+ r1_buffer[1],
+ r1_buffer[2],
+ r1_buffer[3],
+ r1_buffer[4],
+ r1_buffer[5],
+ 0x03, /*r1_buffer[6],*/
+ r1_buffer[7]);
+ }
+}
+
+static void
+init_trackball(int id)
+{
+ struct adb_request req;
+
+ printk(" (trackman/mouseman)");
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 00,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 01,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 02,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 03,0x38);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 00,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 01,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 02,0x81);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id,1), 03,0x38);
+}
+
+static void
+init_turbomouse(int id)
+{
+ struct adb_request req;
+
+ printk(" (TurboMouse 5)");
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(3,2),
+ 0xe7,
+ 0x8c,
+ 0,
+ 0,
+ 0,
+ 0xff,
+ 0xff,
+ 0x94);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 9,
+ ADB_WRITEREG(3,2),
+ 0xa5,
+ 0x14,
+ 0,
+ 0,
+ 0x69,
+ 0xff,
+ 0xff,
+ 0x27);
+}
+
+static void
+init_microspeed(int id)
+{
+ struct adb_request req;
+
+ printk(" (Microspeed/MacPoint or compatible)");
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+ /* This will initialize mice using the Microspeed, MacPoint and
+ other compatible firmware. Bit 12 enables extended protocol.
+
+ Register 1 Listen (4 Bytes)
+ 0 - 3 Button is mouse (set also for double clicking!!!)
+ 4 - 7 Button is locking (affects change speed also)
+ 8 - 11 Button changes speed
+ 12 1 = Extended mouse mode, 0 = normal mouse mode
+ 13 - 15 unused 0
+ 16 - 23 normal speed
+ 24 - 31 changed speed
+
+ Register 1 talk holds version and product identification information.
+ Register 1 Talk (4 Bytes):
+ 0 - 7 Product code
+ 8 - 23 undefined, reserved
+ 24 - 31 Version number
+
+ Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
+ */
+ adb_request(&req, NULL, ADBREQ_SYNC, 5,
+ ADB_WRITEREG(id,1),
+ 0x20, /* alt speed = 0x20 (rather slow) */
+ 0x00, /* norm speed = 0x00 (fastest) */
+ 0x10, /* extended protocol, no speed change */
+ 0x07); /* all buttons enabled as mouse buttons, no locking */
+
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+}
+
+static void
+init_ms_a3(int id)
+{
+ struct adb_request req;
+
+ printk(" (Mouse Systems A3 Mouse, or compatible)");
+ adb_request(&req, NULL, ADBREQ_SYNC, 3,
+ ADB_WRITEREG(id, 0x2),
+ 0x00,
+ 0x07);
+
+ adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+}
+
+static int __init adbhid_init(void)
+{
+ if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
+ return 0;
+
+ led_request.complete = 1;
+
+ adbhid_probe();
+
+ notifier_chain_register(&adb_client_list, &adbhid_adb_notifier);
+
+ return 0;
+}
+
+static void adbhid_exit(void)
+{
+}
+
+module_init(adbhid_init);
+module_exit(adbhid_exit);
--- /dev/null
+/*
+ * drivers/macintosh/mac_hid.c
+ *
+ * HID support stuff for Macintosh computers.
+ *
+ * Copyright (C) 2000 Franz Sirl.
+ *
+ * Stuff inside CONFIG_MAC_ADBKEYCODES should go away during 2.5 when all
+ * major distributions are using the Linux keycodes.
+ * Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/input.h>
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+#include <linux/keyboard.h>
+#include <asm/keyboard.h>
+#include <asm/machdep.h>
+#endif
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mac_hid_kbd_sysrq_xlate[128] =
+ "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */
+ "yt123465=97-80o]" /* 0x10 - 0x1f */
+ "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */
+ "\t `\177\000\033\000\000\000\000\000\000\000\000\000\000"
+ /* 0x30 - 0x3f */
+ "\000\000\000*\000+\000\000\000\000\000/\r\000-\000"
+ /* 0x40 - 0x4f */
+ "\000\0000123456789\000\000\000" /* 0x50 - 0x5f */
+ "\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214";
+ /* 0x60 - 0x6f */
+extern unsigned char pckbd_sysrq_xlate[128];
+#endif
+
+static u_short macplain_map[NR_KEYS] = {
+ 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+ 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72,
+ 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035,
+ 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f,
+ 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027,
+ 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e,
+ 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+ 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macshift_map[NR_KEYS] = {
+ 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58,
+ 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52,
+ 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025,
+ 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f,
+ 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022,
+ 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e,
+ 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117,
+ 0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macaltgr_map[NR_KEYS] = {
+ 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78,
+ 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72,
+ 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+ 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f,
+ 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200,
+ 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f,
+ 0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200,
+ 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516,
+ 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117,
+ 0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macctrl_map[NR_KEYS] = {
+ 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+ 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d,
+ 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f,
+ 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007,
+ 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e,
+ 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a,
+ 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117,
+ 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macshift_ctrl_map[NR_KEYS] = {
+ 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018,
+ 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012,
+ 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f,
+ 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200,
+ 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117,
+ 0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c,
+};
+
+static u_short macalt_map[NR_KEYS] = {
+ 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878,
+ 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872,
+ 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835,
+ 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f,
+ 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827,
+ 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e,
+ 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905,
+ 0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200,
+ 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+ 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+ 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static u_short macctrl_alt_map[NR_KEYS] = {
+ 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818,
+ 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812,
+ 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f,
+ 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200,
+ 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703,
+ 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200,
+ 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208,
+ 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200,
+ 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305,
+ 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200,
+ 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a,
+ 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b,
+ 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117,
+ 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200,
+};
+
+static unsigned short *mac_key_maps_save[MAX_NR_KEYMAPS] = {
+ macplain_map, macshift_map, macaltgr_map, 0,
+ macctrl_map, macshift_ctrl_map, 0, 0,
+ macalt_map, 0, 0, 0,
+ macctrl_alt_map, 0
+};
+
+static unsigned short *pc_key_maps_save[MAX_NR_KEYMAPS];
+
+int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep,
+ char raw_mode);
+static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp);
+char mac_hid_kbd_unexpected_up(unsigned char keycode);
+
+static int keyboard_lock_keycodes = 0;
+int keyboard_sends_linux_keycodes = 0;
+#else
+int keyboard_sends_linux_keycodes = 1;
+#endif /* CONFIG_MAC_ADBKEYCODES */
+
+
+static unsigned char e0_keys[128] = {
+ 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */
+ 0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0, /* 0x08-0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
+ 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18-0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
+ 0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ, /* 0x30-0x37 */
+ KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */
+ 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40-0x47 */
+ KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */
+ KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */
+ 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, 0, 0, KEY_MACRO, /* 0x68-0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
+};
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+static struct input_dev emumousebtn;
+static void emumousebtn_input_register(void);
+static int mouse_emulate_buttons = 0;
+static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */
+static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */
+static int mouse_last_keycode = 0;
+#endif
+
+extern void pckbd_init_hw(void);
+
+#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+/* file(s) in /proc/sys/dev/mac_hid */
+ctl_table mac_hid_files[] =
+{
+#ifdef CONFIG_MAC_ADBKEYCODES
+ {
+ DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES,
+ "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int),
+ 0644, NULL, &mac_hid_sysctl_keycodes
+ },
+ {
+ DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES,
+ "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int),
+ 0644, NULL, &proc_dointvec
+ },
+#endif
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+ {
+ DEV_MAC_HID_MOUSE_BUTTON_EMULATION,
+ "mouse_button_emulation", &mouse_emulate_buttons, sizeof(int),
+ 0644, NULL, &proc_dointvec
+ },
+ {
+ DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE,
+ "mouse_button2_keycode", &mouse_button2_keycode, sizeof(int),
+ 0644, NULL, &proc_dointvec
+ },
+ {
+ DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE,
+ "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int),
+ 0644, NULL, &proc_dointvec
+ },
+#endif
+ { 0 }
+};
+
+/* dir in /proc/sys/dev */
+ctl_table mac_hid_dir[] =
+{
+ { DEV_MAC_HID, "mac_hid", NULL, 0, 0555, mac_hid_files },
+ { 0 }
+};
+
+/* /proc/sys/dev itself, in case that is not there yet */
+ctl_table mac_hid_root_dir[] =
+{
+ { CTL_DEV, "dev", NULL, 0, 0555, mac_hid_dir },
+ { 0 }
+};
+
+static struct ctl_table_header *mac_hid_sysctl_header;
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+static
+int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
+ void *buffer, size_t *lenp)
+{
+ int val = keyboard_sends_linux_keycodes;
+ int ret = 0;
+
+ if (!write
+ || (write && !keyboard_lock_keycodes))
+ ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+
+ if (write
+ && keyboard_sends_linux_keycodes != val) {
+ if (!keyboard_sends_linux_keycodes) {
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate;
+ SYSRQ_KEY = 0x69;
+#endif
+ memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
+ memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
+ } else {
+#ifdef CONFIG_MAGIC_SYSRQ
+ ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate;
+ SYSRQ_KEY = 0x54;
+#endif
+ memcpy(mac_key_maps_save, key_maps, sizeof(key_maps));
+ memcpy(key_maps, pc_key_maps_save, sizeof(key_maps));
+ }
+ }
+
+ return ret;
+}
+#endif
+#endif /* endif CONFIG_SYSCTL */
+
+int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
+{
+#ifdef CONFIG_MAC_ADBKEYCODES
+ if (!keyboard_sends_linux_keycodes) {
+ if (!raw_mode) {
+ /*
+ * Convert R-shift/control/option to L version.
+ */
+ switch (scancode) {
+ case 0x7b: scancode = 0x38; break; /* R-shift */
+ case 0x7c: scancode = 0x3a; break; /* R-option */
+ case 0x7d: scancode = 0x36; break; /* R-control */
+ }
+ }
+ *keycode = scancode;
+ return 1;
+ } else
+#endif
+ {
+ /* This code was copied from char/pc_keyb.c and will be
+ * superflous when the input layer is fully integrated.
+ * We don't need the high_keys handling, so this part
+ * has been removed.
+ */
+ static int prev_scancode = 0;
+
+ /* special prefix scancodes.. */
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ prev_scancode = scancode;
+ return 0;
+ }
+
+ scancode &= 0x7f;
+
+ if (prev_scancode) {
+ if (prev_scancode != 0xe0) {
+ if (prev_scancode == 0xe1 && scancode == 0x1d) {
+ prev_scancode = 0x100;
+ return 0;
+ } else if (prev_scancode == 0x100 && scancode == 0x45) {
+ *keycode = KEY_PAUSE;
+ prev_scancode = 0;
+ } else {
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
+ prev_scancode = 0;
+ return 0;
+ }
+ } else {
+ prev_scancode = 0;
+ if (scancode == 0x2a || scancode == 0x36)
+ return 0;
+ }
+ if (e0_keys[scancode])
+ *keycode = e0_keys[scancode];
+ else {
+ if (!raw_mode)
+ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
+ scancode);
+ return 0;
+ }
+ } else {
+ switch (scancode) {
+ case 91: scancode = KEY_LINEFEED; break;
+ case 92: scancode = KEY_KPEQUAL; break;
+ case 125: scancode = KEY_INTL1; break;
+ }
+ *keycode = scancode;
+ }
+ return 1;
+ }
+}
+
+char mac_hid_kbd_unexpected_up(unsigned char keycode)
+{
+ if (keyboard_sends_linux_keycodes && keycode == KEY_F13)
+ return 0;
+ else
+ return 0x80;
+}
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+int mac_hid_keyboard_sends_linux_keycodes(void)
+{
+ return keyboard_sends_linux_keycodes;
+}
+
+static int __init mac_hid_setup(char *str)
+{
+ int ints[11];
+
+ str = get_options(str, ints);
+ if (ints[0] == 1) {
+ keyboard_sends_linux_keycodes = ints[1] != 0;
+ keyboard_lock_keycodes = 1;
+ }
+ return 1;
+}
+
+__setup("keyboard_sends_linux_keycodes=", mac_hid_setup);
+
+#endif
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
+{
+ switch (caller) {
+ case 1:
+ /* Called from keybdev.c */
+ if (mouse_emulate_buttons
+ && (keycode == mouse_button2_keycode
+ || keycode == mouse_button3_keycode)) {
+ if (mouse_emulate_buttons == 1) {
+ input_report_key(&emumousebtn,
+ keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT,
+ down);
+ return 1;
+ }
+ mouse_last_keycode = down ? keycode : 0;
+ }
+ break;
+ case 2:
+ /* Called from mousedev.c */
+ if (mouse_emulate_buttons == 2 && keycode == 0) {
+ if (mouse_last_keycode == mouse_button2_keycode)
+ return 1; /* map to middle button */
+ if (mouse_last_keycode == mouse_button3_keycode)
+ return 2; /* map to right button */
+ }
+ return keycode; /* keep button */
+ }
+ return 0;
+}
+
+static void emumousebtn_input_register(void)
+{
+ emumousebtn.name = "Macintosh mouse button emulation";
+
+ emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+
+ emumousebtn.idbus = BUS_ADB;
+ emumousebtn.idvendor = 0x0001;
+ emumousebtn.idproduct = 0x0001;
+ emumousebtn.idversion = 0x0100;
+
+ input_register_device(&emumousebtn);
+
+ printk(KERN_INFO "input%d: Macintosh mouse button emulation\n", emumousebtn.number);
+}
+#endif
+
+void __init mac_hid_init_hw(void)
+{
+
+#ifdef CONFIG_MAC_ADBKEYCODES
+ memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
+
+ if (!keyboard_sends_linux_keycodes)
+ memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
+#endif
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+ emumousebtn_input_register();
+#endif
+
+#if CONFIG_PPC
+ if (_machine != _MACH_Pmac)
+ pckbd_init_hw();
+#endif
+
+#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+ mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1);
+#endif /* CONFIG_SYSCTL */
+}
*
* - Standard 1 button mouse
* - All standard Apple Extended protocol (handler ID 4)
- * - mouseman and trackman mice & trackballs
+ * - mouseman and trackman mice & trackballs
* - PowerBook Trackpad (default setup: enable tapping)
* - MicroSpeed mouse & trackball (needs testing)
* - CH Products Trackball Pro (needs testing)
#include <asm/cuda.h>
#include <asm/pmu.h>
#include <asm/init.h>
+#include <asm/machdep.h>
+#include <asm/backlight.h>
#include <linux/kbd_kern.h>
#include <linux/kbd_ll.h>
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
#define KEYB_KEYREG 0 /* register # for key up/down data */
#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */
#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
static void kbd_repeat(unsigned long);
-static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
+static struct timer_list repeat_timer = { function: kbd_repeat };
static int last_keycode;
static void mackeyb_probe(void);
#ifdef CONFIG_ADBMOUSE
/*
* XXX: Add mouse button 2+3 fake codes here if mouse open.
- * Keep track of 'button' states here as we only send
+ * Keep track of 'button' states here as we only send
* single up/down events!
* Really messy; might need to check if keyboard is in
* VC_RAW mode.
}
#endif /* CONFIG_ADBMOUSE */
-/* XXX Needs to get rid of this, see comments in pmu.c */
-extern int backlight_level;
-
static void
buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
{
+ int backlight = get_backlight_level();
+
/*
* XXX: Where is the contrast control for the passive?
* -- Cort
*/
-
+
/* Ignore data from register other than 0 */
- if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2))
+ if ((data[0] & 0x3) || (nb < 2))
return;
- switch (data[1]&0xf )
- {
- /* mute */
- case 0x8:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- }
- break;
- /* contrast decrease */
- case 0x7:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- }
- break;
- /* contrast increase */
- case 0x6:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- }
- break;
- /* brightness decrease */
- case 0xa:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- if (backlight_level > 2)
- pmu_set_brightness(backlight_level-2);
- else
- pmu_set_brightness(0);
- }
+ switch (data[1]) {
+ case 0x8: /* mute */
+ break;
+
+ case 0x7: /* contrast decrease */
+ break;
+
+ case 0x6: /* contrast increase */
+ break;
+
+ case 0xa: /* brightness decrease */
+ if (backlight < 0)
break;
- /* brightness increase */
- case 0x9:
- /* down event */
- if ( data[1] == (data[1]&0xf) ) {
- if (backlight_level < 0x1e)
- pmu_set_brightness(backlight_level+2);
- else
- pmu_set_brightness(0x1f);
- }
+ if (backlight > BACKLIGHT_OFF)
+ set_backlight_level(backlight-1);
+ else
+ set_backlight_level(BACKLIGHT_OFF);
+ break;
+
+ case 0x9: /* brightness increase */
+ if (backlight < 0)
break;
+ if (backlight < BACKLIGHT_MAX)
+ set_backlight_level(backlight+1);
+ else
+ set_backlight_level(BACKLIGHT_MAX);
+ break;
}
}
}
-__initfunc(void mackbd_init_hw(void))
+void __init mackbd_init_hw(void)
{
if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
- return;
+ return;
/* setup key map */
memcpy(key_maps[0], macplain_map, sizeof(plain_map));
switch (code) {
case ADB_MSG_PRE_RESET:
case ADB_MSG_POWERDOWN:
- /* Stop the repeat timer. Autopoll is already off at this point */
+ /* Stop the repeat timer. Autopoll is already off at this point */
save_flags(flags);
cli();
del_timer(&repeat_timer);
if ((req.reply_len) &&
(req.reply[1] == 0x9a) && ((req.reply[2] == 0x21)
- || (req.reply[2] == 0x20)))
+ || (req.reply[2] == 0x20)))
init_trackball(id);
else if ((req.reply_len >= 4) &&
(req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
}
}
-static void
+static void
init_trackpad(int id)
{
struct adb_request req;
adb_request(&req, NULL, ADBREQ_SYNC, 9,
ADB_WRITEREG(id,2),
- 0x99,
- 0x94,
- 0x19,
- 0xff,
- 0xb2,
- 0x8a,
- 0x1b,
- 0x50);
-
+ 0x99,
+ 0x94,
+ 0x19,
+ 0xff,
+ 0xb2,
+ 0x8a,
+ 0x1b,
+ 0x50);
+
adb_request(&req, NULL, ADBREQ_SYNC, 9,
ADB_WRITEREG(id,1),
r1_buffer[0],
}
}
-static void
+static void
init_trackball(int id)
{
struct adb_request req;
/* This will initialize mice using the Microspeed, MacPoint and
other compatible firmware. Bit 12 enables extended protocol.
-
+
Register 1 Listen (4 Bytes)
0 - 3 Button is mouse (set also for double clicking!!!)
4 - 7 Button is locking (affects change speed also)
0 - 7 Product code
8 - 23 undefined, reserved
24 - 31 Version number
-
+
Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
*/
adb_request(&req, NULL, ADBREQ_SYNC, 5,
ADB_WRITEREG(id, 0x2),
0x00,
0x07);
-
+
adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
}
info->dma_initted = 1;
}
+/*
+ * FixZeroBug....Works around a bug in the SCC receving channel.
+ * Taken from Darwin code, 15 Sept. 2000 -DanM
+ *
+ * The following sequence prevents a problem that is seen with O'Hare ASICs
+ * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
+ * at the input to the receiver becomes 'stuck' and locks up the receiver.
+ * This problem can occur as a result of a zero bit at the receiver input
+ * coincident with any of the following events:
+ *
+ * The SCC is initialized (hardware or software).
+ * A framing error is detected.
+ * The clocking option changes from synchronous or X1 asynchronous
+ * clocking to X16, X32, or X64 asynchronous clocking.
+ * The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
+ *
+ * This workaround attempts to recover from the lockup condition by placing
+ * the SCC in synchronous loopback mode with a fast clock before programming
+ * any of the asynchronous modes.
+ */
+static void fix_zero_bug_scc(struct mac_serial * info)
+{
+ write_zsreg(info->zs_channel, 9,
+ (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
+ udelay(10);
+ write_zsreg(info->zs_channel, 9,
+ ((info->zs_channel == info->zs_chan_a? CHRA: CHRB) | NV));
+
+ write_zsreg(info->zs_channel, 4, (X1CLK | EXTSYNC));
+
+ /* I think this is wrong....but, I just copying code....
+ */
+ write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
+
+ write_zsreg(info->zs_channel, 5, (8 & ~TxENAB));
+ write_zsreg(info->zs_channel, 9, NV); /* Didn't we already do this? */
+ write_zsreg(info->zs_channel, 11, (RCBR | TCBR));
+ write_zsreg(info->zs_channel, 12, 0);
+ write_zsreg(info->zs_channel, 13, 0);
+ write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR));
+ write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR | BRENABL));
+ write_zsreg(info->zs_channel, 3, (8 | RxENABLE));
+ write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+ write_zsreg(info->zs_channel, 0, RES_EXT_INT); /* to kill some time */
+
+ /* The channel should be OK now, but it is probably receiving
+ * loopback garbage.
+ * Switch to asynchronous mode, disable the receiver,
+ * and discard everything in the receive buffer.
+ */
+ write_zsreg(info->zs_channel, 9, NV);
+ write_zsreg(info->zs_channel, 4, PAR_ENA);
+ write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
+
+ while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) {
+ (void)read_zsreg(info->zs_channel, 8);
+ write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+ write_zsreg(info->zs_channel, 0, ERR_RES);
+ }
+}
+
static int setup_scc(struct mac_serial * info)
{
unsigned long flags;
save_flags(flags); cli(); /* Disable interrupts */
+ /* Nice buggy HW ... */
+ fix_zero_bug_scc(info);
+
/*
* Reset the chip.
*/
info->curregs[5] &= ~TxENAB;
if (!info->tty || C_HUPCL(info->tty))
- info->curregs[5] &= ~(DTR | RTS);
+ info->curregs[5] &= ~DTR;
info->pendregs[5] = info->curregs[5];
write_zsreg(info->zs_channel, 5, info->curregs[5]);
/* assert DTR, wait 30ms, talk to the chip */
write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
- udelay(30000);
+ mdelay(30);
while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
read_zsdata(info->zs_channel);
if (C_CRTSCTS(tty)) {
/*
* Here we want to turn off the RTS line. On Macintoshes,
- * we only get the DTR line, which goes to both DTR and
- * RTS on the modem. RTS doesn't go out to the serial
- * port socket. So you should make sure your modem is
- * set to ignore DTR if you're using CRTSCTS.
+ * the external serial ports using a DIN-8 or DIN-9
+ * connector only have the DTR line (which is usually
+ * wired to both RTS and DTR on an external modem in
+ * the cable). RTS doesn't go out to the serial port
+ * socket, it acts as an output enable for the transmit
+ * data line. So in this case we don't drop RTS.
+ *
+ * Macs with internal modems generally do have both RTS
+ * and DTR wired to the modem, so in that case we do
+ * drop RTS.
*/
+ if (info->is_internal_modem) {
+ save_flags(flags); cli();
+ info->curregs[5] &= ~RTS;
+ info->pendregs[5] &= ~RTS;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ restore_flags(flags);
+ }
+ }
+
+#ifdef CDTRCTS
+ if (tty->termios->c_cflag & CDTRCTS) {
save_flags(flags); cli();
- info->curregs[5] &= ~(DTR | RTS);
- info->pendregs[5] &= ~(DTR | RTS);
+ info->curregs[5] &= ~DTR;
+ info->pendregs[5] &= ~DTR;
write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags);
}
+#endif /* CDTRCTS */
}
static void rs_unthrottle(struct tty_struct * tty)
restore_flags(flags);
}
- if (C_CRTSCTS(tty)) {
- /* Assert RTS and DTR lines */
+ if (C_CRTSCTS(tty) && info->is_internal_modem) {
+ /* Assert RTS line */
save_flags(flags); cli();
- info->curregs[5] |= DTR | RTS;
- info->pendregs[5] |= DTR | RTS;
+ info->curregs[5] |= RTS;
+ info->pendregs[5] |= RTS;
write_zsreg(info->zs_channel, 5, info->curregs[5]);
restore_flags(flags);
}
+
+#ifdef CDTRCTS
+ if (tty->termios->c_cflag & CDTRCTS) {
+ /* Assert DTR line */
+ save_flags(flags); cli();
+ info->curregs[5] |= DTR;
+ info->pendregs[5] |= DTR;
+ write_zsreg(info->zs_channel, 5, info->curregs[5]);
+ restore_flags(flags);
+ }
+#endif
}
/*
/* setup misc varariables */
zss->kgdb_channel = 0;
zss->is_cobalt_modem = device_is_compatible(ch, "cobalt");
+ zss->is_internal_modem = zss->is_cobalt_modem;
/* XXX tested only with wallstreet PowerBook,
should do no harm anyway */
zss->is_irda = conn && (strcmp(conn, "infrared") == 0);
/* 1999 Powerbook G3 has slot-names property instead */
slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len);
- if (slots && slots->count > 0 && strcmp(slots->name, "IrDA") == 0)
- zss->is_irda = 1;
+ if (slots && slots->count > 0) {
+ if (strcmp(slots->name, "IrDA") == 0)
+ zss->is_irda = 1;
+ else if (strcmp(slots->name, "Modem") == 0)
+ zss->is_internal_modem = 1;
+ }
if (zss->has_dma) {
zss->dma_priv = NULL;
printk(", port = %s", connector);
if (info->is_cobalt_modem)
printk(" (cobalt modem)");
+ else if (info->is_internal_modem)
+ printk(" (internal modem)");
if (info->is_irda)
printk(" (IrDA)");
printk("\n");
/*
* Register console.
*/
-__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+__initfunc (long mac_scc_console_init(long kmem_start, long kmem_end))
{
register_console(&sercons);
return kmem_start;
char break_abort; /* Is serial console in, so process brk/abrt */
char kgdb_channel; /* Kgdb is running on this channel */
char is_cons; /* Is this our console. */
+ char is_internal_modem; /* is connected to an internal modem */
char is_cobalt_modem; /* is a gatwick-based cobalt modem */
char is_irda; /* is connected to an IrDA codec */
unsigned char tx_active; /* character is being xmitted */
} else if (MB_IDE_READY(i)) {
bay->timer = 0;
bay->state = mb_up;
- if (bay->cd_index < 0)
+ if (bay->cd_index < 0) {
+ pmu_suspend();
bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq);
+ pmu_resume();
+ }
if (bay->cd_index == -1) {
/* We eventually do a retry */
bay->cd_retry++;
#ifdef CONFIG_PMAC_PBOOK
/*
- * notify clients before sleep and reset bus afterwards
+ * notify ents before sleep and reset bus afterwards
*/
int
mb_notify_sleep(struct pmu_sleep_notifier *self, int when)
they seem to help the 3400 get it right.
*/
feature_set(bay->dev_node, FEATURE_IOBUS_enable);
- mdelay(MB_STABLE_DELAY);
+ /* Force MB power to 0 */
+ set_mb_power(i, 0);
+ mdelay(MB_POWER_DELAY);
if (!bay->pismo)
out_8(&bay->addr->contents, 0x70);
mdelay(MB_STABLE_DELAY);
bay->last_value = bay->content_id;
bay->value_count = MS_TO_HZ(MB_STABLE_DELAY);
bay->timer = MS_TO_HZ(MB_POWER_DELAY);
+#ifdef CONFIG_BLK_DEV_IDE
bay->cd_retry = 0;
+#endif
do {
mdelay(1000/HZ);
media_bay_step(i);
#include <linux/nvram.h>
#include <linux/init.h>
#include <asm/uaccess.h>
+#include <asm/nvram.h>
#define NVRAM_SIZE 8192
return p - buf;
}
+static int nvram_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch(cmd) {
+ case PMAC_NVRAM_GET_OFFSET:
+ {
+ int part, offset;
+ if (copy_from_user(&part,(void*)arg,sizeof(part))!=0)
+ return -EFAULT;
+ if (part < pmac_nvram_OF || part > pmac_nvram_NR)
+ return -EINVAL;
+ offset = pmac_get_partition(part);
+ if (copy_to_user((void*)arg,&offset,sizeof(offset))!=0)
+ return -EFAULT;
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int nvram_open(struct inode *inode, struct file *file)
{
MOD_INC_USE_COUNT;
write_nvram,
NULL, /* nvram_readdir */
NULL, /* nvram_select */
- NULL, /* nvram_ioctl */
+ nvram_ioctl,
NULL, /* nvram_mmap */
nvram_open,
NULL, /* flush */
*
* The VIA (versatile interface adapter) interfaces to the PMU,
* a 6805 microprocessor core whose primary function is to control
- * battery charging and system power on the PowerBook 3400 and 2400.
- * The PMU also controls the ADB (Apple Desktop Bus) which connects
+ * battery charging and system power on the PowerBooks and new
+ * "Core99" Apple machines.
+ * The PMU may also controls the ADB (Apple Desktop Bus) which connects
* to the keyboard and mouse, as well as the non-volatile RAM
* and the RTC (real time clock) chip.
*
- * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
- *
- * todo: - Check this driver for smp safety (new Core99 motherboards).
- * - Cleanup synchro between VIA interrupt and GPIO-based PMU
- * interrupt.
- *
- *
+ * Copyright (C) 1998 Paul Mackerras, Fabio Riccardi
+ * and Benjamin Herrenschmidt
+ *
*/
+
#include <stdarg.h>
#include <linux/config.h>
#include <linux/types.h>
#include <asm/feature.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
+#include <asm/backlight.h>
+
+#define DEBUG_SLEEP
+#define PMU_CORE99_SLEEP /* Doesn't work yet (almost there...) */
/* Misc minor number allocated for /dev/pmu */
#define PMU_MINOR 154
static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0;
-static int pmu_has_adb, pmu_has_backlight;
+static int pmu_has_adb;
static unsigned char *gpio_reg = NULL;
static int gpio_irq = -1;
+static int pmu_suspended = 0;
+static spinlock_t pmu_lock;
int asleep;
struct pt_regs *regs);
static void set_volume(int level);
static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
+static int pmu_set_backlight_level(int level, void* data);
+static int pmu_set_backlight_enable(int on, int level, void* data);
#ifdef CONFIG_PMAC_PBOOK
static void pmu_pass_intr(unsigned char *data, int len);
#endif
};
extern void low_sleep_handler(void);
-extern void sleep_save_intrs(int);
-extern void sleep_restore_intrs(void);
+extern void pmac_sleep_save_intrs(int);
+extern void pmac_sleep_restore_intrs(void);
+extern void openpic_sleep_save_intrs(void);
+extern void openpic_sleep_restore_intrs(void);
extern int grackle_pcibios_read_config_word(unsigned char bus,
unsigned char dev_fn, unsigned char offset, unsigned short *val);
extern int grackle_pcibios_write_config_word(unsigned char bus,
unsigned char dev_fn, unsigned char offset, unsigned short val);
+#ifdef DEBUG_SLEEP
+int pmu_polled_request(struct adb_request *req);
+int pmu_wink(struct adb_request *req);
+#endif
+
+
/*
* This table indicates for each PMU opcode:
* - the number of data bytes to be sent with the command, or -1
* if a length byte should be sent,
* - the number of response bytes which the PMU will return, or
- * -1 if it will send a length byte.
+ * -1 if it will send a length byte
*/
static s8 pmu_data_len[256][2] __openfirmwaredata = {
/* 0 1 2 3 4 5 6 7 */
"Core99"
};
+static struct backlight_controller pmu_backlight_controller = {
+ pmu_set_backlight_enable,
+ pmu_set_backlight_level
+};
+
int __openfirmware
find_via_pmu()
{
return 0;
}
+ spin_lock_init(&pmu_lock);
+
pmu_has_adb = 1;
- pmu_has_backlight = 1;
if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
|| device_is_compatible(vias->parent, "ohare")))
pmu_kind = PMU_KEYLARGO_BASED;
pmu_has_adb = (find_type_devices("adb") != NULL);
- pmu_has_backlight = 0; /* Not driven by PMU */
gpiop = find_devices("gpio");
if (gpiop && gpiop->n_addrs) {
pmu_fully_inited = 1;
/* Enable backlight */
- pmu_enable_backlight(1);
+ register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
/* Make sure PMU settle down before continuing */
do {
out_8(&via[B], via[B] | TREQ); /* negate TREQ */
out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */
- pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff);
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
timeout = 100000;
while (!req.complete) {
if (--timeout < 0) {
while (!req.complete)
pmu_poll();
}
-
+
return 1;
}
req->next = 0;
req->sent = 0;
req->complete = 0;
- save_flags(flags); cli();
+ spin_lock_irqsave(&pmu_lock, flags);
if (current_req != 0) {
last_req->next = req;
last_req = req;
pmu_start();
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&pmu_lock, flags);
return 0;
}
void __openfirmware
pmu_poll()
{
- int ie;
-
+ if (!via)
+ return;
if (disable_poll)
return;
- ie = _disable_interrupts();
- if ((via[IFR] & (SR_INT | CB1_INT)) ||
- (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0))
+ /* Kicks ADB read when PMU is suspended */
+ if (pmu_suspended)
+ adb_int_pending = 1;
+ do {
via_pmu_interrupt(0, 0, 0);
- _enable_interrupts(ie);
+ } while (pmu_suspended && (adb_int_pending || pmu_state != idle
+ || req_awaiting_reply));
}
-/* This function loops until the PMU is idle, to avoid spurrious shutdowns
- * when prom.c scrollscreen or xmon spends too much time without interupts
- * while some PMU communication is going on
+/* This function loops until the PMU is idle and prevents it from
+ * anwsering to ADB interrupts. pmu_request can still be called.
+ * This is done to avoid spurrious shutdowns when we know we'll have
+ * interrupts switched off for a long time
*/
void __openfirmware
-pmu_safe_poll(void)
+pmu_suspend(void)
{
- int ie;
+#ifdef SUSPEND_USES_PMU
+ struct adb_request *req;
+#endif
+ unsigned long flags;
- if (!via || disable_poll)
+ if (!via)
+ return;
+
+ spin_lock_irqsave(&pmu_lock, flags);
+ pmu_suspended++;
+ if (pmu_suspended != 1) {
+ spin_unlock_irqrestore(&pmu_lock, flags);
return;
+ }
+
do {
- ie = _disable_interrupts();
- if ((via[IFR] & (SR_INT | CB1_INT)) ||
- (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0))
- via_pmu_interrupt(0, 0, 0);
- _enable_interrupts(ie);
- } while (adb_int_pending || pmu_state != idle);
+ spin_unlock(&pmu_lock);
+ via_pmu_interrupt(0, 0, 0);
+ spin_lock(&pmu_lock);
+ if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
+#ifdef SUSPEND_USES_PMU
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ while(!req.complete)
+ pmu_poll();
+#else /* SUSPEND_USES_PMU */
+ if (gpio_irq >= 0)
+ disable_irq(gpio_irq);
+ out_8(&via[IER], CB1_INT | IER_CLR);
+ spin_unlock_irqrestore(&pmu_lock, flags);
+#endif /* SUSPEND_USES_PMU */
+ break;
+ }
+ } while (1);
+}
+
+void __openfirmware
+pmu_resume(void)
+{
+ unsigned long flags;
+
+ if (!via || pmu_suspended < 1)
+ return;
+
+ spin_lock_irqsave(&pmu_lock, flags);
+ pmu_suspended--;
+ if (pmu_suspended > 0) {
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ return;
+ }
+ adb_int_pending = 1;
+#ifdef SUSPEND_USES_PMU
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ while(!req.complete)
+ pmu_poll();
+#else /* SUSPEND_USES_PMU */
+ if (gpio_irq >= 0)
+ enable_irq(gpio_irq);
+ out_8(&via[IER], CB1_INT | IER_SET);
+ spin_unlock_irqrestore(&pmu_lock, flags);
+ pmu_poll();
+#endif /* SUSPEND_USES_PMU */
}
static void __openfirmware
/* Currently, we use brute-force cli() for syncing with GPIO
* interrupt. I'll make this smarter later, along with some
* spinlocks for SMP */
- save_flags(flags);cli();
+ spin_lock_irqsave(&pmu_lock, flags);
++disable_poll;
+
while ((intr = in_8(&via[IFR])) != 0) {
if (++nloop > 1000) {
printk(KERN_DEBUG "PMU: stuck in intr loop, "
out_8(&via[IFR], intr);
}
}
+ /* This is not necessary except if synchronous ADB requests are done
+ * with interrupts off, which should not happen. Since I'm not sure
+ * this "wiring" will remain, I'm commenting it out for now. Please do
+ * not remove. -- BenH.
+ */
+#if 0
if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)
adb_int_pending = 1;
-
+#endif
if (pmu_state == idle) {
if (adb_int_pending) {
pmu_state = intack;
}
}
--disable_poll;
- restore_flags(flags);
+ spin_unlock_irqrestore(&pmu_lock, flags);
}
static void __openfirmware
gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
{
+ adb_int_pending = 1;
via_pmu_interrupt(0, 0, 0);
}
-
+
static void __openfirmware
pmu_sr_intr(struct pt_regs *regs)
{
/* if reading grab the byte, and reset the interrupt */
if (pmu_state == reading || pmu_state == reading_intr)
bite = in_8(&via[SR]);
-
+
out_8(&via[IFR], SR_INT);
switch (pmu_state) {
current_req = req->next;
if (req->reply_expected)
req_awaiting_reply = req;
- else
+ else {
+ spin_unlock(&pmu_lock);
pmu_done(req);
+ spin_lock(&pmu_lock);
+ }
} else {
pmu_state = reading;
data_index = 0;
printk(KERN_ERR "PMU: bad reply len %d\n",
bite);
} else {
- reply_ptr[data_index++] = bite;
+ if (data_index < 32)
+ reply_ptr[data_index++] = bite;
}
if (data_index < data_len) {
recv_byte();
req = current_req;
current_req = req->next;
req->reply_len += data_index;
+ spin_unlock(&pmu_lock);
pmu_done(req);
+ spin_lock(&pmu_lock);
}
pmu_state = idle;
}
} else if (data[0] == 0x08 && len == 3) {
/* sound/brightness buttons pressed */
- pmu_set_brightness(data[1] >> 3);
+ set_backlight_level(data[1] >> 4);
set_volume(data[2]);
} else {
#ifdef CONFIG_PMAC_PBOOK
}
}
-int backlight_level = -1;
-int backlight_enabled = 0;
-
-#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1))
-
-void __openfirmware
-pmu_enable_backlight(int on)
+static int backlight_to_bright[] = {
+ 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
+ 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
+};
+
+static int __openfirmware
+pmu_set_backlight_enable(int on, int level, void* data)
{
struct adb_request req;
+
+ if (vias == NULL)
+ return -ENODEV;
- if ((vias == NULL) || !pmu_has_backlight)
- return;
-
- /* first call: get current backlight value */
- if (on && backlight_level < 0) {
- switch (pmu_kind) {
- case PMU_OHARE_BASED:
- pmu_request(&req, NULL, 2, 0xd9, 0);
- while (!req.complete)
- pmu_poll();
- backlight_level = req.reply[1] >> 3;
- break;
- case PMU_HEATHROW_BASED:
- /* We cannot use nvram_read_byte here (not yet initialized) */
- pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe);
- while (!req.complete)
- pmu_poll();
- backlight_level = req.reply[1];
- printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level);
- break;
- case PMU_PADDINGTON_BASED:
- case PMU_KEYLARGO_BASED:
- /* the G3 PB 1999 has a backlight node
- and chrp-structured nvram */
- /* XXX should read macos's "blkt" property in nvram
- for this node. For now this ensures that the
- backlight doesn't go off as soon as linux boots. */
- backlight_level = 20;
- break;
- default:
- backlight_enabled = 0;
- return;
- }
- }
if (on) {
pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- LEVEL_TO_BRIGHT(backlight_level));
+ backlight_to_bright[level]);
while (!req.complete)
pmu_poll();
}
PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
while (!req.complete)
pmu_poll();
- backlight_enabled = on;
+
+ return 0;
}
-void __openfirmware
-pmu_set_brightness(int level)
+static int __openfirmware
+pmu_set_backlight_level(int level, void* data)
{
- int bright;
+ if (vias == NULL)
+ return -ENODEV;
- if ((vias == NULL) || !pmu_has_backlight)
- return ;
+ if (!bright_req_1.complete)
+ return -EAGAIN;
+ pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+ backlight_to_bright[level]);
+ if (!bright_req_2.complete)
+ return -EAGAIN;
+ pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT
+ | (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF));
- backlight_level = level;
- bright = LEVEL_TO_BRIGHT(level);
- if (!backlight_enabled)
- return;
- if (bright_req_1.complete)
- pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- bright);
- if (bright_req_2.complete)
- pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF));
-
- /* XXX nvram address is hard-coded and looks ok on wallstreet, please
- test on your machine. Note that newer MacOS system software may break
- the nvram layout. */
- if ((pmu_kind == PMU_HEATHROW_BASED) && bright_req_3.complete)
- pmu_request(&bright_req_3, NULL, 4, PMU_WRITE_NVRAM,
- 0x14, 0xe, level);
+ return 0;
}
void __openfirmware
when, current, current->notifier_call);
for (; list != &sleep_notifiers; list = list->next) {
current = list_entry(list, struct pmu_sleep_notifier, list);
- current->notifier_call(current, fallback);
+ current->notifier_call(current, fallback);
}
return ret;
}
}
}
-#if 0
+#ifdef DEBUG_SLEEP
/* N.B. This doesn't work on the 3400 */
-void pmu_blink(int n)
+void
+pmu_blink(int n)
{
struct adb_request req;
+ memset(&req, 0, sizeof(req));
+
for (; n > 0; --n) {
- pmu_request(&req, NULL, 4, 0xee, 4, 0, 1);
- while (!req.complete) pmu_poll();
- udelay(50000);
- pmu_request(&req, NULL, 4, 0xee, 4, 0, 0);
- while (!req.complete) pmu_poll();
- udelay(50000);
+ req.nbytes = 4;
+ req.done = NULL;
+ req.data[0] = 0xee;
+ req.data[1] = 4;
+ req.data[2] = 0;
+ req.data[3] = 1;
+ req.reply[0] = ADB_RET_OK;
+ req.reply_len = 1;
+ req.reply_expected = 0;
+ pmu_polled_request(&req);
+ mdelay(50);
+ req.nbytes = 4;
+ req.done = NULL;
+ req.data[0] = 0xee;
+ req.data[1] = 4;
+ req.data[2] = 0;
+ req.data[3] = 0;
+ req.reply[0] = ADB_RET_OK;
+ req.reply_len = 1;
+ req.reply_expected = 0;
+ pmu_polled_request(&req);
+ mdelay(50);
}
- udelay(50000);
+ mdelay(50);
}
#endif
* Put the powerbook to sleep.
*/
-#define FEATURE_CTRL(base) ((unsigned int *)(base + 0x38))
+static u32 save_via[8];
+static void save_via_state(void)
+{
+ save_via[0] = in_8(&via[ANH]);
+ save_via[1] = in_8(&via[DIRA]);
+ save_via[2] = in_8(&via[B]);
+ save_via[3] = in_8(&via[DIRB]);
+ save_via[4] = in_8(&via[PCR]);
+ save_via[5] = in_8(&via[ACR]);
+ save_via[6] = in_8(&via[T1CL]);
+ save_via[7] = in_8(&via[T1CH]);
+}
+static void restore_via_state(void)
+{
+ out_8(&via[ANH], save_via[0]);
+ out_8(&via[DIRA], save_via[1]);
+ out_8(&via[B], save_via[2]);
+ out_8(&via[DIRB], save_via[3]);
+ out_8(&via[PCR], save_via[4]);
+ out_8(&via[ACR], save_via[5]);
+ out_8(&via[T1CL], save_via[6]);
+ out_8(&via[T1CH], save_via[7]);
+ out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */
+ out_8(&via[IFR], 0x7f); /* clear IFR */
+ out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
+}
+
#define GRACKLE_PM (1<<7)
#define GRACKLE_DOZE (1<<5)
#define GRACKLE_NAP (1<<4)
int __openfirmware powerbook_sleep_G3(void)
{
- int ret;
unsigned long save_l2cr;
- unsigned long save_fcr;
unsigned long wait;
unsigned short pmcr1;
- struct adb_request sleep_req;
- struct device_node *macio;
- unsigned long macio_base = 0;
-
- macio = find_devices("mac-io");
- if (macio != 0 && macio->n_addrs > 0)
- macio_base = (unsigned long)
- ioremap(macio->addrs[0].address, 0x40);
-
+ struct adb_request req;
+ int ret, timeout;
+
/* Notify device drivers */
ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
if (ret != PBOOK_SLEEP_OK) {
}
/* Give the disks a little time to actually finish writing */
- for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
+ for (wait = jiffies + HZ; time_before(jiffies, wait); )
mb();
- /* Disable all interrupts except pmu */
- sleep_save_intrs(vias->intrs[0].line);
+ /* Wait for completion of async backlight requests */
+ while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete)
+ pmu_poll();
+
+ /* Turn off various things. Darwin does some retry tests here... */
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE);
+ while (!req.complete)
+ pmu_poll();
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY);
+ while (!req.complete)
+ pmu_poll();
+
+ /* Disable all interrupts */
+ pmac_sleep_save_intrs(-1);
+
+ /* Make sure the PMU is idle */
+ while (pmu_state != idle)
+ pmu_poll();
/* Make sure the decrementer won't interrupt us */
asm volatile("mtdec %0" : : "r" (0x7fffffff));
-#if 0
- /* Save the state of PCI config space for some slots */
- pbook_pci_save();
-#endif
+ /* Make sure any pending DEC interrupt occuring while we did
+ * the above didn't re-enable the DEC */
+ mb();
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+ /* Giveup the FPU */
+ if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0)
+ giveup_fpu(current);
+
+ /* We can now disable MSR_EE */
+ cli();
+
/* For 750, save backside cache setting and disable it */
save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */
if (save_l2cr)
_set_L2CR(0);
- if (macio_base != 0) {
- save_fcr = in_le32(FEATURE_CTRL(macio_base));
- /* Check if this is still valid on older powerbooks */
- out_le32(FEATURE_CTRL(macio_base), save_fcr & ~(0x00000140UL));
- }
+ /* Ask the PMU to put us to sleep */
+ pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+ while (!req.complete)
+ pmu_poll();
- if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0)
- giveup_fpu(current);
+ /* The VIA is supposed not to be restored correctly*/
+ save_via_state();
+ /* We shut down some HW */
+ feature_prepare_for_sleep();
grackle_pcibios_read_config_word(0,0,0x70,&pmcr1);
/* Apparently, MacOS uses NAP mode for Grackle ??? */
pmcr1 |= GRACKLE_PM|GRACKLE_NAP;
grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
- /* Ask the PMU to put us to sleep */
- pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
- while (!sleep_req.complete)
- mb();
-
- cli();
- while (pmu_state != idle)
- pmu_poll();
-
/* Call low-level ASM sleep handler */
low_sleep_handler();
grackle_pcibios_read_config_word(0, 0, 0x70, &pmcr1);
pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP);
grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1);
+
+ /* Restore things */
+ feature_wake_up();
+ restore_via_state();
+
+ /* Restore L2 cache */
+ if (save_l2cr)
+ _set_L2CR(save_l2cr);
+
+ /* Restore userland MMU context */
+ set_context(current->mm->context);
+
+ /* Re-enable DEC interrupts and kick DEC */
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+ sti();
+ asm volatile("mtdec %0" : : "r" (0x10000000));
+
+ /* Power things up */
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
+ while (!req.complete)
+ pmu_poll();
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL0,
+ PMU_POW0_ON|PMU_POW0_HARD_DRIVE);
+ while (!req.complete)
+ pmu_poll();
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY);
+ while (!req.complete)
+ pmu_poll();
+
+ /* ack all pending interrupts */
+ timeout = 100000;
+ interrupt_data[0] = 1;
+ while (interrupt_data[0] || pmu_state != idle) {
+ if (--timeout < 0)
+ break;
+ if (pmu_state == idle)
+ adb_int_pending = 1;
+ via_pmu_interrupt(0, 0, 0);
+ udelay(10);
+ }
+
+ /* reenable interrupt controller */
+ pmac_sleep_restore_intrs();
+
+ /* Leave some time for HW to settle down */
+ mdelay(100);
+
+ /* Notify drivers */
+ broadcast_wake();
+
+ return 0;
+}
+
+#ifdef PMU_CORE99_SLEEP
+
+/* Not finished yet */
+int __openfirmware powerbook_sleep_Core99(void)
+{
+ unsigned long save_l2cr;
+ unsigned long wait;
+ struct adb_request req;
+ int ret, timeout;
+
+ /* Notify device drivers */
+ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
+ if (ret != PBOOK_SLEEP_OK) {
+ printk("pmu: sleep rejected\n");
+ return -EBUSY;
+ }
+
+ /* Sync the disks. */
+ /* XXX It would be nice to have some way to ensure that
+ * nobody is dirtying any new buffers while we wait.
+ * BenH: Moved to _after_ sleep request and changed video
+ * drivers to vmalloc() during sleep request. This way, all
+ * vmalloc's are done before actual sleep of block drivers */
+ fsync_dev(0);
+
+ /* Sleep can fail now. May not be very robust but useful for debugging */
+ ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
+ if (ret != PBOOK_SLEEP_OK) {
+ printk("pmu: sleep failed\n");
+ return -EBUSY;
+ }
+
+ /* Give the disks a little time to actually finish writing */
+ for (wait = jiffies + HZ; time_before(jiffies, wait); )
+ mb();
+
+ /* Wait for completion of async backlight requests */
+ while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete)
+ pmu_poll();
+
+ /* Tell PMU what events will wake us up */
+ pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
+ 0xff, 0xff);
+ while (!req.complete)
+ pmu_poll();
+ pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS,
+ 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN);
+ while (!req.complete)
+ pmu_poll();
+
+ /* Save & disable all interrupts */
+ openpic_sleep_save_intrs();
/* Make sure the PMU is idle */
while (pmu_state != idle)
pmu_poll();
- sti();
-#if 0
- /* According to someone from Apple, this should not be needed,
- at least not for all devices. Let's keep it for now until we
- have something that works. */
- pbook_pci_restore();
-#endif
- set_context(current->mm->context);
+ /* Make sure the decrementer won't interrupt us */
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+ /* Make sure any pending DEC interrupt occuring while we did
+ * the above didn't re-enable the DEC */
+ mb();
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+
+ /* Giveup the FPU */
+ if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0)
+ giveup_fpu(current);
+
+ /* We can now disable MSR_EE */
+ cli();
+
+ /* For 750, save backside cache setting and disable it */
+ save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */
+ if (save_l2cr)
+ _set_L2CR(0);
+
+ /* Save the state of PCI config space for some slots */
+ // pbook_pci_save();
+
+ /* Ask the PMU to put us to sleep */
+ pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+ while (!req.complete)
+ pmu_poll();
+
+ /* The VIA is supposed not to be restored correctly*/
+ save_via_state();
+
+ /* Shut down various ASICs. There's a chance that we can no longer
+ * talk to the PMU after this, so I moved it to _after_ sending the
+ * sleep command to it. Still need to be checked.
+ */
+ feature_prepare_for_sleep();
+
+ /* Call low-level ASM sleep handler */
+ low_sleep_handler();
+
+ /* Restore things */
+ feature_wake_up();
+ // Don't restore PCI for now, it crashes. Maybe unnecessary on pbook
+ // pbook_pci_restore();
+
+ restore_via_state();
+
/* Restore L2 cache */
if (save_l2cr)
- _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */
+ _set_L2CR(save_l2cr);
+
+ /* Restore userland MMU context */
+ set_context(current->mm->context);
- /* reenable interrupts */
- sleep_restore_intrs();
+ /* Re-enable DEC interrupts and kick DEC */
+ asm volatile("mtdec %0" : : "r" (0x7fffffff));
+ sti();
+ asm volatile("mtdec %0" : : "r" (0x10000000));
+
+ /* Tell PMU we are ready */
+ pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+ while (!req.complete)
+ pmu_poll();
+ pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc);
+ while (!req.complete)
+ pmu_poll();
+
+ /* ack all pending interrupts */
+ timeout = 100000;
+ interrupt_data[0] = 1;
+ while (interrupt_data[0] || pmu_state != idle) {
+ if (--timeout < 0)
+ break;
+ if (pmu_state == idle)
+ adb_int_pending = 1;
+ via_pmu_interrupt(0, 0, 0);
+ udelay(10);
+ }
+
+ /* reenable interrupt controller */
+ openpic_sleep_restore_intrs();
+
+ /* Leave some time for HW to settle down */
+ mdelay(100);
/* Notify drivers */
broadcast_wake();
return 0;
}
+#endif
+
#define PB3400_MEM_CTRL ((unsigned int *)0xf8000070)
int __openfirmware powerbook_sleep_3400(void)
unsigned long msr;
unsigned int hid0;
unsigned long p, wait;
- struct adb_request sleep_req;
+ struct adb_request req;
/* Notify device drivers */
ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
mb();
+ /* Wait for completion of async backlight requests */
+ while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete)
+ pmu_poll();
+
/* Disable all interrupts except pmu */
- sleep_save_intrs(vias->intrs[0].line);
+ pmac_sleep_save_intrs(vias->intrs[0].line);
/* Make sure the decrementer won't interrupt us */
asm volatile("mtdec %0" : : "r" (0x7fffffff));
}
/* Ask the PMU to put us to sleep */
- pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
- while (!sleep_req.complete)
+ pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
+ while (!req.complete)
mb();
/* displacement-flush the L2 cache - necessary? */
asleep = 1;
/* Put the CPU into sleep mode */
- asm volatile("mfspr %0,1008" : "=r" (hid0) :);
+ hid0 = _get_HID0();
hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
- asm volatile("mtspr 1008,%0" : : "r" (hid0));
+ _set_HID0(hid0);
save_flags(msr);
msr |= MSR_POW | MSR_EE;
restore_flags(msr);
mb();
/* reenable interrupts */
- sleep_restore_intrs();
+ pmac_sleep_restore_intrs();
/* Notify drivers */
broadcast_wake();
case PMU_PADDINGTON_BASED:
error = powerbook_sleep_G3();
break;
+#ifdef PMU_CORE99_SLEEP
+ case PMU_KEYLARGO_BASED:
+ error = powerbook_sleep_Core99();
+ break;
+#endif
default:
error = -ENOSYS;
}
return error;
case PMU_IOC_GET_BACKLIGHT:
- if (!pmu_has_backlight)
- return -ENOSYS;
- return put_user(backlight_level, (__u32 *)arg);
+ error = get_backlight_level();
+ if (error < 0)
+ return error;
+ return put_user(error, (__u32 *)arg);
case PMU_IOC_SET_BACKLIGHT:
- if (!pmu_has_backlight)
- return -ENOSYS;
error = get_user(value, (__u32 *)arg);
if (!error)
- pmu_set_brightness(value);
+ error = set_backlight_level(value);
return error;
case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, (__u32 *)arg);
}
#endif /* CONFIG_PMAC_PBOOK */
-#if 0
+#ifdef DEBUG_SLEEP
static inline void polled_handshake(volatile unsigned char *via)
{
via[B] &= ~TREQ; eieio();
restore_flags(flags);
return 0;
}
-#endif /* 0 */
+#endif /* DEBUG_SLEEP */
dbdma_reset(rd);
dbdma_reset(td);
+ dbdma_st32((volatile unsigned long *)&rd->intr_sel, 0x40);
+ dbdma_st32((volatile unsigned long *)&rd->br_sel, 0x40);
+ dbdma_st32((volatile unsigned long *)&td->wait_sel, 0x20);
+
feature_set(bp->node, FEATURE_BMac_IO_enable);
- udelay(10000);
+ mdelay(100);
feature_set(bp->node, FEATURE_BMac_reset);
- udelay(10000);
+ mdelay(10);
feature_clear(bp->node, FEATURE_BMac_reset);
- udelay(10000);
+ mdelay(10);
}
#define MIFDELAY udelay(10)
/* If possible, try to fix a broken card - SMC only so far */
srom_repair(dev, broken);
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_POWERMAC
/*
** If the address starts with 00 a0, we have to bit-reverse
** each byte of the address.
dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1);
}
}
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_POWERMAC */
/* Test for a bad enet address */
status = test_bad_enet(dev, status);
*
* portions based on sunhme.c by David S. Miller
*
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/06/2000
+ * - check init_etherdev return in gmac_probe1
+ * BenH <bh40@calva.net> - 03/09/2000
+ * - Add support for new PHYs
+ * - Add some PowerBook sleep code
+ *
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/timer.h>
+#include <linux/init.h>
#include <linux/pci.h>
#include <asm/prom.h>
#include <asm/io.h>
#include <asm/pgtable.h>
-#include <asm/bitops.h>
+#include <asm/feature.h>
+#include <asm/keylargo.h>
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#include <asm/irq.h>
+#endif
#include "gmac.h"
#define DEBUG_PHY
-/* Driver version 1.1, kernel 2.2.x */
-#define GMAC_VERSION "v1.1k2"
+/* Driver version 1.3, kernel 2.2.x */
+#define GMAC_VERSION "v1.3k2"
static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN];
static struct device *gmacs = NULL;
static void mii_interrupt(struct gmac *gm);
static int mii_lookup_and_reset(struct gmac *gm);
static void mii_setup_phy(struct gmac *gm);
+static int mii_do_reset_phy(struct gmac *gm, int phy_addr);
+static void mii_init_BCM5400(struct gmac *gm);
static void gmac_set_power(struct gmac *gm, int power_up);
static int gmac_powerup_and_reset(struct device *dev);
+static void gmac_set_gigabit_mode(struct gmac *gm, int gigabit);
static void gmac_set_duplex_mode(struct gmac *gm, int full_duplex);
static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr);
static void gmac_init_rings(struct gmac *gm, int from_irq);
extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
unsigned char *devfn_ptr);
+#ifdef CONFIG_PMAC_PBOOK
+int gmac_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier gmac_sleep_notifier = {
+ gmac_sleep_notify, SLEEP_LEVEL_NET,
+};
+#endif
+
/* Stuff for talking to the physical-layer chip */
static int
mii_read(struct gmac *gm, int phy, int r)
udelay(GM_MIF_POLL_DELAY);
}
+/* Link modes of the BCM5400 PHY */
+static int phy_BCM5400_link_table[8][3] = {
+ { 0, 0, 0 }, /* No link */
+ { 0, 0, 0 }, /* 10BT Half Duplex */
+ { 1, 0, 0 }, /* 10BT Full Duplex */
+ { 0, 1, 0 }, /* 100BT Half Duplex */
+ { 0, 1, 0 }, /* 100BT Half Duplex */
+ { 1, 1, 0 }, /* 100BT Full Duplex*/
+ { 1, 0, 1 }, /* 1000BT */
+ { 1, 0, 1 }, /* 1000BT */
+};
+
static void
mii_interrupt(struct gmac *gm)
{
/* We read the Auxilliary Status Summary register */
phy_status = mii_read(gm, gm->phy_addr, MII_SR);
if ((phy_status ^ gm->phy_status) & (MII_SR_ASSC | MII_SR_LKS)) {
- int full_duplex;
- int link_100;
+ int full_duplex = 0;
+ int link_100 = 0;
+ int gigabit = 0;
#ifdef DEBUG_PHY
printk("Link state change, phy_status: 0x%04x\n", phy_status);
#endif
else
GM_BIC(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN);
- /* Link ? For now we handle only the 5201 PHY */
+ /* Link ? Check for speed and duplex */
if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) {
+ int restart = 0;
if (gm->phy_type == PHY_B5201) {
int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS);
#ifdef DEBUG_PHY
#endif
full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0);
link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0);
- } else {
- full_duplex = 1;
- link_100 = 1;
+ } else if (gm->phy_type == PHY_B5400) {
+ int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS);
+ int link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+ MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT;
+#ifdef DEBUG_PHY
+ printk(" Link up ! BCM5400 aux_stat: 0x%04x (link mode: %d)\n",
+ aux_stat, link);
+#endif
+ full_duplex = phy_BCM5400_link_table[link][0];
+ link_100 = phy_BCM5400_link_table[link][1];
+ gigabit = phy_BCM5400_link_table[link][2];
+ } else if (gm->phy_type == PHY_LXT971) {
+ int stat2 = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2);
+#ifdef DEBUG_PHY
+ printk(" Link up ! LXT971 stat2: 0x%04x\n", stat2);
+#endif
+ full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0);
+ link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0);
}
#ifdef DEBUG_PHY
printk(" full_duplex: %d, speed: %s\n", full_duplex,
- link_100 ? "100" : "10");
+ gigabit ? "1000" : (link_100 ? "100" : "10"));
#endif
+ if (gigabit != gm->gigabit) {
+ gm->gigabit = gigabit;
+ gmac_set_gigabit_mode(gm, gm->gigabit);
+ restart = 1;
+ }
if (full_duplex != gm->full_duplex) {
gm->full_duplex = full_duplex;
gmac_set_duplex_mode(gm, gm->full_duplex);
- gmac_start_dma(gm);
+ restart = 1;
}
+ if (restart)
+ gmac_start_dma(gm);
} else if (!(phy_status & MII_SR_LKS)) {
#ifdef DEBUG_PHY
printk(" Link down !\n");
}
}
+static int
+mii_do_reset_phy(struct gmac *gm, int phy_addr)
+{
+ int mii_control, timeout;
+
+ mii_control = mii_read(gm, phy_addr, MII_CR);
+ mii_write(gm, phy_addr, MII_CR, mii_control | MII_CR_RST);
+ mdelay(10);
+ for (timeout = 100; timeout > 0; --timeout) {
+ mii_control = mii_read(gm, phy_addr, MII_CR);
+ if (mii_control == -1) {
+ printk(KERN_ERR "%s PHY died after reset !\n",
+ gm->dev->name);
+ return 1;
+ }
+ if ((mii_control & MII_CR_RST) == 0)
+ break;
+ mdelay(10);
+ }
+ if (mii_control & MII_CR_RST) {
+ printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name);
+ return 1;
+ }
+ mii_write(gm, phy_addr, MII_CR, mii_control & ~MII_CR_ISOL);
+ return 0;
+}
+
+static void
+mii_init_BCM5400(struct gmac *gm)
+{
+ int data;
+
+ data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL);
+ data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
+ mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data);
+
+ data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL);
+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data);
+
+ mdelay(10);
+ mii_do_reset_phy(gm, 0x1f);
+
+ data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY);
+ data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+ mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data);
+
+ data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL);
+ data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
+ mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data);
+}
+
static int
mii_lookup_and_reset(struct gmac *gm)
{
- int i, timeout;
- int mii_status, mii_control;
+ int i, mii_status, mii_control;
- /* Find the PHY */
gm->phy_addr = -1;
gm->phy_type = PHY_UNKNOWN;
+
+ /* Hard reset the PHY */
+ feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_ASSERT);
+ mdelay(10);
+ feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_RELEASE);
+ mdelay(10);
- for(i=31; i>0; --i) {
+ /* Find the PHY */
+ for(i=0; i<32; i++) {
mii_control = mii_read(gm, i, MII_CR);
mii_status = mii_read(gm, i, MII_SR);
if (mii_control != -1 && mii_status != -1 &&
break;
}
gm->phy_addr = i;
- if (gm->phy_addr < 0)
+ if (gm->phy_addr > 31)
return 0;
/* Reset it */
- mii_write(gm, gm->phy_addr, MII_CR, mii_control | MII_CR_RST);
- mdelay(10);
- for (timeout = 100; timeout > 0; --timeout) {
- mii_control = mii_read(gm, gm->phy_addr, MII_CR);
- if (mii_control == -1) {
- printk(KERN_ERR "%s PHY died after reset !\n",
- gm->dev->name);
- goto fail;
- }
- if ((mii_control & MII_CR_RST) == 0)
- break;
- mdelay(10);
- }
- if (mii_control & MII_CR_RST) {
- printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name);
+ if (mii_do_reset_phy(gm, gm->phy_addr))
goto fail;
- }
- mii_write(gm, gm->phy_addr, MII_CR, mii_control & ~MII_CR_ISOL);
-
+
/* Read the PHY ID */
gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) |
mii_read(gm, gm->phy_addr, MII_ID1);
#endif
if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) {
gm->phy_type = PHY_B5400;
- printk(KERN_ERR "%s Warning ! Unsupported BCM5400 PHY !\n",
+ printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n",
gm->dev->name);
+ mii_init_BCM5400(gm);
} else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) {
gm->phy_type = PHY_B5201;
+ printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name);
+ } else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) {
+ gm->phy_type = PHY_LXT971;
+ printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name);
} else {
printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n",
gm->dev->name, gm->phy_id);
gmac_set_power(struct gmac *gm, int power_up)
{
if (power_up) {
- out_le32(gm->sysregs + 0x20/4,
- in_le32(gm->sysregs + 0x20/4) | 0x02000000);
- udelay(20);
+ feature_set_gmac_power(gm->of_node, 1);
if (gm->pci_devfn != 0xff) {
u16 cmd;
} else {
/* FIXME: Add PHY power down */
gm->phy_type = 0;
- out_le32(gm->sysregs + 0x20/4,
- in_le32(gm->sysregs + 0x20/4) & ~0x02000000);
- udelay(20);
+ feature_set_gmac_power(gm->of_node, 0);
}
}
}
}
+/* Set the MAC gigabit mode. Side effect: stops Tx MAC */
+static void
+gmac_set_gigabit_mode(struct gmac *gm, int gigabit)
+{
+ /* Stop Tx MAC */
+ GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE);
+ while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE)
+ ;
+
+ if (gigabit) {
+ GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE);
+ } else {
+ GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE);
+ }
+}
+
static void
gmac_mac_init(struct gmac *gm, unsigned char *mac_addr)
{
(31 << GM_GCONF_TXDMA_LIMIT_SHIFT) |
(31 << GM_GCONF_RXDMA_LIMIT_SHIFT));
GM_OUT(GM_TX_CONF,
- GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT |
+ (GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT) |
NTX_CONF);
-/* 34 byte offset for checksum computation. This works because ip_input() will clear out
- * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are
- * present in the header. 34 == (ethernet header len) + sizeof(struct iphdr)
- */
+ /* 34 byte offset for checksum computation. This works because ip_input() will clear out
+ * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are
+ * present in the header. 34 == (ethernet header len) + sizeof(struct iphdr)
+ */
GM_OUT(GM_RX_CONF,
(RX_OFFSET << GM_RX_CONF_FBYTE_OFF_SHIFT) |
(0x22 << GM_RX_CONF_CHK_START_SHIFT) |
return 0;
}
+#ifdef CONFIG_PMAC_PBOOK
+int
+gmac_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+ struct gmac *gm;
+ int i;
+
+ /* XXX should handle more than one */
+ if (gmacs == NULL)
+ return PBOOK_SLEEP_OK;
+
+ gm = (struct gmac *) gmacs->priv;
+ if (!gm->opened)
+ return PBOOK_SLEEP_OK;
+
+ switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+ break;
+ case PBOOK_SLEEP_REJECT:
+ break;
+ case PBOOK_SLEEP_NOW:
+ disable_irq(gm->dev->irq);
+ gm->dev->tbusy = 1;
+ gmac_stop_dma(gm);
+ mii_poll_stop(gm);
+ gmac_set_power(gm, 0);
+ for (i = 0; i < NRX; ++i) {
+ if (gm->rx_buff[i] != 0) {
+ dev_kfree_skb(gm->rx_buff[i]);
+ gm->rx_buff[i] = 0;
+ }
+ }
+ for (i = 0; i < NTX; ++i) {
+ if (gm->tx_buff[i] != 0) {
+ dev_kfree_skb(gm->tx_buff[i]);
+ gm->tx_buff[i] = 0;
+ }
+ }
+ break;
+ case PBOOK_WAKE:
+ /* see if this is enough */
+ gmac_powerup_and_reset(gm->dev);
+ gm->full_duplex = 0;
+ gm->phy_status = 0;
+ mii_lookup_and_reset(gm);
+ mii_setup_phy(gm);
+ gmac_init_rings(gm, 0);
+ gmac_mac_init(gm, gm->dev->dev_addr);
+ gmac_set_multicast(gm->dev);
+ mii_interrupt(gm);
+ gmac_start_dma(gm);
+ gm->dev->tbusy = 0;
+ enable_irq(gm->dev->irq);
+ break;
+ }
+ return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
/*
* Handle a transmit timeout
*/
struct gmac *gm = (struct gmac *) dev->priv;
int i, timeout;
unsigned long flags;
-
- save_flags(flags);
- cli();
printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
+ spin_lock_irqsave(&gm->lock, flags);
+
/*
* Do something useful here
*
/* Restart chip */
gmac_start_dma(gm);
- restore_flags(flags);
+ spin_unlock_irqrestore(&gm->lock, flags);
dev->tbusy = 0;
}
struct gmac *gm = (struct gmac *) dev->priv;
volatile struct gmac_dma_desc *dp;
int i;
+ unsigned long flags;
/* Check tbusy bit and handle eventual transmitter timeout */
if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
return 1;
}
+ spin_lock_irqsave(&gm->lock, flags);
+
i = gm->next_tx;
if (gm->tx_buff[i] != 0) {
/* buffer is full, can't send this packet at the moment */
+ spin_unlock_irqrestore(&gm->lock, flags);
return 1;
}
gm->next_tx = (i + 1) & (NTX - 1);
dev->tbusy = (gm->tx_buff[gm->next_tx] != 0);
+ spin_unlock_irqrestore(&gm->lock, flags);
+
return 0;
}
int gone, i;
i = gm->tx_gone;
- gone = GM_IN(GM_TX_COMP);
-
- while (force_cleanup || i != gone) {
+ do {
+ gone = GM_IN(GM_TX_COMP);
skb = gm->tx_buff[i];
if (skb == NULL)
break;
dev_kfree_skb(skb);
if (++i >= NTX)
i = 0;
- }
+ } while (force_cleanup || i != gone);
gm->tx_gone = i;
if (!force_cleanup && dev->tbusy &&
}
if (status & GM_IRQ_MIF) {
+ spin_lock(&gm->lock);
mii_interrupt(gm);
+ spin_unlock(&gm->lock);
}
- if (status & GM_IRQ_RX_DONE)
+ if (status & GM_IRQ_RX_DONE) {
+ spin_lock(&gm->lock);
gmac_receive(dev);
-
- if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL))
+ spin_unlock(&gm->lock);
+ }
+
+ if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL)) {
+ spin_lock(&gm->lock);
gmac_tx_cleanup(dev, 0);
-
+ spin_unlock(&gm->lock);
+ }
+
dev->interrupt = 0;
}
dev->base_addr = gmac->addrs[0].address;
gm->regs = (volatile unsigned int *)
ioremap(gmac->addrs[0].address, 0x10000);
- gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000);
dev->irq = gmac->intrs[0].line;
gm->dev = dev;
-
+ gm->of_node = gmac;
+
+ spin_lock_init(&gm->lock);
+
if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) {
gm->pci_bus = gm->pci_devfn = 0xff;
printk(KERN_ERR "Can't locate GMAC PCI entry\n");
gmacs = dev;
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_register_sleep_notifier(&gmac_sleep_notifier);
+#endif
return 0;
}
*/
/* Supported PHYs (phy_type field ) */
-#define PHY_B5400 5400
-#define PHY_B5201 5201
+#define PHY_B5400 0x5400
+#define PHY_B5201 0x5201
+#define PHY_LXT971 0x0971
#define PHY_UNKNOWN 0
/* Identification (for multi-PHY) */
#define MII_BCM5400_REV 0x01
#define MII_BCM5400_ID ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4))
#define MII_BCM5400_MASK 0xfffffff0
+#define MII_LXT971_OUI 0x0004de
+#define MII_LXT971_MODEL 0x0e
+#define MII_LXT971_REV 0x00
+#define MII_LXT971_ID ((MII_LXT971_OUI << 10) | (MII_LXT971_MODEL << 4))
+#define MII_LXT971_MASK 0xfffffff0
/* BCM5201 AUX STATUS register */
#define MII_BCM5201_AUXCTLSTATUS 0x18
#define MII_BCM5201_MULTIPHY_SERIALMODE 0x0002
#define MII_BCM5201_MULTIPHY_SUPERISOLATE 0x0008
+/* MII BCM5400 1000-BASET Control register */
+#define MII_BCM5400_GB_CONTROL 0x09
+#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200
+
+/* MII BCM5400 AUXCONTROL register */
+#define MII_BCM5400_AUXCONTROL 0x18
+#define MII_BCM5400_AUXCONTROL_PWR10BASET 0x0004
+
+/* MII BCM5400 AUXSTATUS register */
+#define MII_BCM5400_AUXSTATUS 0x19
+#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700
+#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
+
+/* MII LXT971 STATUS2 register */
+#define MII_LXT971_STATUS2 0x11
+#define MII_LXT971_STATUS2_SPEED 0x4000
+#define MII_LXT971_STATUS2_LINK 0x0400
+#define MII_LXT971_STATUS2_FULLDUPLEX 0x0200
+#define MII_LXT971_STATUS2_AUTONEG_COMPLETE 0x0080
+
/*
struct gmac {
volatile unsigned int *regs; /* hardware registers, virtual addr */
- volatile unsigned int *sysregs;
struct device *dev;
+ struct device_node *of_node;
unsigned long tx_desc_page; /* page for DMA descriptors */
unsigned long rx_desc_page; /* page for DMA descriptors */
volatile struct gmac_dma_desc *rxring;
int phy_type;
int phy_status; /* Cached PHY status */
int full_duplex; /* Current set to full duplex */
+ int gigabit; /* Current set to 1000BT */
struct net_device_stats stats;
u8 pci_bus;
u8 pci_devfn;
+ spinlock_t lock;
int opened;
};
#define CISCO_ADDR_REQ 0 /* Cisco address request */
#define CISCO_ADDR_REPLY 1 /* Cisco address reply */
#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+#define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */
static int hdlc_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
return;
#endif
+ case CISCO_SYS_INFO:
+ /* Packet is not needed, drop it. */
+ dev_kfree_skb(skb);
+ return;
+
case CISCO_KEEPALIVE:
if (skb->len != CISCO_PACKET_LEN &&
skb->len != CISCO_BIG_PACKET_LEN) {
} /* switch(keepalive type) */
} /* switch(protocol) */
- printk(KERN_INFO "%s: Unusupported protocol %x\n", hdlc->name,
+ printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc->name,
data->protocol);
hdlc->stats.rx_bytes+=skb->len;
hdlc->stats.rx_packets++;
bool 'Network device support' CONFIG_NETDEVICES
if [ "$CONFIG_NETDEVICES" = "y" ]; then
comment 'S390 Network devices'
- bool 'CTC device support' CONFIG_CTC
+ tristate 'CTC device support' CONFIG_CTC
bool 'IUCV device support (VM only)' CONFIG_IUCV
tristate 'Dummy net driver support' CONFIG_DUMMY
bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
CFLAGS +=
O_TARGET := io.o
-O_OBJS := ccwcache.o
+O_OBJS := ccwcache.o idals.o
M_OBJS :=
SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \
arch/s390/drivers/misc arch/s390/drivers/net
MOD_SUB_DIRS += ./net ./block
-O_OBJS := block/s390-block.o \
+O_OBJS += block/s390-block.o \
char/s390-char.o \
misc/s390-misc.o \
- net/s390-net.o \
- ccwcache.o
+ net/s390-net.o
io.o: $(O_OBJS)
net/s390-net.o: dummy
$(MAKE) -C net
-
include $(TOPDIR)/Rules.make
CFLAGS +=
O_TARGET := s390-block.o
-O_OBJS :=
+O_OBJS :=
M_OBJS :=
D_OBJS :=
Adapted request function to make it work on 2.4
* 07/10/00 Added some code to the request function to dequeue requests
that cannot be handled due to errors
- * 07/10/00 Moved linux/ccwcache.h to asm/
+ * 07/10/00 Moved linux/dasd.h and linux/ccwcache.h to asm/
* 07/10/00 Fixed a bug when formatting a 'new' device
* 07/10/00 Removed an annoying message from dasd_format
* 07/11/00 Reanimated probeonly mode
* 07/12/00 fixed a bug in dasd_devices_open when having 'unknown' devices
* 07/13/00 fixed error message when having no device
* 07/13/00 added code for dynamic device recognition
+ * 07/14/00 reorganized the format process for better ERP
+ * 07/17/00 fixed a race condition when sleeping on a request
+ * 07/17/00 modified default ERP action to use TIC instead of NOP
+ * 07/20/00 fixed proc filesystem for 2.4
+ * 07/24/00 fixed missing interrupt handler
+ * 08/01/00 fixed a race condition when sleeping on a request
+ * 09/15/00 fixed a race condition on dasd_do_chanq
+ * 09/15/00 got rid of some paranoia
+ * 09/18/00 fixed the state machine for duplicate devnos in dasd ranges
+ * 10/26/00 fixed ITPM PL020141RSC load module to a kernel with static driver
+ are the fixes in dasd_init
+ * 10/26/00 fixed ITPM PL020062RSC formatting r/o volume
+ are the fixes in dasd_format
+ * 10/26/00 fixed ITPM PL010261EPA race condition when formatting
+ are the fixes in dasd_do_chanq
*/
#include <linux/config.h>
+#include <linux/version.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/stddef.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
#include <linux/ctype.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/spinlock.h>
+#else
+#include <asm/spinlock.h>
+#endif
+
#include <asm/ccwcache.h>
#include <asm/dasd.h>
#include <linux/blk.h>
#include <asm/atomic.h>
#include <asm/delay.h>
#include <asm/io.h>
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-#include <asm/spinlock.h>
-#endif /* LINUX_IS_24 */
#include <asm/semaphore.h>
#include <asm/ebcdic.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/s390_ext.h>
#include <asm/s390dyn.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <asm/idals.h>
+#endif /* LINUX_IS_24 */
#include "dasd.h"
#ifdef CONFIG_DASD_ECKD
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
static struct block_device_operations dasd_device_operations;
#endif /* VERSION_CODE */
-
+
#ifdef MODULE
#define EXPORT_SYMTAB
#include <linux/module.h>
static void dasd_do_chanq (void);
static void schedule_request_fn (void (*func) (void));
static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int);
-static int dasd_oper_handler ( int irq, devreg_t *devreg );
/* SECTION: managing setup of dasd_driver */
typedef struct dasd_range_t {
}
return r;
}
-
+
static void
dasd_add_range (int from, int to)
{
} else {
range -> to = to;
}
-
+
/* chain current range to end of list */
if ( dasd_range_head == NULL ) {
dasd_range_head = range;
count ++;
tmp = end;
} while ( tmp != NULL && *tmp != '\0' );
- }
+}
static char dasd_parm_string[1024] = {0,};
*(dasd_parm_string+strlen(dasd_parm_string))=',';
} else {
first_time = 0;
- }
+ }
memcpy(dasd_parm_string+strlen(dasd_parm_string),str,strlen(str)+1);
return 1;
}
#else
-void
+void
dasd_setup (char *str, int *ints)
{
static int first_time = 1;
{
char *temp;
int from, to;
-
+
if ( *str ) {
dasd_probeonly = 0;
}
} else if ( strncmp ( *str,"probeonly",strlen("probeonly"))== 0) {
dasd_probeonly = 1;
printk (KERN_INFO "turning to probeonly mode\n");
- break;
+ break;
} else {
dasd_autodetect = 0;
from = dasd_strtoul (temp, &temp);
if (*temp == '-') {
temp++;
to = dasd_strtoul (temp, &temp);
- }
+ }
dasd_add_range (from, to);
- }
+ }
str ++;
- }
- }
+ }
+}
int
devindex_from_devno (int devno)
devindex += devno - temp -> from;
break;
}
- }
+ }
if ( temp == NULL )
return -ENODEV;
return devindex;
- }
+}
/* SECTION: ALl needed for multiple major numbers */
#endif /* LINUX_IS_24 */
nr_real:DASD_PER_MAJOR,
}
- }
+ }
#if 0
,
{
max_nr:DASD_PER_MAJOR,
#endif /* LINUX_IS_24 */
nr_real:DASD_PER_MAJOR,
- }
}
+ }
#endif
};
find_dasd_device (int devindex)
{
major_info_t *major_info = dasd_major_info;
- while (major_info && devindex > DASD_PER_MAJOR) {
+ while (major_info && devindex >= DASD_PER_MAJOR) {
devindex -= DASD_PER_MAJOR;
major_info = major_info->next;
}
major_info_from_devindex (int devindex)
{
major_info_t *major_info = dasd_major_info;
- while (major_info && devindex > DASD_PER_MAJOR) {
+ while (major_info && devindex >= DASD_PER_MAJOR) {
devindex -= DASD_PER_MAJOR;
major_info = major_info->next;
}
return major_info;
- }
+}
int
major_from_devindex (int devindex)
* void dasd_discipline_enq (dasd_discipline_t * d)
*/
-void
+void
dasd_discipline_enq (dasd_discipline_t * d)
{
spin_lock (&discipline_lock);
static void
dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
- {
+{
cqr->next = q->head;
q->head = cqr;
if (q->tail == NULL)
q->tail = cqr;
q->queued_requests++;
atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
- }
+}
/*
* int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
if (prev->next == NULL)
q->tail = prev;
}
- cqr->next = NULL;
+/* cqr->next = NULL; */
q->queued_requests--;
return 0;
}
#else
static spinlock_t cq_lock = SPIN_LOCK_UNLOCKED; /* spinlock for cq_head */
#endif /* LINUX_IS_24 */
+#else
+int cq_lock;
#endif /* __SMP__ */
static dasd_chanq_t *qlist_head = NULL; /* head of queue of queues */
static void
qlist_enq (dasd_chanq_t * q)
{
+ long flags;
if (q == NULL) {
printk (KERN_WARNING PRINTK_HEADER " NULL queue to be queued to queue of queues\n");
return;
}
- spin_lock (&cq_lock);
+ spin_lock_irqsave (&cq_lock,flags);
if (atomic_read (&q->flags) & DASD_CHANQ_ACTIVE) {
printk (KERN_WARNING PRINTK_HEADER " Queue already active");
}
atomic_set_mask (DASD_CHANQ_ACTIVE, &q->flags);
q->next_q = qlist_head;
qlist_head = q;
- spin_unlock (&cq_lock);
+ spin_unlock_irqrestore (&cq_lock,flags);
}
/*
static void
qlist_deq (dasd_chanq_t * q)
{
-
- if (qlist_head == NULL) {
+ long flags;
+ if (qlist_head == NULL) {
printk (KERN_ERR PRINTK_HEADER "Channel queue is empty%s\n", "");
return;
}
printk (KERN_WARNING PRINTK_HEADER " NULL queue to be dequeued from queue of queues\n");
return;
}
- spin_lock (&cq_lock);
+ spin_lock_irqsave (&cq_lock,flags);
if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
printk (KERN_WARNING PRINTK_HEADER " Queue not active\n");
} else if (qlist_head == q) {
}
atomic_clear_mask (DASD_CHANQ_ACTIVE, &q->flags);
q->next_q = NULL;
- spin_unlock (&cq_lock);
+ spin_unlock_irqrestore (&cq_lock,flags);
}
/* SECTION: All the gendisk stuff */
resetup_one_dev(dd,minor>>DASD_PARTN_BITS);
#endif /* LINUX_IS_24 */
return rc;
- }
+}
/* SECTION: Managing wrappers for ccwcache */
int i;
for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
dasd_emergency_req[i] = (ccw_req_t*)get_free_page(GFP_KERNEL);
- }
}
+}
static void
dasd_cleanup_emergency_req ( void )
if ( dasd_emergency_req[i] != NULL ) {
rv = dasd_emergency_req[i];
dasd_emergency_req[i] = NULL;
+ break;
}
}
spin_unlock(&dasd_emergency_req_lock);
return rv;
}
-void
+void
dasd_free_request (ccw_req_t * request)
{
if ( request -> cache >= (kmem_cache_t *)dasd_emergency_req &&
request -> cache <= (kmem_cache_t *)(dasd_emergency_req + DASD_EMERGENCY_REQUESTS) ) {
*((ccw_req_t **)(request -> cache)) = request;
- } else {
+ } else {
ccw_free_request(request);
- }
+ }
}
/* SECTION: Managing the device queues etc. */
major_info_t *mi;
for (mi=dasd_major_info; mi != NULL; mi = mi->next ) {
do_dasd_request(BLK_DEFAULT_QUEUE(mi->gendisk.major));
- }
+ }
}
#else
do_dasd_request ();
major_info_t *major_info;
struct request *req;
- if (!cqr) {
+ if (!cqr) {
printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function");
return -EINVAL;
- }
+ }
irq = device->devinfo.irq;
devno = device->devinfo.devno;
req = (struct request *) cqr->req;
return -EINVAL;
}
atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
- do {
+ do {
asm volatile ("STCK %0":"=m" (cqr->startclk));
rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
switch (rc) {
case 0:
if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) {
atomic_set_mask (DASD_CHANQ_BUSY, &device->queue.flags);
- }
+ }
if ( cqr->expires ) {
cqr->expires += cqr->startclk;
- }
- break;
+ }
+ break;
case -ENODEV:
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" appears not to be present %d retries left\n",
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
retries);
- break;
+ break;
case -EIO:
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" I/O error %d retries left\n",
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
retries);
- break;
+ break;
case -EBUSY: /* set up timer, try later */
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" is busy %d retries left\n",
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
retries);
- break;
+ break;
default:
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" Pls report this message to linux390@de.ibm.com\n",
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
rc, retries);
- break;
- }
+ break;
+ }
} while (rc && retries--);
if (rc) {
atomic_compare_and_swap_debug (&cqr->status,
CQR_STATUS_IN_IO,
CQR_STATUS_ERROR);
- }
+ }
return rc;
- }
+}
+
+
+static int
+sleep_on_req ( ccw_req_t * req )
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+ DECLARE_WAITQUEUE (wait,current);
+#else
+ struct wait_queue wait = {current, NULL};
+#endif /* LINUX_VERSION_CODE */
+ unsigned long flags;
+ int cs;
+ int rc = 0;
+ dasd_device_t *device = (dasd_device_t *)req->device;
+ s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+ dasd_chanq_enq (&device->queue, req);
+ if (!(atomic_read (&device->queue.flags) & DASD_CHANQ_ACTIVE)) {
+ qlist_enq (&device->queue);
+ }
+ dasd_schedule_bh();
+ add_wait_queue (&device->wait_q, &wait);
+ do {
+ current->state = TASK_INTERRUPTIBLE;
+ s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
+ schedule ();
+ s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+ cs = atomic_read (&req->status);
+ } while ( ! (cs & CQR_STATUS_FINISHED) );
+ /* was originally: while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_FAILED)); */
+ remove_wait_queue (&device->wait_q, &wait);
+ s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
+ if ( cs & CQR_STATUS_FAILED ) {
+ rc = -EIO;
+ }
+ return rc;
+}
+
static void
dasd_end_request (struct request *req, int uptodate)
{
struct buffer_head *bh;
while ((bh = req->bh) != NULL) {
- req->bh = bh->b_reqnext;
+ req->bh = bh->b_reqnext;
bh->b_reqnext = NULL;
bh->b_end_io (bh, uptodate);
- }
+ }
if (!end_that_request_first (req, uptodate, DASD_NAME)) {
#ifndef DEVICE_NO_RANDOM
add_blkdev_randomness (MAJOR (req->rq_dev));
major_info_t *major_info;
int devno;
int major;
-
+
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
{
#else
for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) {
major = major_info->gendisk.major;
- prev = NULL;
- for (req = CURRENT; req != NULL; req = next) {
- next = req->next;
+ prev = NULL;
+ for (req = CURRENT; req != NULL; req = next) {
+ next = req->next;
if (req == &blk_dev[major].plug) { /* remove plug if applicable */
req->next = NULL;
- if (prev) {
- prev->next = next;
- } else {
- CURRENT = next;
- }
+ if (prev) {
+ prev->next = next;
+ } else {
+ CURRENT = next;
+ }
continue;
- }
+ }
#endif /* LINUX_IS_24 */
devindex = devindex_from_kdev_t(req->rq_dev);
if ( devindex < 0 ) {
printk ( KERN_WARNING PRINTK_HEADER
"requesting I/O on nonexistent device %d -> %d\n",
devindex,req->rq_dev);
- dasd_end_request (req, 0);
+ dasd_end_request(req,0);
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
blkdev_dequeue_request (req);
#else
req->next = NULL;
if (prev) {
prev->next = next;
- } else {
+ } else {
CURRENT = next;
- }
+ }
#endif /* LINUX_IS_24 */
continue;
}
volatile int cqrstatus;
for (qp = qlist_head; qp != NULL; qp = nqp) {
+
+ device = (dasd_device_t *)((long)qp - (long)offsetof(dasd_device_t,queue));
+ irq = device->devinfo.irq;
+
+ s390irq_spin_lock_irqsave (irq, flags);
+
/* Get first request */
cqr = (ccw_req_t *) (qp->head);
nqp = qp->next_q;
/* empty queue -> dequeue and proceed */
if (!cqr) {
qlist_deq (qp);
+ s390irq_spin_unlock_irqrestore(irq,flags);
continue;
}
+ s390irq_spin_unlock_irqrestore(irq,flags);
+
/* process all requests on that queue */
do {
- dasd_discipline_t *discipline;
+ dasd_discipline_t *discipline=device->discipline;
next = NULL;
- /* Sanity check... walk through disciplines */
- for (discipline = dasd_disciplines;
- discipline != NULL;
- discipline = discipline->next)
- if (!strncmp ((char *) &cqr->magic, discipline->ebcname, 4))
- break;
- if (!discipline) { /* 1st sanity check */
+
+ if (strncmp ((char *) &cqr->magic, discipline->ebcname, 4)) {
panic (PRINTK_HEADER
"in dasd_do_chanq: magic no mismatch %p -> 0x%lX\n",
cqr, cqr->magic);
}
- device = (dasd_device_t *) (cqr->device);
- if (discipline != device->discipline) { /* 1st sanity check */
- printk (KERN_WARNING PRINTK_HEADER
- "in dasd_do_chanq: discipline mismatch %p -> 0x%lX\n",
- cqr, cqr->magic);
- discipline = device->discipline;
+ if ( device != cqr->device ) {
+ panic (PRINTK_HEADER
+ "in dasd_do_chanq: device mismatch %p -> %p(qcr) vs. %p\n",
+ cqr, cqr->device,device);
}
- irq = device->devinfo.irq;
devno = device->devinfo.devno;
devindex = devindex_from_devno (devno);
- s390irq_spin_lock_irqsave (irq, flags);
-
+ s390irq_spin_lock_irqsave (irq,
+ flags);
cqrstatus = atomic_read (&cqr->status);
+
switch (cqrstatus) {
case CQR_STATUS_QUEUED:
if (discipline->start_IO &&
case EBUSY:
if (cqr->retries--) {
printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " retrying %d retries left\n",
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d) busy:"
+ " retrying ... %d retries left\n",
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
break;
}
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" Giving up this request!\n",
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
- atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_QUEUED,
+ CQR_STATUS_FAILED | CQR_STATUS_FINISHED);
break;
}
}
}
break;
case CQR_STATUS_IN_IO:{
- unsigned long long now;
- unsigned long long delta;
-
+ unsigned long long now;
+ unsigned long long delta;
+
asm volatile ("STCK %0":"=m" (now));
if (cqr->expires && cqr->startclk &&
cqr->expires < now) {
delta = cqr->expires - cqr->startclk;
printk (KERN_ERR PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " I/O operation outstanding longer than %Ld usecs on req %p\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, delta >> 12, cqr);
+ " I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n",
+ devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr);
+ cqr->expires += delta;
+#if 0
if ( cqr->retries-- ) {
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" You should disable that device by issueing '@#?!'\n", /* FIXME */
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+ halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT);
break;
}
+#endif
}
break;
- }
+ }
case CQR_STATUS_ERROR:{
- dasd_erp_action_fn_t erp_action;
- ccw_req_t *erp_cqr = NULL;
- if (discipline->erp_action &&
- ((erp_action = discipline->erp_action (cqr)) != NULL)) {
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " Taking error recovery action %p on req %p \n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_action,cqr);
- erp_cqr = erp_action (cqr);
- } else {
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " No error recovery action\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
- atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
- }
- if ( erp_cqr != NULL ) {
- dasd_chanq_enq_head (qp, erp_cqr);
- next = erp_cqr; /* prefer execution of erp ccw */
- }
+ dasd_erp_action_fn_t erp_action;
+ ccw_req_t *erp_cqr = NULL;
+
+ if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) {
+ atomic_compare_and_swap_debug(&cqr->status,CQR_STATUS_ERROR,CQR_STATUS_FAILED);
+ next = cqr;
+ } else if ( cqr -> retries-- &&
+ cqr -> refers == NULL &&
+ discipline -> erp_action != NULL &&
+ (erp_action = discipline->erp_action (cqr)) != NULL &&
+ (erp_cqr = erp_action (cqr)) != NULL ) {
+ dasd_chanq_enq_head (qp, erp_cqr);
+ next = erp_cqr; /* prefer execution of erp ccw */
+ } else {
+ atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
+ next = cqr;
+ }
break;
}
case CQR_STATUS_DONE:{
dasd_erp_postaction_fn_t erp_postaction;
next = cqr->next;
+ asm volatile ("STCK %0":"=m" (cqr->endclk));
if (cqr->refers && cqr->function) { /* we deal with an ERP */
- if (discipline->erp_postaction &&
- ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+ if ( discipline->erp_postaction &&
+ ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " postprocessing successful error recovery action %p\n",
+ " postprocessing successful error recovery action using %p\n",
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
erp_postaction (cqr, 1);
- atomic_dec (&device->queue.dirty_requests);
} else {
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
}
+ atomic_dec (&device->queue.dirty_requests);
+ dasd_chanq_deq (&device->queue, cqr);
+ dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
} else if ( cqr->req ) {
- asm volatile ("STCK %0":"=m" (cqr->endclk));
dasd_end_request (cqr->req, 1);
#ifdef DASD_PROFILE
dasd_profile_add (cqr);
#endif /* DASD_PROFILE */
- }
- dasd_chanq_deq (&device->queue, cqr);
- dasd_free_request(cqr);
+ dasd_chanq_deq (&device->queue, cqr);
+ dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
+ } else {
+ /* during format we don't have the request structure */
+ /* notify sleeping task about finished postprocessing */
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_DONE,
+ CQR_STATUS_DONE | CQR_STATUS_FINISHED);
+ dasd_chanq_deq (&device->queue, cqr);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+ wake_up (&device->wait_q);
+#else
+ if (device->wait_q) {
+ wake_up (&device->wait_q);
+ }
+#endif /* LINUX_IS_24 */
+ }
break;
}
case CQR_STATUS_FAILED:{
dasd_erp_postaction_fn_t erp_postaction;
next = cqr->next;
+ asm volatile ("STCK %0":"=m" (cqr->endclk));
if (cqr->refers && cqr->function) { /* we deal with an ERP */
- if (discipline->erp_postaction &&
- ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+ if ( discipline->erp_postaction &&
+ ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " postprocessing unsuccessful error recovery action %p\n",
+ " postprocessing unsuccessful error recovery action using %p\n",
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
erp_postaction (cqr, 0);
- atomic_dec (&device->queue.dirty_requests);
-
} else {
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" No procedure to postprocess unsuccessful error recovery action"
- " giving up request",
+ " giving up request",
devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
}
+ atomic_dec (&device->queue.dirty_requests);
+ dasd_chanq_deq (&device->queue, cqr);
+ dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
} else if (cqr->req) {
- asm volatile ("STCK %0":"=m" (cqr->endclk));
dasd_end_request (cqr->req, 0);
#ifdef DASD_PROFILE
dasd_profile_add (cqr);
#endif /* DASD_PROFILE */
+ dasd_chanq_deq (&device->queue, cqr);
+ dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
} else {
- printk (KERN_WARNING PRINTK_HEADER
- "Internal error in " __FILE__ " on line %d."
- " inconsistent content of ccw_req_t"
- " refers = %p,function = %p, request = %p"
- " Pls send this message and your System.map to"
- " linux390@de.ibm.com\n",
- __LINE__, cqr->refers, cqr->function, cqr->req);
- }
- dasd_chanq_deq (&device->queue, cqr);
- dasd_free_request(cqr);
+ /* during format we don't have the request structure */
+ /* notify sleeping task about finished postprocessing */
+ atomic_compare_and_swap_debug (&cqr->status,
+ CQR_STATUS_FAILED,
+ CQR_STATUS_FAILED | CQR_STATUS_FINISHED);
+
+ dasd_chanq_deq (&device->queue, cqr);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+ wake_up (&device->wait_q);
+#else
+ if (device->wait_q) {
+ wake_up (&device->wait_q);
+ }
+#endif /* LINUX_IS_24 */
+ }
break;
}
+
default:{
printk (KERN_WARNING PRINTK_HEADER
"Internal error in " __FILE__ " on line %d."
- " inconsistent content of ccw_req_t"
+ " inconsistent content of ccw_req_t"
" cqrstatus = %d"
" Pls send this message and your System.map to"
" linux390@de.ibm.com\n",
__LINE__, cqrstatus);
+ }
}
- }
- s390irq_spin_unlock_irqrestore (irq, flags);
+ s390irq_spin_unlock_irqrestore (irq, flags);
} while ((cqr = next) != NULL);
}
schedule_request_fn (try_request_fn);
dasd_device_t *device;
int devno = -1, devindex = -1;
-#undef ERP_DEBUG
+#undef ERP_DEBUG
#ifdef ERP_DEBUG
- static int counter = 0;
+ static int counter = 0;
#endif
if (!stat) {
stat->devno);
return;
}
- if (ip & 0x80000001) {
+ if (ip & 0x80000001) {
PRINT_INFO ("%04X caught spurious interrupt with parm %08x\n",
stat->devno, ip);
- return;
- }
+ return;
+ }
cqr = (ccw_req_t *) ip;
device = (dasd_device_t *) cqr->device;
devno = device->devinfo.devno;
cqr->magic, *(int *) (&device->discipline->name));
return;
}
- asm volatile ("STCK %0":"=m" (cqr->stopclk));
- if ((stat->cstat == 0x00 &&
- stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
- (device->discipline->examine_error &&
+ asm volatile ("STCK %0":"=m" (cqr->stopclk));
+ if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) &&
+ stat->cstat == 0x00 &&
+ stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
+ (device->discipline->examine_error &&
(era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
#ifdef ERP_DEBUG
if ( ++counter % 137 == 0 ) {
stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
stat->dstat |= 0x02;
goto error_fake_done;
- }
+ }
#endif
atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
&device->level);
- if (cqr->next &&
- (atomic_read (&cqr->next->status) ==
- CQR_STATUS_QUEUED)) {
- if (dasd_start_IO (cqr->next) == 0) {
- done_fast_io = 1;
+ if (cqr->next &&
+ (atomic_read (&cqr->next->status) ==
+ CQR_STATUS_QUEUED)) {
+ if (dasd_start_IO (cqr->next) == 0) {
+ done_fast_io = 1;
}
}
- } else { /* only visited in case of error ! */
+ } else { /* only visited in case of error ! */
#ifdef ERP_DEBUG
error_fake_done:
#endif
if (cqr->dstat) {
memcpy (cqr->dstat, stat, sizeof (devstat_t));
} else {
- PRINT_ERR ("no memory for dstat\n");
+ PRINT_ERR ("no memory for dstat\n");
}
if (device->discipline &&
device->discipline->dump_sense) {
}
atomic_inc (&device->queue.dirty_requests);
/* errorprocessing */
- if (era == dasd_era_fatal) {
- PRINT_WARN ("ERP returned fatal error\n");
+ if (era == dasd_era_fatal) {
+ PRINT_WARN ("ERP returned fatal error\n");
atomic_compare_and_swap_debug (&cqr->status,
- CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
- } else {
+ CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+ } else {
atomic_compare_and_swap_debug (&cqr->status,
CQR_STATUS_IN_IO, CQR_STATUS_ERROR);
- }
+ }
}
if (done_fast_io == 0)
atomic_clear_mask (DASD_CHANQ_BUSY, &device->queue.flags);
dasd_schedule_bh ();
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-static wait_queue_head_t watcher_queue;
-#else
-static struct wait_queue watcher_queue_Qend = {NULL,};
-static struct wait_queue *watcher_queue = &watcher_queue_Qend;
-#endif /* LINUX_IS_24 */
-
-static void
-dasd_watcher (void)
-{
- do {
- dasd_schedule_bh ();
- schedule_request_fn (try_request_fn);
- interruptible_sleep_on_timeout (&watcher_queue, 5 * HZ);
- } while (1);
- }
-
/* SECTION: Some stuff related to error recovery */
ccw_req_t *
default_erp_action (ccw_req_t * cqr)
{
ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0);
-
- erp->cpaddr->cmd_code = CCW_CMD_NOOP;
+
+ erp->cpaddr->cmd_code = CCW_CMD_TIC;
+ erp->cpaddr->cda = (__u32)cqr -> cpaddr;
erp->function = default_erp_action;
erp->refers = cqr;
erp->device = cqr->device;
erp->magic = cqr->magic;
+ erp->retries = 16;
atomic_set (&erp->status, CQR_STATUS_FILLED);
- if ( cqr->startclk && cqr->expires )
- cqr->expires -= cqr->startclk;
-
- if (cqr->retries++ <= 16) {
- atomic_compare_and_swap_debug (&cqr->status,
- CQR_STATUS_ERROR,
- CQR_STATUS_QUEUED);
- } else {
- printk (KERN_WARNING PRINTK_HEADER "ERP retry count exceeded\n");
- atomic_compare_and_swap_debug (&cqr->status,
- CQR_STATUS_ERROR,
- CQR_STATUS_FAILED);
+ if ( cqr->startclk && cqr->expires ) {
+ /* cqr->expires -= cqr->startclk; */
}
- return erp;
+ return erp;
}
int
default_erp_postaction (ccw_req_t * cqr, int success)
{
- int rc = 0;
if (cqr->refers == NULL || cqr->function == NULL) {
printk (KERN_WARNING PRINTK_HEADER
"ERP postaction called for non ERP cqr\n");
printk (KERN_WARNING PRINTK_HEADER
"default ERP postaction called for non default ERP cqr\n");
return -EINVAL;
- }
- return rc;
+ }
+ if ( success ) {
+ atomic_compare_and_swap_debug (&cqr->refers->status,
+ CQR_STATUS_ERROR,
+ CQR_STATUS_DONE);
+ } else {
+ atomic_compare_and_swap_debug (&cqr->refers->status,
+ CQR_STATUS_ERROR,
+ CQR_STATUS_FAILED);
+ }
+ return 0;
}
/* SECTION: The helpers of the struct file_operations */
+/*
+ * int dasd_format ( device* device, format_data_t *fdata )
+ * performs formatting of _device_ according to _fdata_
+ * Note: The discipline's format_function is assumed to deliver formatting
+ * commands to format a single unit of the device. In terms of the ECKD
+ * devices this means CCWs are generated to format a single track.
+ */
+
static int
dasd_format (dasd_device_t * device, format_data_t * fdata)
{
- int rc = 0;
- int devno = device->devinfo.devno;
- int irq = device->devinfo.irq;
- int devindex = devindex_from_devno (devno);
-
+ int rc = 0;
+ int devno = device->devinfo.devno;
+ int irq = device->devinfo.irq;
+ int devindex = devindex_from_devno (devno);
+ ccw_req_t *req = NULL;
+
if (device->open_count != 1) {
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " you shouldn't format a device that is already open\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+ " you shouldn't format a device that is already open\n",
+ devno,
+ irq,
+ device->name,
+ major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
return -EINVAL;
}
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " Starting format process\n",
+ devno,
+ irq,
+ device->name,
+ major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
+
dasd_set_device_level( device->devinfo.irq,
DASD_DEVICE_LEVEL_RECOGNIZED,
device->discipline,
0);
- if (device->discipline->format_device)
- rc = device->discipline->format_device (device, fdata);
- if (rc) {
+
+ if (device->discipline->format_device) {
+ format_data_t temp = {
+ fdata->start_unit,
+ fdata->stop_unit,
+ fdata->blksize,
+ fdata->intensity};
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " Formatting failed with rc = %d\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
- return rc;
- }
- printk (KERN_WARNING PRINTK_HEADER
- " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " Formatting finished successfully rc = %d\n",
- devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+ " invalidating disk...\n",
+ devno,
+ irq,
+ device->name,
+ major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
+
+ if ( fdata -> start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
+ fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT &&
+ !(fdata -> intensity & 0x04)) {
+ format_data_t temp2 = { 0,0,DASD_FORMAT_DEFAULT_BLOCKSIZE,0x04};
+ req = device->discipline->format_device (device,&temp2);
+
+ if ( req ) {
+ rc = sleep_on_req(req);
+ dasd_free_request(req); /* request is no longer used */
+ } else {
+ rc = -EINVAL;
+ }
+ if ( rc ) {
+ printk (KERN_WARNING PRINTK_HEADER "Can't invalidate Track 0\n");
+ }
+ temp.start_unit++;
+ }
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " ...invalidation done.\n",
+ devno,
+ irq,
+ device->name,
+ major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
+
+ while ((!rc ) &&
+ ((req = device->discipline->format_device (device, &temp)) != NULL ) ) {
+
+ if ( rc=sleep_on_req(req) ) {
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " Formatting failed with rc = %d\n",
+ devno,
+ irq,
+ device->name,
+ major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS,
+ rc);
+ break;
+ }
+ dasd_free_request(req); /* request is no longer used */
+ temp.start_unit++;
+ } /* end if no more requests */
+
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " revalidating disk...\n",
+ devno,
+ irq,
+ device->name,
+ major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
+
+ if (!rc &&
+ req == NULL ) {
+ if ( fdata -> start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
+ fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT &&
+ !(fdata -> intensity & 0x04)) {
+ format_data_t temp2 = { 0,0,fdata->blksize,fdata->intensity};
+
+ req = device->discipline->format_device (device,
+ &temp2);
+ if ( req ) {
+ rc = sleep_on_req(req);
+ dasd_free_request(req); /* request is no longer used */
+ } else {
+ rc = -EINVAL;
+ }
+ if ( rc ) {
+ printk (KERN_WARNING PRINTK_HEADER "Can't revalidate Track 0\n");
+ }
+ }
+ }
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " ...revalidation done\n",
+ devno,
+ irq,
+ device->name,
+ major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
+ } /* end if discipline->format_device */
+ printk (KERN_WARNING PRINTK_HEADER
+ " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+ " Formatting finished successfully\n",
+ devno,
+ irq,
+ device->name,
+ major_from_devindex (devindex),
+ devindex << DASD_PARTN_BITS);
+
dasd_set_device_level( device->devinfo.irq,
- DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+ DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
device->discipline,
0);
udelay(1500000);
+
dasd_set_device_level( device->devinfo.irq,
DASD_DEVICE_LEVEL_ANALYSED,
device->discipline,
0);
+
return rc;
-}
+} /* end dasd_format */
static int
do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
case BIODASDFORMAT:{
/* fdata == NULL is a valid arg to dasd_format ! */
int partn;
- format_data_t *fdata = NULL;
+ format_data_t fdata = {
+ DASD_FORMAT_DEFAULT_START_UNIT,
+ DASD_FORMAT_DEFAULT_STOP_UNIT,
+ DASD_FORMAT_DEFAULT_BLOCKSIZE,
+ DASD_FORMAT_DEFAULT_INTENSITY };
+
if (data) {
- fdata = kmalloc (sizeof (format_data_t),
- GFP_ATOMIC);
- if (!fdata) {
- rc = -ENOMEM;
- break;
- }
- rc = copy_from_user (fdata, (void *) data,
+ rc = copy_from_user (&fdata, (void *) data,
sizeof (format_data_t));
if (rc)
break;
if (partn != 0) {
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
- " Cannot low-level format a partition\n",
+ " Cannot low-level format a partition\n",
device->devinfo.devno, device->devinfo.irq, device->name,
- MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+ MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
return -EINVAL;
}
- rc = dasd_format (device, fdata);
- if (fdata) {
- kfree (fdata);
- }
+ rc = dasd_format (device, &fdata);
break;
}
case BIODASDEXCP:{
static int
dasd_ioctl (struct inode *inp, struct file *filp,
unsigned int no, unsigned long data)
- {
+{
int rc = 0;
if ((!inp) || !(inp->i_rdev)) {
return -EINVAL;
- }
+ }
rc = do_dasd_ioctl (inp, no, data);
return rc;
}
printk (KERN_WARNING PRINTK_HEADER
" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
" Cannot open unrecognized device\n",
- device->devinfo.devno, device->devinfo.irq, device->name,
+ device->devinfo.devno, device->devinfo.irq, device->name,
MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
return -EINVAL;
}
if (rc < 0) {
printk (KERN_WARNING PRINTK_HEADER
"Cannot register to major no %d, rc = %d\n", major, rc);
- return rc;
+ return rc;
} else if (rc > 0) {
if (major == 0) {
major = rc;
if ( hd ) {
index = devindex_from_kdev_t (MKDEV(hd->major,index<<hd->minor_shift));
-}
+ }
third = index % 26;
second = (index / 26) % 27;
first = ((index / 26) / 27) % 27;
-
+
len = sprintf (str, "dasd");
if (first) {
len += sprintf (str + len, "%c", first + 'a' - 1 );
return -EINVAL;
} else {
len += sprintf (str + len, "%d", partition);
- }
+ }
}
str[len] = '\0';
return 0;
static void
dasd_not_oper_handler ( int irq, int status ) {
- int devno,devindex;
- dasd_device_t *device;
- devno = get_devno_by_irq(irq);
+ dasd_device_t *device=NULL;
+ major_info_t * major_info;
+ int i,devno = -ENODEV;
+
+ for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) {
+ for ( i = 0; i <= DASD_PER_MAJOR; i ++ ) {
+ device = major_info->dasd_device[i];
+ if ( device &&
+ device -> devinfo.irq == irq ) {
+ devno = device->devinfo.devno;
+ break;
+ }
+ }
+ if ( devno != -ENODEV )
+ break;
+ }
if ( devno < 0 ) {
- printk (KERN_WARNING PRINTK_HEADER
- "not_oper_handler called on irq %d no devno!\n", irq);
- return;
- }
+ printk ( KERN_WARNING PRINTK_HEADER
+ "not_oper_handler called on irq %d no devno!\n", irq);
+ return;
+ }
printk ( KERN_INFO PRINTK_HEADER
"not_oper_handler called on irq %d devno %04X\n", irq,devno);
- devindex = devindex_from_devno(devno);
- device = find_dasd_device(devindex);
- dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 );
+ if ( device -> open_count != 0 ) {
+ printk (KERN_ALERT PRINTK_HEADER
+ "Device %04X detached has still been open. expect errors\n", devno);
}
+ dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 );
+}
static int
dasd_enable_single_volume ( int irq ) {
int rc = 0;
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+ dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
NULL, 0);
printk (KERN_INFO PRINTK_HEADER "waiting for response...\n");
{
}
dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
NULL, 0);
- return rc;
+ return rc;
}
-static int
+int
dasd_oper_handler ( int irq, devreg_t *devreg ) {
int devno;
int devindex;
- int rc;
+ int rc;
devno = get_devno_by_irq(irq);
if ( devno == -ENODEV )
return -ENODEV;
if ( dasd_autodetect ) {
dasd_add_range(devno,0);
} else {
- return -ENODEV;
- }
+ return -ENODEV;
+ }
} while ( devindex == -ENODEV );
rc = dasd_enable_single_volume(irq);
- return rc;
- }
+ return rc;
+}
/*
* int
devindex = devindex_from_devno (devno);
if (devindex < 0) {
printk (KERN_WARNING PRINTK_HEADER " device %d is not in list of known DASDs\n", irq);
- return -ENODEV;
- }
+ return -ENODEV;
+ }
device = find_dasd_device (devindex);
while ( (major_info = major_info_from_devindex (devindex)) == NULL ) {
if ((rc = dasd_register_major (major_info)) > 0) {
printk (KERN_WARNING PRINTK_HEADER
"Couldn't register successfully to another major no\n");
return -ERANGE;
- }
- }
+ }
+ }
ind = devindex & (DASD_PER_MAJOR-1);
device = major_info->dasd_device[ind];
if (!device) { /* allocate device descriptor */
if (temp->check_characteristics) {
if (temp->check_characteristics (device))
continue;
- }
+ }
discipline = temp;
break;
}
devno, irq, discipline->name,
device->name, major_from_devindex (devindex),
(devindex % 64) << DASD_PARTN_BITS);
- } else {
+ } else {
break;
- }
+ }
device->discipline = discipline;
if (device->discipline->int_handler) {
+#ifdef CONFIG_DASD_DYNAMIC
s390_request_irq_special(irq,
device->discipline->int_handler,
dasd_not_oper_handler,
0,
DASD_NAME,
&device->dev_status);
+#else /* !defined(CONFIG_DASD_DYNAMIC) */
+ request_irq(irq,
+ device->discipline->int_handler,
+ 0,
+ DASD_NAME,
+ &device->dev_status);
+#endif /* CONFIG_DASD_DYNAMIC */
}
atomic_compare_and_swap_debug (&device->level,
DASD_DEVICE_LEVEL_UNKNOWN,
DASD_DEVICE_LEVEL_RECOGNIZED,
DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
s390irq_spin_unlock_irqrestore (irq, flags);
-}
+ }
}
} else {
atomic_compare_and_swap_debug (& device->level,DASD_DEVICE_LEVEL_RECOGNIZED,
DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
}
- if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
+ if (desired_level >= DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
break;
case DASD_DEVICE_LEVEL_ANALYSIS_PENDING: /* Fallthrough ?? */
return -EAGAIN;
case 4096:
break;
default:
-{
+ {
printk (KERN_INFO PRINTK_HEADER
"/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes"
" Did you format the drive?\n",
}
} else if (desired_level < current_level) { /* donwgrade device status */
switch (current_level) {
- case DASD_DEVICE_LEVEL_PARTITIONED: /* Fallthrough ?? */
- /* delete the partition information */
- for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
- struct hd_struct *p = &major_info->gendisk.part[minor+i];
- p->start_sect = 0;
- p->nr_sects = 0;
- p->type = 0;
- }
- atomic_compare_and_swap_debug (&device->level,
- DASD_DEVICE_LEVEL_PARTITIONED,
- DASD_DEVICE_LEVEL_ANALYSED);
- if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
- break;
case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */
atomic_compare_and_swap_debug (&device->level,
DASD_DEVICE_LEVEL_ANALYSED,
#endif /* KERNEL_VERSION */
static struct proc_dir_entry* dasd_devices_entry;
-
+
static int
dasd_devices_open (struct inode* inode, struct file* file )
{
return -ENOMEM;
} else {
file->private_data = (void *)info;
- }
+ }
while ( temp ) {
int i;
for ( i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i ++ ) {
temp = temp->next;
}
info->len=len;
- return rc;
+ return rc;
}
#define MIN(a,b) ((a)<(b)?(a):(b))
if(*offset >= p_info->len)
{
return 0; /* EOF */
- }
+ }
else
{
len = MIN(user_len, (p_info->len - *offset));
copy_to_user(user_buf, &(p_info->data[*offset]), len);
(*offset) += len;
return len; /* number of bytes "read" */
+ }
+}
+
+static ssize_t
+dasd_devices_write ( struct file *file, const char* user_buf, size_t user_len, loff_t* offset )
+{
+ char * buffer = vmalloc(user_len);
+
+ if ( buffer == NULL)
+ return -ENOMEM;
+ copy_from_user ( buffer, user_buf, user_len);
+ buffer[user_len] = 0;
+ printk ( KERN_INFO PRINTK_HEADER "Now executing %s\n",buffer);
+ if ( ! strncmp(buffer,"add range",strlen("add_range"))) {
+
+ } else if ( ! strncmp(buffer,"enable device",strlen("enable device"))) {
+
+ } else if ( ! strncmp(buffer,"disable device",strlen("disable device"))) {
+
+ } else {
+ printk (KERN_WARNING PRINTK_HEADER "unknown command %s",
+ buffer );
}
+ vfree(buffer);
+ return user_len;
}
-static int
+static int
dasd_devices_close (struct inode* inode, struct file* file)
{
- int rc = 0;
+ int rc = 0;
tempinfo_t* p_info = (tempinfo_t*)file->private_data;
if ( p_info ) {
if ( p_info->data ) vfree(p_info->data);
vfree(p_info);
- }
- return rc;
+ }
+ return rc;
}
static struct file_operations dasd_devices_file_ops =
{
- NULL, /* lseek */
- dasd_devices_read, /* read */
- NULL, /* dasd_devices_write, */ /* write */
- NULL, /* readdir */
- NULL, /* select */
- NULL, /* ioctl */
- NULL, /* mmap */
- dasd_devices_open, /* open */
- NULL, /* flush */
- dasd_devices_close, /* close */
+ read: dasd_devices_read, /* read */
+ write: dasd_devices_write, /* write */
+ open: dasd_devices_open, /* open */
+ release: dasd_devices_close, /* close */
};
static struct inode_operations dasd_devices_inode_ops =
#endif /* LINUX_IS_24 */
};
-void
+int
dasd_proc_init (void)
{
+ int rc = 0;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- dasd_proc_root_entry = create_proc_entry("dasd",
- S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR,
- &proc_root);
+ dasd_proc_root_entry = proc_mkdir("dasd",&proc_root);
dasd_devices_entry = create_proc_entry("devices",
S_IFREG | S_IRUGO | S_IWUSR,
dasd_proc_root_entry);
+ dasd_devices_entry -> proc_fops = &dasd_devices_file_ops;
+ dasd_devices_entry -> proc_iops = &dasd_devices_inode_ops;
#else
proc_register (&proc_root, &dasd_proc_root_entry);
dasd_devices_entry = (struct proc_dir_entry*)kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC);
proc_register(&dasd_proc_root_entry, dasd_devices_entry);
}
#endif /* LINUX_IS_24 */
+ return rc;
}
void
dasd_range_t *range;
printk (KERN_INFO PRINTK_HEADER "initializing...\n");
- genhd_dasd_name = dasd_device_name;
#ifndef MODULE
dasd_split_parm_string(dasd_parm_string);
#endif /* ! MODULE */
dasd_parse(dasd);
- dasd_proc_init();
dasd_init_emergency_req();
-
+
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
init_waitqueue_head(&watcher_queue);
spin_lock_init(&cq_lock);
} else {
printk (KERN_WARNING PRINTK_HEADER
"Couldn't register successfully to major no %d\n", major_info->gendisk.major);
- }
+ /* revert registration of major infos */
+ goto major_failed;
}
+ }
+ rc = dasd_proc_init();
+ if ( rc ) {
+ goto proc_failed;
+ }
+
+ genhd_dasd_name = dasd_device_name;
#ifdef CONFIG_DASD_ECKD
rc = dasd_eckd_init ();
if (rc==0) {
printk (KERN_INFO PRINTK_HEADER
"Registered ECKD discipline successfully\n");
- }
+ } else {
+ goto eckd_failed;
+ }
#endif /* CONFIG_DASD_ECKD */
#ifdef CONFIG_DASD_FBA
rc = dasd_fba_init ();
if (rc == 0) {
printk (KERN_INFO PRINTK_HEADER
"Registered FBA discipline successfully\n");
+ } else {
+ goto fba_failed;
}
#endif /* CONFIG_DASD_FBA */
#ifdef CONFIG_DASD_MDSK
- rc = dasd_diag_init ();
- if (rc == 0) {
+ if ( MACHINE_IS_VM ) {
+ rc = dasd_diag_init ();
+ if (rc == 0) {
printk (KERN_INFO PRINTK_HEADER
"Registered MDSK discipline successfully\n");
- }
+ } else {
+ goto mdsk_failed;
+ }
+ }
#endif /* CONFIG_DASD_MDSK */
rc = 0;
for (range = dasd_range_head; range; range= range->next) {
for (j = range->from; j <= range->to; j++) {
irq = get_irq_by_devno (j);
if (irq >= 0)
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+ dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
NULL, 0);
+ }
}
- }
if ( dasd_autodetect ) {
for ( irq = get_irq_first(); irq != -ENODEV; irq = get_irq_next(irq) ) {
int devno = get_devno_by_irq(irq);
int index = devindex_from_devno(devno);
if ( index == -ENODEV ) { /* not included in ranges */
dasd_add_range (devno,0);
- dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+ dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
NULL, 0);
- }
- }
-}
+ }
+ }
+ }
printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
-{
+ {
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
static wait_queue_head_t wait_queue;
init_waitqueue_head(&wait_queue);
#else
static struct wait_queue *wait_queue = NULL;
#endif /* LINUX_IS_24 */
- interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1 );
- }
+ interruptible_sleep_on_timeout (&wait_queue,
+ (20 * HZ) >> 1 );
+ }
for (range = dasd_range_head; range; range= range->next) {
for (j = range->from; j <= range->to; j++) {
irq = get_irq_by_devno (j);
if (irq >= 0) {
dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
NULL, 0);
- }
+ }
}
}
-
- printk (KERN_INFO PRINTK_HEADER "initialization completed\n");
- return rc;
+ goto out;
+#ifdef CONFIG_DASD_MDSK
+ mdsk_failed:
+ dasd_diag_cleanup ();
+#endif /* CONFIG_DASD_MDSK */
+#ifdef CONFIG_DASD_FBA
+ fba_failed:
+ dasd_fba_cleanup ();
+#endif /* CONFIG_DASD_FBA */
+#ifdef CONFIG_DASD_ECKD
+ eckd_failed:
+ dasd_eckd_cleanup ();
+#endif /* CONFIG_DASD_ECKD */
+ proc_failed:
+ dasd_proc_cleanup();
+ major_failed: {
+ for (major_info = dasd_major_info;
+ major_info;
+ major_info = major_info->next) {
+ dasd_unregister_major(major_info);
+ }
+ }
+ emergency_failed:
+ dasd_cleanup_emergency_req();
+ failed:
+ printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n");
+ out:
+ printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
+ return rc;
}
void
dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN,
NULL, 0);
kfree(find_dasd_device(devindex_from_devno(j)));
- }
+ }
}
}
for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
next = range -> next;
kfree (range);
if ( next == NULL )
- break;
+ break;
else
range = next;
- }
+ }
dasd_range_head = NULL;
while ( dasd_devreg_head ) {
reg = dasd_devreg_head->next;
kfree ( dasd_devreg_head );
dasd_devreg_head = reg;
- }
+ }
printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
- }
+}
#ifdef MODULE
int
int rc=0;
return dasd_init();
return rc;
- }
+}
void
cleanup_module ( void )
ccw_req_t * dasd_alloc_request (char *, int , int ) ;
void dasd_free_request(ccw_req_t *);
int (*genhd_dasd_name)(char*,int,int,struct gendisk*);
-
-
+int dasd_oper_handler ( int irq, devreg_t *devreg );
dasd_3990_erp_examine_24 (char *sense)
{
- /* check for 'Command Recejct' which is always a fatal error */
+ /* check for 'Command Recejct' whithout environmental data present */
if (sense[0] & 0x80) {
- return dasd_era_fatal;
- }
- /* check for 'Invalid Track Format' */
+ if (sense[2] &0x10){
+ return dasd_era_recover;
+ } else {
+ return dasd_era_fatal;
+ }
+ }
+
+ /* check for 'Invalid Track Format' whithout environmental data present */
if (sense[1] & 0x40) {
- return dasd_era_fatal;
+ if (sense[2] &0x10){
+ return dasd_era_recover;
+ } else {
+ return dasd_era_fatal;
+ }
}
/* check for 'No Record Found' */
if (sense[1] & 0x08) {
* ...............: by Hartmunt Penner <hpenner@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+
+ * History of changes
+ * 07/13/00 Added fixup sections for diagnoses ans saved some registers
+ * 07/14/00 fixed constraints in newly generated inline asm
*/
#include <linux/stddef.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/s390dyn.h>
#include "dasd.h"
#include "dasd_diag.h"
{
int rc;
- __asm__ __volatile__ (" lr 2,%1\n"
- " .long 0x83200210\n"
+ __asm__ __volatile__ (" diag %1,0,0x210\n"
"0: ipm %0\n"
- " srl %0,28"
+ " srl %0,28\n"
+ "1:\n"
+ ".section .fixup,\"ax\"\n"
+ "2: lhi %0,3\n"
+ " bras 1,3f\n"
+ " .long 1b\n"
+ "3: l 1,0(1)\n"
+ " br 1\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 0b,2b\n"
+ ".previous\n"
:"=d" (rc)
:"d" ((void *) __pa (devchar))
- :"2");
+ :"1");
return rc;
}
{
int rc;
- __asm__ __volatile__ (" lr 2,%1\n"
- " lr 3,%2\n"
- " .long 0x83230250\n"
- " lr %0,3"
- :"=d" (rc)
- :"d" ((void *) __pa (iob)), "d" (cmd)
- :"2", "3");
+ __asm__ __volatile__ (" lr 1,%1\n"
+ " diag 1,%2,0x250\n"
+ "1:\n"
+ ".section .fixup,\"ax\"\n"
+ "2: lhi %0,3\n"
+ " bras 1,3f\n"
+ " .long 1b\n"
+ "3: l 1,0(1)\n"
+ " br 1\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 1b,2b\n"
+ ".previous\n"
+ : "=d" (rc)
+ : "d" ((void *) __pa (iob)), "0" (cmd)
+ : "1" );
return rc;
}
}
return rc;
}
+
+void
+dasd_diag_cleanup( void ) {
+ int rc = 0;
+ if ( MACHINE_IS_VM ) {
+ printk ( KERN_INFO PRINTK_HEADER
+ "%s discipline cleaning up\n", dasd_diag_discipline.name);
+ dasd_discipline_deq(&dasd_diag_discipline);
+ unregister_external_interrupt (0x2603, dasd_ext_handler);
+ ctl_clear_bit (0, 9);
+ } else {
+ printk ( KERN_INFO PRINTK_HEADER
+ "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name);
+ rc = -EINVAL;
+ }
+ return rc;
+}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* History of changes (starts July 2000)
* 07/11/00 Enabled rotational position sensing
+ * 07/14/00 Reorganized the format process for better ERP
+ * 07/20/00 added experimental support for 2105 control unit (ESS)
+ * 07/24/00 increased expiration time and added the missing zero
+ * 08/07/00 added some bits to define_extent for ESS support
+ * 10/26/00 fixed ITPMPL020144ASC (problems when accesing a device formatted by VIF)
+ * 10/30/00 fixed ITPMPL010263EPA (erronoeous timeout messages)
*/
#include <linux/stddef.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/s390dyn.h>
#include "dasd.h"
#include "dasd_eckd.h"
#define PRINTK_HEADER DASD_NAME"(eckd):"
#define ECKD_C0(i) (i->home_bytes)
-#define ECKD_F(i) (i -> formula)
+ #define ECKD_F(i) (i->formula)
#define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1))
#define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2))
#define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3))
#define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0)
#define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0)
-#define ECKD_F6(i) (i -> factor6)
-#define ECKD_F7(i) (i -> factor7)
-#define ECKD_F8(i) (i -> factor8)
+#define ECKD_F6(i) (i->factor6)
+#define ECKD_F7(i) (i->factor7)
+#define ECKD_F8(i) (i->factor8)
#define DASD_ECKD_CCW_WRITE 0x05
#define DASD_ECKD_CCW_READ 0x06
eckd_count_t count_area;
} dasd_eckd_private_t;
+static
+devreg_t dasd_eckd_known_devices[] = {
+ {
+ ci : { hc: { ctype: 0x3990, dtype: 0x3390 } },
+ flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+ oper_func: dasd_oper_handler
+ },
+ {
+ ci : { hc: { ctype: 0x3990, dtype: 0x3380 } },
+ flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+ oper_func: dasd_oper_handler
+ },
+ {
+ ci : { hc: { ctype: 0x9343, dtype: 0x9345 } },
+ flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+ oper_func: dasd_oper_handler
+ }
+};
+
static inline unsigned int
round_up_multiple (unsigned int no, unsigned int mult)
{
{
int rpt = 0;
int dn;
- switch ( rdc -> dev_type ) {
- case 0x3380:
+ switch (rdc->dev_type) {
+ case 0x3380:
if (kl)
return 1499 / (15 +
7 + ceil_quot (kl + 12, 32) +
ceil_quot (dl + 12, 32));
else
return 1499 / (15 + ceil_quot (dl + 12, 32));
- case 0x3390:
+ case 0x3390:
dn = ceil_quot (dl + 6, 232) + 1;
if (kl) {
int kn = ceil_quot (kl + 6, 232) + 1;
} else
return 1729 / (10 +
9 + ceil_quot (dl + 6 * dn, 34));
- case 0x9345:
- dn = ceil_quot (dl + 6, 232) + 1;
- if (kl) {
- int kn = ceil_quot (kl + 6, 232) + 1;
- return 1420 / (18 +
- 7 + ceil_quot (kl + 6 * kn, 34) +
- ceil_quot (dl + 6 * dn, 34));
- } else
- return 1420 / (18 +
- 7 + ceil_quot (dl + 6 * dn, 34));
+ case 0x9345:
+ dn = ceil_quot (dl + 6, 232) + 1;
+ if (kl) {
+ int kn = ceil_quot (kl + 6, 232) + 1;
+ return 1420 / (18 +
+ 7 + ceil_quot (kl + 6 * kn, 34) +
+ ceil_quot (dl + 6 * dn, 34));
+ } else
+ return 1420 / (18 +
+ 7 + ceil_quot (dl + 6 * dn, 34));
}
return rpt;
}
memset (de_ccw, 0, sizeof (ccw1_t));
de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
de_ccw->count = 16;
- de_ccw->cda = (void *) __pa (data);
+ de_ccw->cda = (__u32) __pa (data);
memset (data, 0, sizeof (DE_eckd_data_t));
switch (cmd) {
case DASD_ECKD_CCW_READ_CKD_MT:
case DASD_ECKD_CCW_READ_COUNT:
data->mask.perm = 0x1;
- data->attributes.operation = 0x3; /* enable seq. caching */
+ data->attributes.operation = 0x3; /* enable seq. caching */
break;
case DASD_ECKD_CCW_WRITE:
case DASD_ECKD_CCW_WRITE_MT:
data->mask.perm = 0x02;
- data->attributes.operation = 0x3; /* enable seq. caching */
+ data->attributes.operation = 0x3; /* enable seq. caching */
break;
case DASD_ECKD_CCW_WRITE_CKD:
case DASD_ECKD_CCW_WRITE_CKD_MT:
break;
}
data->attributes.mode = 0x3;
+ if ( private -> rdc_data.cu_type == 0x2105 ) {
+ data -> reserved |= 0x40;
+ }
data->beg_ext.cyl = beg.cyl;
data->beg_ext.head = beg.head;
data->end_ext.cyl = end.cyl;
int rec_on_trk,
int no_rec,
int cmd,
- dasd_device_t * device)
+ dasd_device_t * device,
+ int reclen)
{
dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
ch_t geo = {private->rdc_data.no_cyl,
private->rdc_data.trk_per_cyl};
ch_t seek ={trk / (geo.head), trk % (geo.head)};
- int reclen = device->sizes.bp_block;
int sector;
memset (lo_ccw, 0, sizeof (ccw1_t));
lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
lo_ccw->count = 16;
- lo_ccw->cda = (void *) __pa (data);
+ lo_ccw->cda = (__u32) __pa (data);
memset (data, 0, sizeof (LO_eckd_data_t));
switch (cmd) {
break;
case DASD_ECKD_CCW_READ_COUNT:
data->operation.operation = 0x06;
- break;
+ break;
default:
INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
}
static int
dasd_eckd_id_check ( dev_info_t *info )
{
- if ( info->sid_data.cu_type == 0x3990 )
+ if ( info->sid_data.cu_type == 0x3990 ||
+ info->sid_data.cu_type == 0x2105 )
if ( info->sid_data.dev_type == 0x3390 )
return 0;
- if ( info->sid_data.cu_type == 0x3990 )
+ if ( info->sid_data.cu_type == 0x3990 ||
+ info->sid_data.cu_type == 0x2105 )
if ( info->sid_data.dev_type == 0x3380 )
return 0;
if ( info->sid_data.cu_type == 0x9343 )
if ( info->sid_data.dev_type == 0x9345 )
return 0;
return -ENODEV;
- }
+}
static int
dasd_eckd_check_characteristics (struct dasd_device_t *device)
printk ( KERN_WARNING PRINTK_HEADER
"Read device characteristics returned error %d\n",rc);
return rc;
- }
+ }
printk ( KERN_INFO PRINTK_HEADER
"%04X on sch %d: %04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d\n",
device->devinfo.devno, device->devinfo.irq,
printk ( KERN_WARNING PRINTK_HEADER
"Read configuration data returned error %d\n",rc);
return rc;
- }
+ }
if ( conf_len != sizeof(dasd_eckd_confdata_t)) {
printk ( KERN_WARNING PRINTK_HEADER
"sizes of configuration data mismatch %d (read) vs %ld (expected)\n",
define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device);
ccw->flags = CCW_FLAG_CC;
ccw++;
- locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, device);
+ locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device,0);
ccw->flags = CCW_FLAG_CC;
ccw++;
ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
ccw->count = 8;
- ccw->cda = (void *) __pa (count_data);
+ ccw->cda = (__u32) __pa (count_data);
cqr->device = device;
+ cqr->retries = 0;
atomic_set (&cqr->status, CQR_STATUS_FILLED);
return cqr;
return rc;
}
-static inline int
-dasd_eckd_format_track (dasd_device_t *device, int trk, int bs, int flags)
+static ccw_req_t *
+dasd_eckd_format_device (dasd_device_t *device, format_data_t *fdata)
{
- int rc = 0;
int i;
ccw_req_t *fcp = NULL;
DE_eckd_data_t *DE_data = NULL;
ccw1_t *last_ccw = NULL;
void * last_data = NULL;
dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
- int retries;
-
+ int trk = fdata -> start_unit;
+ int bs = fdata -> blksize == DASD_FORMAT_DEFAULT_BLOCKSIZE ? 4096 : fdata->blksize;
+ int flags = fdata -> intensity == DASD_FORMAT_DEFAULT_INTENSITY ? 0 : fdata -> intensity;
+
int rpt = recs_per_track (&(private->rdc_data), 0, bs);
int cyl = trk / private->rdc_data.trk_per_cyl;
int head = trk % private->rdc_data.trk_per_cyl;
int wrccws = rpt;
int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
+
+ if ( ( (fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) &&
+ trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl ) ) ||
+ ( (fdata -> stop_unit != DASD_FORMAT_DEFAULT_STOP_UNIT) &&
+ trk > fdata->stop_unit ) ) {
+ printk (KERN_WARNING PRINTK_HEADER "Track %d reached...ending!\n",trk);
+ return NULL;
+ }
+ switch(bs) {
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ break;
+ default:
+ printk (KERN_WARNING PRINTK_HEADER "Invalid blocksize %d...terminating!\n",bs);
+ return NULL;
+ }
switch ( flags ) {
case 0x00:
case 0x01:
case 0x03:
- break;
+ case 0x04: /* make track invalid */
+ break;
default:
- return -EINVAL;
+ printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n",flags);
+ return NULL;
}
-
- if ( flags & 0x1 ) {
- wrccws++;
- datasize += sizeof(eckd_count_t);
+
+ /* print status line */
+ if ( (private->rdc_data.no_cyl < 20 ) ?
+ ( trk % private->rdc_data.no_cyl == 0 ) :
+ ( trk % private->rdc_data.no_cyl == 0 &&
+ (trk / private->rdc_data.no_cyl) %
+ (private->rdc_data.no_cyl / 20 ) ) ) {
+
+ printk (KERN_INFO PRINTK_HEADER
+ "Format %04X Cylinder: %d Flags: %d\n",
+ device->devinfo.devno,
+ trk / private->rdc_data.trk_per_cyl,
+ flags);
}
- if ( flags & 0x2 ) {
- wrccws++;
- datasize += sizeof(eckd_home_t);
+
+ if ( flags & 0x04) {
+ rpt = 1;
+ wrccws = 1;
+ } else {
+ if ( flags & 0x1 ) {
+ wrccws++;
+ datasize += sizeof(eckd_count_t);
+ }
+ if ( flags & 0x2 ) {
+ wrccws++;
+ datasize += sizeof(eckd_home_t);
+ }
}
fcp = ccw_alloc_request (dasd_eckd_discipline.name,
wrccws + 2,
datasize+rpt*sizeof(eckd_count_t));
- fcp->device = device;
-
- last_data = fcp->data;
- DE_data = (DE_eckd_data_t *) last_data;
- last_data = (void*)(DE_data +1);
- LO_data = (LO_eckd_data_t *) last_data;
- last_data = (void*)(LO_data +1);
- if ( flags & 0x2 ) {
- ha_data = (eckd_home_t *) last_data;
- last_data = (void*)(ha_data +1);
- }
- if ( flags & 0x1 ) {
- r0_data = (eckd_count_t *) last_data;
- last_data = (void*)(r0_data +1);
- }
- ct_data = (eckd_count_t *)last_data;
-
- last_ccw = fcp->cpaddr;
-
- switch (flags) {
- case 0x03:
- define_extent (last_ccw, DE_data, trk, trk,
- DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
- last_ccw->flags = CCW_FLAG_CC;
- last_ccw++;
- locate_record (last_ccw, LO_data, trk, 0, wrccws,
- DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
- last_ccw->flags = CCW_FLAG_CC;
- last_ccw++;
- break;
- case 0x01:
- define_extent (last_ccw, DE_data, trk, trk,
- DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
- last_ccw->flags = CCW_FLAG_CC;
- last_ccw++;
- locate_record (last_ccw, LO_data, trk, 0, wrccws,
+ if ( fcp != NULL ) {
+ fcp->device = device;
+ last_data = fcp->data;
+ DE_data = (DE_eckd_data_t *) last_data;
+ last_data = (void*)(DE_data +1);
+ LO_data = (LO_eckd_data_t *) last_data;
+ last_data = (void*)(LO_data +1);
+ if ( flags & 0x2 ) {
+ ha_data = (eckd_home_t *) last_data;
+ last_data = (void*)(ha_data +1);
+ }
+ if ( flags & 0x1 ) {
+ r0_data = (eckd_count_t *) last_data;
+ last_data = (void*)(r0_data +1);
+ }
+ ct_data = (eckd_count_t *)last_data;
+
+ last_ccw = fcp->cpaddr;
+
+ switch (flags) {
+ case 0x03:
+ define_extent (last_ccw, DE_data, trk, trk,
+ DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
+ last_ccw->flags = CCW_FLAG_CC;
+ last_ccw++;
+ locate_record (last_ccw, LO_data, trk, 0, wrccws,
+ DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,device->sizes.bp_block );
+ last_ccw->flags = CCW_FLAG_CC;
+ last_ccw++;
+ break;
+ case 0x01:
+ define_extent (last_ccw, DE_data, trk, trk,
DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
- last_ccw->flags = CCW_FLAG_CC;
- last_ccw++;
- memset (r0_data, 0, sizeof (eckd_count_t));
- break;
- case 0x00:
- define_extent (last_ccw, DE_data, trk, trk,
- DASD_ECKD_CCW_WRITE_CKD, device);
- last_ccw->flags = CCW_FLAG_CC;
- last_ccw++;
- locate_record (last_ccw, LO_data, trk, 0, wrccws,
- DASD_ECKD_CCW_WRITE_CKD, device);
- LO_data->length = bs;
- last_ccw->flags = CCW_FLAG_CC;
- last_ccw++;
- break;
- default:
- PRINT_WARN ("Unknown format flags...%d\n", flags);
- return -EINVAL;
- }
- if (flags & 0x02) {
- PRINT_WARN ("Unsupported format flag...%d\n", flags);
- return -EINVAL;
- }
- if (flags & 0x01) { /* write record zero */
- r0_data->cyl = cyl;
- r0_data->head = head;
- r0_data->record = 0;
- r0_data->kl = 0;
- r0_data->dl = 8;
- last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
- last_ccw->count = 8;
- last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
- last_ccw->cda = (void *) __pa (r0_data);
- last_ccw++;
- }
- /* write remaining records */
- for (i = 0; i < rpt; i++, last_ccw++) {
- memset (ct_data + i, 0, sizeof (eckd_count_t));
- (ct_data + i)->cyl = cyl;
- (ct_data + i)->head = head;
- (ct_data + i)->record = i + 1;
- (ct_data + i)->kl = 0;
- (ct_data + i)->dl = bs;
- last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
- last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
- last_ccw->count = 8;
- last_ccw->cda = (void *) __pa (ct_data + i);
- }
- (last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
- fcp->device = device;
- do {
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- DECLARE_WAITQUEUE (wait,current);
-#else
- struct wait_queue wait = {current, NULL};
-#endif /* LINUX_VERSION_CODE */
- unsigned long flags;
- int cs;
-
- retries = 1;
- s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
- atomic_set(&fcp->status,CQR_STATUS_QUEUED);
- do {
- rc = dasd_eckd_discipline.start_IO (fcp);
- } while ( rc && retries-- );
- if ( rc && retries == 0 )
+ last_ccw->flags = CCW_FLAG_CC;
+ last_ccw++;
+ locate_record (last_ccw, LO_data, trk, 0, wrccws,
+ DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,device->sizes.bp_block);
+ last_ccw->flags = CCW_FLAG_CC;
+ last_ccw++;
+ memset (r0_data, 0, sizeof (eckd_count_t));
break;
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- add_wait_queue (&device->wait_q, &wait);
-#endif /* LINUX_VERSION_CODE */
- do {
- current->state = TASK_INTERRUPTIBLE;
- s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
- schedule ();
- s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
- cs = atomic_read (&fcp->status);
- } while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_ERROR));
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- remove_wait_queue (&device->wait_q, &wait);
-#endif /* LINUX_VERSION_CODE */
- s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
- } while ( (rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)) &&
- retries--);
- if ( retries == 0 )
- rc = -EIO;
- ccw_free_request (fcp);
- return rc;
-}
-
-static int
-dasd_eckd_format_device (struct dasd_device_t *device, struct format_data_t *fdata)
-{
- int rc = 0;
- int i;
- format_data_t fd;
- dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
- int last_track =private->rdc_data.no_cyl*private->rdc_data.trk_per_cyl-1;
- int intensity;
- kdev_t kdev = device->kdev;
- int nr_tracks, blocksize;
-
- if (fdata==NULL) {
- fd.start_unit = 0;
- fd.stop_unit = last_track;
- fd.blksize = 4096;
- } else {
- memcpy (&fd, fdata, sizeof (format_data_t));
- if (fd.stop_unit == -1) {
- fd.stop_unit = last_track;
- }
- if (fd.blksize == 0) {
- fd.blksize = 4096;
- }
- }
- if (fd.start_unit > fd.stop_unit) {
- return -EINVAL;
- }
- if (fd.start_unit > last_track ) {
- return -EINVAL;
- }
- if (fd.stop_unit > last_track ) {
- return -EINVAL;
- }
- switch(fd.blksize) {
- case 512:
- case 1024:
- case 2048:
- case 4096:
- break;
- default:
- return -EINVAL;
- }
- fd.intensity = 0x0;
- intensity = fd.intensity;
- set_blocksize(kdev, fd.blksize);
- printk (KERN_INFO PRINTK_HEADER
- "Formatting device %04X from track %d to %d with bs %d\n",
- device->devinfo.devno,fd.start_unit, fd.stop_unit, fd.blksize);
- nr_tracks = fd.stop_unit-fd.start_unit+1;
- for (i = 0; i <= nr_tracks; i++) {
- /* print 20 messages per format cmd at all */
- if ( i % (nr_tracks / 20) == 0 ) {
- printk (KERN_INFO PRINTK_HEADER
- "Format %04X Cylinder: %d Track %d Intensity %d\n",
- device->devinfo.devno,
- (i+fd.start_unit) / private->rdc_data.trk_per_cyl,
- (i+fd.start_unit) % private->rdc_data.trk_per_cyl,
- intensity);
- }
- do {
- if ( i == 0 ) {
- blocksize = 8;
- } else {
- blocksize = fd.blksize;
- }
- rc = dasd_eckd_format_track (device,
- (i % nr_tracks) + fd.start_unit ,
- blocksize, intensity);
- /* fix VM controlled minidisk */
- if ( rc ) {
- if ( intensity ) {
- intensity = intensity >> 1;
- }
- printk (KERN_WARNING PRINTK_HEADER
- "decreasing format intensity to %d\n",
- intensity);
- }
- } while ( rc && intensity > 0);
- if (rc) {
- printk (KERN_WARNING PRINTK_HEADER
- "Formatting of device %04X Cylinder %d Track %d failed...exiting\n",
- device->devinfo.devno,
- i / private->rdc_data.trk_per_cyl,
- i % private->rdc_data.trk_per_cyl);
+ case 0x04:
+ define_extent (last_ccw, DE_data, trk, trk,
+ DASD_ECKD_CCW_WRITE_CKD, device);
+ last_ccw->flags = CCW_FLAG_CC;
+ last_ccw++;
+ locate_record (last_ccw, LO_data, trk, 0, wrccws,
+ DASD_ECKD_CCW_WRITE_CKD, device,0);
+ LO_data->length = bs;
+ last_ccw->flags = CCW_FLAG_CC;
+ last_ccw++;
break;
- }
- }
- printk ( KERN_INFO PRINTK_HEADER
- "Formatting of device %04X completed from track %d to %d with bs %d\n",
- device->devinfo.devno, fd.start_unit, fd.stop_unit, fd.blksize);
- return rc;
+ case 0x00:
+ define_extent (last_ccw, DE_data, trk, trk,
+ DASD_ECKD_CCW_WRITE_CKD, device);
+ last_ccw->flags = CCW_FLAG_CC;
+ last_ccw++;
+ locate_record (last_ccw, LO_data, trk, 0, wrccws,
+ DASD_ECKD_CCW_WRITE_CKD, device,device->sizes.bp_block);
+ LO_data->length = bs;
+ last_ccw->flags = CCW_FLAG_CC;
+ last_ccw++;
+ break;
+ default:
+ PRINT_WARN ("Unknown format flags...%d\n", flags);
+ return NULL;
+ }
+ if (flags & 0x02 ) {
+ PRINT_WARN ("Unsupported format flag...%d\n", flags);
+ return NULL;
+ }
+ if (flags & 0x01) { /* write record zero */
+ r0_data->cyl = cyl;
+ r0_data->head = head;
+ r0_data->record = 0;
+ r0_data->kl = 0;
+ r0_data->dl = 8;
+ last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
+ last_ccw->count = 8;
+ last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+ last_ccw->cda = (__u32) __pa (r0_data);
+ last_ccw++;
+ }
+ /* write remaining records */
+ for (i = 0; i < rpt; i++) {
+ memset (ct_data + i, 0, sizeof (eckd_count_t));
+ (ct_data + i)->cyl = cyl;
+ (ct_data + i)->head = head;
+ (ct_data + i)->record = i + 1;
+ (ct_data + i)->kl = 0;
+ (ct_data + i)->dl = bs;
+ last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+ last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+ last_ccw->count = 8;
+ last_ccw->cda = (__u32) __pa (ct_data + i);
+ last_ccw ++;
+ }
+ (last_ccw-1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
+ fcp->device = device;
+ atomic_set(&fcp->status,CQR_STATUS_FILLED);
+ }
+ return fcp;
}
static dasd_era_t
stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
return dasd_era_none;
- switch (device->devinfo.sid_data.cu_model) {
+ switch (device->devinfo.sid_data.cu_type) {
case 0x3990:
+ case 0x2105:
return dasd_3990_erp_examine (cqr, stat);
case 0x9343:
return dasd_9343_erp_examine (cqr, stat);
/* count bhs to prevent errors, when bh smaller than block */
bhct = 0;
for (bh = req->bh; bh; bh = bh->b_reqnext) {
- if (bh->b_size > byt_per_blk)
- for (size = 0; size < bh->b_size; size += byt_per_blk)
+ if (bh->b_size > byt_per_blk)
+ for (size = 0; size < bh->b_size; size += byt_per_blk)
bhct++;
else
bhct++;
}
-
+
rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
2 + bhct,
- sizeof (DE_eckd_data_t) +
- sizeof (LO_eckd_data_t));
- if ( ! rw_cp ) {
- return NULL;
- }
+ sizeof (DE_eckd_data_t) +
+ sizeof (LO_eckd_data_t));
+ if (!rw_cp) {
+ return NULL;
+ }
DE_data = rw_cp->data;
LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
ccw = rw_cp->cpaddr;
ccw->flags = CCW_FLAG_CC;
ccw++;
locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1,
- req->nr_sectors >> shift, rw_cmd, device);
+ req->nr_sectors >> shift, rw_cmd, device,device->sizes.bp_block);
ccw->flags = CCW_FLAG_CC;
for (bh = req->bh; bh != NULL;) {
if (bh->b_size > byt_per_blk) {
- for (size = 0; size < bh->b_size; size += byt_per_blk) {
- ccw++;
- ccw->flags = CCW_FLAG_CC;
- ccw->cmd_code = rw_cmd;
- ccw->count = byt_per_blk;
- ccw->cda = (void *) __pa (bh->b_data + size);
- }
+ for (size = 0; size < bh->b_size; size += byt_per_blk) {
+ ccw++;
+ ccw->flags = CCW_FLAG_CC;
+ ccw->cmd_code = rw_cmd;
+ ccw->count = byt_per_blk;
+ ccw->cda = (__u32) __pa (bh->b_data + size);
+ }
bh = bh->b_reqnext;
} else { /* group N bhs to fit into byt_per_blk */
for (size = 0; bh != NULL && size < byt_per_blk;) {
ccw->flags = CCW_FLAG_DC;
ccw->cmd_code = rw_cmd;
ccw->count = bh->b_size;
- ccw->cda = (void *) __pa (bh->b_data);
+ ccw->cda = (__u32) __pa (bh->b_data);
size += bh->b_size;
bh = bh->b_reqnext;
- }
+ }
if (size != byt_per_blk) {
- PRINT_WARN ("Cannot fulfill small request %d vs. %d (%d sects)\n", size, byt_per_blk, req->nr_sectors);
+ PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", size, byt_per_blk, req->nr_sectors);
ccw_free_request (rw_cp);
- return NULL;
- }
+ return NULL;
+ }
ccw->flags = CCW_FLAG_CC;
}
}
ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
rw_cp->device = device;
- rw_cp->expires = 5 * 0xf424000; /* 5 seconds */
+ rw_cp->expires = 60 * (unsigned long long)0xf4240000; /* 60 seconds */
rw_cp->req = req;
+ rw_cp->retries = 2;
atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED);
return rw_cp;
}
for (sct = 0; sct < 8; sct++) {
len += sprintf ( page + len," %2d:0x%02x",
8 * sl + sct, sense[8 * sl + sct]);
- }
+ }
len += sprintf ( page + len,"\n");
}
if (sense[27] & 0x80) {
len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER
"32 Byte: Format: %x Exception class %x\n",
sense[6] & 0x0f, sense[22] >> 4);
- }
- }
+ }
+ }
return page;
}
int
dasd_eckd_init( void ) {
int rc = 0;
+ int i;
printk ( KERN_INFO PRINTK_HEADER
"%s discipline initializing\n", dasd_eckd_discipline.name);
ASCEBC(dasd_eckd_discipline.ebcname,4);
dasd_discipline_enq(&dasd_eckd_discipline);
-
+#ifdef CONFIG_DASD_DYNAMIC
+ for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) {
+ printk (KERN_INFO PRINTK_HEADER
+ "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+ dasd_eckd_known_devices[i].ci.hc.ctype,
+ dasd_eckd_known_devices[i].ci.hc.cmode,
+ dasd_eckd_known_devices[i].ci.hc.dtype,
+ dasd_eckd_known_devices[i].ci.hc.dmode);
+ s390_device_register(&dasd_eckd_known_devices[i]);
+ }
+#endif /* CONFIG_DASD_DYNAMIC */
+ return rc;
+}
+
+void
+dasd_eckd_cleanup( void ) {
+ int rc = 0;
+ int i;
+ printk ( KERN_INFO PRINTK_HEADER
+ "%s discipline cleaning up\n", dasd_eckd_discipline.name);
+#ifdef CONFIG_DASD_DYNAMIC
+ for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) {
+ printk (KERN_INFO PRINTK_HEADER
+ "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+ dasd_eckd_known_devices[i].ci.hc.ctype,
+ dasd_eckd_known_devices[i].ci.hc.cmode,
+ dasd_eckd_known_devices[i].ci.hc.dtype,
+ dasd_eckd_known_devices[i].ci.hc.dmode);
+ s390_device_register(&dasd_eckd_known_devices[i]);
+ }
+#endif /* CONFIG_DASD_DYNAMIC */
+ dasd_discipline_deq(&dasd_eckd_discipline);
return rc;
}
#include <asm/ebcdic.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/s390dyn.h>
#include "dasd.h"
#include "dasd_fba.h"
dasd_fba_characteristics_t rdc_data;
} dasd_fba_private_t;
+static
+devreg_t dasd_fba_known_devices[] = {
+ {
+ ci : { hc: { ctype: 0x6310, dtype: 0x9336 } },
+ flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+ oper_func: dasd_oper_handler
+ },
+ {
+ ci : { hc: { ctype: 0x3880, dtype: 0x3370 } },
+ flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE,
+ oper_func: dasd_oper_handler
+ }
+};
+
static inline void
define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
int blksize, int beg, int nr)
return 0;
if ( info->sid_data.cu_type == 0x6310 )
if ( info->sid_data.dev_type == 0x9336 )
- return 0;
+ return 0;
return -ENODEV;
}
/* count bhs to prevent errors, when bh smaller than block */
bhct = 0;
for (bh = req->bh; bh; bh = bh->b_reqnext) {
- if (bh->b_size > byt_per_blk)
- for (size = 0; size < bh->b_size; size += byt_per_blk)
+ if (bh->b_size > byt_per_blk)
+ for (size = 0; size < bh->b_size; size += byt_per_blk)
bhct++;
else
bhct++;
}
-
+
rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
2 + bhct,
- sizeof (DE_fba_data_t) +
- sizeof (LO_fba_data_t));
+ sizeof (DE_fba_data_t) +
+ sizeof (LO_fba_data_t));
if (!rw_cp) {
return NULL;
}
int len;
if ( page == NULL ) {
return NULL;
-}
+ }
len = sprintf ( page, KERN_WARNING PRINTK_HEADER
"device %04X on irq %d: I/O status report:\n",
int_handler: dasd_int_handler
};
+
int
dasd_fba_init( void ) {
- int rc = 0;
+ int rc = 0;
+ int i;
printk ( KERN_INFO PRINTK_HEADER
"%s discipline initializing\n", dasd_fba_discipline.name);
ASCEBC(dasd_fba_discipline.ebcname,4);
dasd_discipline_enq(&dasd_fba_discipline);
+#ifdef CONFIG_DASD_DYNAMIC
+ for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) {
+ printk (KERN_INFO PRINTK_HEADER
+ "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+ dasd_fba_known_devices[i].ci.hc.ctype,
+ dasd_fba_known_devices[i].ci.hc.cmode,
+ dasd_fba_known_devices[i].ci.hc.dtype,
+ dasd_fba_known_devices[i].ci.hc.dmode);
+ s390_device_register(&dasd_fba_known_devices[i]);
+ }
+#endif /* CONFIG_DASD_DYNAMIC */
+ return rc;
+}
- return rc;
+void
+dasd_fba_cleanup( void ) {
+ int rc = 0;
+ int i;
+ printk ( KERN_INFO PRINTK_HEADER
+ "%s discipline cleaning up\n", dasd_fba_discipline.name);
+#ifdef CONFIG_DASD_DYNAMIC
+ for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) {
+ printk (KERN_INFO PRINTK_HEADER
+ "We are interested in: CU %04X/%02x DEV: %04X/%02Xi\n",
+ dasd_fba_known_devices[i].ci.hc.ctype,
+ dasd_fba_known_devices[i].ci.hc.cmode,
+ dasd_fba_known_devices[i].ci.hc.dtype,
+ dasd_fba_known_devices[i].ci.hc.dmode);
+ s390_device_register(&dasd_fba_known_devices[i]);
+ }
+#endif /* CONFIG_DASD_DYNAMIC */
+ dasd_discipline_deq(&dasd_fba_discipline);
+ return rc;
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
fail_malloc:
read_ahead[major] = 0;
blk_dev[major].request_fn = NULL;
- unregister_chrdev(major, "xpram");
+ unregister_blkdev(major, "xpram");
return result;
}
/*
- * File...........: linux/drivers/s390/block/ccwcache.c
+ * File...........: linux/drivers/s390/ccwcache.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
#include <asm/ebcdic.h>
#include <asm/spinlock.h>
-
#ifdef PRINTK_HEADER
#undef PRINTK_HEADER
#endif
/* pointer to list of allocated requests */
static ccw_req_t *ccwreq_actual = NULL;
+static spinlock_t ccwchain_lock = SPIN_LOCK_UNLOCKED;
/* pointer to debug area */
static debug_info_t *debug_area = NULL;
static void
dechain ( ccw_req_t *request )
{
+ long flags;
+
/* Sanity checks */
if ( request == NULL ) {
printk( KERN_WARNING PRINTK_HEADER
"Trying to deallocate NULL request\n");
return;
}
+
+ spin_lock_irqsave(&ccwchain_lock,flags);
/* first deallocate request from list of allocates requests */
if ( request -> int_next && request -> int_prev ) {
if ( request -> int_next == request -> int_prev ) {
}
} else if ( request -> int_next || request -> int_prev ) {
}
+ spin_unlock_irqrestore(&ccwchain_lock,flags);
return;
}
ccw_req_t * request = NULL;
int cachind = 0;
int size_needed = 0;
+ long flags;
debug_text_event ( debug_area, 1, "ALLC");
if ( magic ) {
debug_text_event ( debug_area, 1, magic);
}
- debug_event ( debug_area, 1, cplength);
- debug_event ( debug_area, 1, datasize);
+ debug_int_event ( debug_area, 1, cplength);
+ debug_int_event ( debug_area, 1, datasize);
/* Sanity checks */
if ( cplength == 0 ) {
/* Try to fulfill the request from a cache */
while ( cachind < CCW_NUMBER_CACHES ) { /* Now try to get an entry from a cache above or equal to cachind */
if ( ccw_cache[cachind] == NULL ){
- printk("cache=%p index %d\n",cachind,cachind);
+ printk(KERN_WARNING PRINTK_HEADER "NULL cache found! cache=%p index %d\n",ccw_cache[cachind],cachind);
}
request = kmem_cache_alloc ( ccw_cache[cachind], GFP_ATOMIC );
if ( request != NULL ) {
request->cache = ccw_cache[cachind];
break;
} else {
- printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache");
+ printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache\n");
}
cachind++;
}
/* if no success, fall back to kmalloc */
if ( request == NULL ) {
- printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc");
+ printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc\n");
request = kmalloc ( sizeof(ccw_req_t), GFP_ATOMIC );
if ( request != NULL ) {
memset ( request, 0, sizeof(ccw_req_t));
}
/* Initialize request */
if ( request == NULL ) {
- printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request");
+ printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request\n");
} else {
if ( request -> cache != NULL ) {
/* Three cases when coming from a cache */
request -> cplength = cplength;
request -> datasize = datasize;
/* enqueue request to list of allocated requests */
+ spin_lock_irqsave(&ccwchain_lock,flags);
if ( ccwreq_actual == NULL ) { /* queue empty */
ccwreq_actual = request;
request->int_prev = ccwreq_actual;
request->int_prev->int_next = request;
request->int_next->int_prev = request;
}
+ spin_unlock_irqrestore(&ccwchain_lock,flags);
}
- debug_event ( debug_area, 1, (long)request);
+ debug_int_event ( debug_area, 1, (long)request);
return request;
}
int slabsize;
debug_text_event ( debug_area, 1, "FREE");
- debug_event ( debug_area, 1, (long)request);
+ debug_int_event ( debug_area, 1, (long)request);
/* Sanity checks */
if ( request == NULL ) {
printk(KERN_DEBUG PRINTK_HEADER"Trying to deallocate NULL request\n");
if ( request ->cpaddr ) {
kfree ( request -> cpaddr );
}
- dechain ( request);
+ dechain (request);
kfree ( request );
} else {
/* Find which area has been allocated by kmalloc */
int cachind;
/* allocate a debug area */
- debug_area = debug_register( "ccwcache", 2, 4);
+ debug_area = debug_register( "ccwcache", 2, 4,4);
if ( ! debug_area ) {
printk ( KERN_WARNING PRINTK_HEADER"cannot allocate debug area\n" );
} else {
printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area );
}
+ debug_register_view(debug_area,&debug_hex_view);
+ debug_register_view(debug_area,&debug_ebcdic_view);
debug_text_event ( debug_area, 0, "INIT");
/* First allocate the kmem caches */
for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
int slabsize = SMALLEST_SLAB << cachind;
debug_text_event ( debug_area, 1, "allc");
- debug_event ( debug_area, 1, slabsize);
+ debug_int_event ( debug_area, 1, slabsize);
sprintf ( ccw_cache_name[cachind],
"%s%d%c", ccw_name_template, slabsize, 0);
ccw_cache[cachind] = kmem_cache_create( ccw_cache_name[cachind],
slabsize, 0,
SLAB_HWCACHE_ALIGN,
NULL, NULL );
- debug_event ( debug_area, 1, (long)ccw_cache[cachind]);
+ debug_int_event ( debug_area, 1, (long)ccw_cache[cachind]);
if ( ! ccw_cache [cachind] ) {
printk (KERN_WARNING PRINTK_HEADER "Allocation of CCW cache failed\n");
}
}
}
}
- debug_unregister( debug_area ,"ccwcache");
+ debug_unregister( debug_area );
}
#ifdef MODULE
* S390 version
* Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * Updated:
+ * Aug-2000: Added tab support
+ * Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu)
*/
#include <linux/config.h>
#define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */
#define RAW3215_BH_PENDING 256 /* indication for bh scheduling */
+#define TAB_STOP_SIZE 8 /* tab stop size */
+
struct _raw3215_info; /* forward declaration ... */
int raw3215_condevice = -1; /* preset console device */
char *message; /* pending message from raw3215_irq */
int msg_dstat; /* dstat for pending message */
int msg_cstat; /* cstat for pending message */
+ int line_pos; /* position on the line (for tabs) */
} raw3215_info;
static raw3215_info *raw3215[NR_3215]; /* array of 3215 devices structures */
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
+extern void tod_wait(unsigned long usecs);
+
__initfunc(void con3215_setup(char *str, char *ints))
{
int vdev;
ccw->cmd_code = 0x0A; /* read inquiry */
ccw->flags = 0x20; /* ignore incorrect length */
ccw->count = 160;
- ccw->cda = (void *) virt_to_phys(raw->inbuf);
+ ccw->cda = (__u32) __pa(raw->inbuf);
}
/*
*/
static void raw3215_mk_write_req(raw3215_info *raw)
{
- raw3215_req *req;
+ raw3215_req *req;
ccw1_t *ccw;
int len, count, ix, lines;
return;
/* check if there is a queued write request */
req = raw->queued_write;
- if (req == NULL) {
+ if (req == NULL) {
/* no queued write request, use new req structure */
- req = raw3215_alloc_req();
+ req = raw3215_alloc_req();
req->type = RAW3215_WRITE;
- req->info = raw;
+ req->info = raw;
raw->queued_write = req;
} else {
raw->written -= req->len;
-}
+ }
ccw = req->ccws;
req->start = (raw->head - raw->count + raw->written) &
(RAW3215_BUFFER_SIZE - 1);
-/*
+ /*
* now we have to count newlines. We can at max accept
* RAW3215_MAX_NEWLINE newlines in a single ssch due to
* a restriction in VM
- */
+ */
lines = 0;
ix = req->start;
while (lines < RAW3215_MAX_NEWLINE && ix != raw->head) {
- if (raw->buffer[ix] == '\n')
+ if (raw->buffer[ix] == 0x15)
lines++;
ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1);
}
ccw[-1].flags |= 0x40; /* use command chaining */
ccw->cmd_code = 0x01; /* write, auto carrier return */
ccw->flags = 0x20; /* ignore incorrect length ind. */
- ccw->cda =
- (void *) virt_to_phys(raw->buffer + ix);
+ ccw->cda = (__u32) __pa(raw->buffer + ix);
count = len;
if (ix + count > RAW3215_BUFFER_SIZE)
- count = RAW3215_BUFFER_SIZE-ix;
+ count = RAW3215_BUFFER_SIZE - ix;
ccw->count = count;
len -= count;
ix = (ix + count) & (RAW3215_BUFFER_SIZE - 1);
ccw++;
}
-/*
+ /*
* Add a NOP to the channel program. 3215 devices are purely
* emulated and its much better to avoid the channel end
* interrupt in this case.
- */
+ */
if (ccw > req->ccws)
ccw[-1].flags |= 0x40; /* use command chaining */
ccw->cmd_code = 0x03; /* NOP */
if ((raw->queued_write->delayable == 0) ||
(raw->flags & RAW3215_FLUSHING)) {
/* execute write requests bigger than minimum size */
- raw3215_start_io(raw);
+ raw3215_start_io(raw);
if (raw->flags & RAW3215_TIMER_RUNS) {
del_timer(&raw->timer);
raw->flags &= ~RAW3215_TIMER_RUNS;
return; /* That shouldn't happen ... */
if (req->type == RAW3215_READ && raw->tty != NULL) {
tty = raw->tty;
- count = 160 - req->residual;
+ count = 160 - req->residual;
if (MACHINE_IS_P390) {
slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE);
if (count > slen)
} else if (req->type == RAW3215_WRITE) {
raw->count -= req->len;
raw->written -= req->len;
- }
+ }
raw->flags &= ~RAW3215_WORKING;
raw3215_free_req(req);
/* check for empty wait */
raw3215_sched_bh(raw);
break;
default:
- /* Strange interrupt, I'll do my best to clean up */
+ /* Strange interrupt, I'll do my best to clean up */
if ((raw = raw3215_find_info(irq)) == NULL)
return; /* That shouldn't happen ... */
if (req != NULL && req->type != RAW3215_FREE) {
}
raw->flags &= ~RAW3215_WORKING;
raw3215_free_req(req);
- }
- raw->message = KERN_WARNING
- "Spurious interrupt in in raw3215_irq "
- "(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
- raw->msg_dstat = dstat;
- raw->msg_cstat = cstat;
+ }
+ raw->message = KERN_WARNING
+ "Spurious interrupt in in raw3215_irq "
+ "(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
+ raw->msg_dstat = dstat;
+ raw->msg_cstat = cstat;
raw3215_sched_bh(raw);
}
return;
}
+/*
+ * Wait until length bytes are available int the output buffer.
+ * Has to be called with the s390irq lock held. Can be called
+ * disabled.
+ */
+void raw3215_make_room(raw3215_info *raw, unsigned int length)
+{
+ while (RAW3215_BUFFER_SIZE - raw->count < length) {
+ /* there might be a request pending */
+ raw->flags |= RAW3215_FLUSHING;
+ raw3215_mk_write_req(raw);
+ raw3215_try_io(raw);
+ raw->flags &= ~RAW3215_FLUSHING;
+ if (wait_cons_dev(raw->irq) != 0) {
+ /* that shouldn't happen */
+ raw->count = 0;
+ raw->written = 0;
+ }
+ /* Enough room freed up ? */
+ if (RAW3215_BUFFER_SIZE - raw->count >= length)
+ break;
+ /* there might be another cpu waiting for the lock */
+ s390irq_spin_unlock(raw->irq);
+ tod_wait(100);
+ s390irq_spin_lock(raw->irq);
+ }
+}
+
/*
* String write routine for 3215 devices
*/
RAW3215_BUFFER_SIZE : length;
length -= count;
- while (RAW3215_BUFFER_SIZE - raw->count < count) {
- /* there might be a request pending */
- raw3215_mk_write_req(raw);
- raw3215_try_io(raw);
- if (wait_cons_dev(raw->irq) != 0) {
- /* that shouldn't happen */
- raw->count = 0;
- raw->written = 0;
- }
- }
+ raw3215_make_room(raw, count);
/* copy string to output buffer and convert it to EBCDIC */
if (from_user) {
raw->head = (raw->head + c) &
(RAW3215_BUFFER_SIZE - 1);
raw->count += c;
+ raw->line_pos += c;
str += c;
count -= c;
ret += c;
raw->head = (raw->head + c) &
(RAW3215_BUFFER_SIZE - 1);
raw->count += c;
+ raw->line_pos += c;
str += c;
count -= c;
ret += c;
}
if (!(raw->flags & RAW3215_WORKING)) {
raw3215_mk_write_req(raw);
- /* start or queue request */
- raw3215_try_io(raw);
+ /* start or queue request */
+ raw3215_try_io(raw);
}
s390irq_spin_unlock_irqrestore(raw->irq, flags);
}
/*
* Put character routine for 3215 devices
*/
+
static void raw3215_putchar(raw3215_info *raw, unsigned char ch)
{
unsigned long flags;
+ unsigned int length, i;
s390irq_spin_lock_irqsave(raw->irq, flags);
- while (RAW3215_BUFFER_SIZE - raw->count < 1) {
- /* there might be a request pending */
- raw3215_mk_write_req(raw);
- raw3215_try_io(raw);
- if (wait_cons_dev(raw->irq) != 0) {
- /* that shouldn't happen */
- raw->count = 0;
- raw->written = 0;
- }
+ if (ch == '\t') {
+ length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE);
+ raw->line_pos += length;
+ ch = ' ';
+ } else if (ch == '\n') {
+ length = 1;
+ raw->line_pos = 0;
+ } else {
+ length = 1;
+ raw->line_pos++;
}
+ raw3215_make_room(raw, length);
- raw->buffer[raw->head] = (char) _ascebc[(int) ch];
- raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
- raw->count++;
+ for (i = 0; i < length; i++) {
+ raw->buffer[raw->head] = (char) _ascebc[(int) ch];
+ raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
+ raw->count++;
+ }
if (!(raw->flags & RAW3215_WORKING)) {
raw3215_mk_write_req(raw);
- /* start or queue request */
- raw3215_try_io(raw);
+ /* start or queue request */
+ raw3215_try_io(raw);
}
s390irq_spin_unlock_irqrestore(raw->irq, flags);
}
if (request_irq(raw->irq, raw3215_irq, SA_INTERRUPT,
"3215 terminal driver", &raw->devstat) != 0)
return -1;
+ raw->line_pos = 0;
raw->flags |= RAW3215_ACTIVE;
s390irq_spin_lock_irqsave(raw->irq, flags);
set_cons_dev(raw->irq);
while (count <= number && irq != -ENODEV) {
if (get_dev_info(irq, &dinfo) == -ENODEV)
break;
- if (dinfo.devno == raw3215_condevice ||
+ if (dinfo.devno == raw3215_condevice ||
dinfo.sid_data.cu_type == 0x3215) {
- count++;
+ count++;
if (count > number)
- return irq;
-}
+ return irq;
+ }
irq = get_irq_next(irq);
}
return -1; /* console not found */
if (!MACHINE_IS_VM && !MACHINE_IS_P390)
return 0;
raw = raw3215[0]; /* 3215 console is the first one */
- if (raw->irq == -1) /* now console device found in con3215_init */
+ if (raw == NULL || raw->irq == -1)
+ /* console device not found in con3215_init */
return -1;
return raw3215_startup(raw);
}
con3215_write(struct console *co, const char *str, unsigned int count)
{
raw3215_info *raw;
+ int i;
if (count <= 0)
return;
- raw = raw3215[0]; /* console 3215 is the first one */
- raw3215_write(raw, str, 0, count);
+ raw = raw3215[0]; /* console 3215 is the first one */
+ while (count > 0) {
+ for (i = 0; i < count; i++)
+ if (str[i] == '\t' || str[i] == '\n')
+ break;
+ raw3215_write(raw, str, 0, i);
+ count -= i;
+ str += i;
+ if (count > 0) {
+ raw3215_putchar(raw, *str);
+ count--;
+ str++;
+ }
+ }
}
kdev_t con3215_device(struct console *c)
raw = raw3215[0]; /* console 3215 is the first one */
s390irq_spin_lock_irqsave(raw->irq, flags);
- while (raw->count > 0) {
- /* there might be a request pending */
- raw->flags |= RAW3215_FLUSHING;
- raw3215_try_io(raw);
- if (wait_cons_dev(raw->irq) != 0) {
- /* that shouldn't happen */
- raw->count = 0;
- raw->written = 0;
- }
- raw->flags &= ~RAW3215_FLUSHING;
- }
+ raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
s390irq_spin_unlock_irqrestore(raw->irq, flags);
}
raw3215_info *raw;
raw = (raw3215_info *) tty->driver_data;
- return RAW3215_BUFFER_SIZE - raw->count;
+
+ /* Subtract TAB_STOP_SIZE to allow for a tab, 8 <<< 64K */
+ if ((RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE) >= 0)
+ return RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE;
+ else
+ return 0;
}
/*
const unsigned char *buf, int count)
{
raw3215_info *raw;
- int ret;
+ int ret = 0;
if (!tty)
return 0;
if (!MACHINE_IS_VM && !MACHINE_IS_P390)
return kmem_start;
if (MACHINE_IS_VM) {
- cpcmd("TERM CONMODE 3215", NULL, 0);
- cpcmd("TERM AUTOCR OFF", NULL, 0);
+ cpcmd("TERM CONMODE 3215", NULL, 0);
+ cpcmd("TERM AUTOCR OFF", NULL, 0);
}
kmem_start = (kmem_start + 7) & -8L;
/*
* drivers/s390/char/hwc.h
- *
+ *
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Peschke <peschke@fh-brandenburg.de>
*
- *
- *
+ *
+ *
*/
#ifndef __HWC_H__
go_t;
-typedef struct {
- go_t go;
+typedef struct {
+ go_t go;
} __attribute__ ((packed))
mdb_body_t;
typedef struct {
_MDB_HEADER
- mdb_body_t mdb_body;
+ mdb_body_t mdb_body;
} __attribute__ ((packed))
mdb_t;
typedef struct {
_EBUF_HEADER
- mdb_t mdb;
+ mdb_t mdb;
} __attribute__ ((packed))
msgbuf_t;
typedef struct {
_HWCB_HEADER
- msgbuf_t msgbuf;
+ msgbuf_t msgbuf;
} __attribute__ ((packed))
write_hwcb_t;
static write_hwcb_t write_hwcb_template =
{
- sizeof(write_hwcb_t),
- 0x00,
+ sizeof (write_hwcb_t),
+ 0x00,
{
0x00,
- 0x00,
- 0x00
+ 0x00,
+ 0x00
},
- 0x0000,
- {
- sizeof(msgbuf_t),
- ET_Msg,
- 0x00,
- 0x0000,
- {
- sizeof(mdb_t),
+ 0x0000,
+ {
+ sizeof (msgbuf_t),
+ ET_Msg,
+ 0x00,
+ 0x0000,
+ {
+ sizeof (mdb_t),
0x0001,
0xD4C4C240,
0x00000001,
- {
- {
- sizeof(go_t),
+ {
+ {
+ sizeof (go_t),
0x0001
}
static mto_t mto_template =
{
- sizeof(mto_t),
+ sizeof (mto_t),
0x0004,
- LTF_EndText,
- 0x00
+ LTF_EndText,
+ 0x00
};
typedef u32 _hwcb_mask_t;
typedef struct {
_HWCB_HEADER
- u16 _reserved;
- u16 mask_length;
- _hwcb_mask_t cp_receive_mask;
- _hwcb_mask_t cp_send_mask;
- _hwcb_mask_t hwc_receive_mask;
- _hwcb_mask_t hwc_send_mask;
+ u16 _reserved;
+ u16 mask_length;
+ _hwcb_mask_t cp_receive_mask;
+ _hwcb_mask_t cp_send_mask;
+ _hwcb_mask_t hwc_receive_mask;
+ _hwcb_mask_t hwc_send_mask;
} __attribute__ ((packed))
init_hwcb_t;
static init_hwcb_t init_hwcb_template =
{
- sizeof(init_hwcb_t),
+ sizeof (init_hwcb_t),
0x00,
{
0x00,
- 0x00,
- 0x00
+ 0x00,
+ 0x00
},
- 0x0000,
- 0x0000,
- sizeof(_hwcb_mask_t),
+ 0x0000,
+ 0x0000,
+ sizeof (_hwcb_mask_t),
ET_OpCmd_Mask | ET_PMsgCmd_Mask,
ET_Msg_Mask
};
static read_hwcb_t read_hwcb_template =
{
PAGE_SIZE,
- 0x00,
+ 0x00,
{
- 0x00,
- 0x00,
- 0x80
+ 0x00,
+ 0x00,
+ 0x80
}
};
-#endif /* __HWC_H__ */
+#endif /* __HWC_H__ */
#include "hwc_rw.h"
-extern void hwc_tty_init(void);
+extern void hwc_tty_init (void);
#ifdef CONFIG_HWC_CONSOLE
-#define hwc_console_major 4
+#define hwc_console_major 4
#define hwc_console_minor 0
-#define hwc_console_name "console"
+#define hwc_console_name "console"
-void hwc_console_write(struct console *, const char *, unsigned int);
-kdev_t hwc_console_device(struct console *);
+void hwc_console_write (struct console *, const char *, unsigned int);
+kdev_t hwc_console_device (struct console *);
void hwc_console_unblank (void);
#define HWC_CON_PRINT_HEADER "hwc console driver: "
hwc_console_write,
NULL,
hwc_console_device,
- NULL,
+ NULL,
hwc_console_unblank,
- NULL,
+ NULL,
CON_PRINTBUFFER,
0,
0,
NULL
};
-
+
void
hwc_console_write (
- struct console *console,
- const char *message,
- unsigned int count)
+ struct console *console,
+ const char *message,
+ unsigned int count)
{
if (console->device (console) != hwc_console.device (&hwc_console)) {
- hwc_printk(KERN_WARNING HWC_CON_PRINT_HEADER
- "hwc_console_write() called with wrong "
- "device number");
+ hwc_printk (KERN_WARNING HWC_CON_PRINT_HEADER
+ "hwc_console_write() called with wrong "
+ "device number");
return;
}
- hwc_write(0, message, count);
+ hwc_write (0, message, count);
}
kdev_t
hwc_console_device (struct console * c)
{
- return MKDEV(hwc_console_major, hwc_console_minor);
+ return MKDEV (hwc_console_major, hwc_console_minor);
}
void
hwc_unblank ();
}
-#endif
+#endif
-__initfunc(unsigned long hwc_console_init(unsigned long kmem_start))
+__initfunc (unsigned long hwc_console_init (unsigned long kmem_start))
{
#ifdef CONFIG_3215
- if (MACHINE_IS_VM)
- return kmem_start;
+ if (MACHINE_IS_VM)
+ return kmem_start;
#endif
if (MACHINE_IS_P390)
return kmem_start;
- if (hwc_init(&kmem_start) == 0) {
+ if (hwc_init (&kmem_start) == 0) {
hwc_tty_init ();
#ifdef CONFIG_HWC_CONSOLE
- register_console(&hwc_console);
-#endif
+ register_console (&hwc_console);
+#endif
} else
panic (HWC_CON_PRINT_HEADER "hwc initialisation failed !");
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Peschke <peschke@fh-brandenburg.de>
*
+ *
*
- *
- *
- *
- *
+ *
+ *
+ *
*/
#include <linux/kernel.h>
#undef BUFFER_STRESS_TEST
+#define MEASURE_HWC_OUTPUT
+
typedef struct {
unsigned char *next;
unsigned short int mto_char_sum;
static unsigned char _obuf[MAX_HWCB_ROOM];
static unsigned char
- _page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
+ _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
typedef u32 kmem_pages_t;
{
{
},
- {
- 8,
- 0,
- 80,
- CODE_ASCII,
- 1,
- 50,
- MAX_KMEM_PAGES,
+ {
+ 8,
+ 0,
+ 80,
+ CODE_ASCII,
+ 1,
+ 50,
+ MAX_KMEM_PAGES,
- 0,
+ 0,
- 0x6c
+ 0x6c,
+ 0,
+ 0,
+ 0
},
- NULL,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- _obuf,
- 0,
- 0,
- 0,
- _page,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 0,
+ NULL,
+ NULL,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ _obuf,
+ 0,
+ 0,
+ 0,
+ _page,
+ 0,
+ NULL,
+ 0,
+ 0,
+ 0,
+ 0,
0,
NULL
#define IMMEDIATE_WRITE 1
static signed int do_hwc_write (int from_user, unsigned char *,
- unsigned int,
- unsigned char,
- unsigned char);
+ unsigned int,
+ unsigned char,
+ unsigned char);
static asmlinkage int
internal_print (char write_time, char *fmt,...)
int i;
unsigned char buf[512];
- va_start(args, fmt);
- i = vsprintf(buf, fmt, args);
- va_end(args);
- return do_hwc_write(0, buf, i, CODE_ASCII, write_time);
+ va_start (args, fmt);
+ i = vsprintf (buf, fmt, args);
+ va_end (args);
+ return do_hwc_write (0, buf, i, CODE_ASCII, write_time);
}
int
unsigned char buf[512];
unsigned long flags;
int retval;
-
- spin_lock_irqsave(&hwc_data.lock, flags);
- i = vsprintf(buf, fmt, args);
- va_end(args);
- retval = do_hwc_write(0, buf, i, CODE_ASCII, IMMEDIATE_WRITE);
-
- spin_unlock_irqrestore(&hwc_data.lock, flags);
+ spin_lock_irqsave (&hwc_data.lock, flags);
+
+ i = vsprintf (buf, fmt, args);
+ va_end (args);
+ retval = do_hwc_write (0, buf, i, CODE_ASCII, IMMEDIATE_WRITE);
+
+ spin_unlock_irqrestore (&hwc_data.lock, flags);
return retval;
}
-
+
#ifdef DUMP_HWCB_INPUT
static void
old_final_nl = hwc_data.ioctls.final_nl;
hwc_data.ioctls.final_nl = 1;
-
- internal_print(DELAYED_WRITE, "\n%8x ", area);
+
+ internal_print (DELAYED_WRITE, "\n%8x ", area);
for (index = 0; index < count; index++) {
-
+
if (area[index] <= 0xF)
- internal_print(DELAYED_WRITE, "0%x", area[index]);
+ internal_print (DELAYED_WRITE, "0%x", area[index]);
else
internal_print (DELAYED_WRITE, "%x", area[index]);
-
+
if ((index & 0xF) == 0xF)
- internal_print(DELAYED_WRITE, "\n%8x ",
- &area[index + 1]);
- else if ((index & 3) == 3)
- internal_print(DELAYED_WRITE, " ");
+ internal_print (DELAYED_WRITE, "\n%8x ",
+ &area[index + 1]);
+ else if ((index & 3) == 3)
+ internal_print (DELAYED_WRITE, " ");
}
-
- internal_print(IMMEDIATE_WRITE, "\n");
+
+ internal_print (IMMEDIATE_WRITE, "\n");
hwc_data.ioctls.final_nl = old_final_nl;
}
-#endif
+#endif
static inline u32
service_call (
- u32 hwc_command_word,
- unsigned char hwcb[])
+ u32 hwc_command_word,
+ unsigned char hwcb[])
{
unsigned int condition_code = 1;
- __asm__ __volatile__("L 1, 0(0,%0) \n\t"
- "LRA 2, 0(0,%1) \n\t"
- ".long 0xB2200012 \n\t"
- :
- :"a"(&hwc_command_word), "a"(hwcb)
- :"1", "2", "memory");
+ __asm__ __volatile__ ("L 1, 0(0,%0) \n\t"
+ "LRA 2, 0(0,%1) \n\t"
+ ".long 0xB2200012 \n\t"
+ :
+ :"a" (&hwc_command_word), "a" (hwcb)
+ :"1", "2", "memory");
- __asm__ __volatile__("IPM %0 \n\t"
- "SRL %0, 28 \n\t"
- :"=r"(condition_code));
+ __asm__ __volatile__ ("IPM %0 \n\t"
+ "SRL %0, 28 \n\t"
+ :"=r" (condition_code));
return condition_code;
}
{
u32 param;
- __asm__ __volatile__("L %0,128(0,0)\n\t"
- :"=r"(param));
+ __asm__ __volatile__ ("L %0,128(0,0)\n\t"
+ :"=r" (param));
return ((unsigned char *) param);
}
if (!BUF_HWCB)
return -ENOMEM;
-
+
BUF_HWCB_MTO = 0;
BUF_HWCB_CHAR = 0;
hwcb = (write_hwcb_t *) BUF_HWCB;
- memcpy(hwcb, &write_hwcb_template, sizeof(write_hwcb_t));
-
+ memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));
+
if (!hwc_data.write_nonprio && hwc_data.write_prio)
hwcb->msgbuf.type = ET_PMsgCmd;
if (!OUT_HWCB)
return -ENOMEM;
-
- if ((unsigned long)OUT_HWCB & 0xFFF) {
+
+ if ((unsigned long) OUT_HWCB & 0xFFF) {
bad_addr = OUT_HWCB;
#ifdef DUMP_HWC_WRITE_LIST_ERROR
- __asm__("LHI 1,0xe30\n\t"
- "LRA 2,0(0,%0) \n\t"
- "J .+0 \n\t"
- :
- :"a"(bad_addr)
- :"1", "2");
-#endif
-
+ __asm__ ("LHI 1,0xe30\n\t"
+ "LRA 2,0(0,%0) \n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (bad_addr)
+ : "1", "2");
+#endif
+
hwc_data.kmem_pages = 0;
- if ((unsigned long)BUF_HWCB & 0xFFF) {
+ if ((unsigned long) BUF_HWCB & 0xFFF) {
lost_hwcb = hwc_data.hwcb_count;
lost_msg = ALL_HWCB_MTO;
lost_char = ALL_HWCB_CHAR;
-
+
OUT_HWCB = NULL;
BUF_HWCB = NULL;
ALL_HWCB_MTO = 0;
ALL_HWCB_CHAR = BUF_HWCB_CHAR;
hwc_data.hwcb_count = 1;
page = (unsigned long) BUF_HWCB;
-
+
if (page >= hwc_data.kmem_start &&
- page < hwc_data.kmem_end) {
-
+ page <= hwc_data.kmem_end) {
+
page_nr = (int)
- ((page - hwc_data.kmem_start) >> 12);
- set_bit(page_nr, &hwc_data.kmem_pages);
+ ((page - hwc_data.kmem_start) >> 12);
+ set_bit (page_nr, &hwc_data.kmem_pages);
}
}
-
- internal_print(
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
+
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
"found invalid HWCB at address 0x%x. List corrupted. "
- "Lost %i HWCBs with %i characters within up to %i "
- "messages. Saved %i HWCB with last %i characters i"
- "within up to %i messages.\n",
- (unsigned int)bad_addr,
- lost_hwcb, lost_char, lost_msg,
- hwc_data.hwcb_count,
- ALL_HWCB_CHAR, ALL_HWCB_MTO);
+ "Lost %i HWCBs with %i characters within up to %i "
+ "messages. Saved %i HWCB with last %i characters i"
+ "within up to %i messages.\n",
+ (unsigned int) bad_addr,
+ lost_hwcb, lost_char, lost_msg,
+ hwc_data.hwcb_count,
+ ALL_HWCB_CHAR, ALL_HWCB_MTO);
}
return 0;
}
int retval;
if (hwc_data.hwcb_count < 2)
-#ifdef DUMP_HWC_WRITE_LIST_ERROR
- __asm__("LHI 1,0xe31\n\t"
- "LRA 2,0(0,%0)\n\t"
- "LRA 3,0(0,%1)\n\t"
- "J .+0 \n\t"
- :
- :"a"(BUF_HWCB), "a"(OUT_HWCB)
- :"1", "2", "3");
+#ifdef DUMP_HWC_WRITE_LIST_ERROR
+ __asm__ ("LHI 1,0xe31\n\t"
+ "LRA 2,0(0,%0)\n\t"
+ "LRA 3,0(0,%1)\n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (BUF_HWCB), "a" (OUT_HWCB)
+ : "1", "2", "3");
#else
return -EPERM;
-#endif
-
+#endif
+
if (hwc_data.current_hwcb == OUT_HWCB) {
if (hwc_data.hwcb_count > 2) {
ALL_HWCB_MTO -= BUF_HWCB_MTO;
ALL_HWCB_CHAR -= BUF_HWCB_CHAR;
- retval = prepare_write_hwcb();
+ retval = prepare_write_hwcb ();
if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
- internal_print(
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "reached my own limit of "
- "allowed buffer space for output (%i HWCBs = %li "
- "bytes), skipped content of oldest HWCB %i time(s) "
- "(%i lines = %i characters)\n",
- hwc_data.ioctls.max_hwcb,
- hwc_data.ioctls.max_hwcb * PAGE_SIZE,
- BUF_HWCB_TIMES_LOST,
- BUF_HWCB_MTO_LOST,
- BUF_HWCB_CHAR_LOST);
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "reached my own limit of "
+ "allowed buffer space for output (%i HWCBs = %li "
+ "bytes), skipped content of oldest HWCB %i time(s) "
+ "(%i lines = %i characters)\n",
+ hwc_data.ioctls.max_hwcb,
+ hwc_data.ioctls.max_hwcb * PAGE_SIZE,
+ BUF_HWCB_TIMES_LOST,
+ BUF_HWCB_MTO_LOST,
+ BUF_HWCB_CHAR_LOST);
else
internal_print (
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "page allocation failed, "
- "could not expand buffer for output (currently in "
- "use: %i HWCBs = %li bytes), skipped content of "
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "page allocation failed, "
+ "could not expand buffer for output (currently in "
+ "use: %i HWCBs = %li bytes), skipped content of "
"oldest HWCB %i time(s) (%i lines = %i characters)\n",
- hwc_data.hwcb_count,
- hwc_data.hwcb_count * PAGE_SIZE,
- BUF_HWCB_TIMES_LOST,
- BUF_HWCB_MTO_LOST,
- BUF_HWCB_CHAR_LOST);
+ hwc_data.hwcb_count,
+ hwc_data.hwcb_count * PAGE_SIZE,
+ BUF_HWCB_TIMES_LOST,
+ BUF_HWCB_MTO_LOST,
+ BUF_HWCB_CHAR_LOST);
return retval;
}
{
unsigned char *page;
int page_nr;
-
+
if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb)
return -ENOMEM;
-
- page_nr = find_first_zero_bit(&hwc_data.kmem_pages, MAX_KMEM_PAGES);
+
+ page_nr = find_first_zero_bit (&hwc_data.kmem_pages, MAX_KMEM_PAGES);
if (page_nr < hwc_data.ioctls.kmem_hwcb) {
page = (unsigned char *)
- (hwc_data.kmem_start + (page_nr << 12));
- set_bit(page_nr, &hwc_data.kmem_pages);
+ (hwc_data.kmem_start + (page_nr << 12));
+ set_bit (page_nr, &hwc_data.kmem_pages);
} else
page = (unsigned char *) __get_free_page (GFP_ATOMIC);
if (!OUT_HWCB)
OUT_HWCB = page;
- else
+ else
BUF_HWCB_NEXT = page;
BUF_HWCB = page;
hwc_data.hwcb_count++;
- prepare_write_hwcb();
+ prepare_write_hwcb ();
BUF_HWCB_TIMES_LOST = 0;
BUF_HWCB_MTO_LOST = 0;
#ifdef BUFFER_STRESS_TEST
- internal_print(
- DELAYED_WRITE,
- "*** " HWC_RW_PRINT_HEADER
- "page #%i at 0x%x for buffering allocated. ***\n",
- hwc_data.hwcb_count, page);
+ internal_print (
+ DELAYED_WRITE,
+ "*** " HWC_RW_PRINT_HEADER
+ "page #%i at 0x%x for buffering allocated. ***\n",
+ hwc_data.hwcb_count, page);
-#endif
+#endif
return 0;
}
{
unsigned long page;
int page_nr;
-
- if (!hwc_data.hwcb_count)
- return -ENODATA;
-
- if (hwc_data.hwcb_count == 1) {
-
- prepare_write_hwcb();
-
- ALL_HWCB_CHAR = 0;
- ALL_HWCB_MTO = 0;
- BUF_HWCB_TIMES_LOST = 0;
- BUF_HWCB_MTO_LOST = 0;
- BUF_HWCB_CHAR_LOST = 0;
+
+ if (!hwc_data.hwcb_count)
+ return -ENODATA;
+
+ if (hwc_data.hwcb_count == 1) {
+
+ prepare_write_hwcb ();
+
+ ALL_HWCB_CHAR = 0;
+ ALL_HWCB_MTO = 0;
+ BUF_HWCB_TIMES_LOST = 0;
+ BUF_HWCB_MTO_LOST = 0;
+ BUF_HWCB_CHAR_LOST = 0;
} else {
- page = (unsigned long) OUT_HWCB;
-
- ALL_HWCB_MTO -= OUT_HWCB_MTO;
- ALL_HWCB_CHAR -= OUT_HWCB_CHAR;
- hwc_data.hwcb_count--;
-
- OUT_HWCB = OUT_HWCB_NEXT;
-
- if (page >= hwc_data.kmem_start &&
- page < hwc_data.kmem_end) {
-
-/* memset((void *) page, 0, PAGE_SIZE); */
-
- page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
- clear_bit(page_nr, &hwc_data.kmem_pages);
+ page = (unsigned long) OUT_HWCB;
+
+ ALL_HWCB_MTO -= OUT_HWCB_MTO;
+ ALL_HWCB_CHAR -= OUT_HWCB_CHAR;
+ hwc_data.hwcb_count--;
+
+ OUT_HWCB = OUT_HWCB_NEXT;
+
+ if (page >= hwc_data.kmem_start &&
+ page <= hwc_data.kmem_end) {
+ /*memset((void *) page, 0, PAGE_SIZE); */
+
+ page_nr = (int) ((page - hwc_data.kmem_start) >> 12);
+ clear_bit (page_nr, &hwc_data.kmem_pages);
} else
- free_page(page);
+ free_page (page);
#ifdef BUFFER_STRESS_TEST
- internal_print(
- DELAYED_WRITE,
- "*** " HWC_RW_PRINT_HEADER
- "page at 0x%x released, %i pages still in use ***\n",
- page, hwc_data.hwcb_count);
+ internal_print (
+ DELAYED_WRITE,
+ "*** " HWC_RW_PRINT_HEADER
+ "page at 0x%x released, %i pages still in use ***\n",
+ page, hwc_data.hwcb_count);
-#endif
- }
+#endif
+ }
return 0;
}
static int
add_mto (
- unsigned char *message,
- unsigned short int count)
+ unsigned char *message,
+ unsigned short int count)
{
unsigned short int mto_size;
write_hwcb_t *hwcb;
if (BUF_HWCB == hwc_data.current_hwcb)
return -ENOMEM;
- mto_size = sizeof(mto_t) + count;
+ mto_size = sizeof (mto_t) + count;
hwcb = (write_hwcb_t *) BUF_HWCB;
-
+
if ((MAX_HWCB_ROOM - hwcb->length) < mto_size)
return -ENOMEM;
mto = (mto_t *) (((unsigned long) hwcb) + hwcb->length);
- memcpy(mto, &mto_template, sizeof(mto_t));
+ memcpy (mto, &mto_template, sizeof (mto_t));
- dest = (void *) (((unsigned long) mto) + sizeof(mto_t));
+ dest = (void *) (((unsigned long) mto) + sizeof (mto_t));
- memcpy(dest, message, count);
+ memcpy (dest, message, count);
mto->length += count;
-
- hwcb->length += mto_size;
- hwcb->msgbuf.length += mto_size;
- hwcb->msgbuf.mdb.length += mto_size;
+
+ hwcb->length += mto_size;
+ hwcb->msgbuf.length += mto_size;
+ hwcb->msgbuf.mdb.length += mto_size;
BUF_HWCB_MTO++;
ALL_HWCB_MTO++;
BUF_HWCB_CHAR += count;
ALL_HWCB_CHAR += count;
+#ifdef MEASURE_HWC_OUTPUT
+
+ hwc_data.ioctls.measured_lines++;
+ hwc_data.ioctls.measured_chars += count;
+#endif
+
return count;
}
if (hwc_data.current_servc)
return -EBUSY;
-
- retval = sane_write_hwcb();
+
+ retval = sane_write_hwcb ();
if (retval < 0)
return retval;
if (!OUT_HWCB_MTO)
return -ENODATA;
- condition_code = service_call(HWC_CMDW_WRITEDATA, OUT_HWCB);
+ condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);
-#ifdef DUMP_HWC_WRITE_ERROR
+#ifdef DUMP_HWC_WRITE_ERROR
if (condition_code != HWC_COMMAND_INITIATED)
- __asm__("LHI 1,0xe20\n\t"
- "L 2,0(0,%0)\n\t"
- "LRA 3,0(0,%1)\n\t"
- "J .+0 \n\t"
- :
- :"a"(&condition_code), "a"(OUT_HWCB)
- :"1", "2", "3");
-#endif
+ __asm__ ("LHI 1,0xe20\n\t"
+ "L 2,0(0,%0)\n\t"
+ "LRA 3,0(0,%1)\n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (&condition_code), "a" (OUT_HWCB)
+ : "1", "2", "3");
+#endif
switch (condition_code) {
- case HWC_COMMAND_INITIATED :
- hwc_data.current_servc = HWC_CMDW_WRITEDATA;
- hwc_data.current_hwcb = OUT_HWCB;
- retval = condition_code;
- break;
- case HWC_BUSY :
- retval = -EBUSY;
- break;
- default :
- retval = -EIO;
+ case HWC_COMMAND_INITIATED:
+ hwc_data.current_servc = HWC_CMDW_WRITEDATA;
+ hwc_data.current_hwcb = OUT_HWCB;
+ retval = condition_code;
+#ifdef MEASURE_HWC_OUTPUT
+ hwc_data.ioctls.measured_wcalls++;
+#endif
+ break;
+ case HWC_BUSY:
+ retval = -EBUSY;
+ break;
+ default:
+ retval = -EIO;
}
return retval;
flush_hwcbs (void)
{
while (hwc_data.hwcb_count > 1)
- release_write_hwcb();
+ release_write_hwcb ();
- release_write_hwcb();
+ release_write_hwcb ();
hwc_data.flags &= ~HWC_FLUSH;
}
#ifdef DUMP_HWC_WRITE_ERROR
unsigned char *param;
- param = ext_int_param();
+ param = ext_int_param ();
if (param != hwc_data.current_hwcb) {
internal_print (
DELAYED_WRITE,
#ifdef DUMP_HWC_WRITE_LIST_ERROR
if (((unsigned char *) hwcb) != hwc_data.current_hwcb) {
- __asm__("LHI 1,0xe22\n\t"
- "LRA 2,0(0,%0)\n\t"
- "LRA 3,0(0,%1)\n\t"
- "LRA 4,0(0,%2)\n\t"
- "LRA 5,0(0,%3)\n\t"
- "J .+0 \n\t"
- :
- :"a"(OUT_HWCB),
- "a"(hwc_data.current_hwcb),
- "a"(BUF_HWCB),
+ __asm__ ("LHI 1,0xe22\n\t"
+ "LRA 2,0(0,%0)\n\t"
+ "LRA 3,0(0,%1)\n\t"
+ "LRA 4,0(0,%2)\n\t"
+ "LRA 5,0(0,%3)\n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (OUT_HWCB),
+ "a" (hwc_data.current_hwcb),
+ "a" (BUF_HWCB),
"a" (hwcb)
- :"1", "2", "3", "4", "5");
+ : "1", "2", "3", "4", "5");
}
#endif
#ifdef DUMP_HWC_WRITE_ERROR
if (hwcb->response_code != 0x0020) {
- __asm__("LHI 1,0xe21\n\t"
- "LRA 2,0(0,%0)\n\t"
- "LRA 3,0(0,%1)\n\t"
- "LRA 4,0(0,%2)\n\t"
- "LH 5,0(0,%3)\n\t"
- "SRL 5,8(0)\n\t"
- "J .+0 \n\t"
- :
- :"a"(OUT_HWCB), "a"(hwc_data.current_hwcb),
- "a"(BUF_HWCB),
- "a"(&(hwc_data.hwcb_count))
- :"1", "2", "3", "4", "5");
+ __asm__ ("LHI 1,0xe21\n\t"
+ "LRA 2,0(0,%0)\n\t"
+ "LRA 3,0(0,%1)\n\t"
+ "LRA 4,0(0,%2)\n\t"
+ "LH 5,0(0,%3)\n\t"
+ "SRL 5,8(0)\n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (OUT_HWCB), "a" (hwc_data.current_hwcb),
+ "a" (BUF_HWCB),
+ "a" (&(hwc_data.hwcb_count))
+ : "1", "2", "3", "4", "5");
}
-#endif
+#endif
if (hwcb->response_code == 0x0020) {
retval = OUT_HWCB_CHAR;
- release_write_hwcb();
+ release_write_hwcb ();
} else {
internal_print (
DELAYED_WRITE,
hwc_data.current_hwcb = NULL;
if (hwc_data.flags & HWC_FLUSH)
- flush_hwcbs();
+ flush_hwcbs ();
return retval;
}
static void
do_put_line (
- unsigned char * message,
- unsigned short count)
+ unsigned char *message,
+ unsigned short count)
{
- if (add_mto(message, count) != count) {
-
- if (allocate_write_hwcb() < 0)
- reuse_write_hwcb();
-
-#ifdef DUMP_HWC_WRITE_LIST_ERROR
- if (add_mto(message, count) != count)
- __asm__("LHI 1,0xe32\n\t"
- "LRA 2,0(0,%0)\n\t"
- "L 3,0(0,%1)\n\t"
- "LRA 4,0(0,%2)\n\t"
- "LRA 5,0(0,%3)\n\t"
- "J .+0 \n\t"
- :
- :"a"(message), "a"(&hwc_data.kmem_pages),
- "a"(BUF_HWCB), "a"(OUT_HWCB)
- :"1", "2", "3", "4", "5");
+ if (add_mto (message, count) != count) {
+
+ if (allocate_write_hwcb () < 0)
+ reuse_write_hwcb ();
+
+#ifdef DUMP_HWC_WRITE_LIST_ERROR
+ if (add_mto (message, count) != count)
+ __asm__ ("LHI 1,0xe32\n\t"
+ "LRA 2,0(0,%0)\n\t"
+ "L 3,0(0,%1)\n\t"
+ "LRA 4,0(0,%2)\n\t"
+ "LRA 5,0(0,%3)\n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (message), "a" (&hwc_data.kmem_pages),
+ "a" (BUF_HWCB), "a" (OUT_HWCB)
+ : "1", "2", "3", "4", "5");
#else
- add_mto(message, count);
-#endif
+ add_mto (message, count);
+#endif
}
}
static void
put_line (
- unsigned char * message,
- unsigned short count)
+ unsigned char *message,
+ unsigned short count)
{
-
+
if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) {
- del_timer(&hwc_data.write_timer);
+ del_timer (&hwc_data.write_timer);
hwc_data.flags &= ~HWC_TIMER_RUNS;
}
hwc_data.obuf_start += count;
- do_put_line(message, count);
+ do_put_line (message, count);
hwc_data.obuf_start -= count;
}
write_hwcb_t *hwcb;
if ((!BUF_HWCB) || (BUF_HWCB == hwc_data.current_hwcb))
- allocate_write_hwcb();
+ allocate_write_hwcb ();
hwcb = (write_hwcb_t *) BUF_HWCB;
hwcb->msgbuf.mdb.mdb_body.go.general_msg_flags |= GMF_SndAlrm;
-}
+}
static void
hwc_write_timeout (unsigned long data)
{
unsigned long flags;
-
- spin_lock_irqsave(&hwc_data.lock, flags);
-
+
+ spin_lock_irqsave (&hwc_data.lock, flags);
+
hwc_data.obuf_start = hwc_data.obuf_count;
if (hwc_data.obuf_count)
- put_line(hwc_data.obuf, hwc_data.obuf_count);
+ put_line (hwc_data.obuf, hwc_data.obuf_count);
hwc_data.obuf_start = 0;
hwc_data.obuf_cursor = 0;
hwc_data.obuf_count = 0;
-
- write_event_data_1();
- spin_unlock_irqrestore(&hwc_data.lock, flags);
+ write_event_data_1 ();
+
+ spin_unlock_irqrestore (&hwc_data.lock, flags);
}
static int
do_hwc_write (
- int from_user,
+ int from_user,
unsigned char *msg,
- unsigned int count,
- unsigned char code,
- unsigned char write_time)
+ unsigned int count,
+ unsigned char code,
+ unsigned char write_time)
{
unsigned int i_msg = 0;
unsigned short int spaces = 0;
if (hwc_data.obuf_start) {
obuf_cursor = 0;
obuf_count = 0;
- obuf_columns = MIN(hwc_data.ioctls.columns,
- MAX_MESSAGE_SIZE - hwc_data.obuf_start);
+ obuf_columns = MIN (hwc_data.ioctls.columns,
+ MAX_MESSAGE_SIZE - hwc_data.obuf_start);
} else {
obuf_cursor = hwc_data.obuf_cursor;
obuf_count = hwc_data.obuf_count;
obuf_columns = hwc_data.ioctls.columns;
}
-
+
for (i_msg = 0; i_msg < count; i_msg++) {
if (from_user)
- get_user(orig_ch, msg + i_msg);
+ get_user (orig_ch, msg + i_msg);
else
orig_ch = msg[i_msg];
if (code == CODE_EBCDIC)
ch = orig_ch;
processed_characters++;
-
+
if ((obuf_cursor == obuf_columns) &&
(ch != '\n') &&
(ch != '\t')) {
- put_line(&hwc_data.obuf[hwc_data.obuf_start],
- obuf_columns);
+ put_line (&hwc_data.obuf[hwc_data.obuf_start],
+ obuf_columns);
obuf_cursor = 0;
obuf_count = 0;
}
switch (ch) {
- case '\n' :
+ case '\n':
- put_line(&hwc_data.obuf[hwc_data.obuf_start],
- obuf_count);
+ put_line (&hwc_data.obuf[hwc_data.obuf_start],
+ obuf_count);
obuf_cursor = 0;
obuf_count = 0;
break;
- case '\a' :
+ case '\a':
hwc_data.obuf_start += obuf_count;
- set_alarm();
+ set_alarm ();
hwc_data.obuf_start -= obuf_count;
break;
- case '\t' :
+ case '\t':
do {
if (obuf_cursor < obuf_columns) {
hwc_data.obuf[hwc_data.obuf_start +
- obuf_cursor]
- = 0x20;
+ obuf_cursor]
+ = 0x20;
obuf_cursor++;
} else
break;
break;
- case '\f' :
- case '\v' :
+ case '\f':
+ case '\v':
spaces = obuf_cursor;
- put_line(&hwc_data.obuf[hwc_data.obuf_start],
- obuf_count);
+ put_line (&hwc_data.obuf[hwc_data.obuf_start],
+ obuf_count);
obuf_count = obuf_cursor;
while (spaces) {
hwc_data.obuf[hwc_data.obuf_start +
- obuf_cursor - spaces]
- = 0x20;
+ obuf_cursor - spaces]
+ = 0x20;
spaces--;
}
break;
- case '\b' :
+ case '\b':
if (obuf_cursor)
obuf_cursor--;
break;
- case '\r' :
+ case '\r':
obuf_cursor = 0;
break;
- case 0x00 :
+ case 0x00:
- put_line(&hwc_data.obuf[hwc_data.obuf_start],
- obuf_count);
+ put_line (&hwc_data.obuf[hwc_data.obuf_start],
+ obuf_count);
obuf_cursor = 0;
obuf_count = 0;
goto out;
- default:
+ default:
- if (isprint(ch))
+ if (isprint (ch))
hwc_data.obuf[hwc_data.obuf_start +
- obuf_cursor++]
- = (code == CODE_ASCII) ?
+ obuf_cursor++]
+ = (code == CODE_ASCII) ?
(MACHINE_IS_VM ?
_ascebc[orig_ch] :
_ascebc_500[orig_ch]) :
if (hwc_data.obuf_start ||
(hwc_data.ioctls.final_nl == 0)) {
-
- put_line(&hwc_data.obuf[hwc_data.obuf_start],
- obuf_count);
+
+ put_line (&hwc_data.obuf[hwc_data.obuf_start],
+ obuf_count);
obuf_cursor = 0;
obuf_count = 0;
} else {
if (hwc_data.flags & HWC_TIMER_RUNS) {
hwc_data.write_timer.expires =
- jiffies +
- hwc_data.ioctls.final_nl*HZ/10;
+ jiffies +
+ hwc_data.ioctls.final_nl * HZ / 10;
} else {
- init_timer(&hwc_data.write_timer);
+ init_timer (&hwc_data.write_timer);
hwc_data.write_timer.function =
- hwc_write_timeout;
+ hwc_write_timeout;
hwc_data.write_timer.data =
- (unsigned long)NULL;
+ (unsigned long) NULL;
hwc_data.write_timer.expires =
- jiffies +
- hwc_data.ioctls.final_nl*HZ/10;
- add_timer(&hwc_data.write_timer);
+ jiffies +
+ hwc_data.ioctls.final_nl * HZ / 10;
+ add_timer (&hwc_data.write_timer);
hwc_data.flags |= HWC_TIMER_RUNS;
}
} else;
- }
+ }
} else;
-out :
+ out:
if (!hwc_data.obuf_start) {
hwc_data.obuf_cursor = obuf_cursor;
hwc_data.obuf_count = obuf_count;
}
if (write_time == IMMEDIATE_WRITE)
- write_event_data_1();
+ write_event_data_1 ();
return processed_characters;
}
{
unsigned long flags;
int retval;
-
- spin_lock_irqsave(&hwc_data.lock, flags);
+
+ spin_lock_irqsave (&hwc_data.lock, flags);
retval = do_hwc_write (from_user, (unsigned char *) msg,
count, hwc_data.ioctls.code,
- IMMEDIATE_WRITE);
+ IMMEDIATE_WRITE);
- spin_unlock_irqrestore(&hwc_data.lock, flags);
+ spin_unlock_irqrestore (&hwc_data.lock, flags);
return retval;
}
unsigned short int number = 0;
unsigned long flags;
- spin_lock_irqsave(&hwc_data.lock, flags);
+ spin_lock_irqsave (&hwc_data.lock, flags);
if (flag & IN_HWCB)
number += ALL_HWCB_CHAR;
-
+
if (flag & IN_WRITE_BUF)
number += hwc_data.obuf_cursor;
-
- spin_unlock_irqrestore(&hwc_data.lock, flags);
+
+ spin_unlock_irqrestore (&hwc_data.lock, flags);
return number;
}
int i;
int nr = 0;
- for (i = 0; i < (sizeof(arg) << 3); i++) {
+ for (i = 0; i < (sizeof (arg) << 3); i++) {
if (arg & 1)
nr++;
arg >>= 1;
unsigned int number = 0;
unsigned long flags;
write_hwcb_t *hwcb;
-
- spin_lock_irqsave(&hwc_data.lock, flags);
- if (flag & IN_HWCB) {
+ spin_lock_irqsave (&hwc_data.lock, flags);
+
+ if (flag & IN_HWCB) {
if (BUF_HWCB) {
hwcb = (write_hwcb_t *) BUF_HWCB;
- number += MAX_HWCB_ROOM - hwcb->length;
+ number += MAX_HWCB_ROOM - hwcb->length;
}
number += (hwc_data.ioctls.kmem_hwcb -
- nr_setbits(hwc_data.kmem_pages)) *
- (MAX_HWCB_ROOM -
- (sizeof(write_hwcb_t) + sizeof(mto_t)));
+ nr_setbits (hwc_data.kmem_pages)) *
+ (MAX_HWCB_ROOM -
+ (sizeof (write_hwcb_t) + sizeof (mto_t)));
}
- if (flag & IN_WRITE_BUF)
- number += MAX_HWCB_ROOM - hwc_data.obuf_cursor;
+ if (flag & IN_WRITE_BUF)
+ number += MAX_HWCB_ROOM - hwc_data.obuf_cursor;
- spin_unlock_irqrestore(&hwc_data.lock, flags);
+ spin_unlock_irqrestore (&hwc_data.lock, flags);
return number;
}
{
unsigned long flags;
- spin_lock_irqsave(&hwc_data.lock, flags);
+ spin_lock_irqsave (&hwc_data.lock, flags);
if (flag & IN_HWCB) {
if (hwc_data.current_servc != HWC_CMDW_WRITEDATA)
- flush_hwcbs();
+ flush_hwcbs ();
else
hwc_data.flags |= HWC_FLUSH;
}
if (flag & IN_WRITE_BUF) {
- hwc_data.obuf_cursor = 0;
+ hwc_data.obuf_cursor = 0;
hwc_data.obuf_count = 0;
}
- spin_unlock_irqrestore(&hwc_data.lock, flags);
+ spin_unlock_irqrestore (&hwc_data.lock, flags);
}
unsigned short int
i_out++;
- i_in++;
+ i_in++;
} else
_case = ~_case;
if (_case) {
- if (hwc_data.ioctls.tolower)
+ if (hwc_data.ioctls.tolower)
buf[i_out] = _ebc_toupper[buf[i_in]];
else
int retval = 0;
switch (id) {
- case GDS_ID_MDSMU :
- name = "Multiple Domain Support Message Unit";
- break;
- case GDS_ID_MDSRouteInfo :
- name = "MDS Routing Information";
- break;
- case GDS_ID_AgUnWrkCorr :
- name = "Agent Unit of Work Correlator";
- break;
- case GDS_ID_SNACondReport :
- name = "SNA Condition Report";
- break;
- case GDS_ID_CPMSU :
- name = "CP Management Services Unit";
- break;
- case GDS_ID_RoutTargInstr :
- name = "Routing and Targeting Instructions";
- break;
- case GDS_ID_OpReq :
- name = "Operate Request";
- break;
- case GDS_ID_TextCmd :
- name = "Text Command";
- break;
+ case GDS_ID_MDSMU:
+ name = "Multiple Domain Support Message Unit";
+ break;
+ case GDS_ID_MDSRouteInfo:
+ name = "MDS Routing Information";
+ break;
+ case GDS_ID_AgUnWrkCorr:
+ name = "Agent Unit of Work Correlator";
+ break;
+ case GDS_ID_SNACondReport:
+ name = "SNA Condition Report";
+ break;
+ case GDS_ID_CPMSU:
+ name = "CP Management Services Unit";
+ break;
+ case GDS_ID_RoutTargInstr:
+ name = "Routing and Targeting Instructions";
+ break;
+ case GDS_ID_OpReq:
+ name = "Operate Request";
+ break;
+ case GDS_ID_TextCmd:
+ name = "Text Command";
+ break;
- default :
- name = "unknown GDS variable";
- retval = -EINVAL;
+ default:
+ name = "unknown GDS variable";
+ retval = -EINVAL;
}
return retval;
}
-#endif
+#endif
inline static gds_vector_t *
find_gds_vector (
- gds_vector_t *start, void *end, u16 id)
+ gds_vector_t * start, void *end, u16 id)
{
gds_vector_t *vec;
gds_vector_t *retval = NULL;
vec = start;
while (((void *) vec) < end) {
- if (vec->gds_id == id) {
+ if (vec->gds_id == id) {
#ifdef DUMP_HWCB_INPUT
int retval_name;
unsigned char name[64];
- retval_name = gds_vector_name(id, name);
- internal_print(
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "%s at 0x%x up to 0x%x, length: %d",
- name,
- (unsigned long) vec,
- ((unsigned long) vec) + vec->length - 1,
- vec->length);
+ retval_name = gds_vector_name (id, name);
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "%s at 0x%x up to 0x%x, length: %d",
+ name,
+ (unsigned long) vec,
+ ((unsigned long) vec) + vec->length - 1,
+ vec->length);
if (retval_name < 0)
- internal_print(
- IMMEDIATE_WRITE,
- ", id: 0x%x\n",
- vec->gds_id);
+ internal_print (
+ IMMEDIATE_WRITE,
+ ", id: 0x%x\n",
+ vec->gds_id);
else
internal_print (
- IMMEDIATE_WRITE,
- "\n");
-#endif
+ IMMEDIATE_WRITE,
+ "\n");
+#endif
retval = vec;
break;
inline static gds_subvector_t *
find_gds_subvector (
- gds_subvector_t *start, void *end, u8 key)
+ gds_subvector_t * start, void *end, u8 key)
{
gds_subvector_t *subvec;
gds_subvector_t *retval = NULL;
subvec = start;
while (((void *) subvec) < end) {
- if (subvec->key == key) {
+ if (subvec->key == key) {
retval = subvec;
break;
}
subvec = (gds_subvector_t *)
- (((unsigned long) subvec) + subvec->length);
+ (((unsigned long) subvec) + subvec->length);
}
return retval;
count = ((unsigned long) end) - ((unsigned long) start);
if (hwc_data.ioctls.tolower)
- EBC_TOLOWER(start, count);
+ EBC_TOLOWER (start, count);
if (hwc_data.ioctls.delim)
- count = seperate_cases(start, count);
+ count = seperate_cases (start, count);
if (hwc_data.ioctls.echo)
- do_hwc_write(0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE);
+ do_hwc_write (0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE);
if (hwc_data.ioctls.code == CODE_ASCII) {
if (MACHINE_IS_VM)
- EBCASC(start, count);
+ EBCASC (start, count);
else
EBCASC_500 (start, count);
}
subvec = start;
while (((void *) subvec) < end) {
- subvec = find_gds_subvector(subvec, end, 0x30);
+ subvec = find_gds_subvector (subvec, end, 0x30);
if (!subvec)
break;
subvec_data = (void *)
- (((unsigned long) subvec) +
- sizeof(gds_subvector_t));
+ (((unsigned long) subvec) +
+ sizeof (gds_subvector_t));
subvec_end = (void *)
- (((unsigned long) subvec) + subvec->length);
- retval += get_input(subvec_data, subvec_end);
+ (((unsigned long) subvec) + subvec->length);
+ retval += get_input (subvec_data, subvec_end);
subvec = (gds_subvector_t *) subvec_end;
}
subvec = start;
while (((void *) subvec) < end) {
- subvec = find_gds_subvector(
- subvec, end, GDS_KEY_SelfDefTextMsg);
+ subvec = find_gds_subvector (
+ subvec, end, GDS_KEY_SelfDefTextMsg);
if (!subvec)
break;
subvec_data = (gds_subvector_t *)
- (((unsigned long) subvec) +
- sizeof(gds_subvector_t));
+ (((unsigned long) subvec) +
+ sizeof (gds_subvector_t));
subvec_end = (void *)
- (((unsigned long) subvec) + subvec->length);
- retval += eval_selfdeftextmsg(subvec_data, subvec_end);
+ (((unsigned long) subvec) + subvec->length);
+ retval += eval_selfdeftextmsg (subvec_data, subvec_end);
subvec = (gds_subvector_t *) subvec_end;
}
vec = start;
while (((void *) vec) < end) {
- vec = find_gds_vector(vec, end, GDS_ID_TextCmd);
+ vec = find_gds_vector (vec, end, GDS_ID_TextCmd);
if (!vec)
break;
vec_data = (gds_subvector_t *)
- (((unsigned long) vec) + sizeof(gds_vector_t));
+ (((unsigned long) vec) + sizeof (gds_vector_t));
vec_end = (void *) (((unsigned long) vec) + vec->length);
- retval += eval_textcmd(vec_data, vec_end);
+ retval += eval_textcmd (vec_data, vec_end);
vec = (gds_vector_t *) vec_end;
}
void *vec_end;
int retval = 0;
- vec = find_gds_vector(start, end, GDS_ID_CPMSU);
+ vec = find_gds_vector (start, end, GDS_ID_CPMSU);
if (vec) {
vec_data = (gds_vector_t *)
- (((unsigned long) vec) + sizeof(gds_vector_t));
+ (((unsigned long) vec) + sizeof (gds_vector_t));
vec_end = (void *) (((unsigned long) vec) + vec->length);
- retval = eval_cpmsu(vec_data, vec_end);
+ retval = eval_cpmsu (vec_data, vec_end);
}
return retval;
}
void *vec_end;
int retval = 0;
- vec = find_gds_vector(start, end, GDS_ID_MDSMU);
+ vec = find_gds_vector (start, end, GDS_ID_MDSMU);
if (vec) {
vec_data = (gds_vector_t *)
- (((unsigned long) vec) + sizeof(gds_vector_t));
+ (((unsigned long) vec) + sizeof (gds_vector_t));
vec_end = (void *) (((unsigned long) vec) + vec->length);
- retval = eval_mdsmu(vec_data, vec_end);
+ retval = eval_mdsmu (vec_data, vec_end);
}
return retval;
}
evbuf = (evbuf_t *) start;
while (((void *) evbuf) < end) {
evbuf_data = (gds_vector_t *)
- (((unsigned long) evbuf) + sizeof(evbuf_t));
+ (((unsigned long) evbuf) + sizeof (evbuf_t));
evbuf_end = (void *) (((unsigned long) evbuf) + evbuf->length);
switch (evbuf->type) {
- case ET_OpCmd :
- case ET_CntlProgOpCmd :
- case ET_PMsgCmd :
+ case ET_OpCmd:
+ case ET_CntlProgOpCmd:
+ case ET_PMsgCmd:
#ifdef DUMP_HWCB_INPUT
-
- internal_print(
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "event buffer "
- "at 0x%x up to 0x%x, length: %d\n",
- (unsigned long) evbuf,
- (unsigned long) (evbuf_end - 1),
- evbuf->length);
- dump_storage_area((void *)evbuf, evbuf->length);
+
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "event buffer "
+ "at 0x%x up to 0x%x, length: %d\n",
+ (unsigned long) evbuf,
+ (unsigned long) (evbuf_end - 1),
+ evbuf->length);
+ dump_storage_area ((void *) evbuf, evbuf->length);
#endif
- retval += eval_evbuf(evbuf_data, evbuf_end);
- break;
- case ET_StateChange :
-
- retval = -ENOSYS;
- break;
- default :
- printk(
- KERN_WARNING
- HWC_RW_PRINT_HEADER
- "unconditional read: "
- "unknown event buffer found, "
- "type 0x%x",
- evbuf->type);
- retval = -ENOSYS;
+ retval += eval_evbuf (evbuf_data, evbuf_end);
+ break;
+ case ET_StateChange:
+
+ retval = -ENOSYS;
+ break;
+ default:
+ printk (
+ KERN_WARNING
+ HWC_RW_PRINT_HEADER
+ "unconditional read: "
+ "unknown event buffer found, "
+ "type 0x%x",
+ evbuf->type);
+ retval = -ENOSYS;
}
evbuf = (evbuf_t *) evbuf_end;
}
unsigned short int condition_code;
read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
int retval;
-
+
if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
return -EOPNOTSUPP;
if (hwc_data.current_servc)
return -EBUSY;
-
- memset(hwcb, 0x00, PAGE_SIZE);
- memcpy(hwcb, &read_hwcb_template, sizeof(read_hwcb_t));
- condition_code = service_call(HWC_CMDW_READDATA, hwc_data.page);
+ memset (hwcb, 0x00, PAGE_SIZE);
+ memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t));
-#ifdef DUMP_HWC_READ_ERROR
+ condition_code = service_call (HWC_CMDW_READDATA, hwc_data.page);
+
+#ifdef DUMP_HWC_READ_ERROR
if (condition_code == HWC_NOT_OPERATIONAL)
- __asm__("LHI 1,0xe40\n\t"
- "L 2,0(0,%0)\n\t"
- "LRA 3,0(0,%1)\n\t"
- "J .+0 \n\t"
- :
- :"a"(&condition_code), "a"(hwc_data.page)
- :"1", "2", "3");
-#endif
+ __asm__ ("LHI 1,0xe40\n\t"
+ "L 2,0(0,%0)\n\t"
+ "LRA 3,0(0,%1)\n\t"
+ "J .+0 \n\t"
+ :
+ : "a" (&condition_code), "a" (hwc_data.page)
+ : "1", "2", "3");
+#endif
switch (condition_code) {
- case HWC_COMMAND_INITIATED :
- hwc_data.current_servc = HWC_CMDW_READDATA;
- hwc_data.current_hwcb = hwc_data.page;
- retval = condition_code;
- break;
- case HWC_BUSY :
- retval = -EBUSY;
- break;
- default :
- retval = -EIO;
+ case HWC_COMMAND_INITIATED:
+ hwc_data.current_servc = HWC_CMDW_READDATA;
+ hwc_data.current_hwcb = hwc_data.page;
+ retval = condition_code;
+ break;
+ case HWC_BUSY:
+ retval = -EBUSY;
+ break;
+ default:
+ retval = -EIO;
}
return retval;
{
read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
-#ifdef DUMP_HWC_READ_ERROR
+#ifdef DUMP_HWC_READ_ERROR
if ((hwcb->response_code != 0x0020) &&
(hwcb->response_code != 0x0220) &&
(hwcb->response_code != 0x60F0) &&
(hwcb->response_code != 0x62F0))
- __asm__("LHI 1,0xe41\n\t"
- "LRA 2,0(0,%0)\n\t"
- "L 3,0(0,%1)\n\t"
- "J .+0\n\t"
- :
- :"a"(hwc_data.page), "a"(&(hwcb->response_code))
- :"1", "2", "3");
-#endif
+ __asm__ ("LHI 1,0xe41\n\t"
+ "LRA 2,0(0,%0)\n\t"
+ "L 3,0(0,%1)\n\t"
+ "J .+0\n\t"
+ :
+ : "a" (hwc_data.page), "a" (&(hwcb->response_code))
+ : "1", "2", "3");
+#endif
hwc_data.current_servc = 0;
hwc_data.current_hwcb = NULL;
switch (hwcb->response_code) {
- case 0x0020 :
- case 0x0220 :
- return process_evbufs(
- (void *) (((unsigned long) hwcb) + sizeof(read_hwcb_t)),
- (void *) (((unsigned long) hwcb) + hwcb->length));
+ case 0x0020:
+ case 0x0220:
+ return process_evbufs (
+ (void *) (((unsigned long) hwcb) + sizeof (read_hwcb_t)),
+ (void *) (((unsigned long) hwcb) + hwcb->length));
- case 0x60F0 :
- case 0x62F0 :
+ case 0x60F0:
+ case 0x62F0:
internal_print (
IMMEDIATE_WRITE,
HWC_RW_PRINT_HEADER
hwcb->response_code);
return 0;
- case 0x0100 :
- internal_print(
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: HWCB boundary violation - this "
- "must not occur in a correct driver, please contact "
- "author\n");
+ case 0x0100:
+ internal_print (
+ IMMEDIATE_WRITE,
+ HWC_RW_PRINT_HEADER
+ "unconditional read: HWCB boundary violation - this "
+ "must not occur in a correct driver, please contact "
+ "author\n");
return -EIO;
- case 0x0300 :
- internal_print(
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: "
+ case 0x0300:
+ internal_print (
+ IMMEDIATE_WRITE,
+ HWC_RW_PRINT_HEADER
+ "unconditional read: "
"insufficient HWCB length - this must not occur in a "
- "correct driver, please contact author\n");
+ "correct driver, please contact author\n");
return -EIO;
- case 0x01F0 :
- internal_print(
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: "
- "invalid command - this must not occur in a correct "
- "driver, please contact author\n");
+ case 0x01F0:
+ internal_print (
+ IMMEDIATE_WRITE,
+ HWC_RW_PRINT_HEADER
+ "unconditional read: "
+ "invalid command - this must not occur in a correct "
+ "driver, please contact author\n");
return -EIO;
- case 0x40F0 :
- internal_print(
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: invalid function code - this "
- "must not occur in a correct driver, please contact "
- "author\n");
+ case 0x40F0:
+ internal_print (
+ IMMEDIATE_WRITE,
+ HWC_RW_PRINT_HEADER
+ "unconditional read: invalid function code - this "
+ "must not occur in a correct driver, please contact "
+ "author\n");
return -EIO;
- case 0x70F0 :
- internal_print(
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: invalid selection mask - this "
- "must not occur in a correct driver, please contact "
- "author\n");
+ case 0x70F0:
+ internal_print (
+ IMMEDIATE_WRITE,
+ HWC_RW_PRINT_HEADER
+ "unconditional read: invalid selection mask - this "
+ "must not occur in a correct driver, please contact "
+ "author\n");
return -EIO;
- case 0x0040 :
- internal_print(
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
- "unconditional read: HWC equipment check - don't "
- "know how to handle this case\n");
+ case 0x0040:
+ internal_print (
+ IMMEDIATE_WRITE,
+ HWC_RW_PRINT_HEADER
+ "unconditional read: HWC equipment check - don't "
+ "know how to handle this case\n");
return -EIO;
-
- default :
- internal_print(
- IMMEDIATE_WRITE,
- HWC_RW_PRINT_HEADER
+
+ default:
+ internal_print (
+ IMMEDIATE_WRITE,
+ HWC_RW_PRINT_HEADER
"unconditional read: invalid response code %x - this "
- "must not occur in a correct driver, please contact "
- "author\n",
- hwcb->response_code);
+ "must not occur in a correct driver, please contact "
+ "author\n",
+ hwcb->response_code);
return -EIO;
}
}
{
unsigned int condition_code;
int retval;
-
- condition_code = service_call(HWC_CMDW_WRITEMASK, hwc_data.page);
+
+ condition_code = service_call (HWC_CMDW_WRITEMASK, hwc_data.page);
#ifdef DUMP_HWC_INIT_ERROR
if (condition_code == HWC_NOT_OPERATIONAL)
- __asm__("LHI 1,0xe10\n\t"
- "L 2,0(0,%0)\n\t"
- "LRA 3,0(0,%1)\n\t"
- "J .+0\n\t"
- :
- :"a"(&condition_code), "a"(hwc_data.page)
- :"1", "2", "3");
-#endif
+ __asm__ ("LHI 1,0xe10\n\t"
+ "L 2,0(0,%0)\n\t"
+ "LRA 3,0(0,%1)\n\t"
+ "J .+0\n\t"
+ :
+ : "a" (&condition_code), "a" (hwc_data.page)
+ : "1", "2", "3");
+#endif
switch (condition_code) {
- case HWC_COMMAND_INITIATED :
- hwc_data.current_servc = HWC_CMDW_WRITEMASK;
- hwc_data.current_hwcb = hwc_data.page;
- retval = condition_code;
- break;
- case HWC_BUSY :
- retval = -EBUSY;
- break;
- default :
- retval = -EIO;
+ case HWC_COMMAND_INITIATED:
+ hwc_data.current_servc = HWC_CMDW_WRITEMASK;
+ hwc_data.current_hwcb = hwc_data.page;
+ retval = condition_code;
+ break;
+ case HWC_BUSY:
+ retval = -EBUSY;
+ break;
+ default:
+ retval = -EIO;
}
return retval;
if (hwcb->hwc_receive_mask & ET_Msg_Mask)
hwc_data.write_nonprio = 1;
-
+
if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask)
hwc_data.write_prio = 1;
-
+
if (hwcb->hwc_send_mask & ET_OpCmd_Mask) {
internal_print (DELAYED_WRITE,
HWC_RW_PRINT_HEADER
(!hwc_data.write_nonprio) ||
((!hwc_data.read_nonprio) && (!hwc_data.read_prio)))
#ifdef DUMP_HWC_INIT_ERROR
- __asm__("LHI 1,0xe11\n\t"
- "LRA 2,0(0,%0)\n\t"
- "L 3,0(0,%1)\n\t"
- "J .+0\n\t"
- :
- :"a"(hwcb), "a"(&(hwcb->response_code))
- :"1", "2", "3");
+ __asm__ ("LHI 1,0xe11\n\t"
+ "LRA 2,0(0,%0)\n\t"
+ "L 3,0(0,%1)\n\t"
+ "J .+0\n\t"
+ :
+ : "a" (hwcb), "a" (&(hwcb->response_code))
+ : "1", "2", "3");
#else
retval = -EIO;
-#endif
+#endif
hwc_data.current_servc = 0;
hwc_data.current_hwcb = NULL;
{
int retval = 0;
hwc_ioctls_t tmp;
-
+
if (ioctls->width_htab > MAX_MESSAGE_SIZE) {
if (correct)
tmp.width_htab = MAX_MESSAGE_SIZE;
tmp.width_htab = ioctls->width_htab;
tmp.echo = ioctls->echo;
-
+
if (ioctls->columns > MAX_MESSAGE_SIZE) {
if (correct)
tmp.columns = MAX_MESSAGE_SIZE;
retval = -EINVAL;
} else
tmp.columns = ioctls->columns;
-
+
switch (ioctls->code) {
- case CODE_EBCDIC :
- case CODE_ASCII :
- tmp.code = ioctls->code;
- break;
- default :
- if (correct)
- tmp.code = CODE_ASCII;
+ case CODE_EBCDIC:
+ case CODE_ASCII:
+ tmp.code = ioctls->code;
+ break;
+ default:
+ if (correct)
+ tmp.code = CODE_ASCII;
else
retval = -EINVAL;
}
-
+
tmp.final_nl = ioctls->final_nl;
-
+
if (ioctls->max_hwcb < 2) {
if (correct)
tmp.max_hwcb = 2;
retval = -EINVAL;
} else
tmp.max_hwcb = ioctls->max_hwcb;
-
+
tmp.tolower = ioctls->tolower;
-
+
if (ioctls->kmem_hwcb > ioctls->max_hwcb) {
if (correct)
tmp.kmem_hwcb = ioctls->max_hwcb;
retval = -EINVAL;
} else
tmp.kmem_hwcb = ioctls->kmem_hwcb;
-
+
if (ioctls->kmem_hwcb > MAX_KMEM_PAGES) {
if (correct)
ioctls->kmem_hwcb = MAX_KMEM_PAGES;
}
tmp.delim = ioctls->delim;
+ tmp.measured_lines = ioctls->measured_lines;
+ tmp.measured_chars = ioctls->measured_chars;
+ tmp.measured_wcalls = ioctls->measured_wcalls;
+
if (!(retval < 0))
hwc_data.ioctls = tmp;
if (register_external_interrupt (0x2401, do_hwc_interrupt) != 0)
panic ("Couldn't request external interrupts 0x2401");
- spin_lock_init(&hwc_data.lock);
+ spin_lock_init (&hwc_data.lock);
#ifdef USE_VM_DETECTION
hwc_data.init_ioctls.delim = 0;
}
#endif
- retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1);
+ retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
*kmem_start = (*kmem_start + PAGE_SIZE - 1) & -4096L;
hwc_data.kmem_start = *kmem_start;
retval = do_hwc_init ();
- ctl_set_bit(0, 9);
+ ctl_set_bit (0, 9);
-#ifdef BUFFER_STRESS_TEST
+#ifdef BUFFER_STRESS_TEST
- internal_print(
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "use %i bytes for buffering.\n",
- hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "use %i bytes for buffering.\n",
+ hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
for (i = 0; i < 500; i++) {
hwcb = (init_hwcb_t *) BUF_HWCB;
- internal_print(
- DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "This is stress test message #%i, free: %i bytes\n",
- i,
- MAX_HWCB_ROOM - (hwcb->length + sizeof(mto_t)));
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "This is stress test message #%i, free: %i bytes\n",
+ i,
+ MAX_HWCB_ROOM - (hwcb->length + sizeof (mto_t)));
}
-#endif
+#endif
return /*retval */ 0;
}
" temporary breakdown\n");
}
} else {
- spin_lock(&hwc_data.lock);
+ spin_lock (&hwc_data.lock);
- if (!hwc_data.current_servc) {
+ if (!hwc_data.current_servc) {
- unconditional_read_1();
+ unconditional_read_1 ();
- } else {
+ } else {
- switch (hwc_data.current_servc) {
+ switch (hwc_data.current_servc) {
- case HWC_CMDW_WRITEMASK :
+ case HWC_CMDW_WRITEMASK:
- write_event_mask_2();
+ write_event_mask_2 ();
break;
-
- case HWC_CMDW_WRITEDATA :
- write_event_data_2();
+ case HWC_CMDW_WRITEDATA:
+
+ write_event_data_2 ();
break;
- case HWC_CMDW_READDATA :
+ case HWC_CMDW_READDATA:
- unconditional_read_2();
+ unconditional_read_2 ();
break;
- }
+ }
- write_event_data_1();
- }
+ write_event_data_1 ();
+ }
if (hwc_data.calls != NULL)
if (hwc_data.calls->wake_up != NULL)
(hwc_data.calls->wake_up) ();
{
spin_lock (&hwc_data.lock);
- spin_unlock(&hwc_data.lock);
+ spin_unlock (&hwc_data.lock);
asm volatile ("STCTL 0,0,%0":"=m" (cr0));
cr0_save = cr0;
int retval = 0;
unsigned long flags;
unsigned int obuf;
-
- spin_lock_irqsave(&hwc_data.lock, flags);
-
+
+ spin_lock_irqsave (&hwc_data.lock, flags);
+
switch (cmd) {
- case TIOCHWCSHTAB :
- if (get_user(tmp.width_htab, (ioctl_htab_t *) arg))
+ case TIOCHWCSMEAS:
+ hwc_data.ioctls.measured_lines = 0;
+ hwc_data.ioctls.measured_chars = 0;
+ hwc_data.ioctls.measured_wcalls = 0;
+ break;
+
+ case TIOCHWCSHTAB:
+ if (get_user (tmp.width_htab, (ioctl_htab_t *) arg))
goto fault;
break;
-
- case TIOCHWCSECHO :
- if (get_user(tmp.echo, (ioctl_echo_t *) arg))
+
+ case TIOCHWCSECHO:
+ if (get_user (tmp.echo, (ioctl_echo_t *) arg))
goto fault;
break;
-
- case TIOCHWCSCOLS :
- if (get_user(tmp.columns, (ioctl_cols_t *) arg))
+
+ case TIOCHWCSCOLS:
+ if (get_user (tmp.columns, (ioctl_cols_t *) arg))
goto fault;
break;
-
- case TIOCHWCSCODE :
- if (get_user(tmp.code, (ioctl_code_t *) arg))
+
+ case TIOCHWCSCODE:
+ if (get_user (tmp.code, (ioctl_code_t *) arg))
goto fault;
break;
-
- case TIOCHWCSNL :
- if (get_user(tmp.final_nl, (ioctl_nl_t *) arg))
+
+ case TIOCHWCSNL:
+ if (get_user (tmp.final_nl, (ioctl_nl_t *) arg))
goto fault;
break;
- case TIOCHWCSOBUF :
- if (get_user(obuf, (unsigned int *) arg))
+ case TIOCHWCSOBUF:
+ if (get_user (obuf, (unsigned int *) arg))
goto fault;
if (obuf & 0xFFF)
tmp.max_hwcb = (((obuf | 0xFFF) + 1) >> 12);
tmp.max_hwcb = (obuf >> 12);
break;
- case TIOCHWCSCASE :
- if (get_user(tmp.tolower, (ioctl_case_t *) arg))
+ case TIOCHWCSCASE:
+ if (get_user (tmp.tolower, (ioctl_case_t *) arg))
goto fault;
break;
-
- case TIOCHWCSDELIM :
- if (get_user(tmp.delim, (ioctl_delim_t *) arg))
+
+ case TIOCHWCSDELIM:
+ if (get_user (tmp.delim, (ioctl_delim_t *) arg))
goto fault;
break;
- case TIOCHWCSINIT :
- retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1);
+ case TIOCHWCSINIT:
+ retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1);
break;
- case TIOCHWCGHTAB :
- if (put_user(tmp.width_htab, (ioctl_htab_t *) arg))
+ case TIOCHWCGMEASL:
+ if (put_user (tmp.measured_lines, (ioctl_meas_t *) arg))
goto fault;
break;
- case TIOCHWCGECHO :
- if (put_user(tmp.echo, (ioctl_echo_t *) arg))
+ case TIOCHWCGMEASC:
+ if (put_user (tmp.measured_chars, (ioctl_meas_t *) arg))
goto fault;
break;
- case TIOCHWCGCOLS :
- if (put_user(tmp.columns, (ioctl_cols_t *) arg))
+ case TIOCHWCGMEASS:
+ if (put_user (tmp.measured_wcalls, (ioctl_meas_t *) arg))
goto fault;
break;
- case TIOCHWCGCODE :
- if (put_user(tmp.code, (ioctl_code_t *) arg))
+ case TIOCHWCGHTAB:
+ if (put_user (tmp.width_htab, (ioctl_htab_t *) arg))
goto fault;
+ break;
+ case TIOCHWCGECHO:
+ if (put_user (tmp.echo, (ioctl_echo_t *) arg))
+ goto fault;
break;
- case TIOCHWCGNL :
- if (put_user(tmp.final_nl, (ioctl_nl_t *) arg))
+ case TIOCHWCGCOLS:
+ if (put_user (tmp.columns, (ioctl_cols_t *) arg))
goto fault;
break;
- case TIOCHWCGOBUF :
- if (put_user(tmp.max_hwcb, (ioctl_obuf_t *) arg))
+ case TIOCHWCGCODE:
+ if (put_user (tmp.code, (ioctl_code_t *) arg))
goto fault;
+
break;
- case TIOCHWCGKBUF :
- if (put_user(tmp.kmem_hwcb, (ioctl_obuf_t *) arg))
+ case TIOCHWCGNL:
+ if (put_user (tmp.final_nl, (ioctl_nl_t *) arg))
goto fault;
break;
- case TIOCHWCGCASE :
- if (put_user(tmp.tolower, (ioctl_case_t *) arg))
+ case TIOCHWCGOBUF:
+ if (put_user (tmp.max_hwcb, (ioctl_obuf_t *) arg))
goto fault;
break;
-
- case TIOCHWCGDELIM :
- if (put_user(tmp.delim, (ioctl_delim_t *) arg))
+
+ case TIOCHWCGKBUF:
+ if (put_user (tmp.kmem_hwcb, (ioctl_obuf_t *) arg))
goto fault;
break;
-#if 0
-
- case TIOCHWCGINIT :
- if (put_user(&hwc_data.init_ioctls, (hwc_ioctls_t *) arg))
+
+ case TIOCHWCGCASE:
+ if (put_user (tmp.tolower, (ioctl_case_t *) arg))
goto fault;
break;
- case TIOCHWCGCURR :
- if (put_user(&hwc_data.ioctls, (hwc_ioctls_t *) arg))
+ case TIOCHWCGDELIM:
+ if (put_user (tmp.delim, (ioctl_delim_t *) arg))
+ goto fault;
+ break;
+#if 0
+
+ case TIOCHWCGINIT:
+ if (put_user (&hwc_data.init_ioctls, (hwc_ioctls_t *) arg))
+ goto fault;
+ break;
+
+ case TIOCHWCGCURR:
+ if (put_user (&hwc_data.ioctls, (hwc_ioctls_t *) arg))
goto fault;
break;
#endif
-
- default :
+
+ default:
goto noioctlcmd;
}
- if (_IOC_DIR(cmd) == _IOC_WRITE)
- retval = set_hwc_ioctls(&tmp, 0);
+ if (_IOC_DIR (cmd) == _IOC_WRITE)
+ retval = set_hwc_ioctls (&tmp, 0);
goto out;
- fault:
- retval = -EFAULT;
- goto out;
- noioctlcmd:
- retval = -ENOIOCTLCMD;
- out:
- spin_unlock_irqrestore(&hwc_data.lock, flags);
- return retval;
+ fault:
+ retval = -EFAULT;
+ goto out;
+ noioctlcmd:
+ retval = -ENOIOCTLCMD;
+ out:
+ spin_unlock_irqrestore (&hwc_data.lock, flags);
+ return retval;
}
typedef unsigned short int ioctl_obuf_t;
typedef unsigned char ioctl_case_t;
typedef unsigned char ioctl_delim_t;
+typedef unsigned long ioctl_meas_t;
typedef struct {
ioctl_htab_t width_htab;
ioctl_code_t code;
ioctl_nl_t final_nl;
ioctl_obuf_t max_hwcb;
- ioctl_obuf_t kmem_hwcb;
+ ioctl_obuf_t kmem_hwcb;
ioctl_case_t tolower;
ioctl_delim_t delim;
+ ioctl_meas_t measured_lines;
+ ioctl_meas_t measured_chars;
+ ioctl_meas_t measured_wcalls;
} hwc_ioctls_t;
static hwc_ioctls_t _hwc_ioctls;
#define TIOCHWCSCASE _IOW(HWC_IOCTL_LETTER, 7, _hwc_ioctls.tolower)
+#define TIOCHWCSMEAS _IO(HWC_IOCTL_LETTER, 8)
+
#define TIOCHWCSDELIM _IOW(HWC_IOCTL_LETTER, 9, _hwc_ioctls.delim)
#define TIOCHWCGHTAB _IOR(HWC_IOCTL_LETTER, 10, _hwc_ioctls.width_htab)
#define TIOCHWCGCASE _IOR(HWC_IOCTL_LETTER, 17, _hwc_ioctls.tolower)
-#define TIOCHWCGDELIM _IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.delim)
+#define TIOCHWCGDELIM _IOR(HWC_IOCTL_LETTER, 18, _hwc_ioctls.delim)
+
+#define TIOCHWCGKBUF _IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.max_hwcb)
+
+#define TIOCHWCGCURR _IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls)
-#define TIOCHWCGKBUF _IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls.max_hwcb)
+#define TIOCHWCGMEASL _IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls.measured_lines)
-#define TIOCHWCGCURR _IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls)
+#define TIOCHWCGMEASC _IOR(HWC_IOCTL_LETTER, 22, _hwc_ioctls.measured_chars)
+
+#define TIOCHWCGMEASS _IOR(HWC_IOCTL_LETTER, 23, _hwc_ioctls.measured_wcalls)
#define CODE_ASCII 0x0
#define CODE_EBCDIC 0x1
#endif
-#endif
+#endif
static hwc_tty_data_struct hwc_tty_data =
{ /* NULL/0 */ };
static struct tty_driver hwc_tty_driver;
-static struct tty_struct * hwc_tty_table[1];
-static struct termios * hwc_tty_termios[1];
-static struct termios * hwc_tty_termios_locked[1];
+static struct tty_struct *hwc_tty_table[1];
+static struct termios *hwc_tty_termios[1];
+static struct termios *hwc_tty_termios_locked[1];
static int hwc_tty_refcount = 0;
-extern struct termios tty_std_termios;
+extern struct termios tty_std_termios;
void hwc_tty_wake_up (void);
void hwc_tty_input (unsigned char *, unsigned int);
static int
hwc_tty_open (struct tty_struct *tty,
- struct file *filp)
+ struct file *filp)
{
- if (MINOR(tty->device) - tty->driver.minor_start)
+ if (MINOR (tty->device) - tty->driver.minor_start)
return -ENODEV;
tty->driver_data = &hwc_tty_data;
static void
hwc_tty_close (struct tty_struct *tty,
- struct file *filp)
+ struct file *filp)
{
- if (MINOR(tty->device) != tty->driver.minor_start) {
- printk(KERN_WARNING HWC_TTY_PRINT_HEADER
+ if (MINOR (tty->device) != tty->driver.minor_start) {
+ printk (KERN_WARNING HWC_TTY_PRINT_HEADER
"do not close hwc tty because of wrong device number");
return;
}
{
int retval;
- retval = hwc_write_room(IN_BUFS_TOTAL);
+ retval = hwc_write_room (IN_BUFS_TOTAL);
return retval;
}
static int
hwc_tty_write (struct tty_struct *tty,
- int from_user,
- const unsigned char *buf,
- int count)
+ int from_user,
+ const unsigned char *buf,
+ int count)
{
int retval;
if (hwc_tty_data.buf_count > 0) {
- hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count);
+ hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
hwc_tty_data.buf_count = 0;
}
- retval = hwc_write(from_user, buf, count);
+ retval = hwc_write (from_user, buf, count);
return retval;
}
static void
hwc_tty_put_char (struct tty_struct *tty,
- unsigned char ch)
+ unsigned char ch)
{
unsigned long flags;
- spin_lock_irqsave(&hwc_tty_data.lock, flags);
+ spin_lock_irqsave (&hwc_tty_data.lock, flags);
if (hwc_tty_data.buf_count >= HWC_TTY_BUF_SIZE) {
- hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count);
+ hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
hwc_tty_data.buf_count = 0;
}
hwc_tty_data.buf[hwc_tty_data.buf_count] = ch;
hwc_tty_data.buf_count++;
- spin_unlock_irqrestore(&hwc_tty_data.lock, flags);
+ spin_unlock_irqrestore (&hwc_tty_data.lock, flags);
}
static void
{
unsigned long flags;
- spin_lock_irqsave(&hwc_tty_data.lock, flags);
- hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count);
+ spin_lock_irqsave (&hwc_tty_data.lock, flags);
+ hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count);
hwc_tty_data.buf_count = 0;
- spin_unlock_irqrestore(&hwc_tty_data.lock, flags);
+ spin_unlock_irqrestore (&hwc_tty_data.lock, flags);
}
static int
{
int retval;
- retval = hwc_chars_in_buffer(IN_BUFS_TOTAL);
+ retval = hwc_chars_in_buffer (IN_BUFS_TOTAL);
return retval;
}
static int
hwc_tty_ioctl (
- struct tty_struct *tty,
- struct file * file,
- unsigned int cmd,
- unsigned long arg)
+ struct tty_struct *tty,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
{
unsigned long count;
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
switch (cmd) {
case TIOCHWCTTYSINTRC:
(long) hwc_tty_data.ioctl.intr_char_size);
default:
- return hwc_ioctl(cmd, arg);
-}
+ return hwc_ioctl (cmd, arg);
+ }
}
void
hwc_tty_data.ioctl.intr_char_size) == 0) {
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = INTR_CHAR(tty);
+ *tty->flip.char_buf_ptr++ = INTR_CHAR (tty);
} else if (count == 2 && (
strncmp (buf, "^d", 2) == 0 ||
strncmp (buf, "\0252d", 2) == 0)) {
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = EOF_CHAR(tty);
+ *tty->flip.char_buf_ptr++ = EOF_CHAR (tty);
} else if (count == 2 && (
strncmp (buf, "^z", 2) == 0 ||
strncmp (buf, "\0252z", 2) == 0)) {
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = SUSP_CHAR(tty);
+ *tty->flip.char_buf_ptr++ = SUSP_CHAR (tty);
} else {
- memcpy(tty->flip.char_buf_ptr, buf, count);
+ memcpy (tty->flip.char_buf_ptr, buf, count);
if (count < 2 || (
strncmp (buf + count - 2, "^n", 2) ||
strncmp (buf + count - 2, "\0252n", 2))) {
count++;
} else
count -= 2;
- memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count);
+ memset (tty->flip.flag_buf_ptr, TTY_NORMAL, count);
tty->flip.char_buf_ptr += count;
tty->flip.flag_buf_ptr += count;
tty->flip.count += count;
}
- tty_flip_buffer_push(tty);
+ tty_flip_buffer_push (tty);
hwc_tty_wake_up ();
}
#endif
void
hwc_tty_init (void)
{
- memset (&hwc_tty_driver, 0, sizeof(struct tty_driver));
+ memset (&hwc_tty_driver, 0, sizeof (struct tty_driver));
memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct));
hwc_tty_driver.magic = TTY_DRIVER_MAGIC;
hwc_tty_driver.driver_name = "tty_hwc";
hwc_tty_driver.init_termios.c_lflag = ISIG | ECHO;
hwc_tty_driver.flags = TTY_DRIVER_REAL_RAW;
hwc_tty_driver.refcount = &hwc_tty_refcount;
-
+
hwc_tty_driver.table = hwc_tty_table;
hwc_tty_driver.termios = hwc_tty_termios;
hwc_tty_driver.termios_locked = hwc_tty_termios_locked;
hwc_tty_driver.chars_in_buffer = hwc_tty_chars_in_buffer;
hwc_tty_driver.flush_buffer = hwc_tty_flush_buffer;
hwc_tty_driver.ioctl = hwc_tty_ioctl;
-
+
hwc_tty_driver.throttle = NULL;
hwc_tty_driver.unthrottle = NULL;
hwc_tty_driver.send_xchar = NULL;
hwc_tty_driver.set_termios = NULL;
hwc_tty_driver.set_ldisc = NULL;
- hwc_tty_driver.stop = NULL;
- hwc_tty_driver.start = NULL;
+ hwc_tty_driver.stop = NULL;
+ hwc_tty_driver.start = NULL;
hwc_tty_driver.hangup = NULL;
hwc_tty_driver.break_ctl = NULL;
hwc_tty_driver.wait_until_sent = NULL;
hwc_tty_driver.read_proc = NULL;
hwc_tty_driver.write_proc = NULL;
- if (tty_register_driver(&hwc_tty_driver))
- panic("Couldn't register hwc_tty driver\n");
+ if (tty_register_driver (&hwc_tty_driver))
+ panic ("Couldn't register hwc_tty driver\n");
}
--- /dev/null
+/*
+ * File...........: linux/drivers/s390x/idals.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
+
+ * History of changes
+ * 07/24/00 new file
+ */
+
+#include <linux/malloc.h>
+#include <asm/irq.h>
+#include <asm/idals.h>
+#include <asm/spinlock.h>
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif
+#define PRINTK_HEADER "idals:"
+
+/* a name template for the cache-names */
+static char idal_name_template[] = "idalcache-\0\0\0\0"; /* fill name with zeroes! */
+/* the cache's names */
+static char idal_cache_name[IDAL_NUMBER_CACHES][sizeof(idal_name_template)+1];
+/* the caches itself*/
+static kmem_cache_t *idal_cache[IDAL_NUMBER_CACHES];
+
+void
+free_idal ( ccw1_t *cp )
+{
+ idaw_t *idal;
+ unsigned long upper2k,lower2k;
+ int nridaws,cacheind;
+ if ( cp -> flags & CCW_FLAG_IDA ) {
+ idal = cp -> cda;
+ lower2k = *idal & 0xfffffffffffff800;
+ upper2k = (*idal + cp -> count - 1) & 0xfffffffffffff800;
+ nridaws = ((upper2k - lower2k) >> 11) + 1;
+ for ( cacheind = 0; (1 << cacheind) < nridaws ; cacheind ++ );
+ kmem_cache_free ( idal_cache[cacheind], idal );
+ }
+}
+
+int
+idal_support_init ( void )
+{
+ int rc=0;
+ int cachind;
+
+ for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) {
+ int slabsize = 8 << cachind;
+ sprintf ( idal_cache_name[cachind],
+ "%s%d%c", idal_name_template, slabsize, 0);
+ idal_cache[cachind] = kmem_cache_create( idal_cache_name[cachind],
+ slabsize, 0,
+ SLAB_HWCACHE_ALIGN | SLAB_DMA,
+ NULL, NULL );
+ if ( ! idal_cache [cachind] ) {
+ printk (KERN_WARNING PRINTK_HEADER "Allocation of IDAL cache failed\n");
+ }
+ }
+
+ return rc;
+}
+
+void idal_support_cleanup ( void )
+{
+ int cachind;
+
+ /* Shrink the caches, if available */
+ for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) {
+ if ( idal_cache[cachind] ) {
+ if ( kmem_cache_shrink(idal_cache[cachind]) == 0 ) {
+ idal_cache[cachind] = NULL;
+ }
+ }
+ }
+
+}
ifeq ($(CONFIG_CTC),y)
O_OBJS += ctc.o
+else
+ ifeq ($(CONFIG_CTC),m)
+ M_OBJS += ctc.o
+ endif
endif
ifeq ($(CONFIG_IUCV),y)
/*
+ * $Id: ctc.c,v 1.25.2.5 2000/10/11 15:08:59 bird Exp $
+ *
* drivers/s390/net/ctc.c
* CTC / ESCON network driver
*
* Author(s): Dieter Wellerdiek (wel@de.ibm.com)
*
* 2.3 Updates Martin Schwidefsky (schwidefsky@de.ibm.com)
- * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *
+ * Modularization & Bugfixes by Fritz Elfert (fritz.elfert@millenux.de)
+ *
+ * Bugfixes by Jochen Röhrig (roehrig@de.ibm.com)
*
*
* Description of the Kernel Parameter
* order or doesn't want to have automatic channel selection on, you can do
* this with the "ctc= kernel keyword".
*
- * ctc=0,0xrrrr,0xwwww,ddddd
+ * ctc=0,0xrrrr,0xwwww,ddddd
*
* Where:
*
- * "rrrr" is the read channel address
- * "wwww" is the write channel address
- * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0
- * to escon7 for ESCON channels).
+ * "rrrr" is the read channel address
+ * "wwww" is the write channel address
+ * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0
+ * to escon7 for ESCON channels).
*
* To switch the automatic channel selection off use the ctc= keyword with
* parameter "noauto". This may be necessary if you 3271 devices or other devices
* which use the ctc device type and model, but operate with a different protocol.
*
- * ctc=noauto
+ * ctc=noauto
+ *
+ * $Log: ctc.c,v $
+ * Revision 1.25.2.5 2000/10/11 15:08:59 bird
+ * ctc_tx(): Quick fix of possible underflow when calculating free block space
+ *
+ * Revision 1.25.2.4 2000/09/25 16:40:56 bird
+ * Some more debug information
+ *
+ * Revision 1.25.2.3 2000/09/20 13:28:19 bird
+ * - ctc_open(): fixed bug
+ * - ctc_release(): added timer for terminating in case of halt_io()-hang
+ *
+ * Revision 1.25.2.2 2000/09/20 09:48:27 bird
+ * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in
+ * instead of direct waiting on a wait queue
+ * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check():
+ * print more debug information
+ *
+ * Revision 1.25.2.1 2000/09/19 09:09:56 bird
+ * Merged in changes from 1.25 to 1.26
+ *
+ * Revision 1.25 2000/09/08 09:22:11 bird
+ * Proper cleanup and bugfixes in ctc_probe()
+ *
+ * Revision 1.24 2000/08/30 15:14:38 bird
+ * Some bugfixes and simplifications in ctc_probe()
+ *
+ * Revision 1.23 2000/08/28 16:50:35 bird
+ * - Suppress warning if discarding initial handshake block
+ * - Removed strstr() (now exported in arch/s390/kernel/s390_ksyms.c)
+ *
+ * Revision 1.22 2000/08/28 11:33:21 felfert
+ * Remove some dead code in ctc_open().
+ *
+ * Revision 1.21 2000/08/28 09:31:06 bird
+ * init_module(): fixed pointer arithmetic (device name)
+ *
+ * Revision 1.20 2000/08/25 20:11:56 bird
+ * Didn´t build as non-module.
+ *
+ * Revision 1.19 2000/08/25 19:48:46 felfert
+ * Modularized version.
+ *
+ * Revision 1.18 2000/08/25 19:34:29 bird
+ * extract_channel_id():
+ * - check for valid channel id;
+ * return -EINVAL in case of violation
*
- * Change History
+ * ctc_setup():
+ * - check for valid channel id;
+ * return without doing anything in case of violation
+ *
+ * ctc_irq_bh():
+ * - check for valid block length and packet length;
+ * discard block in case of invalid values
+ * (solves infinite loop problem that occurs if (for some unknown reason)
+ * the packet length = 0)
+ *
+ * Revision 1.17 2000/08/25 09:22:51 bird
+ * ctc_buffer_alloc():
+ * fixed kmalloc()-bug (allocated buffer of wrong size)
+ *
+ * Revision 1.16 2000/08/24 17:46:19 bird
+ * ctc_write_retry():
+ * - removed (presumably useless) loop for cleaning up the proc_anchor list.
+ * - inserted warning if proc_anchor (unexpectedly) != NULL
+ *
+ * Revision 1.15 2000/08/24 15:25:04 bird
+ * ctc_read_retry():
+ * - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set
+ * - removed some useless debug-messages
+ * ctc_write_retry():
+ * - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set
+ *
+ * Revision 1.14 2000/08/24 09:34:47 felfert
+ * Fixed bug in ctc_release:
+ * - ctc_unprotect_busy_irqrestore was called with wrong parameter.
+ *
+ *
+ * Old Change History
* 0.50 Initial release shipped
* 0.51 Bug fixes
- * - CTC / ESCON network device can now handle up to 64 channels
- * - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON
- * - 3088-62 info message suppressed - OSA/D
- * - channel: def ffffffed ... error message suppressed
- * - CTC / ESCON device was not recoverable after a lost connection with
- * IFCONFIG dev DOWN and IFCONFIG dev UP
- * - Possibility to switch the automatic selection off
- * - Minor bug fixes
+ * - CTC / ESCON network device can now handle up to 64 channels
+ * - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON
+ * - 3088-62 info message suppressed - OSA/D
+ * - channel: def ffffffed ... error message suppressed
+ * - CTC / ESCON device was not recoverable after a lost connection with
+ * IFCONFIG dev DOWN and IFCONFIG dev UP
+ * - Possibility to switch the automatic selection off
+ * - Minor bug fixes
* 0.52 Bug fixes
- * - Subchannel check message enhanced
- * - Read / Write retry routine check for CTC_STOP added
+ * - Subchannel check message enhanced
+ * - Read / Write retry routine check for CTC_STOP added
* 0.53 Enhancement
- * - Connect time changed from 150 to 300 seconds
- * This gives more a better chance to connect during IPL
+ * - Connect time changed from 150 to 300 seconds
+ * This gives more a better chance to connect during IPL
* 0.54 Bug fixes
- * - Out of memory message enhanced
- * - Zero buffer problem in ctc_irq_hb solved
- * A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop,
- * which could end in a out of memory situation.
+ * - Out of memory message enhanced
+ * - Zero buffer problem in ctc_irq_hb solved
+ * A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop,
+ * which could end in a out of memory situation.
* 0.55 Bug fixes
- * - Connect problems with systems which IPL later
- * SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently
- * not available. When systemB comes up it is nearly inpossible to setup a
- * connection.
+ * - Connect problems with systems which IPL later
+ * SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently
+ * not available. When systemB comes up it is nearly inpossible to setup a
+ * connection.
+ *
+ * 0.56 Bug fixes
+ * - ctc_open(): In case of failure stop read/write-retry timers before
+ * freeing buffers (stops kernel panics due to NULL-pointer
+ * dereferences in ctc_read_retry())
+ * - Added some sanity checks concerning NULL-pointer dereferences
+ * - Added some comments
+ *
+ * 0.57 Bug fixes
+ * - CTC / ESCON network device can now handle up to 256 channels
+ * - ctc_read_retry(): added sanity check: if ctc->free_anchor == NULL
+ * print a warning and simply return
*/
+
#include <linux/version.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/if_arp.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
+#include <linux/ctype.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/irq.h>
+#ifdef MODULE
+MODULE_AUTHOR("(C) 2000 IBM Corp. by Dieter Wellerdiek (wel@de.ibm.com)");
+MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
+MODULE_PARM(setup,"s");
+MODULE_PARM_DESC(setup,
+"One or more definitions in the same format like the kernel parameter line for ctc.\n"
+"E.g.: \"ctc=0,0x700,0x701,ctc0 ctc=0,0x702,0x703,ctc1\".\n");
+
+char *setup = NULL;
+#endif
+
//#define DEBUG
/* Redefine message level, so that all messages occur on 3215 console in DEBUG mode */
-#ifdef DEBUG
- #undef KERN_INFO
- #undef KERN_WARNING
- #undef KERN_DEBUG
- #define KERN_INFO KERN_EMERG
- #define KERN_WARNING KERN_EMERG
- #define KERN_DEBUG KERN_EMERG
-#endif
-
-
-#define CCW_CMD_WRITE 0x01
-#define CCW_CMD_READ 0x02
-#define CCW_CMD_SET_EXTENDED 0xc3
-#define CCW_CMD_PREPARE 0xe3
-
-#define MAX_CHANNEL_DEVICES 64
-#define MAX_ADAPTERS 8
-#define CTC_DEFAULT_MTU_SIZE 1500
-#define READ 0
-#define WRITE 1
-#define CTC 0
-#define ESCON 1
-#define CHANNEL_MEDIA 2
-#define CTC_BLOCKS 8 /* 8 blocks * 2 times * 64k = 1M */
-
-#define TB_TX 0 /* sk buffer handling in process */
-#define TB_STOP 1 /* network device stop in process */
-#define TB_RETRY 2 /* retry in process */
-#define TB_NOBUFFER 3 /* no buffer on free queue */
+#ifdef DEBUG
+ #undef KERN_INFO
+ #undef KERN_WARNING
+ #undef KERN_DEBUG
+ #define KERN_INFO KERN_EMERG
+ #define KERN_WARNING KERN_EMERG
+ #define KERN_DEBUG KERN_EMERG
+#endif
+
+
+#define CCW_CMD_WRITE 0x01
+#define CCW_CMD_READ 0x02
+#define CCW_CMD_SET_EXTENDED 0xc3
+#define CCW_CMD_PREPARE 0xe3
+
+#define MAX_CHANNEL_DEVICES 256
+#define MAX_ADAPTERS 8
+#define CTC_DEFAULT_MTU_SIZE 1500
+#define READ 0
+#define WRITE 1
+#define CTC 0
+#define ESCON 1
+#define CHANNEL_MEDIA 2
+#define CTC_BLOCKS 8 /* 8 blocks * 2 times * 64k = 1M */
+
+#define TB_TX 0 /* sk buffer handling in process */
+#define TB_STOP 1 /* network device stop in process */
+#define TB_RETRY 2 /* retry in process */
+#define TB_NOBUFFER 3 /* no buffer on free queue */
/* state machine codes used in ctc_irq_handler */
-#define CTC_STOP 0
-#define CTC_START_HALT_IO 1
-#define CTC_START_SET_X_MODE 2
-#define CTC_START_SELECT 4
-#define CTC_START_READ_TEST 32
-#define CTC_START_READ 33
-#define CTC_START_WRITE_TEST 64
-#define CTC_START_WRITE 65
+#define CTC_STOP 0
+#define CTC_START_HALT_IO 1
+#define CTC_START_SET_X_MODE 2
+#define CTC_START_SELECT 4
+#define CTC_START_READ_TEST 32
+#define CTC_START_READ 33
+#define CTC_START_WRITE_TEST 64
+#define CTC_START_WRITE 65
typedef enum {
- channel_type_none, /* Device is not a channel */
- channel_type_undefined, /* Device is a channel but we don't know anything about it */
- channel_type_ctca, /* Device is a CTC/A and we can deal with it */
- channel_type_escon, /* Device is a ESCON channel and we can deal with it */
- channel_type_unsupported /* Device is a unsupported model */
+ channel_type_none, /* Device is not a channel */
+ channel_type_undefined, /* Device is a channel but we don't know anything about it */
+ channel_type_ctca, /* Device is a CTC/A and we can deal with it */
+ channel_type_escon, /* Device is a ESCON channel and we can deal with it */
+ channel_type_unsupported /* Device is a unsupported model */
} channel_type_t;
*
*/
-static int channel_tab_initialized = 0; /* channel[] structure initialized */
+static long channel_tab_initialized = 0; /* channel[] structure initialized */
struct devicelist {
- unsigned int devno;
- __u8 flag;
-#define CHANNEL_IN_USE 0x08 /* - Show that channel is in use */
+ unsigned int devno;
+ __u8 flag;
+#define CHANNEL_IN_USE 0x08 /* - Show that channel is in use */
};
static struct {
- struct devicelist list[MAX_CHANNEL_DEVICES];
- int count;
- int left;
+ struct devicelist list[MAX_CHANNEL_DEVICES];
+ int count;
+ int left;
} channel[CHANNEL_MEDIA];
static int ctc_no_auto = 0;
+#if LINUX_VERSION_CODE>=0x020300
+typedef struct net_device net_device;
+#else
+typedef struct device net_device;
+typedef struct wait_queue* wait_queue_head_t;
+#define init_waitqueue_head(nothing)
+#endif
+
struct adapterlist{
- unsigned int devno[2];
- __u16 protocol;
+ unsigned int devno[2];
+ __u16 protocol;
+ net_device *netdev;
};
-static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */
+static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */
/*
*/
struct buffer {
- struct buffer *next;
- int packets;
- struct block *block;
+ struct buffer *next;
+ int packets;
+ struct block *block;
};
-#if LINUX_VERSION_CODE>=0x020300
-typedef struct net_device net_device;
-#else
-typedef struct device net_device;
-typedef struct wait_queue* wait_queue_head_t;
-#define DECLARE_WAITQUEUE(waitqname,waitqtask) struct wait_queue waitqname = {waitqtask, NULL }
-#define init_waitqueue_head(nothing)
-#endif
-
-
struct channel {
- unsigned int devno;
- int irq;
- unsigned long IO_active;
- ccw1_t ccw[3];
- __u32 state;
- int buffer_count;
- struct buffer *free_anchor;
- struct buffer *proc_anchor;
- devstat_t *devstat;
- net_device *dev; /* backward pointer to the network device */
+ unsigned int devno;
+ int irq;
+ unsigned long IO_active;
+ ccw1_t ccw[3];
+ __u32 state;
+ int buffer_count;
+ struct buffer *free_anchor;
+ struct buffer *proc_anchor;
+ devstat_t *devstat;
+ net_device *dev; /* backward pointer to the network device */
wait_queue_head_t wait;
- struct tq_struct tq;
- struct timer_list timer;
- unsigned long flag_a; /* atomic flags */
-#define CTC_BH_ACTIVE 0
- __u8 last_dstat;
- __u8 flag;
-#define CTC_WRITE 0x01 /* - Set if this is a write channel */
-#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */
+ struct tq_struct tq;
+ int initial_block_received; /* only used for read channel */
+ struct timer_list timer;
+ unsigned long flag_a; /* atomic flags */
+#define CTC_BH_ACTIVE 0
+ __u8 last_dstat;
+ __u8 flag;
+#define CTC_WRITE 0x01 /* - Set if this is a write channel */
+#define CTC_WAKEUP 0x02 /* - Set if this channel should wake up from waiting for an event */
+#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */
};
-struct ctc_priv {
- struct net_device_stats stats;
+struct ctc_priv {
+ struct net_device_stats stats;
#if LINUX_VERSION_CODE>=0x02032D
- int tbusy;
+ unsigned long tbusy;
#endif
- struct channel channel[2];
- __u16 protocol;
+ struct channel channel[2];
+ __u16 protocol;
};
/*
#define PACKET_HEADER_LENGTH 6
struct packet {
- __u16 length;
- __u16 type;
- __u16 unused;
- __u8 data;
+ __u16 length;
+ __u16 type;
+ __u16 unused;
+ __u8 data;
};
#define BLOCK_HEADER_LENGTH 2
struct block {
- __u16 length;
- struct packet data;
+ __u16 length;
+ struct packet data;
};
#if LINUX_VERSION_CODE>=0x02032D
static __inline__ void ctc_setbit_busy(int nr,net_device *dev)
{
set_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy));
- netif_stop_queue(dev);
+ netif_stop_queue(dev);
}
static __inline__ void ctc_clearbit_busy(int nr,net_device *dev)
static __inline__ void ctc_setbit_busy(int nr,net_device *dev)
{
- set_bit(nr,(void *)&dev->tbusy);
+ set_bit(nr,&dev->tbusy);
}
static __inline__ void ctc_clearbit_busy(int nr,net_device *dev)
{
- clear_bit(nr,(void *)&dev->tbusy);
+ clear_bit(nr,&dev->tbusy);
}
static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev)
{
- return(test_and_set_bit(nr,(void *)&dev->tbusy));
+ return(test_and_set_bit(nr,&dev->tbusy));
}
#endif
/* Interrupt handler */
static void ctc_irq_handler(int irq, void *initparm, struct pt_regs *regs);
-static void ctc_irq_bh(struct channel *ctc);
-static void ctc_read_retry (struct channel *ctc);
-static void ctc_write_retry (struct channel *ctc);
+static void ctc_irq_bh(void *data);
+static void ctc_read_retry (unsigned long data);
+static void ctc_write_retry (unsigned long data);
/* Functions for the DEV methods */
static int ctc_open(net_device *dev);
-static void ctc_timer (struct channel *ctc);
+static void ctc_timer (unsigned long data);
static int ctc_release(net_device *dev);
static int ctc_tx(struct sk_buff *skb, net_device *dev);
static int ctc_change_mtu(net_device *dev, int new_mtu);
static void channel_sort(struct devicelist list[], int n);
+/*
+ * misc.
+ */
+static void print_banner(void) {
+ static int printed = 0;
+ char vbuf[] = "$Revision: 1.25.2.5 $";
+ char *version = vbuf;
+
+ if (printed)
+ return;
+ if ((version = strchr(version, ':'))) {
+ char *p = strchr(version + 1, '$');
+ if (p)
+ *p = '\0';
+ } else
+ version = " ??? ";
+ printk(KERN_INFO "CTC driver Version%s initialized\n", version);
+ printed = 1;
+}
+
/*
* initialize the channel[].list
*/
static void channel_init(void)
{
- int m;
+ int m;
#ifdef DEBUG
- int c;
+ int c;
#endif
- if (!test_and_set_bit(0, (void *)& channel_tab_initialized)){
- channel_scan();
- for (m = 0; m < CHANNEL_MEDIA; m++) {
- channel_sort (channel[m].list, MAX_CHANNEL_DEVICES);
- channel[m].left = channel[m].count;
- }
- if (channel[CTC].count == 0 && channel[ESCON].count == 0)
- printk(KERN_INFO "channel: no Channel devices recognized\n");
- else
- printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n",
- channel[CTC].count, channel[ESCON].count);
+ if (!test_and_set_bit(0, &channel_tab_initialized)){
+ channel_scan();
+ for (m = 0; m < CHANNEL_MEDIA; m++) {
+ channel_sort (channel[m].list, MAX_CHANNEL_DEVICES);
+ channel[m].left = channel[m].count;
+ }
+ if (channel[CTC].count == 0 && channel[ESCON].count == 0)
+ printk(KERN_INFO "channel: no Channel devices recognized\n");
+ else
+ printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n",
+ channel[CTC].count, channel[ESCON].count);
#ifdef DEBUG
- for (m = 0; m < CHANNEL_MEDIA; m++) {
- for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
- printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n",
- m, c, channel[m].list[c].devno);
- }
- }
+ for (m = 0; m < CHANNEL_MEDIA; m++) {
+ for (c = 0; c < channel[m].count; c++){
+ printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n",
+ m, c, channel[m].list[c].devno);
+ }
+ }
#endif
- }
+ }
}
*/
static void channel_scan(void)
{
- int m;
- int c;
- int irq;
- dev_info_t temp;
-
- for (m = 0; m < CHANNEL_MEDIA; m++) {
- for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
- channel[m].list[c].devno = -ENODEV;
- }
- }
-
- for (irq = 0; irq < NR_IRQS; irq++) {
- /* CTC/A */
- if (channel[CTC].count < MAX_CHANNEL_DEVICES ) {
- if (get_dev_info(irq, &temp) == 0 &&
- channel_check_for_type(&temp.sid_data) == channel_type_ctca) {
- channel[CTC].list[channel[CTC].count].devno = temp.devno;
- channel[CTC].count++;
- }
- }
-
- /* ESCON */
- if (channel[ESCON].count < MAX_CHANNEL_DEVICES ) {
- if (get_dev_info(irq, &temp) == 0 &&
- channel_check_for_type(&temp.sid_data) == channel_type_escon) {
- channel[ESCON].list[channel[ESCON].count].devno = temp.devno;
- channel[ESCON].count++;
-
- }
- }
- }
-}
+ int m;
+ int c;
+ int irq;
+ dev_info_t temp;
+
+ for (m = 0; m < CHANNEL_MEDIA; m++) {
+ for (c = 0; c < MAX_CHANNEL_DEVICES; c++){
+ channel[m].list[c].devno = -ENODEV;
+ }
+ }
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ if (get_dev_info_by_irq(irq, &temp) == 0) {
+ if ((temp.status == DEVSTAT_NOT_OPER) ||
+ (temp.status == DEVSTAT_DEVICE_OWNED))
+ continue;
+ /* CTC/A */
+ if ((channel[CTC].count < MAX_CHANNEL_DEVICES ) &&
+ (channel_check_for_type(&temp.sid_data) == channel_type_ctca)) {
+ channel[CTC].list[channel[CTC].count].devno = temp.devno;
+ channel[CTC].count++;
+ }
+ /* ESCON */
+ if ((channel[ESCON].count < MAX_CHANNEL_DEVICES ) &&
+ (channel_check_for_type(&temp.sid_data) == channel_type_escon)) {
+ channel[ESCON].list[channel[ESCON].count].devno = temp.devno;
+ channel[ESCON].count++;
+ }
+ }
+ }
+}
/*
*/
static int channel_free(int media, int devno)
{
- int i;
-
- for (i = 0; i < channel[media].count; i++) {
- if ((devno == channel[media].list[i].devno) &&
- ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) {
- channel[media].list[i].flag &= ~CHANNEL_IN_USE;
- return 0;
- }
- }
- printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
- return -ENODEV;
+ int i;
+
+ for (i = 0; i < channel[media].count; i++) {
+ if ((devno == channel[media].list[i].devno) &&
+ ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) {
+ channel[media].list[i].flag &= ~CHANNEL_IN_USE;
+ return 0;
+ }
+ }
+ printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
+ return -ENODEV;
}
*/
static int channel_get(int media, int devno)
{
- int i;
-
- for (i = 0; i < channel[media].count; i++) {
- if ((devno == channel[media].list[i].devno) &&
- ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) {
- channel[media].list[i].flag |= CHANNEL_IN_USE;
- return channel[media].list[i].devno;
- }
- }
- printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
- return -ENODEV;
+ int i;
+
+ for (i = 0; i < channel[media].count; i++) {
+ if ((devno == channel[media].list[i].devno) &&
+ ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) {
+ channel[media].list[i].flag |= CHANNEL_IN_USE;
+ return channel[media].list[i].devno;
+ }
+ }
+ printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno);
+ return -ENODEV;
}
*/
static int channel_get_next(int media)
{
- int i;
+ int i;
- for (i = 0; i < channel[media].count; i++) {
- if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) {
+ for (i = 0; i < channel[media].count; i++) {
+ if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) {
#ifdef DEBUG
- printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno);
+ printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno);
#endif
- channel[media].list[i].flag |= CHANNEL_IN_USE;
- return channel[media].list[i].devno;
- }
- }
- return -ENODEV;
+ channel[media].list[i].flag |= CHANNEL_IN_USE;
+ return channel[media].list[i].devno;
+ }
+ }
+ return -ENODEV;
}
*/
static int channel_left(int media)
{
- return channel[media].left;
+ return channel[media].left;
}
*/
static channel_type_t channel_check_for_type (senseid_t *id)
{
- channel_type_t type;
+ channel_type_t type;
- switch (id->cu_type) {
- case 0x3088:
+ switch (id->cu_type) {
+ case 0x3088:
- switch (id->cu_model) {
- case 0x08:
- type = channel_type_ctca; /* 3088-08 ==> CTCA */
- break;
+ switch (id->cu_model) {
+ case 0x08:
+ type = channel_type_ctca; /* 3088-08 ==> CTCA */
+ break;
- case 0x1F:
- type = channel_type_escon; /* 3088-1F ==> ESCON channel */
- break;
+ case 0x1F:
+ type = channel_type_escon; /* 3088-1F ==> ESCON channel */
+ break;
- case 0x01: /* 3088-01 ==> P390 OSA emulation */
- case 0x60: /* 3088-60 ==> OSA/2 adapter */
- case 0x61: /* 3088-61 ==> CISCO 7206 CLAW protocol ESCON connected */
- case 0x62: /* 3088-62 ==> OSA/D device */
- type = channel_type_unsupported;
- break;
-
- default:
- type = channel_type_undefined;
- printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model);
- }
- break;
-
- default:
- type = channel_type_none;
-
- }
- return type;
+ case 0x01: /* 3088-01 ==> P390 OSA emulation */
+ case 0x60: /* 3088-60 ==> OSA/2 adapter */
+ case 0x61: /* 3088-61 ==> CISCO 7206 CLAW protocol ESCON connected */
+ case 0x62: /* 3088-62 ==> OSA/D device */
+ type = channel_type_unsupported;
+ break;
+
+ default:
+ type = channel_type_undefined;
+ printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model);
+ }
+ break;
+
+ default:
+ type = channel_type_none;
+
+ }
+ return type;
}
*/
static void channel_sort(struct devicelist list[], int n)
{
- int i;
- int sorted = 0;
- struct devicelist tmp;
-
- while (!sorted) {
- sorted = 1;
-
- for (i = 0; i < n-1; i++) {
- if (list[i].devno > list[i+1].devno) {
- tmp = list[i];
- list[i] = list[i+1];
- list[i+1] = tmp;
- sorted = 0;
- }
- }
- }
+ int i;
+ int sorted = 0;
+ struct devicelist tmp;
+
+ while (!sorted) {
+ sorted = 1;
+
+ for (i = 0; i < n-1; i++) {
+ if (list[i].devno > list[i+1].devno) {
+ tmp = list[i];
+ list[i] = list[i+1];
+ list[i+1] = tmp;
+ sorted = 0;
+ }
+ }
+ }
}
static int inline extract_channel_id(char *name)
{
- if (name[0] == 'c')
- return (name[3]-'0');
- else
- return (name[5]-'0');
+ int rv = -1;
+
+ if (name[0] == 'c')
+ rv = name[3]-'0';
+ else
+ rv = name[5]-'0';
+
+ if ((rv < 0) || (rv >= MAX_ADAPTERS))
+ rv= -EINVAL;
+
+ return rv;
}
static int inline extract_channel_media(char *name)
{
- if (name[0] == 'c')
- return CTC;
- else
- return ESCON;
+ if (name[0] == 'c')
+ return CTC;
+ else
+ return ESCON;
}
static void ctc_tab_init(void)
-{
- int m;
- int i;
- static int t;
-
- if (t == 0){
- for (m = 0; m < CHANNEL_MEDIA; m++) {
- for (i = 0; i < MAX_ADAPTERS; i++) {
- ctc_adapter[m][i].devno[WRITE] = -ENODEV;
- ctc_adapter[m][i].devno[READ] = -ENODEV;
- }
- }
- t = 1;
- }
+{
+ int m;
+ int i;
+ static int t;
+
+ if (t == 0){
+ for (m = 0; m < CHANNEL_MEDIA; m++) {
+ for (i = 0; i < MAX_ADAPTERS; i++) {
+ ctc_adapter[m][i].devno[WRITE] = -ENODEV;
+ ctc_adapter[m][i].devno[READ] = -ENODEV;
+ ctc_adapter[m][i].netdev = NULL;
+ }
+ }
+ t = 1;
+ }
}
static int ctc_buffer_alloc(struct channel *ctc) {
-
- struct buffer *p;
- struct buffer *q;
-
- p = kmalloc(sizeof(p), GFP_KERNEL);
- if (p == NULL)
- return -ENOMEM;
- else {
- p->next = NULL;
- p->packets = 0;
- p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
- if (p->block == NULL) {
- kfree(p);
- return -ENOMEM;
- }
- p->block->length = 0;
- }
+
+ struct buffer *p;
+ struct buffer *q;
+
+ p = kmalloc(sizeof(struct buffer), GFP_KERNEL);
+ if (p == NULL)
+ return -ENOMEM;
+ else {
+ p->next = NULL;
+ p->packets = 0;
+ p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
+ if (p->block == NULL) {
+ kfree(p);
+ return -ENOMEM;
+ }
+ p->block->length = 0;
+ }
- if (ctc->free_anchor == NULL)
- ctc->free_anchor = p;
- else {
- q = ctc->free_anchor;
- while (q->next != NULL)
- q = q->next;
- q->next = p;
- }
- ctc->buffer_count++;
+ if (ctc->free_anchor == NULL)
+ ctc->free_anchor = p;
+ else {
+ q = ctc->free_anchor;
+ while (q->next != NULL)
+ q = q->next;
+ q->next = p;
+ }
+ ctc->buffer_count++;
return 0;
}
static int ctc_buffer_free(struct channel *ctc) {
-
- struct buffer *p;
-
-
- if (ctc->free_anchor == NULL)
- return -ENOMEM;
-
- p = ctc->free_anchor;
- ctc->free_anchor = p->next;
- free_pages((__u32)p->block, 4);
- kfree(p);
-
- return 0;
+
+ struct buffer *p;
+
+
+ if (ctc->free_anchor == NULL)
+ return -ENOMEM;
+
+ p = ctc->free_anchor;
+ ctc->free_anchor = p->next;
+ free_pages((unsigned long)p->block, 4);
+ kfree(p);
+
+ return 0;
}
-static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to) {
-
- struct buffer *p = NULL;
- struct buffer *q = NULL;
+static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to, net_device *dev) {
+
+ struct buffer *p = NULL;
+ struct buffer *q = NULL;
- if (*from == NULL)
- return -ENOMEM;
-
- p = *from;
- *from = p->next;
- p->next = NULL;
-
- if (*to == NULL)
- *to = p;
- else {
- q = *to;
- while (q->next != NULL)
- q = q->next;
- q->next = p;
-
- }
- return 0;
+ if (*from == NULL)
+ {
+ printk(KERN_DEBUG
+ "%s: %s(): Trying to swap buffer from empty list - doing nothing\n", dev ? dev->name : "<unknown ctc dev>", __FUNCTION__);
+
+ return -ENOMEM;
+ }
+
+ p = *from;
+ *from = p->next;
+ p->next = NULL;
+
+ if (*to == NULL)
+ *to = p;
+ else {
+ q = *to;
+ while (q->next != NULL)
+ q = q->next;
+ q->next = p;
+
+ }
+ return 0;
}
-
+#ifdef MODULE
+ static void ctc_setup(char *dev_name,int *ints)
+# define ctc_setup_return return
+#else
+# if LINUX_VERSION_CODE>=0x020300
+ static int __init ctc_setup(char *dev_name)
+# define ctc_setup_return return(1)
+# else
+ __initfunc(void ctc_setup(char *dev_name,int *ints))
+# define ctc_setup_return return
+# endif
+#endif
/*
* ctc_setup function
* this function is called for each ctc= keyword passed into the kernel
*
* valid parameter are: ctc=n,0xnnnn,0xnnnn,ctcx
- * where n is the channel protocol always 0
- * 0xnnnn is the cu number read
- * 0xnnnn is the cu number write
- * ctcx can be ctc0 to ctc7 or escon0 to escon7
+ * where n is the channel protocol always 0
+ * 0xnnnn is the cu number read
+ * 0xnnnn is the cu number write
+ * ctcx can be ctc0 to ctc7 or escon0 to escon7
*/
-#if LINUX_VERSION_CODE>=0x020300
-static int __init ctc_setup(char *dev_name)
-#else
-__initfunc(void ctc_setup(char *dev_name,int *ints))
-#endif
+
{
- struct adapterlist tmp;
+ struct adapterlist tmp;
+ int id;
#if LINUX_VERSION_CODE>=0x020300
#define CTC_MAX_PARMS 4
- int ints[CTC_MAX_PARMS+1];
- get_options(dev_name,CTC_MAX_PARMS,ints);
- #define ctc_setup_return return(1)
-#else
- #define ctc_setup_return return
+ int ints[CTC_MAX_PARMS+1];
+ dev_name = get_options(dev_name, CTC_MAX_PARMS, ints);
#endif
- ctc_tab_init();
-
- ctc_no_auto = 1;
-
- if (!strcmp(dev_name,"noauto")) {
- printk(KERN_INFO "ctc: automatic channel selection deactivated\n");
- ctc_setup_return;
- }
-
- tmp.devno[WRITE] = -ENODEV;
- tmp.devno[READ] = -ENODEV;
-
- switch (ints[0]) {
-
- case 3: /* write channel passed */
- tmp.devno[WRITE] = ints[3];
-
- case 2: /* read channel passed */
- tmp.devno[READ] = ints[2];
- if (tmp.devno[WRITE] == -ENODEV)
- tmp.devno[WRITE] = tmp.devno[READ] + 1;
-
- case 1: /* protocol type passed */
- tmp.protocol = ints[1];
- if (tmp.protocol == 0) {
- break;
- } else {
- printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name);
- ctc_setup_return;
- }
- break;
-
- default:
- printk(KERN_WARNING "ctc: wrong number of parameter passed\n");
- ctc_setup_return;
- }
- ctc_adapter[extract_channel_media(dev_name)][extract_channel_id(dev_name)] = tmp;
+ ctc_tab_init();
+
+ ctc_no_auto = 1;
+
+ if (!dev_name) { /* happens if device name is not specified in
+ parameter line (cf. init/main.c:get_options() */
+ printk(KERN_WARNING
+ "ctc: %s(): Device name not specified\n",
+ __FUNCTION__);
+ ctc_setup_return;
+ }
+
+ if (!strcmp(dev_name,"noauto")) {
+ printk(KERN_INFO "ctc: automatic channel selection deactivated\n");
+ ctc_setup_return;
+ }
+
+ if ((id = extract_channel_id(dev_name)) == -EINVAL)
+ {
+ printk(KERN_WARNING
+ "ctc: %s(): Invalid device name specified: %s\n",
+ __FUNCTION__, dev_name);
+ ctc_setup_return;
+ }
+
+ tmp.devno[WRITE] = -ENODEV;
+ tmp.devno[READ] = -ENODEV;
+
+ switch (ints[0]) {
+
+ case 3: /* write channel passed */
+ tmp.devno[WRITE] = ints[3];
+
+ case 2: /* read channel passed */
+ tmp.devno[READ] = ints[2];
+ if (tmp.devno[WRITE] == -ENODEV)
+ tmp.devno[WRITE] = tmp.devno[READ] + 1;
+
+ case 1: /* protocol type passed */
+ tmp.protocol = ints[1];
+ if (tmp.protocol == 0) {
+ break;
+ } else {
+ printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name);
+ ctc_setup_return;
+ }
+ break;
+
+ default:
+ printk(KERN_WARNING "ctc: wrong number of parameter passed\n");
+ ctc_setup_return;
+ }
+ ctc_adapter[extract_channel_media(dev_name)][id] = tmp;
#ifdef DEBUG
- printk(DEBUG "%s: protocol=%x read=%04x write=%04x\n",
- dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]);
-#endif
- ctc_setup_return;
-
+ printk(KERN_DEBUG "%s: protocol=%x read=%04x write=%04x\n",
+ dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]);
+#endif
+ ctc_setup_return;
+
}
#if LINUX_VERSION_CODE>=0x020300
__setup("ctc=", ctc_setup);
/*
* ctc_probe
- * this function is called for each channel network device,
- * which is defined in the /init/main.c
+ * this function is called for each channel network device,
+ * which is defined in the /init/main.c
*/
int ctc_probe(net_device *dev)
-{
- int rc;
- int c;
- int i;
- int m;
-
- struct ctc_priv *privptr;
-
- /* Only the first time the ctc_probe gets control */
- if (channel_tab_initialized == 0) {
- channel_init();
-
-
- }
-
- ctc_tab_init();
-
- m = extract_channel_media(dev->name);
- i = extract_channel_id(dev->name);
-
- if (channel_left(m) <=1)
- return -ENODEV;
-
- if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV))
- return -ENODEV;
-
- dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
- memset(dev->priv, 0, sizeof(struct ctc_priv));
- privptr = (struct ctc_priv *) (dev->priv);
-
-
- for (c = 0; c < 2; c++) {
-
- privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL);
- if (privptr->channel[c].devstat == NULL){
- if (i == WRITE)
- kfree(privptr->channel[READ].devstat);
- return -ENOMEM;
- }
- memset(privptr->channel[c].devstat, 0, sizeof(devstat_t));
-
- if (ctc_no_auto == 0)
- ctc_adapter[m][i].devno[c] = channel_get_next(m);
- else
- ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]);
-
- if ( ctc_adapter[m][i].devno[c] != -ENODEV){
- rc = request_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]),
- (void *)ctc_irq_handler, SA_INTERRUPT, dev->name,
- privptr->channel[c].devstat);
- if (rc) {
- printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc);
- return -EBUSY;
- }
- } else {
- if (i == WRITE) {
- free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), privptr->channel[i].devstat);
- channel_free(m, ctc_adapter[m][i].devno[READ]);
- kfree(privptr->channel[READ].devstat);
- }
- kfree(privptr->channel[i].devstat);
- return -ENODEV;
- }
- }
-
- privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ];
- privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]);
- privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE];
- privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]);
- privptr->protocol = ctc_adapter[m][i].protocol;
- channel[m].left = channel[m].left - 2;
-
- printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n",
- dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq,
- privptr->channel[WRITE].devno, privptr->channel[WRITE].irq);
-
- dev->mtu = CTC_DEFAULT_MTU_SIZE;
- dev->hard_start_xmit = ctc_tx;
- dev->open = ctc_open;
- dev->stop = ctc_release;
- dev->get_stats = ctc_stats;
- dev->change_mtu = ctc_change_mtu;
- dev->hard_header_len = 0;
- dev->addr_len = 0;
- dev->type = ARPHRD_SLIP;
- dev->tx_queue_len = 100;
- dev_init_buffers(dev);
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-
- return 0;
+{
+ int rc;
+ int c;
+ int i;
+ int m;
+ struct ctc_priv *privptr;
+
+ /* Only the first time the ctc_probe gets control */
+ if (channel_tab_initialized == 0) {
+ channel_init();
+ }
+
+ ctc_tab_init();
+
+ m = extract_channel_media(dev->name);
+ i = extract_channel_id(dev->name);
+
+ if (channel_left(m) <= 1)
+ return -ENODEV;
+
+ if (i < 0 || i >= MAX_ADAPTERS)
+ return -ENODEV;
+
+ if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV))
+ return -ENODEV;
+
+ dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL|GFP_DMA);
+ if (dev->priv == NULL)
+ return -ENOMEM;
+ memset(dev->priv, 0, sizeof(struct ctc_priv));
+ privptr = (struct ctc_priv *) (dev->priv);
+
+
+ for (c = 0; c < 2; c++) {
+ devstat_t *devstat;
+ unsigned int devno;
+
+ privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL);
+ devstat = privptr->channel[c].devstat;
+ if (devstat == NULL) {
+ if (c == 1) {
+ free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat);
+ channel_free(m, ctc_adapter[m][i].devno[0]);
+ kfree(privptr->channel[0].devstat);
+ }
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return -ENOMEM;
+ }
+
+ memset(devstat, 0, sizeof(devstat_t));
+
+ if (ctc_no_auto == 0) {
+ ctc_adapter[m][i].devno[c] = channel_get_next(m);
+ devno = ctc_adapter[m][i].devno[c];
+ }
+ else {
+ ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]);
+ devno = ctc_adapter[m][i].devno[c];
+ }
+
+
+ if (devno != -ENODEV) {
+ rc = request_irq(get_irq_by_devno(devno),
+ ctc_irq_handler, SA_INTERRUPT, dev->name,
+ devstat);
+ if (rc) {
+ printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc);
+ if (c == 1) {
+ free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]),
+ privptr->channel[0].devstat);
+ channel_free(m, ctc_adapter[m][i].devno[0]);
+ kfree(privptr->channel[0].devstat);
+ }
+ channel_free(m, devno);
+ kfree(devstat);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return -EBUSY;
+ }
+ } else {
+ if (c == 1) {
+ free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat);
+ channel_free(m, ctc_adapter[m][i].devno[0]);
+ kfree(privptr->channel[0].devstat);
+ }
+ kfree(devstat);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ return -ENODEV;
+ }
+ }
+
+ privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ];
+ privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]);
+ privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE];
+ privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]);
+ privptr->channel[READ].dev = privptr->channel[WRITE].dev = dev;
+ privptr->protocol = ctc_adapter[m][i].protocol;
+ channel[m].left = channel[m].left - 2;
+
+ print_banner();
+ printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n",
+ dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq,
+ privptr->channel[WRITE].devno, privptr->channel[WRITE].irq);
+
+ dev->mtu = CTC_DEFAULT_MTU_SIZE;
+ dev->hard_start_xmit = ctc_tx;
+ dev->open = ctc_open;
+ dev->stop = ctc_release;
+ dev->get_stats = ctc_stats;
+ dev->change_mtu = ctc_change_mtu;
+ dev->hard_header_len = 6;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_SLIP;
+ dev->tx_queue_len = 100;
+ dev_init_buffers(dev);
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ ctc_adapter[m][i].netdev = dev;
+
+ return 0;
}
*
*/
-static void inline ccw_check_return_code (net_device *dev, int return_code)
+static void inline ccw_check_return_code (net_device *dev, int return_code, char *caller)
{
- if (return_code != 0) {
- switch (return_code) {
- case -EBUSY:
- printk(KERN_INFO "%s: Busy !\n", dev->name);
- break;
- case -ENODEV:
- printk(KERN_EMERG "%s: Invalid device called for IO\n", dev->name);
- break;
- case -EIO:
- printk(KERN_EMERG "%s: Status pending... \n", dev->name);
- break;
- default:
- printk(KERN_EMERG "%s: Unknown error in Do_IO %04x\n",
- dev->name, return_code);
- }
- }
+ if (return_code != 0) {
+ switch (return_code) {
+ case -EBUSY:
+ printk(KERN_INFO "%s: %s: Busy !\n", dev->name, caller);
+ break;
+ case -ENODEV:
+ printk(KERN_EMERG "%s: %s: Invalid device called for IO\n", dev->name, caller);
+ break;
+ case -EIO:
+ printk(KERN_EMERG "%s: %s: Status pending... \n", dev->name, caller);
+ break;
+ default:
+ printk(KERN_EMERG "%s: %s: Unknown error in Do_IO %04x\n",
+ dev->name, caller, return_code);
+ }
+ }
}
-static void inline ccw_check_unit_check (net_device *dev, char sense)
+static void inline ccw_check_unit_check (net_device *dev, char sense, char *caller)
{
#ifdef DEBUG
- printk(KERN_INFO "%s: Unit Check with sense code: %02x\n",
- dev->name, sense);
+ printk(KERN_INFO "%s: %s: Unit Check with sense code: %02x\n",
+ dev->name, caller, sense);
#endif
- if (sense & 0x40) {
+ if (sense & 0x40) {
#ifdef DEBUG
- if (sense & 0x01)
- printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name);
- else
- printk(KERN_DEBUG "%s: System reset occured (remote side)\n", dev->name);
+ if (sense & 0x01)
+ printk(KERN_DEBUG "%s: %s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name, caller);
+ else
+ printk(KERN_DEBUG "%s: %s: System reset occured (remote side)\n", dev->name, caller);
#endif
- } else if (sense & 0x20) {
- if (sense & 0x04)
- printk(KERN_WARNING "%s: Data-streaming timeout)\n", dev->name);
- else
- printk(KERN_WARNING "%s: Data-transfer parity error\n", dev->name);
- } else if (sense & 0x10) {
- if (sense & 0x20)
- printk(KERN_WARNING "%s: Hardware malfunction (remote side)\n", dev->name);
- else
- printk(KERN_WARNING "%s: Read-data parity error (remote side)\n", dev->name);
- }
+ } else if (sense & 0x20) {
+ if (sense & 0x04)
+ printk(KERN_WARNING "%s: %s: Data-streaming timeout)\n", dev->name, caller);
+ else
+ printk(KERN_WARNING "%s: %s: Data-transfer parity error\n", dev->name, caller);
+ } else if (sense & 0x10) {
+ if (sense & 0x20)
+ printk(KERN_WARNING "%s: %s: Hardware malfunction (remote side)\n", dev->name, caller);
+ else
+ printk(KERN_WARNING "%s: %s: Read-data parity error (remote side)\n", dev->name, caller);
+ }
}
-
+
static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
{
- int rc = 0;
- __u32 parm;
- __u8 flags = 0x00;
- struct channel *ctc = NULL;
- struct ctc_priv *privptr = NULL;
- net_device *dev = NULL;
-
- /* ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
- {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; */
-
- ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, NULL},
- {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}};
+ int rc = 0;
+ __u32 parm;
+ __u8 flags = 0x00;
+ struct channel *ctc = NULL;
+ struct ctc_priv *privptr = NULL;
+ net_device *dev = NULL;
+
+ /* ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
+ {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; */
+
+ static ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, 0},
+ {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, 0}};
- devstat_t *devstat = ((devstat_t *)initparm);
+ devstat_t *devstat = ((devstat_t *)initparm);
- /* Bypass all 'unsolicited interrupts' */
- if (devstat->intparm == 0) {
+ /* Bypass all 'unsolicited interrupts' */
+ if (devstat->intparm == 0) {
#ifdef DEBUG
- printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
- devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
+ printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received cstat: %02x dstat: %02x flag: %02x\n",
+ devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
#endif
- /* FIXME - find the related intparm!!! No IO outstanding!!!! */
- return;
- }
-
- ctc = (struct channel *) (devstat->intparm);
- dev = (net_device *) ctc->dev;
- privptr = dev->priv;
+ /* FIXME - find the related intparm!!! No IO outstanding!!!! */
+ return;
+ }
+
+ ctc = (struct channel *) (devstat->intparm);
+ if(ctc==NULL)
+ {
+ printk(KERN_CRIT "ctc:ctc_irq_handler ctc=NULL irq=%d\n",irq);
+ return;
+ }
+
+ dev = (net_device *) ctc->dev;
+ if(dev==NULL)
+ {
+ printk(KERN_CRIT "ctc:ctc_irq_handler dev=NULL irq=%d, ctc=0x%p\n",
+ irq, ctc);
+ return;
+ }
+
+ privptr = dev->priv;
+ if(privptr==NULL)
+ {
+ printk(KERN_CRIT "ctc:ctc_irq_handler privptr=NULL "
+ "irq=%d, ctc=0x%p, dev=0x%p\n", irq, ctc, privptr);
+ return;
+ }
#ifdef DEBUG
- printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n",
- dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state);
+ printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n",
+ dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state);
#endif
- /* Check for good subchannel return code, otherwise error message */
- if (devstat->cstat) {
- printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n",
- dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag);
- return;
- }
+ /* Check for good subchannel return code, otherwise error message */
+ if (devstat->cstat) {
+ printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n",
+ dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag);
+ return;
+ }
- /* Check the reason-code of a unit check */
- if (devstat->dstat & DEV_STAT_UNIT_CHECK)
- ccw_check_unit_check(dev, devstat->ii.sense.data[0]);
+ /* Check the reason-code of a unit check */
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK)
+ ccw_check_unit_check(dev, devstat->ii.sense.data[0], __FUNCTION__ "()");
- /* State machine to bring the connection up / down and to restart */
+ /* State machine to bring the connection up / down and to restart */
- ctc->last_dstat = devstat->dstat;
+ ctc->last_dstat = devstat->dstat;
- switch (ctc->state) {
+ switch (ctc->state) {
- case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */
- if (!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
- wake_up(&ctc->wait); /* wake up ctc_release */
- return;
+ case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_STOP");
+#endif
+ if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
+ ctc->flag |= CTC_WAKEUP;
+ wake_up(&ctc->wait); /* wake up ctc_release */
+ return;
- case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */
- if (!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
-
- ctc->state = CTC_START_SET_X_MODE;
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags);
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- return;
+ case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_HALT_IO");
+#endif
+ if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
+
+ ctc->state = CTC_START_SET_X_MODE;
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags);
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+ return;
-
- case CTC_START_SET_X_MODE:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- if ((devstat->ii.sense.data[0] & 0x41) != 0x41 ||
- (devstat->ii.sense.data[0] & 0x40) != 0x40) {
- wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */
- return;
- }
- }
- if (!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
- ctc->state = CTC_START_SELECT;
+
+ case CTC_START_SET_X_MODE:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SET_X_MODE");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ if ((devstat->ii.sense.data[0] & 0x41) != 0x41 ||
+ (devstat->ii.sense.data[0] & 0x40) != 0x40) {
+ ctc->flag |= CTC_WAKEUP;
+ wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */
+ return;
+ }
+ }
+ if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
+ ctc->state = CTC_START_SELECT;
- case CTC_START_SELECT:
- if (!ctc->flag & CTC_WRITE) {
- ctc->state = CTC_START_READ_TEST;
- ctc->free_anchor->block->length = 0;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- wake_up(&ctc->wait); /* wake up ctc_open (READ) */
-
- } else {
- ctc->state = CTC_START_WRITE_TEST;
- /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
- ctc->free_anchor->block->length = 0;
- ctc->ccw[1].count = 2; /* Transfer only length */
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- }
- return;
-
-
- case CTC_START_READ_TEST:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
- (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
- devstat->ii.sense.data[0] == 0 ) {
- init_timer(&ctc->timer);
- ctc->timer.function = (void *)ctc_read_retry;
- ctc->timer.data = (__u32)ctc;
- ctc->timer.expires = jiffies + 10*HZ;
- add_timer(&ctc->timer);
+ case CTC_START_SELECT:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SELECT");
+#endif
+ if(ctc->free_anchor==NULL)
+ {
+ printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_SELECT ctc_free_anchor=NULL "
+ "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr);
+ return;
+ }
+ if (!(ctc->flag & CTC_WRITE)) {
+ ctc->state = CTC_START_READ_TEST;
+ ctc->free_anchor->block->length = 0;
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[2]");
+ ctc->flag |= CTC_WAKEUP;
+ wake_up(&ctc->wait); /* wake up ctc_open (READ) */
+
+ } else {
+ ctc->state = CTC_START_WRITE_TEST;
+ /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
+ ctc->free_anchor->block->length = 0;
+ ctc->ccw[1].count = BLOCK_HEADER_LENGTH; /* Transfer only length */
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[3]");
+ }
+ return;
+
+
+ case CTC_START_READ_TEST:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ_TEST");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+ (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+ devstat->ii.sense.data[0] == 0 ) {
+ init_timer(&ctc->timer);
+ ctc->timer.function = ctc_read_retry;
+ ctc->timer.data = (unsigned long)ctc;
+ ctc->timer.expires = jiffies + 10*HZ;
+ add_timer(&ctc->timer);
#ifdef DEBUG
- printk(KERN_DEBUG "%s: read connection restarted\n",dev->name);
+ printk(KERN_DEBUG "%s: read connection restarted\n",dev->name);
#endif
- }
- return;
- }
-
- if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
- if ((devstat->dstat & DEV_STAT_ATTENTION) &&
- (devstat->dstat & DEV_STAT_BUSY)) {
- printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name);
- }
- wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */
- return;
- }
-
- ctc->state = CTC_START_READ;
- set_bit(0, (void *)&ctc->IO_active);
-
- /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */
- /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */
-
-
- case CTC_START_READ:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
- (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
- devstat->ii.sense.data[0] == 0 ) {
- privptr->stats.rx_errors++;
+ }
+ return;
+ }
+
+ if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+ if ((devstat->dstat & DEV_STAT_ATTENTION) &&
+ (devstat->dstat & DEV_STAT_BUSY)) {
+ printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name);
+ }
+ privptr->channel[WRITE].flag |= CTC_WAKEUP;
+ wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */
+ return;
+ }
+
+ ctc->state = CTC_START_READ;
+ set_bit(0, &ctc->IO_active);
+
+ /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */
+ /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */
+
+
+ case CTC_START_READ:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+ (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+ devstat->ii.sense.data[0] == 0 ) {
+ privptr->stats.rx_errors++;
/* Need protection here cos we are in the read irq */
/* handler the tbusy is for the write subchannel */
ctc_protect_busy(dev);
- ctc_setbit_busy(TB_RETRY,dev);
+ ctc_setbit_busy(TB_RETRY,dev);
ctc_unprotect_busy(dev);
- init_timer(&ctc->timer);
- ctc->timer.function = (void *)ctc_read_retry;
- ctc->timer.data = (__u32)ctc;
- ctc->timer.expires = jiffies + 30*HZ;
- add_timer(&ctc->timer);
- printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name);
- }
- return;
- }
-
- if(!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
+ init_timer(&ctc->timer);
+ ctc->timer.function = ctc_read_retry;
+ ctc->timer.data = (unsigned long)ctc;
+ ctc->timer.expires = jiffies + 30*HZ;
+ add_timer(&ctc->timer);
+ printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name);
+ }
+ return;
+ }
+
+ if(!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
ctc_protect_busy(dev);
ctc_clearbit_busy(TB_RETRY,dev);
ctc_unprotect_busy(dev);
- ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
-
- if (ctc->free_anchor != NULL) {
- ctc->free_anchor->block->length = 0;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- } else {
- clear_bit(0, (void *)&ctc->IO_active);
+ ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
+
+ if (ctc->free_anchor != NULL) {
+ ctc->free_anchor->block->length = 0;
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[4]");
+ } else {
+ clear_bit(0, &ctc->IO_active);
#ifdef DEBUG
- printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name);
+ printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name);
#endif
- }
-
- if (test_and_set_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a) == 0) {
- queue_task(&ctc->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- }
- return;
-
-
- case CTC_START_WRITE_TEST:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
- (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
- devstat->ii.sense.data[0] == 0 ) {
- init_timer(&ctc->timer);
- ctc->timer.function = (void *)ctc_write_retry;
- ctc->timer.data = (__u32)ctc;
- ctc->timer.expires = jiffies + 10*HZ;
- add_timer(&ctc->timer);
+ }
+
+ if (test_and_set_bit(CTC_BH_ACTIVE, &ctc->flag_a) == 0) {
+ queue_task(&ctc->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+ return;
+
+
+ case CTC_START_WRITE_TEST:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE_TEST");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ if ((devstat->ii.sense.data[0] & 0x41) == 0x41 ||
+ (devstat->ii.sense.data[0] & 0x40) == 0x40 ||
+ devstat->ii.sense.data[0] == 0 ) {
+ init_timer(&ctc->timer);
+ ctc->timer.function = ctc_write_retry;
+ ctc->timer.data = (unsigned long)ctc;
+ ctc->timer.expires = jiffies + 10*HZ;
+ add_timer(&ctc->timer);
#ifdef DEBUG
- printk(KERN_DEBUG "%s: write connection restarted\n",dev->name);
+ printk(KERN_DEBUG "%s: write connection restarted\n",dev->name);
#endif
- }
- return;
- }
-
- ctc->state = CTC_START_WRITE;
- wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */
- return;
+ }
+ return;
+ }
+
+ ctc->state = CTC_START_WRITE;
+ ctc->flag |= CTC_WAKEUP;
+ wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */
+ return;
- case CTC_START_WRITE:
- if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
- privptr->stats.tx_errors += ctc->proc_anchor->packets;
+ case CTC_START_WRITE:
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE");
+#endif
+ if (devstat->dstat & DEV_STAT_UNIT_CHECK) {
+ privptr->stats.tx_errors += ctc->proc_anchor->packets;
#ifdef DEBUG
- printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name);
+ printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name);
#endif
- } else {
- if (!devstat->flag & DEVSTAT_FINAL_STATUS)
- return;
- privptr->stats.tx_packets += ctc->proc_anchor->packets;
- }
-
- ctc->proc_anchor->block->length = 0;
- ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
- ctc_clearbit_busy(TB_NOBUFFER,dev);
- if (ctc->proc_anchor != NULL) {
+ } else {
+ if (!(devstat->flag & DEVSTAT_FINAL_STATUS))
+ return;
+ privptr->stats.tx_packets += ctc->proc_anchor->packets;
+ }
+
+ ctc->proc_anchor->block->length = 0;
+ ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev);
+ ctc_clearbit_busy(TB_NOBUFFER, dev);
+ if (ctc->proc_anchor != NULL) {
#ifdef DEBUG
- printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name);
+ printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name);
#endif
- ctc->ccw[1].count = ctc->proc_anchor->block->length;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- dev->trans_start = jiffies;
- return;
-
- }
-
- if (ctc->free_anchor->block->length != 0) {
- if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {
- /* set transmission to busy */
- ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
- ctc_clearbit_busy(TB_TX,dev);
+ ctc->ccw[1].count = ctc->proc_anchor->block->length;
+ ctc->ccw[1].cda = __pa(ctc->proc_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[5]");
+ dev->trans_start = jiffies;
+ return;
+
+ }
+ if (ctc->free_anchor==NULL) {
+ printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_WRITE ctc_free_anchor=NULL "
+ "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr);
+ return;
+ }
+ if (ctc->free_anchor->block->length != 0) {
+ if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {
+ /* set transmission to busy */
+ ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
+ ctc_clearbit_busy(TB_TX,dev);
#ifdef DEBUG
- printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name);
+ printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name);
#endif
- ctc->ccw[1].count = ctc->proc_anchor->block->length;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- dev->trans_start = jiffies;
- return;
- }
- }
-
- clear_bit(0, (void *)&ctc->IO_active); /* set by ctc_tx or ctc_bh */
- return;
+ ctc->ccw[1].count = ctc->proc_anchor->block->length;
+ ctc->ccw[1].cda = __pa(ctc->proc_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[6]");
+ dev->trans_start = jiffies;
+ return;
+ }
+ }
+
+ clear_bit(0, &ctc->IO_active); /* set by ctc_tx or ctc_bh */
+ return;
- default:
- printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name);
- return;
- }
+ default:
+ printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name);
+ return;
+ }
}
-static void ctc_irq_bh (struct channel *ctc)
+static void ctc_irq_bh (void *data)
{
- int rc = 0;
- __u16 data_len;
- __u32 parm;
-
- __u8 flags = 0x00;
- __u32 saveflags;
- net_device *dev;
- struct ctc_priv *privptr;
- struct packet *lp;
- struct sk_buff *skb;
-
- dev = (net_device *) ctc->dev;
- privptr = (struct ctc_priv *) dev->priv;
+ struct channel *ctc = (struct channel *) data;
+ net_device *dev = (net_device *) ctc->dev;
+ struct ctc_priv *privptr = (struct ctc_priv *) dev->priv;
+
+ int rc = 0;
+ __u16 data_len;
+ __u32 parm;
+
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+ struct block *block;
+ struct packet *lp;
+ struct sk_buff *skb;
+
#ifdef DEBUG
- printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state);
+ printk(KERN_DEBUG "%s: %s(): initial_block_received = %d\n" ,dev->name, __FUNCTION__, ctc->initial_block_received);
+ printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state);
#endif
- while (ctc->proc_anchor != NULL) {
-
- if (ctc->proc_anchor->block->length != 0) {
-
- lp = &ctc->proc_anchor->block->data;
- while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) {
- data_len = lp->length - PACKET_HEADER_LENGTH;
- skb = dev_alloc_skb(data_len);
- if (skb) {
- memcpy(skb_put(skb, data_len),&lp->data, data_len);
- skb->mac.raw = skb->data;
- skb->dev = dev;
- skb->protocol = htons(ETH_P_IP);
- skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */
- netif_rx(skb);
- privptr->stats.rx_packets++;
- } else {
- privptr->stats.rx_dropped++;
- printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name);
- }
- (__u8 *)lp += lp->length;
- }
- }
-
- s390irq_spin_lock_irqsave(ctc->irq, saveflags);
- ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
-
- if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) {
+ while (ctc->proc_anchor != NULL) {
+ block = ctc->proc_anchor->block;
+ if (block->length < BLOCK_HEADER_LENGTH) {
+ if(block->length == 0 && !ctc->initial_block_received)
+ ctc->initial_block_received = 1;
+ else
+ printk(KERN_INFO "%s: %s(): discarding block at 0x%p: "
+ "block length=%d<%d=block header length\n",
+ dev->name, __FUNCTION__, block, block->length, BLOCK_HEADER_LENGTH);
+ }
+ else {
+ lp = &block->data;
+ while ((__u8 *) lp < (__u8 *) block + block->length) {
+ if(lp->length < PACKET_HEADER_LENGTH) {
+ printk(KERN_INFO "%s: %s(): discarding rest of block at 0x%p (block length=%d:) "
+ "packet at 0x%p, packet length=%d<%d=packet header length\n",
+ dev->name, __FUNCTION__,
+ block, block->length, lp, lp->length, PACKET_HEADER_LENGTH);
+ break;
+ }
+
+ data_len = lp->length - PACKET_HEADER_LENGTH;
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: %s(): block=0x%p, block->length=%d, lp=0x%p, "
+ "lp->length=%d, data_len=%d\n",
+ dev->name, __FUNCTION__, block, block->length, lp, lp->length, data_len);
+#endif
+ skb = dev_alloc_skb(data_len);
+ if (skb) {
+ memcpy(skb_put(skb, data_len),&lp->data, data_len);
+ skb->mac.raw = skb->data;
+ skb->dev = dev;
+ skb->protocol = htons(ETH_P_IP);
+ skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */
+ netif_rx(skb);
+ privptr->stats.rx_packets++;
+ } else {
+ privptr->stats.rx_dropped++;
+ printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name);
+ }
+ (__u8 *)lp += lp->length;
+ }
+ }
+
+ s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+ ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev);
+
+ if (test_and_set_bit(0, &ctc->IO_active) == 0) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name);
+#endif
+ if(ctc->free_anchor==NULL || ctc->free_anchor->block==NULL)
+ {
+ printk(KERN_CRIT "ctc: bad anchor free_anchor "
+ "ctc=0x%p, ctc->free_anchor=0x%p, ctc->irq=%d\n",
+ ctc, ctc->free_anchor, ctc->irq);
+ }
+ else
+ {
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+ }
+ }
+ s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+ }
+ clear_bit(CTC_BH_ACTIVE, &ctc->flag_a);
#ifdef DEBUG
- printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name);
+ printk(KERN_DEBUG "%s: end bh routine - state-%02x\n" ,dev->name, ctc->state);
#endif
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- }
- s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
- }
- clear_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a);
- return;
+ return;
}
-static void ctc_read_retry (struct channel *ctc)
+static void ctc_read_retry (unsigned long data)
{
- int rc = 0;
- __u32 parm;
- __u8 flags = 0x00;
- __u32 saveflags;
- net_device *dev;
+ struct channel *ctc = (struct channel *) data;
+ net_device *dev = (net_device *) ctc->dev;
+ int rc = 0;
+ __u32 parm;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+
- dev = (net_device *) ctc->dev;
-
#ifdef DEBUG
- printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state);
-#endif
- if (ctc->state == CTC_STOP)
- return;
- s390irq_spin_lock_irqsave(ctc->irq, saveflags);
- ctc->free_anchor->block->length = 0;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- return;
+ printk(KERN_DEBUG "%s: read retry - state-%02x\n",
+ dev->name, ctc->state);
+#endif
+ s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+ if (ctc->state != CTC_STOP) {
+ if (!ctc->free_anchor) {
+ s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+ printk(KERN_WARNING
+ "%s: %s(): ctc->free_anchor=NULL, ctc=0x%p\n",
+ dev->name, __FUNCTION__, ctc);
+ return;
+ }
+
+ ctc->free_anchor->block->length = 0;
+ ctc->ccw[1].cda = __pa(ctc->free_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO(ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
+ }
+
+ s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+
+ return;
}
-static void ctc_write_retry (struct channel *ctc)
+static void ctc_write_retry (unsigned long data)
{
- int rc = 0;
- __u32 parm;
- __u8 flags = 0x00;
- __u32 saveflags;
- net_device *dev;
+ struct channel *ctc = (struct channel *) data;
+ net_device *dev = (net_device *) ctc->dev;
+ int rc = 0;
+ __u32 parm;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
- dev = (net_device *) ctc->dev;
#ifdef DEBUG
- printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
-#endif
- if (ctc->state == CTC_STOP)
- return;
-
- while (ctc->proc_anchor != NULL) {
- ctc->proc_anchor->block->length = 0;
- ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
- }
-
- ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
- s390irq_spin_lock_irqsave(ctc->irq, saveflags);
- ctc->ccw[1].count = 2;
- ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block);
- parm = (__u32) ctc;
- rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
- s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
- if (rc != 0)
- ccw_check_return_code(dev, rc);
- return;
+ printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
+#endif
+
+ if (ctc->proc_anchor != NULL) {
+ printk(KERN_WARNING "%s: %s(): ctc->proc_anchor != NULL\n" ,dev->name, __FUNCTION__);
+ }
+
+ s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+
+ if (ctc->state != CTC_STOP)
+ {
+ ctc->ccw[1].count = 2;
+ ctc->ccw[1].cda = __pa(ctc->proc_anchor->block);
+ parm = (__u32)(long) ctc;
+ rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
+ }
+
+ s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
+
+ if (rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+
+ return;
}
*/
static int ctc_open(net_device *dev)
{
- int rc;
- int i;
- int j;
- __u8 flags = 0x00;
- __u32 saveflags;
- __u32 parm;
- struct ctc_priv *privptr;
- DECLARE_WAITQUEUE(wait, current);
- struct timer_list timer;
-
-
- ctc_set_busy(dev);
-
- privptr = (struct ctc_priv *) (dev->priv);
-
- privptr->channel[READ].flag = 0x00;
- privptr->channel[WRITE].flag = CTC_WRITE;
-
- for (i = 0; i < 2; i++) {
- for (j = 0; j < CTC_BLOCKS; j++) {
- rc = ctc_buffer_alloc(&privptr->channel[i]);
- if (rc != 0)
- return -ENOMEM;
- }
- init_waitqueue_head(&privptr->channel[i].wait);
- privptr->channel[i].tq.next = NULL;
- privptr->channel[i].tq.sync = 0;
- privptr->channel[i].tq.routine = (void *)(void *)ctc_irq_bh;
- privptr->channel[i].tq.data = &privptr->channel[i];
-
- privptr->channel[i].dev = dev;
-
- privptr->channel[i].flag_a = 0;
- privptr->channel[i].IO_active = 0;
-
- privptr->channel[i].ccw[0].cmd_code = CCW_CMD_PREPARE;
- privptr->channel[i].ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- privptr->channel[i].ccw[0].count = 0;
- privptr->channel[i].ccw[0].cda = NULL;
- if (i == READ) {
- privptr->channel[i].ccw[1].cmd_code = CCW_CMD_READ;
- privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI;
- privptr->channel[i].ccw[1].count = 0xffff; /* MAX size */
- privptr->channel[i].ccw[1].cda = NULL;
- } else {
- privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE;
- privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- privptr->channel[i].ccw[1].count = 0;
- privptr->channel[i].ccw[1].cda = NULL;
- }
- privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE+DE */
- privptr->channel[i].ccw[2].flags = CCW_FLAG_SLI;
- privptr->channel[i].ccw[2].count = 0;
- privptr->channel[i].ccw[2].cda = NULL;
-
- privptr->channel[i].flag &= ~CTC_TIMER;
- init_timer(&timer);
- timer.function = (void *)ctc_timer;
- timer.data = (__u32)&privptr->channel[i];
- timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */
- add_timer(&timer);
-
- s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
- parm = (unsigned long) &privptr->channel[i];
- privptr->channel[i].state = CTC_START_HALT_IO;
- rc = halt_IO(privptr->channel[i].irq, parm, flags);
- add_wait_queue(&privptr->channel[i].wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
- s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
- schedule();
- remove_wait_queue(&privptr->channel[i].wait, &wait);
- if(rc != 0)
- ccw_check_return_code(dev, rc);
- if((privptr->channel[i].flag & CTC_TIMER) == 0x00)
- del_timer(&timer);
- }
-
- if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
- ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
- (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) {
+ int rc, wait_rc;
+ int i, ii;
+ int j;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+ __u32 parm;
+ struct ctc_priv *privptr;
+ struct timer_list timer;
+
+
+ ctc_set_busy(dev);
+
+ privptr = (struct ctc_priv *) (dev->priv);
+
+ privptr->channel[READ].flag = 0x00;
+ privptr->channel[WRITE].flag = CTC_WRITE;
+
+ for (i = 0; i < 2; i++) {
+ privptr->channel[i].free_anchor = NULL;
+ privptr->channel[i].proc_anchor = NULL;;
+ for (j = 0; j < CTC_BLOCKS; j++) {
+ rc = ctc_buffer_alloc(&privptr->channel[i]);
+ if (rc != 0)
+ return -ENOMEM;
+ }
+ init_waitqueue_head(&privptr->channel[i].wait);
+ privptr->channel[i].tq.next = NULL;
+ privptr->channel[i].tq.sync = 0;
+ privptr->channel[i].tq.routine = ctc_irq_bh;
+ privptr->channel[i].tq.data = &privptr->channel[i];
+
+ privptr->channel[i].initial_block_received = 0;
+
+ privptr->channel[i].dev = dev;
+
+ privptr->channel[i].flag_a = 0;
+ privptr->channel[i].IO_active = 0;
+
+ privptr->channel[i].ccw[0].cmd_code = CCW_CMD_PREPARE;
+ privptr->channel[i].ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ privptr->channel[i].ccw[0].count = 0;
+ privptr->channel[i].ccw[0].cda = 0;
+ if (i == READ) {
+ privptr->channel[i].ccw[1].cmd_code = CCW_CMD_READ;
+ privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI;
+ privptr->channel[i].ccw[1].count = 0xffff; /* MAX size */
+ privptr->channel[i].ccw[1].cda = 0;
+ } else {
+ privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE;
+ privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+ privptr->channel[i].ccw[1].count = 0;
+ privptr->channel[i].ccw[1].cda = 0;
+ }
+ privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE+DE */
+ privptr->channel[i].ccw[2].flags = CCW_FLAG_SLI;
+ privptr->channel[i].ccw[2].count = 0;
+ privptr->channel[i].ccw[2].cda = 0;
+
+ privptr->channel[i].flag &= ~(CTC_TIMER | CTC_WAKEUP);
+ init_timer(&timer);
+ timer.function = ctc_timer;
+ timer.data = (unsigned long)&privptr->channel[i];
+ timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */
+ add_timer(&timer);
+
+ s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+ parm = (unsigned long) &privptr->channel[i];
+ privptr->channel[i].state = CTC_START_HALT_IO;
+ rc = halt_IO(privptr->channel[i].irq, parm, flags);
+ s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
+
+ wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
+
+ del_timer(&timer);
+
+ if(rc != 0)
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+
+ if (wait_rc == -ERESTARTSYS) { /* wait_event_interruptible() was terminated by a signal */
+ for (ii=0; ii<=i; ii++) {
+
+ del_timer(&privptr->channel[ii].timer);
+
+ for (j=0; privptr->channel[ii].free_anchor != NULL && j < CTC_BLOCKS; j++)
+ ctc_buffer_free(&privptr->channel[ii]);
+
+ if (privptr->channel[ii].free_anchor != NULL)
+ printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n",
+ dev->name, __FUNCTION__, CTC_BLOCKS);
+ }
+ return -ERESTARTSYS;
+ }
+ }
+
+ if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
+ ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
+ (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) {
#ifdef DEBUG
- printk(KERN_DEBUG "%s: channel problems during open - read: %02x - write: %02x\n",
- dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
+ printk(KERN_DEBUG "%s: channel problems during open - read: %02x - write: %02x\n",
+ dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
#endif
- printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
-
- for (i = 0; i < 2; i++) {
- /* s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
- parm = (unsigned long) &privptr->channel[i];
- privptr->channel[i].state = CTC_STOP;
- rc = halt_IO(privptr->channel[i].irq, parm, flags); /
- s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
- if (rc != 0)
- ccw_check_return_code(dev, rc); */
- for (j = 0; j < CTC_BLOCKS; j++)
- ctc_buffer_free(&privptr->channel[i]);
- }
- return -EIO;
- }
-
- printk(KERN_INFO "%s: connected with remote side\n",dev->name);
- ctc_clear_busy(dev);
- return 0;
+ printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
+
+ for (i = 0; i < 2; i++) {
+ del_timer(&privptr->channel[i].timer);
+
+ for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS; j++)
+ ctc_buffer_free(&privptr->channel[i]);
+
+ if (privptr->channel[i].free_anchor != NULL)
+ printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n",
+ dev->name, __FUNCTION__, CTC_BLOCKS);
+ }
+ return -EIO;
+ }
+
+ printk(KERN_INFO "%s: connected with remote side\n",dev->name);
+ ctc_clear_busy(dev);
+ MOD_INC_USE_COUNT;
+ return 0;
}
-static void ctc_timer (struct channel *ctc)
+static void ctc_timer (unsigned long data)
{
+ struct channel *ctc = (struct channel *) data;
#ifdef DEBUG
- net_device *dev;
-
- dev = (net_device *) ctc->dev;
- printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
+ net_device *dev = (net_device *) ctc->dev;
+ printk(KERN_DEBUG "%s: timer return\n" ,dev->name);
#endif
- ctc->flag |= CTC_TIMER;
- wake_up(&ctc->wait);
- return;
+ ctc->flag |= (CTC_TIMER|CTC_WAKEUP);
+ wake_up(&ctc->wait);
+ return;
}
/*
*/
static int ctc_release(net_device *dev)
{
- int rc;
- int i;
- int j;
- __u8 flags = 0x00;
- __u32 saveflags;
- __u32 parm;
- struct ctc_priv *privptr;
- DECLARE_WAITQUEUE(wait, current);
-
- privptr = (struct ctc_priv *) dev->priv;
-
- ctc_protect_busy_irqsave(dev,saveflags);
- ctc_setbit_busy(TB_STOP,dev);
- ctc_unprotect_busy_irqrestore(dev,flags);
- for (i = 0; i < 2; i++) {
- s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
- del_timer(&privptr->channel[READ].timer);
- privptr->channel[i].state = CTC_STOP;
- parm = (__u32) &privptr->channel[i];
- rc = halt_IO (privptr->channel[i].irq, parm, flags );
- add_wait_queue(&privptr->channel[i].wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
- s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
- schedule();
- remove_wait_queue(&privptr->channel[i].wait, &wait);
- if (rc != 0) {
- ccw_check_return_code(dev, rc);
- }
-
- for (j = 0; j < CTC_BLOCKS; j++) {
- ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor);
- ctc_buffer_free(&privptr->channel[i]);
- }
- }
-
- if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
- ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
- printk(KERN_WARNING "%s: channel problems during close - read: %02x - write: %02x\n",
- dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
- return -EIO;
- }
-
- return 0;
+ int rc;
+ int i;
+ int j;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+ __u32 parm;
+ struct ctc_priv *privptr;
+ struct timer_list timer;
+
+ privptr = (struct ctc_priv *) dev->priv;
+
+ ctc_protect_busy_irqsave(dev, saveflags);
+ ctc_setbit_busy(TB_STOP,dev);
+ ctc_unprotect_busy_irqrestore(dev, saveflags);
+
+ for (i = 0; i < 2; i++) {
+ privptr->channel[i].flag &= ~(CTC_WAKEUP | CTC_TIMER);
+ init_timer(&timer);
+ timer.function = ctc_timer;
+ timer.data = (unsigned long)&privptr->channel[i];
+ timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */
+ add_timer(&timer);
+
+ s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+ del_timer(&privptr->channel[i].timer);
+ privptr->channel[i].state = CTC_STOP;
+ parm = (__u32)(long) &privptr->channel[i];
+ rc = halt_IO (privptr->channel[i].irq, parm, flags );
+ s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
+
+ wait_event(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
+
+ del_timer(&timer);
+
+ if (rc != 0) {
+ ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
+ }
+
+ if(privptr->channel[i].flag & CTC_TIMER)
+ {
+ printk(KERN_WARNING "%s: %s(): timeout during halt_io()\n",
+ dev->name, __FUNCTION__);
+ }
+
+
+ for (j=0; privptr->channel[i].proc_anchor != NULL && j < CTC_BLOCKS; j++)
+ ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor, dev);
+
+ if (privptr->channel[i].proc_anchor != NULL)
+ printk(KERN_WARNING "%s: %s(): trying to move more than maximal number %d of blocks to free list\n",
+ dev->name, __FUNCTION__, CTC_BLOCKS);
+
+ for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS; j++)
+ ctc_buffer_free(&privptr->channel[i]);
+
+ if (privptr->channel[i].free_anchor != NULL)
+ printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n",
+ dev->name, __FUNCTION__, CTC_BLOCKS);
+ }
+
+ if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) &
+ ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) {
+ printk(KERN_WARNING "%s: channel problems during close - read: %02x - write: %02x\n",
+ dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat);
+ return -EIO;
+ }
+
+ MOD_DEC_USE_COUNT;
+ return 0;
}
*/
static int ctc_tx(struct sk_buff *skb, net_device *dev)
{
- int rc=0,rc2;
- __u32 parm;
- __u8 flags = 0x00;
- __u32 saveflags;
- struct ctc_priv *privptr;
- struct packet *lp;
-
+ int rc=0,rc2;
+ __u32 parm;
+ __u8 flags = 0x00;
+ unsigned long saveflags;
+ struct ctc_priv *privptr;
+ struct packet *lp;
+
- privptr = (struct ctc_priv *) (dev->priv);
-
- if (skb == NULL) {
- printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name);
- privptr->stats.tx_dropped++;
- return -EIO;
- }
-
- s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
- if (ctc_check_busy(dev)) {
- rc=-EBUSY;
+ privptr = (struct ctc_priv *) (dev->priv);
+
+ if (skb == NULL) {
+ printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name);
+ privptr->stats.tx_dropped++;
+ return -EIO;
+ }
+
+ s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags);
+ if (ctc_check_busy(dev)) {
+ rc=-EBUSY;
goto Done;
- }
+ }
- if (ctc_test_and_setbit_busy(TB_TX,dev)) { /* set transmission to busy */
- rc=-EBUSY;
+ if (ctc_test_and_setbit_busy(TB_TX,dev)) { /* set transmission to busy */
+ rc=-EBUSY;
goto Done;
- }
+ }
- if (65535 - privptr->channel[WRITE].free_anchor->block->length - PACKET_HEADER_LENGTH <= skb->len + PACKET_HEADER_LENGTH + 2) {
+ if (privptr->channel[WRITE].free_anchor->block->length + BLOCK_HEADER_LENGTH + PACKET_HEADER_LENGTH + skb->len > 65535) {
#ifdef DEBUG
- printk(KERN_DEBUG "%s: early swap\n", dev->name);
+ printk(KERN_DEBUG "%s: early swap\n", dev->name);
#endif
-
- ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor);
- if (privptr->channel[WRITE].free_anchor == NULL){
- ctc_setbit_busy(TB_NOBUFFER,dev);
- rc=-EBUSY;
+
+ ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor, dev);
+ if (privptr->channel[WRITE].free_anchor == NULL){
+ ctc_setbit_busy(TB_NOBUFFER,dev);
+ rc=-EBUSY;
goto Done2;
- }
- }
-
- if (privptr->channel[WRITE].free_anchor->block->length == 0) {
- privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH;
- privptr->channel[WRITE].free_anchor->packets = 0;
- }
-
-
- (__u8 *)lp = (__u8 *) &privptr->channel[WRITE].free_anchor->block->length + privptr->channel[WRITE].free_anchor->block->length;
- privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH;
- lp->length = skb->len + PACKET_HEADER_LENGTH;
- lp->type = 0x0800;
- lp->unused = 0;
- memcpy(&lp->data, skb->data, skb->len);
- (__u8 *) lp += lp->length;
- lp->length = 0;
- dev_kfree_skb(skb);
- privptr->channel[WRITE].free_anchor->packets++;
-
- if (test_and_set_bit(0, (void *)&privptr->channel[WRITE].IO_active) == 0) {
- ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor);
- privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length;
- privptr->channel[WRITE].ccw[1].cda = (char *)virt_to_phys(privptr->channel[WRITE].proc_anchor->block);
- parm = (__u32) &privptr->channel[WRITE];
- rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags );
- if (rc2 != 0)
- ccw_check_return_code(dev, rc2);
- dev->trans_start = jiffies;
- }
- if (privptr->channel[WRITE].free_anchor == NULL)
- ctc_setbit_busy(TB_NOBUFFER,dev);
+ }
+ }
+
+ if (privptr->channel[WRITE].free_anchor->block->length == 0) {
+ privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH;
+ privptr->channel[WRITE].free_anchor->packets = 0;
+ }
+
+
+ (__u8 *)lp = (__u8 *) (privptr->channel[WRITE].free_anchor->block) + privptr->channel[WRITE].free_anchor->block->length;
+ privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH;
+ lp->length = skb->len + PACKET_HEADER_LENGTH;
+ lp->type = 0x0800;
+ lp->unused = 0;
+ memcpy(&lp->data, skb->data, skb->len);
+ (__u8 *) lp += lp->length;
+ lp->length = 0;
+ dev_kfree_skb(skb);
+ privptr->channel[WRITE].free_anchor->packets++;
+
+ if (test_and_set_bit(0, &privptr->channel[WRITE].IO_active) == 0) {
+ ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor, dev);
+ privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length;
+ privptr->channel[WRITE].ccw[1].cda = __pa(privptr->channel[WRITE].proc_anchor->block);
+ parm = (__u32)(long) &privptr->channel[WRITE];
+ rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags );
+ if (rc2 != 0)
+ ccw_check_return_code(dev, rc2, __FUNCTION__ "()[1]");
+ dev->trans_start = jiffies;
+ }
+ if (privptr->channel[WRITE].free_anchor == NULL)
+ ctc_setbit_busy(TB_NOBUFFER,dev);
Done2:
- ctc_clearbit_busy(TB_TX,dev);
+ ctc_clearbit_busy(TB_TX,dev);
Done:
s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags);
- return(rc);
+ return(rc);
}
* ctc_change_mtu
*
* S/390 can handle MTU sizes from 576 to 32760 for VM, VSE
- * 576 to 65527 for OS/390
+ * 576 to 65527 for OS/390
*
*/
static int ctc_change_mtu(net_device *dev, int new_mtu)
{
- if ((new_mtu < 576) || (new_mtu > 65528))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
+ if ((new_mtu < 576) || (new_mtu > 65528))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
}
*/
struct net_device_stats *ctc_stats(net_device *dev)
{
- struct ctc_priv *privptr;
+ struct ctc_priv *privptr;
- privptr = dev->priv;
- return &privptr->stats;
+ privptr = dev->priv;
+ return &privptr->stats;
}
-
/* Module code goes here */
-/*
- free_irq(privptr->channel[i].irq, privptr->channel[i].devstat);
- kfree(privptr->channel[i].devstat);
+#ifdef MODULE
+void cleanup_module(void) {
+ int m;
+ int i;
+ int c;
+
+ /* we are called if all interfaces are down only, so no need
+ * to bother around with locking stuff
+ */
+ for (m = 0; m < CHANNEL_MEDIA; m++) {
+ for (i = 0; i < MAX_ADAPTERS; i++)
+ if (ctc_adapter[m][i].netdev) {
+ struct ctc_priv *privptr = ctc_adapter[m][i].netdev->priv;
+
+ unregister_netdev(ctc_adapter[m][i].netdev);
+ for (c = 0; c < 2; c++) {
+ free_irq(privptr->channel[c].irq, privptr->channel[c].devstat);
+ kfree(privptr->channel[c].devstat);
+ }
+ kfree(privptr);
+ kfree(ctc_adapter[m][i].netdev);
+ }
+ }
+ printk(KERN_INFO "CTC driver unloaded\n");
+}
+
+static char *parse_opts(char *str, int *ints) {
+ char *cur = str;
+ int i = 1;
+
+ while (cur && (*cur == '-' || isdigit(*cur)) && i <= 10) {
+ ints[i++] = simple_strtoul(cur, NULL, 0);
+ if ((cur = strchr(cur, ',')) != NULL)
+ cur++;
+ }
+ ints[0] = i - 1;
+ return(cur);
+}
+
+int init_module(void) {
+ char *p = setup; /* This string is set by insmod, it is writeable */
+ int cnt;
+ int itype;
+ int activated;
+ int ints[10];
+
+ print_banner();
+
+ /**
+ * Parse setup string just like in init/main.c
+ */
+ while (p && *p) {
+ char *q = strstr(p, "ctc=");
+ if (q) {
+ /**
+ * Found "ctc=" in string
+ */
+ q += 4;
+ if ((p = parse_opts(q, ints))) {
+ /**
+ * p is now pointing to the first non-number parameter
+ *
+ */
+ if ((q = strchr(p, ' ')))
+ *q = '\0';
+ ctc_setup(p, ints);
+ if (q)
+ p = q + 1;
+ else
+ p = NULL;
+ }
+ } else
+ p = NULL;
+ }
+
+ activated = 0;
+ for (itype = 0; itype < 2; itype++) {
+ cnt = 0;
+ do {
+ net_device *dev = kmalloc(sizeof(net_device) + 11 /* name + trailing zero */ , GFP_KERNEL);
+ if (!dev) {
+ return -ENOMEM;
+ }
+ memset((unsigned char *)dev, 0, sizeof(net_device));
+ dev->name = (unsigned char *)dev + sizeof(net_device);
+ sprintf(dev->name, "%s%d", (itype) ? "escon" : "ctc", cnt++);
+ if (ctc_probe(dev) == 0) {
+ if (register_netdev(dev) != 0) {
+ struct ctc_priv *privptr = dev->priv;
+ int m = extract_channel_media(dev->name);
+ int i = extract_channel_id(dev->name);
+
+ printk(KERN_WARNING "ctc: Couldn't register %s\n", dev->name);
+ free_irq(privptr->channel[READ].irq, privptr->channel[READ].devstat);
+ kfree(privptr->channel[READ].devstat);
+ free_irq(privptr->channel[WRITE].irq, privptr->channel[WRITE].devstat);
+ kfree(privptr->channel[WRITE].devstat);
+ channel_free(m, ctc_adapter[m][i].devno[READ]);
+ channel_free(m, ctc_adapter[m][i].devno[WRITE]);
+ kfree(dev->priv);
+ kfree(dev);
+ } else
+ activated++;
+ } else {
+ kfree(dev);
+ cnt = MAX_ADAPTERS;
+ }
+ } while (cnt < MAX_ADAPTERS);
+ }
+ if (!activated) {
+ printk(KERN_WARNING "ctc: No devices registered\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+#endif
-*/
/* --- This is the END my friend --- */
*
* \r
* 2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)\r
* Alan Altmark (Alan_Altmark@us.ibm.com)
*
printk( "iucv: extern_int_buffer:\n");
dumpit((char *)&extern_int_buffer[0],40);
#endif
-
+
if (extern_int_buffer->iptype == 0x01)
dev = get_device_from_userid(&((char*) extern_int_buffer)[8]);
else
dev = get_device_from_pathid(extern_int_buffer->ippathid);
+ if (dev == NULL)
+ return;
+
netif_enter_interrupt(dev); /* lock ! */
privptr = (struct iucv_priv *)(dev->priv);
printk( "message pending.\n");
#endif
rcvptr = &privptr->receive_buffer[0];
-
+
/* re-set receive buffer */
memset(privptr->receive_buffer,0,privptr->receive_buffer_len);
len = privptr->receive_buffer_len;
-/* $Id: envctrl.c,v 1.9.2.1 2000/05/02 04:23:33 davem Exp $
+/* $Id: envctrl.c,v 1.9.2.2 2000/11/08 09:43:04 davem Exp $
* envctrl.c: Temperature and Fan monitoring on Machines providing it.
*
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* http://www-eu2.semiconductors.com/pip/PCF8584P
* http://www-eu2.semiconductors.com/pip/PCF8574AP
* http://www-eu2.semiconductors.com/pip/PCF8591P
+ *
+ * EB - Added support for CP1500 Global Address and PS/Voltage monitoring.
+ * Eric Brower <ebrower@usa.net>
*
*/
* Firmware definitions.
*/
#define PCF8584_MAX_CHANNELS 8
+#define PCF8584_GLOBALADDR_TYPE 6 /* global address monitor */
#define PCF8584_FANSTAT_TYPE 3 /* fan status monitor */
#define PCF8584_VOLTAGE_TYPE 2 /* voltage monitor */
-#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/
+#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/
/* Monitor type of i2c child device.
* Driver definitions.
*/
-#define ENVCTRL_NOMON 0
-#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */
+#define ENVCTRL_NOMON 0
+#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */
#define ENVCTRL_CPUVOLTAGE_MON 2 /* voltage monitor */
#define ENVCTRL_FANSTAT_MON 3 /* fan status monitor */
#define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperarture */
#define ENVCTRL_VOLTAGESTAT_MON 5 /* voltage status monitor */
#define ENVCTRL_MTHRBDTEMP_MON 6 /* motherboard temperature */
#define ENVCTRL_SCSITEMP_MON 7 /* scsi temperarture */
+#define ENVCTRL_GLOBALADDR_MON 8 /* global address */
/* Child device type.
* Driver definitions.
#define ENVCTRL_MAX_CPU 4
#define CHANNEL_DESC_SZ 256
+/* Mask values for combined GlobalAddress/PowerStatus node */
+#define ENVCTRL_GLOBALADDR_ADDR_MASK 0x1F
+#define ENVCTRL_GLOBALADDR_PSTAT_MASK 0x60
+
+/* Node 0x70 ignored on CompactPCI CP1400/1500 platforms
+ * (see envctrl_init_i2c_child)
+ */
+#define ENVCTRL_CPCI_IGNORED_NODE 0x70
+
struct pcf8584_reg {
unsigned char data;
unsigned char csr;
int limit = 1000000;
while (--limit > 0) {
- if(!(envctrl_readb(&i2c->csr) & STATUS_PIN))
+ if (!(envctrl_readb(&i2c->csr) & STATUS_PIN))
break;
udelay(1);
}
return 1;
}
+/* Function Description: Read global addressing line.
+ * Return : Always 1 byte. Status stored in bufdata.
+ */
+static int envctrl_i2c_globaladdr(struct i2c_child_t *pchild,
+ unsigned char data,
+ char *bufdata)
+{
+ /* Translatation table is not necessary, as global
+ * addr is the integer value of the GA# bits.
+ *
+ * NOTE: MSB is documented as zero, but I see it as '1' always....
+ *
+ * -----------------------------------------------
+ * | 0 | FAL | DEG | GA4 | GA3 | GA2 | GA1 | GA0 |
+ * -----------------------------------------------
+ * GA0 - GA4 integer value of Global Address (backplane slot#)
+ * DEG 0 = cPCI Power supply output is starting to degrade
+ * 1 = cPCI Power supply output is OK
+ * FAL 0 = cPCI Power supply has failed
+ * 1 = cPCI Power supply output is OK
+ */
+ bufdata[0] = (data & ENVCTRL_GLOBALADDR_ADDR_MASK);
+ return 1;
+}
+
/* Function Description: Read voltage and power supply status.
* Return : Always 1 byte. Status stored in bufdata.
*/
copy_to_user((unsigned char*)buf, data, ret);
break;
+ case ENVCTRL_RD_GLOBALADDRESS:
+ if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+ return 0;
+ data[0] = envctrl_i2c_read_8574(pchild->addr);
+ ret = envctrl_i2c_globaladdr(pchild, data[0], data);
+ copy_to_user((unsigned char*)buf, data, ret);
+ break;
+
case ENVCTRL_RD_VOLTAGE_STATUS:
if (!(pchild = envctrl_get_i2c_child(ENVCTRL_VOLTAGESTAT_MON)))
- return 0;
+ /* If voltage monitor not present, check for CPCI equivalent */
+ if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON)))
+ return 0;
data[0] = envctrl_i2c_read_8574(pchild->addr);
ret = envctrl_i2c_voltage_status(pchild, data[0], data);
copy_to_user((unsigned char*)buf, data, ret);
case ENVCTRL_RD_VOLTAGE_STATUS:
case ENVCTRL_RD_ETHERNET_TEMPERATURE:
case ENVCTRL_RD_SCSI_TEMPERATURE:
+ case ENVCTRL_RD_GLOBALADDRESS:
file->private_data = (void *)(long)cmd;
break;
if (!(strcmp(chnl_desc,"temp,ethernet")))
pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
-
- if (!(strcmp(chnl_desc,"temp,ethernet")))
- pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON;
}
/* Function Description: Initialize monitor channel with channel desc,
pchild->mon_type[0] = ENVCTRL_FANSTAT_MON;
}
+/* Function Description: Initialize child device for global addressing line.
+ * Return: None.
+ */
+static void envctrl_init_globaladdr(struct i2c_child_t *pchild)
+{
+ int i;
+
+ /* Voltage/PowerSupply monitoring is piggybacked
+ * with Global Address on CompactPCI. See comments
+ * within envctrl_i2c_globaladdr for bit assignments.
+ *
+ * The mask is created here by assigning mask bits to each
+ * bit position that represents PCF8584_VOLTAGE_TYPE data.
+ * Channel numbers are not consecutive within the globaladdr
+ * node (why?), so we use the actual counter value as chnls_mask
+ * index instead of the chnl_array[x].chnl_no value.
+ *
+ * NOTE: This loop could be replaced with a constant representing
+ * a mask of bits 5&6 (ENVCTRL_GLOBALADDR_PSTAT_MASK).
+ */
+ for (i = 0; i < pchild->total_chnls; i++) {
+ if (PCF8584_VOLTAGE_TYPE == pchild->chnl_array[i].type) {
+ pchild->voltage_mask |= chnls_mask[i];
+ }
+ }
+
+ /* We only need to know if this child has global addressing
+ * line monitored. We dont care which channels since we know
+ * the mask already (ENVCTRL_GLOBALADDR_ADDR_MASK).
+ */
+ pchild->mon_type[0] = ENVCTRL_GLOBALADDR_MON;
+}
+
/* Initialize child device monitoring voltage status. */
static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
{
}
}
+ /* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)
+ * sections 2.5, 3.5, 4.5 state node 0x70 for CP1400/1500 is
+ * "For Factory Use Only."
+ *
+ * We ignore the node on these platforms by assigning the
+ * 'NULL' monitor type.
+ */
+ if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {
+ int len;
+ char prop[56];
+
+ len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
+ if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len))) {
+ for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
+ pchild->mon_type[len] = ENVCTRL_NOMON;
+ }
+ return;
+ }
+ }
+
/* Get the monitor channels. */
len = prom_getproperty(node, "channels-in-use", (char *)pchild->chnl_array,
PCF8584_MAX_CHANNELS*sizeof(struct pcf8584_channel));
envctrl_init_adc(pchild, node);
break;
+ case PCF8584_GLOBALADDR_TYPE:
+ envctrl_init_globaladdr(pchild);
+ i = pchild->total_chnls;
+ break;
+
case PCF8584_FANSTAT_TYPE:
envctrl_init_fanstat(pchild);
i = pchild->total_chnls;
envctrl_dev.minor);
}
+ /* Note above traversal routine post-incremented 'i' to accomodate
+ * a next child device, so we decrement before reverse-traversal of
+ * child devices.
+ */
+ printk("envctrl: initialized ");
+ for (--i; i >= 0; --i) {
+ printk("[%s 0x%lx]%s",
+ (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") :
+ ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")),
+ i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
+ }
+
return 0;
#else
return -ENODEV;
#define MASK_ADDR_VOLC MASK_ADDR4 /* Volume Control C -- Speaker */
#define MASK_ADDR_VOLSPK MASK_ADDR4
+/* additional registers of screamer */
+#define MASK_ADDR5 (0x5 << 12) /* Expanded Data Mode Address 5 */
+#define MASK_ADDR6 (0x6 << 12) /* Expanded Data Mode Address 6 */
+#define MASK_ADDR7 (0x7 << 12) /* Expanded Data Mode Address 7 */
+
+
/* Address 0 Bit Masks & Macros */
/* ------- - --- ----- - ------ */
#define MASK_GAINRIGHT (0xf) /* Gain Right Mask */
#define MASK_GAINLEFT (0xf << 4) /* Gain Left Mask */
-#define MASK_GAINLINE (0x1 << 8) /* Change Gain for Line??? */
-#define MASK_GAINMIC (0x0 << 8) /* Change Gain for Mic??? */
+#define MASK_GAINLINE (0x1 << 8) /* Disable Mic preamp */
+#define MASK_GAINMIC (0x0 << 8) /* Enable Mic preamp */
#define MASK_MUX_CD (0x1 << 9) /* Select CD in MUX */
#define MASK_MUX_MIC (0x1 << 10) /* Select Mic in MUX */
static struct device_node* awacs_node;
static int awacs_revision;
+int awacs_is_screamer = 0;
+int awacs_device_id = 0;
+int awacs_has_iic = 0;
#define AWACS_BURGUNDY 100 /* fake revision # for burgundy */
/*
* Cached values of AWACS registers (we can't read them).
* Except on the burgundy. XXX
*/
-int awacs_reg[5];
+int awacs_reg[8];
#define HAS_16BIT_TABLES
#undef HAS_8BIT_TABLES
awacs_write(awacs_reg[1] | MASK_ADDR1);
awacs_write(awacs_reg[2] | MASK_ADDR2);
awacs_write(awacs_reg[4] | MASK_ADDR4);
+ if (awacs_is_screamer) {
+ awacs_write(awacs_reg[5] + MASK_ADDR5);
+ awacs_write(awacs_reg[6] + MASK_ADDR6);
+ awacs_write(awacs_reg[7] + MASK_ADDR7);
+ }
out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
enable_irq(awacs_irq);
enable_irq(awacs_tx_irq);
size = bufSize << 10;
sq_setup(numBufs, size, sound_buffers);
sq.max_active = nbufs;
- return 0;
+ return IOCTL_OUT(arg,size | numBufs << 16);
case SNDCTL_DSP_GETOSPACE:
info.fragments = sq.max_active - sq.count;
info.fragstotal = sq.max_active;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
-
- default:
- return mixer_ioctl(inode, file, cmd, arg);
+ case SNDCTL_DSP_GETCAPS:
+ data = 1; /* Revision level of this ioctl() */
+ return IOCTL_OUT(arg, data);
+ default:
+ return mixer_ioctl(inode, file, cmd, arg);
}
return -EINVAL;
}
awacs_subframe = *prop;
if (device_is_compatible(sound, "burgundy"))
awacs_revision = AWACS_BURGUNDY;
-
+ /* This should be verified on older screamers */
+ if (device_is_compatible(sound, "screamer"))
+ awacs_is_screamer = 1;
+ prop = (unsigned int *)get_property(sound, "device-id", 0);
+ if (prop != 0)
+ awacs_device_id = *prop;
+ awacs_has_iic = (find_devices("perch") != NULL);
+
/* look for a property saying what sample rates
are available */
for (i = 0; i < 8; ++i)
awacs_tx_cmds = (volatile struct dbdma_cmd *)
DBDMA_ALIGN(awacs_tx_cmd_space);
awacs_reg[0] = MASK_MUX_CD;
- awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
+ /* FIXME: Only machines with external SRS module need MASK_PAROUT */
+ awacs_reg[1] = MASK_LOOPTHRU;
+ if (awacs_has_iic || awacs_device_id == 0x5 || /*awacs_device_id == 0x8
+ || */awacs_device_id == 0xb)
+ awacs_reg[1] |= MASK_PAROUT;
/* get default volume from nvram */
vol = (~nvram_read_byte(0x1308) & 7) << 1;
awacs_reg[2] = vol + (vol << 6);
awacs_reg[4] = vol + (vol << 6);
+ awacs_reg[5] = 0;
+ awacs_reg[6] = 0;
+ awacs_reg[7] = 0;
out_le32(&awacs->control, 0x11);
awacs_write(awacs_reg[0] + MASK_ADDR0);
awacs_write(awacs_reg[1] + MASK_ADDR1);
awacs_write(awacs_reg[2] + MASK_ADDR2);
awacs_write(awacs_reg[4] + MASK_ADDR4);
-
+ if (awacs_is_screamer) {
+ awacs_write(awacs_reg[5] + MASK_ADDR5);
+ awacs_write(awacs_reg[6] + MASK_ADDR6);
+ awacs_write(awacs_reg[7] + MASK_ADDR7);
+ }
+
/* Initialize recent versions of the awacs */
if (awacs_revision == 0) {
awacs_revision =
fi
dep_tristate ' USB Digi International AccelePort USB Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL
+ dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
fi
bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
fi
#include <linux/kbd_kern.h>
#include <linux/kcomp.h>
-#if defined(__i386__) || defined(__alpha__) || defined(__mips__)
+#if defined(__i386__) || defined(__alpha__) || defined(__mips__) || defined(__powerpc__)
static int x86_sysrq_alt = 0;
332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372
};
+#ifdef CONFIG_INPUT_ADBHID
+extern int mac_hid_keyboard_sends_linux_keycodes(void);
+
+static unsigned char mac_keycodes[256] = {
+ 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
+ 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1,
+ 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
+ 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
+ 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
+ 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0,
+ 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117,
+ 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 95, 55, 55, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102
+};
+
+#ifdef CONFIG_INPUT_MOUSEDEV
+extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int);
+#endif /* CONFIG_INPUT_MOUSEDEV */
+#endif /* CONFIG_INPUT_ADBHID */
+
static int emulate_raw(unsigned int keycode, int down)
{
+#ifdef CONFIG_INPUT_ADBHID
+#ifdef CONFIG_INPUT_MOUSEDEV
+ if (mac_hid_mouse_emulate_buttons(1, keycode, down))
+ return 0;
+#endif /* CONFIG_INPUT_MOUSEDEV */
+ if (!mac_hid_keyboard_sends_linux_keycodes()) {
+ if (keycode > 255 || !mac_keycodes[keycode])
+ return -1;
+
+ handle_scancode(mac_keycodes[keycode] & 0x7f, down);
+
+ return 0;
+ }
+#endif /* CONFIG_INPUT_ADBHID */
if (keycode > 255 || !x86_keycodes[keycode])
return -1;
return 0;
}
-#elif defined(CONFIG_MAC_KEYBOARD)
-
-static unsigned char mac_keycodes[128] =
- { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
- 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1,
- 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
- 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
- 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
- 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0,
- 76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117,
- 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 };
-
-static int emulate_raw(unsigned int keycode, int down)
-{
- if (keycode > 127 || !mac_keycodes[keycode])
- return -1;
-
- handle_scancode(mac_keycodes[keycode] & 0x7f, down);
-
- return 0;
-}
-
#endif
static struct input_handler keybdev_handler;
obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o
+obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
# Objects that export symbols.
export-objs := usbserial.o
--- /dev/null
+/*
+ * Belkin USB Serial Adapter Driver
+ *
+ * Copyright (C) 2000
+ * William Greathouse (wgreathouse@smva.com)
+ *
+ * This program is largely derived from work by the linux-usb group
+ * and associated source files. Please see the usb/serial files for
+ * individual credits and copyrights.
+ *
+ * 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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * TODO:
+ * -- Add true modem contol line query capability. Currently we track the
+ * states reported by the interrupt and the states we request.
+ * -- Add error reporting back to application for UART error conditions.
+ * Just point me at how to implement this and I'll do it. I've put the
+ * framework in, but haven't analyzed the "tty_flip" interface yet.
+ * -- Add support for flush commands
+ * -- Add everything that is missing :)
+ *
+ * (11/06/2000) gkh
+ * - Added support for the old Belkin and Peracom devices.
+ * - Made the port able to be opened multiple times.
+ * - Added some defaults incase the line settings are things these devices
+ * can't support.
+ *
+ * 18-Oct-2000 William Greathouse
+ * Released into the wild (linux-usb-devel)
+ *
+ * 17-Oct-2000 William Greathouse
+ * Add code to recognize firmware version and set hardware flow control
+ * appropriately. Belkin states that firmware prior to 3.05 does not
+ * operate correctly in hardware handshake mode. I have verified this
+ * on firmware 2.05 -- for both RTS and DTR input flow control, the control
+ * line is not reset. The test performed by the Belkin Win* driver is
+ * to enable hardware flow control for firmware 2.06 or greater and
+ * for 1.00 or prior. I am only enabling for 2.06 or greater.
+ *
+ * 12-Oct-2000 William Greathouse
+ * First cut at supporting Belkin USB Serial Adapter F5U103
+ * I did not have a copy of the original work to support this
+ * adapter, so pardon any stupid mistakes. All of the information
+ * I am using to write this driver was acquired by using a modified
+ * UsbSnoop on Windows2000 and from examining the other USB drivers.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+#include "belkin_sa.h"
+
+/* function prototypes for a Belkin USB Serial Adapter F5U103 */
+static int belkin_sa_startup (struct usb_serial *serial);
+static void belkin_sa_shutdown (struct usb_serial *serial);
+static int belkin_sa_open (struct usb_serial_port *port, struct file *filp);
+static void belkin_sa_close (struct usb_serial_port *port, struct file *filp);
+static void belkin_sa_read_int_callback (struct urb *urb);
+static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old);
+static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
+static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state );
+
+/* All of the device info needed for the Belkin serial converter */
+static __u16 belkin_sa_vendor_id = BELKIN_SA_VID;
+static __u16 belkin_sa_product_id = BELKIN_SA_PID;
+struct usb_serial_device_type belkin_sa_device = {
+ name: "Belkin F5U103 USB Serial Adapter",
+ idVendor: &belkin_sa_vendor_id, /* the Belkin vendor ID */
+ idProduct: &belkin_sa_product_id, /* the Belkin F5U103 product id */
+ needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */
+ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
+ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
+ num_interrupt_in: 1,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: belkin_sa_open,
+ close: belkin_sa_close,
+ read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */
+ ioctl: belkin_sa_ioctl,
+ set_termios: belkin_sa_set_termios,
+ break_ctl: belkin_sa_break_ctl,
+ startup: belkin_sa_startup,
+ shutdown: belkin_sa_shutdown,
+};
+
+
+/* This driver also supports the "old" school Belkin single port adaptor */
+static __u16 belkin_old_vendor_id = BELKIN_OLD_VID;
+static __u16 belkin_old_product_id = BELKIN_OLD_PID;
+struct usb_serial_device_type belkin_old_device = {
+ name: "Belkin USB Serial Adapter",
+ idVendor: &belkin_old_vendor_id, /* the Belkin vendor ID */
+ idProduct: &belkin_old_product_id, /* the Belkin product id */
+ needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */
+ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
+ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
+ num_interrupt_in: 1,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: belkin_sa_open,
+ close: belkin_sa_close,
+ read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */
+ ioctl: belkin_sa_ioctl,
+ set_termios: belkin_sa_set_termios,
+ break_ctl: belkin_sa_break_ctl,
+ startup: belkin_sa_startup,
+ shutdown: belkin_sa_shutdown,
+};
+
+/* this driver also works for the Peracom single port adapter */
+static __u16 peracom_vendor_id = PERACOM_VID;
+static __u16 peracom_product_id = PERACOM_PID;
+struct usb_serial_device_type peracom_device = {
+ name: "Peracom single port USB Serial Adapter",
+ idVendor: &peracom_vendor_id, /* the Peracom vendor ID */
+ idProduct: &peracom_product_id, /* the Peracom product id */
+ needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */
+ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */
+ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */
+ num_interrupt_in: 1,
+ num_bulk_in: 1,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: belkin_sa_open,
+ close: belkin_sa_close,
+ read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */
+ ioctl: belkin_sa_ioctl,
+ set_termios: belkin_sa_set_termios,
+ break_ctl: belkin_sa_break_ctl,
+ startup: belkin_sa_startup,
+ shutdown: belkin_sa_shutdown,
+};
+
+
+struct belkin_sa_private {
+ unsigned long control_state;
+ unsigned char last_lsr;
+ unsigned char last_msr;
+ int bad_flow_control;
+};
+
+
+/*
+ * ***************************************************************************
+ * Belkin USB Serial Adapter F5U103 specific driver functions
+ * ***************************************************************************
+ */
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+/* assumes that struct usb_serial *serial is available */
+#define BSA_USB_CMD(c,v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \
+ (c), BELKIN_SA_SET_REQUEST_TYPE, \
+ (v), 0, NULL, 0, WDR_TIMEOUT)
+
+/* do some startup allocations not currently performed by usb_serial_probe() */
+static int belkin_sa_startup (struct usb_serial *serial)
+{
+ struct usb_device *dev = serial->dev;
+ struct belkin_sa_private *priv;
+
+ /* allocate the private data structure */
+ serial->port->private = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL);
+ if (!serial->port->private)
+ return (-1); /* error */
+ priv = (struct belkin_sa_private *)serial->port->private;
+ /* set initial values for control structures */
+ priv->control_state = 0;
+ priv->last_lsr = 0;
+ priv->last_msr = 0;
+ /* see comments at top of file */
+ priv->bad_flow_control = (dev->descriptor.bcdDevice <= 0x0206) ? 1 : 0;
+ info("bcdDevice: %04x, bfc: %d", dev->descriptor.bcdDevice, priv->bad_flow_control);
+
+ init_waitqueue_head(&serial->port->write_wait);
+
+ return (0);
+}
+
+
+static void belkin_sa_shutdown (struct usb_serial *serial)
+{
+ int i;
+
+ dbg (__FUNCTION__);
+
+ /* stop reads and writes on all ports */
+ for (i=0; i < serial->num_ports; ++i) {
+ while (serial->port[i].open_count > 0) {
+ belkin_sa_close (&serial->port[i], NULL);
+ }
+ /* My special items, the standard routines free my urbs */
+ if (serial->port->private)
+ kfree(serial->port->private);
+ }
+}
+
+
+static int belkin_sa_open (struct usb_serial_port *port, struct file *filp)
+{
+ unsigned long flags;
+
+ dbg(__FUNCTION__" port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ ++port->open_count;
+ MOD_INC_USE_COUNT;
+
+ if (!port->active) {
+ port->active = 1;
+
+ /*Start reading from the device*/
+ /* TODO: Look at possibility of submitting mulitple URBs to device to
+ * enhance buffering. Win trace shows 16 initial read URBs.
+ */
+ port->read_urb->dev = port->serial->dev;
+ if (usb_submit_urb(port->read_urb))
+ err("usb_submit_urb(read bulk) failed");
+
+ port->interrupt_in_urb->dev = port->serial->dev;
+ if (usb_submit_urb(port->interrupt_in_urb))
+ err(" usb_submit_urb(read int) failed");
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return 0;
+} /* belkin_sa_open */
+
+
+static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
+{
+ unsigned long flags;
+
+ dbg(__FUNCTION__" port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ --port->open_count;
+ MOD_DEC_USE_COUNT;
+
+ if (port->open_count <= 0) {
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb); /* wgg - do I need this? I think so. */
+ port->active = 0;
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+} /* belkin_sa_close */
+
+
+static void belkin_sa_read_int_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+
+ /* the urb might have been killed. */
+ if (urb->status)
+ return;
+
+ if (port_paranoia_check (port, "belkin_sa_read_interrupt")) return;
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "belkin_sa_read_interrupt")) return;
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+ /* Handle known interrupt data */
+ /* ignore data[0] and data[1] */
+
+ priv->last_msr = data[BELKIN_SA_MSR_INDEX];
+
+ /* Record Control Line states */
+ if (priv->last_msr & BELKIN_SA_MSR_DSR)
+ priv->control_state |= TIOCM_DSR;
+ else
+ priv->control_state &= ~TIOCM_DSR;
+
+ if (priv->last_msr & BELKIN_SA_MSR_CTS)
+ priv->control_state |= TIOCM_CTS;
+ else
+ priv->control_state &= ~TIOCM_CTS;
+
+ if (priv->last_msr & BELKIN_SA_MSR_RI)
+ priv->control_state |= TIOCM_RI;
+ else
+ priv->control_state &= ~TIOCM_RI;
+
+ if (priv->last_msr & BELKIN_SA_MSR_CD)
+ priv->control_state |= TIOCM_CD;
+ else
+ priv->control_state &= ~TIOCM_CD;
+
+ /* Now to report any errors */
+ priv->last_lsr = data[BELKIN_SA_LSR_INDEX];
+#if 0
+ /*
+ * fill in the flip buffer here, but I do not know the relation
+ * to the current/next receive buffer or characters. I need
+ * to look in to this before committing any code.
+ */
+ if (priv->last_lsr & BELKIN_SA_LSR_ERR) {
+ tty = port->tty;
+ /* Overrun Error */
+ if (priv->last_lsr & BELKIN_SA_LSR_OE) {
+ }
+ /* Parity Error */
+ if (priv->last_lsr & BELKIN_SA_LSR_PE) {
+ }
+ /* Framing Error */
+ if (priv->last_lsr & BELKIN_SA_LSR_FE) {
+ }
+ /* Break Indicator */
+ if (priv->last_lsr & BELKIN_SA_LSR_BI) {
+ }
+ }
+#endif
+
+ /* INT urbs are automatically re-submitted */
+}
+
+static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+ struct usb_serial *serial = port->serial;
+ struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+ unsigned int iflag = port->tty->termios->c_iflag;
+ unsigned int cflag = port->tty->termios->c_cflag;
+ unsigned int old_iflag = old_termios->c_iflag;
+ unsigned int old_cflag = old_termios->c_cflag;
+ __u16 urb_value; /* Will hold the new flags */
+
+ /* Set the baud rate */
+ if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
+ /* reassert DTR and (maybe) RTS on transition from B0 */
+ if( (old_cflag&CBAUD) == B0 ) {
+ priv->control_state |= (TIOCM_DTR|TIOCM_RTS);
+ if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0)
+ err("Set DTR error");
+ /* don't set RTS if using hardware flow control */
+ if (!(old_cflag&CRTSCTS) )
+ if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
+ err("Set RTS error");
+ }
+
+ switch(cflag & CBAUD) {
+ case B0: /* handled below */ break;
+ case B300: urb_value = BELKIN_SA_BAUD(300); break;
+ case B600: urb_value = BELKIN_SA_BAUD(600); break;
+ case B1200: urb_value = BELKIN_SA_BAUD(1200); break;
+ case B2400: urb_value = BELKIN_SA_BAUD(2400); break;
+ case B4800: urb_value = BELKIN_SA_BAUD(4800); break;
+ case B9600: urb_value = BELKIN_SA_BAUD(9600); break;
+ case B19200: urb_value = BELKIN_SA_BAUD(19200); break;
+ case B38400: urb_value = BELKIN_SA_BAUD(38400); break;
+ case B57600: urb_value = BELKIN_SA_BAUD(57600); break;
+ case B115200: urb_value = BELKIN_SA_BAUD(115200); break;
+ case B230400: urb_value = BELKIN_SA_BAUD(230400); break;
+ default: err("BELKIN USB Serial Adapter: unsupported baudrate request, using default of 9600");
+ urb_value = BELKIN_SA_BAUD(9600); break;
+ }
+ if ((cflag & CBAUD) != B0 ) {
+ if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
+ err("Set baudrate error");
+ } else {
+ /* Disable flow control */
+ if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0)
+ err("Disable flowcontrol error");
+
+ /* Drop RTS and DTR */
+ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
+ err("DTR LOW error");
+ if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
+ err("RTS LOW error");
+ }
+ }
+
+ /* set the parity */
+ if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) {
+ if (cflag & PARENB)
+ urb_value = (cflag & PARODD) ? BELKIN_SA_PARITY_ODD : BELKIN_SA_PARITY_EVEN;
+ else
+ urb_value = BELKIN_SA_PARITY_NONE;
+ if (BSA_USB_CMD(BELKIN_SA_SET_PARITY_REQUEST, urb_value) < 0)
+ err("Set parity error");
+ }
+
+ /* set the number of data bits */
+ if( (cflag&CSIZE) != (old_cflag&CSIZE) ) {
+ switch (cflag & CSIZE) {
+ case CS5: urb_value = BELKIN_SA_DATA_BITS(5); break;
+ case CS6: urb_value = BELKIN_SA_DATA_BITS(6); break;
+ case CS7: urb_value = BELKIN_SA_DATA_BITS(7); break;
+ case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break;
+ default: err("CSIZE was not CS5-CS8, using default of 8");
+ urb_value = BELKIN_SA_DATA_BITS(8);
+ break;
+ }
+ if (BSA_USB_CMD(BELKIN_SA_SET_DATA_BITS_REQUEST, urb_value) < 0)
+ err("Set data bits error");
+ }
+
+ /* set the number of stop bits */
+ if( (cflag&CSTOPB) != (old_cflag&CSTOPB) ) {
+ urb_value = (cflag & CSTOPB) ? BELKIN_SA_STOP_BITS(2) : BELKIN_SA_STOP_BITS(1);
+ if (BSA_USB_CMD(BELKIN_SA_SET_STOP_BITS_REQUEST, urb_value) < 0)
+ err("Set stop bits error");
+ }
+
+ /* Set flow control */
+ if( (iflag&IXOFF) != (old_iflag&IXOFF)
+ || (iflag&IXON) != (old_iflag&IXON)
+ || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
+ urb_value = 0;
+ if ((iflag & IXOFF) || (iflag & IXON))
+ urb_value |= (BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON);
+ else
+ urb_value &= ~(BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON);
+
+ if (cflag & CRTSCTS)
+ urb_value |= (BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS);
+ else
+ urb_value &= ~(BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS);
+
+ if (priv->bad_flow_control)
+ urb_value &= ~(BELKIN_SA_FLOW_IRTS);
+
+ if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0)
+ err("Set flow control error");
+ }
+} /* belkin_sa_set_termios */
+
+
+static void belkin_sa_break_ctl( struct usb_serial_port *port, int break_state )
+{
+ struct usb_serial *serial = port->serial;
+
+ if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0)
+ err("Set break_ctl %d", break_state);
+}
+
+
+static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = port->serial;
+ __u16 urb_value; /* Will hold the new flags */
+ struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+ int ret, mask;
+
+ /* Based on code from acm.c and others */
+ switch (cmd) {
+ case TIOCMGET:
+ return put_user(priv->control_state, (unsigned long *) arg);
+ break;
+
+ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+ case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+ case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+
+ if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
+ /* RTS needs set */
+ urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || (cmd == TIOCMBIS) ? 1 : 0;
+ if (urb_value)
+ priv->control_state |= TIOCM_RTS;
+ else
+ priv->control_state &= ~TIOCM_RTS;
+
+ if ((ret = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, urb_value)) < 0) {
+ err("Set RTS error %d", ret);
+ return(ret);
+ }
+ }
+
+ if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
+ /* DTR needs set */
+ urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || (cmd == TIOCMBIS) ? 1 : 0;
+ if (urb_value)
+ priv->control_state |= TIOCM_DTR;
+ else
+ priv->control_state &= ~TIOCM_DTR;
+ if ((ret = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, urb_value)) < 0) {
+ err("Set DTR error %d", ret);
+ return(ret);
+ }
+ }
+ break;
+
+ case TIOCMIWAIT:
+ /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+ /* TODO */
+ return( 0 );
+
+ case TIOCGICOUNT:
+ /* return count of modemline transitions */
+ /* TODO */
+ return 0;
+
+ default:
+ dbg("belkin_sa_ioctl arg not supported - 0x%04x",cmd);
+ return(-ENOIOCTLCMD);
+ break;
+ }
+ return 0;
+} /* belkin_sa_ioctl */
+
+
+static int __init belkin_sa_init (void)
+{
+ usb_serial_register (&belkin_sa_device);
+ usb_serial_register (&belkin_old_device);
+ usb_serial_register (&peracom_device);
+ return 0;
+}
+
+
+static void __exit belkin_sa_exit (void)
+{
+ usb_serial_deregister (&belkin_sa_device);
+ usb_serial_deregister (&belkin_old_device);
+ usb_serial_deregister (&peracom_device);
+}
+
+
+module_init (belkin_sa_init);
+module_exit(belkin_sa_exit);
+
+MODULE_DESCRIPTION("USB Belkin Serial converter driver");
--- /dev/null
+/*
+ * Definitions for Belkin USB Serial Adapter Driver
+ *
+ * Copyright (C) 2000
+ * William Greathouse (wgreathouse@smva.com)
+ *
+ * This program is largely derived from work by the linux-usb group
+ * and associated source files. Please see the usb/serial files for
+ * individual credits and copyrights.
+ *
+ * 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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (11/06/2000) gkh
+ * Added old Belkin and Peracom device ids, which this driver supports
+ *
+ * 12-Oct-2000 William Greathouse
+ * First cut at supporting Belkin USB Serial Adapter F5U103
+ * I did not have a copy of the original work to support this
+ * adapter, so pardon any stupid mistakes. All of the information
+ * I am using to write this driver was acquired by using a modified
+ * UsbSnoop on Windows2000.
+ *
+ */
+
+#ifndef __LINUX_USB_SERIAL_BSA_H
+#define __LINUX_USB_SERIAL_BSA_H
+
+#define BELKIN_SA_VID 0x050d /* Vendor Id */
+#define BELKIN_SA_PID 0x0103 /* Product Id */
+
+#define BELKIN_OLD_VID 0x056c /* Belkin's "old" vendor id */
+#define BELKIN_OLD_PID 0x8007 /* Belkin's "old" single port serial converter's id */
+
+#define PERACOM_VID 0x0565 /* Peracom's vendor id */
+#define PERACOM_PID 0x0001 /* Peracom's single port serial converter's id */
+
+/* Vendor Request Interface */
+#define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */
+#define BELKIN_SA_SET_STOP_BITS_REQUEST 1 /* Set stop bits (1,2) */
+#define BELKIN_SA_SET_DATA_BITS_REQUEST 2 /* Set data bits (5,6,7,8) */
+#define BELKIN_SA_SET_PARITY_REQUEST 3 /* Set parity (None, Even, Odd) */
+
+#define BELKIN_SA_SET_DTR_REQUEST 10 /* Set DTR state */
+#define BELKIN_SA_SET_RTS_REQUEST 11 /* Set RTS state */
+#define BELKIN_SA_SET_BREAK_REQUEST 12 /* Set BREAK state */
+
+#define BELKIN_SA_SET_FLOW_CTRL_REQUEST 16 /* Set flow control mode */
+
+
+#ifdef WHEN_I_LEARN_THIS
+#define BELKIN_SA_SET_MAGIC_REQUEST 17 /* I don't know, possibly flush */
+ /* (always in Wininit sequence before flow control) */
+#define BELKIN_SA_RESET xx /* Reset the port */
+#define BELKIN_SA_GET_MODEM_STATUS xx /* Force return of modem status register */
+#endif
+
+#define BELKIN_SA_SET_REQUEST_TYPE 0x40
+
+#define BELKIN_SA_BAUD(b) (230400/b)
+
+#define BELKIN_SA_STOP_BITS(b) (b-1)
+
+#define BELKIN_SA_DATA_BITS(b) (b-5)
+
+#define BELKIN_SA_PARITY_NONE 0
+#define BELKIN_SA_PARITY_EVEN 1
+#define BELKIN_SA_PARITY_ODD 2
+#define BELKIN_SA_PARITY_MARK 3
+#define BELKIN_SA_PARITY_SPACE 4
+
+#define BELKIN_SA_FLOW_NONE 0x0000 /* No flow control */
+#define BELKIN_SA_FLOW_OCTS 0x0001 /* use CTS input to throttle output */
+#define BELKIN_SA_FLOW_ODSR 0x0002 /* use DSR input to throttle output */
+#define BELKIN_SA_FLOW_IDSR 0x0004 /* use DSR input to enable receive */
+#define BELKIN_SA_FLOW_IDTR 0x0008 /* use DTR output for input flow control */
+#define BELKIN_SA_FLOW_IRTS 0x0010 /* use RTS output for input flow control */
+#define BELKIN_SA_FLOW_ORTS 0x0020 /* use RTS to indicate data available to send */
+#define BELKIN_SA_FLOW_ERRSUB 0x0040 /* ???? guess ???? substitute inline errors */
+#define BELKIN_SA_FLOW_OXON 0x0080 /* use XON/XOFF for output flow control */
+#define BELKIN_SA_FLOW_IXON 0x0100 /* use XON/XOFF for input flow control */
+
+/*
+ * It seems that the interrupt pipe is closely modelled after the
+ * 16550 register layout. This is probably because the adapter can
+ * be used in a "DOS" environment to simulate a standard hardware port.
+ */
+#define BELKIN_SA_LSR_INDEX 2 /* Line Status Register */
+#define BELKIN_SA_LSR_RDR 0x01 /* receive data ready */
+#define BELKIN_SA_LSR_OE 0x02 /* overrun error */
+#define BELKIN_SA_LSR_PE 0x04 /* parity error */
+#define BELKIN_SA_LSR_FE 0x08 /* framing error */
+#define BELKIN_SA_LSR_BI 0x10 /* break indicator */
+#define BELKIN_SA_LSR_THE 0x20 /* transmit holding register empty */
+#define BELKIN_SA_LSR_TE 0x40 /* transmit register empty */
+#define BELKIN_SA_LSR_ERR 0x80 /* OE | PE | FE | BI */
+
+#define BELKIN_SA_MSR_INDEX 3 /* Modem Status Register */
+#define BELKIN_SA_MSR_DCTS 0x01 /* Delta CTS */
+#define BELKIN_SA_MSR_DDSR 0x02 /* Delta DSR */
+#define BELKIN_SA_MSR_DRI 0x04 /* Delta RI */
+#define BELKIN_SA_MSR_DCD 0x08 /* Delta CD */
+#define BELKIN_SA_MSR_CTS 0x10 /* Current CTS */
+#define BELKIN_SA_MSR_DSR 0x20 /* Current DSR */
+#define BELKIN_SA_MSR_RI 0x40 /* Current RI */
+#define BELKIN_SA_MSR_CD 0x80 /* Current CD */
+
+#endif /* __LINUX_USB_SERIAL_BSA_H */
+
#include <linux/pm.h>
static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data);
+static void dl_del_list (ohci_t * ohci, unsigned int frame);
#ifdef CONFIG_PMAC_PBOOK
+#include <asm/prom.h>
#include <asm/adb.h>
#include <asm/pmu.h>
+#include <asm/feature.h>
#endif
urb_priv_t * urb_priv = urb->hcpriv;
urb_priv->state = URB_DEL;
+ /* we need to do this *before* we can possibly
+ * get the interrupt which will wake us up. */
+ if (!(urb->transfer_flags & USB_ASYNC_UNLINK)
+ && !in_interrupt() && !ohci->disabled) {
+ add_wait_queue (&op_wakeup, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
+ }
+
/* we want to delete the TDs of an URB from an ed
* request the deletion, it will be handled at the
* next USB-frame */
urb_priv->ed->state |= ED_URB_DEL;
spin_unlock_irqrestore (&usb_ed_lock, flags);
if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
- usb_dec_dev_use (urb->dev);
- add_wait_queue (&op_wakeup, &wait);
- current->state = TASK_UNINTERRUPTIBLE;
- if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
- err("unlink URB timeout!");
- remove_wait_queue (&op_wakeup, &wait);
- urb->status = -ENOENT;
+ if (ohci->disabled) {
+ /* Need to handle that case */
+ } else if (in_interrupt()) {
+ volatile u16* frame_p = (volatile u16*)&ohci->hcca.frame_no;
+ u16 frame_prev, frame, count;
+ count = 0;
+ writel (OHCI_INTR_SF, &ohci->regs->intrdisable);
+ frame_prev = le16_to_cpu(*frame_p) & 1;
+ do {
+ mb();
+ frame = le16_to_cpu(*frame_p) & 1;
+ if (frame != frame_prev) {
+ if (ohci->ed_rm_list[!frame] != NULL)
+ dl_del_list (ohci, !frame);
+ frame_prev = frame;
+ count++;
+ }
+ } while(count < 2);
+ writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+ urb->status = -ENOENT;
+ usb_dec_dev_use (urb->dev);
+ } else {
+ if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */
+ err("unlink URB timeout!");
+ remove_wait_queue (&op_wakeup, &wait);
+ urb->status = -ENOENT;
+ usb_dec_dev_use (urb->dev);
+ }
} else {
/* usb_dec_dev_use done in dl_del_list() */
urb->status = -EINPROGRESS;
volatile ed_t * ed = edi;
ed->state = ED_OPER;
+ ed->hwNextED = 0;
+ wmb();
switch (ed->type) {
case CTRL:
- ed->hwNextED = 0;
if (ohci->ed_controltail == NULL) {
writel (virt_to_bus (ed), &ohci->regs->ed_controlhead);
} else {
break;
case BULK:
- ed->hwNextED = 0;
if (ohci->ed_bulktail == NULL) {
writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead);
} else {
ed->int_interval = interval;
int_branch = ep_int_ballance (ohci, interval, load);
ed->int_branch = int_branch;
-
+
for (i = 0; i < ep_rev (6, interval); i += inter) {
inter = 1;
for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]);
ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED))
inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
ed->hwNextED = *ed_p;
+ wmb();
*ed_p = cpu_to_le32 (virt_to_bus (ed));
}
#ifdef DEBUG
break;
case ISO:
- ed->hwNextED = 0;
ed->int_interval = 1;
if (ohci->ed_isotail != NULL) {
ohci->ed_isotail->hwNextED = cpu_to_le32 (virt_to_bus (ed));
inter = 1;
for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]);
*ed_p != 0;
- ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED))
+ ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED))
inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval);
*ed_p = cpu_to_le32 (virt_to_bus (ed));
}
td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt));
td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000);
td_pt->hwNextTD = 0;
+ wmb();
td->ed->hwTailP = td->hwNextTD;
td->next_dl_td = NULL; //td_pt;
TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
cnt++;
+ wmb();
writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
break;
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
td_fill (info, NULL, 0, urb, cnt++);
+ wmb();
writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
break;
}
if (ints & OHCI_INTR_WDH) {
- writel (OHCI_INTR_WDH, ®s->intrdisable);
+ writel (OHCI_INTR_WDH, ®s->intrdisable);
+ (void)readl(®s->intrdisable); // PCI write posting will hurt you
dl_done_list (ohci, dl_reverse_done_list (ohci));
writel (OHCI_INTR_WDH, ®s->intrenable);
}
if (ints & OHCI_INTR_SF) {
unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1;
writel (OHCI_INTR_SF, ®s->intrdisable);
+ (void)readl(®s->intrdisable); // PCI write posting will hurt you
if (ohci->ed_rm_list[!frame] != NULL) {
dl_del_list (ohci, !frame);
}
if (!ohci) {
return -ENOMEM;
}
+ ohci->pci_dev = dev;
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
{
struct list_head * ohci_l;
ohci_t * ohci;
-
- for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
- ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
-
+
+ for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list;
+ ohci_l = ohci_l->next) {
+ struct device_node* node;
+ ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
+ node = find_pci_device_OFnode(ohci->pci_dev->bus->number,
+ ohci->pci_dev->devfn);
switch (when) {
case PBOOK_SLEEP_NOW:
+ /* We should make sure processing of current frames have
+ * finished and WDH has been porcessed
+ */
+ dbg("USB suspend: %p", ohci->regs);
disable_irq (ohci->irq);
- writel (ohci->hc_control = OHCI_USB_SUSPEND, &ohci->regs->control);
- wait_ms (10);
+
+ ohci->hc_control &= ~(OHCI_CTRL_CLE | OHCI_CTRL_BLE | OHCI_CTRL_PLE | OHCI_CTRL_IE);
+ writel (ohci->hc_control, &ohci->regs->control);
+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+ (void)readl(&ohci->regs->intrstatus);
+ mdelay(2);
+
+ ohci->hc_control = OHCI_USB_SUSPEND;
+ writel (ohci->hc_control, &ohci->regs->control);
+ mdelay (10);
+ ohci->disabled = 1;
+ if (node)
+ feature_set_usb_power(node, 0);
break;
case PBOOK_WAKE:
- writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control);
- wait_ms (20);
+ /* did we suspend, or were we powered off? */
+ if (node)
+ feature_set_usb_power(node, 1);
+ mdelay(100);
+ ohci->disabled = 0;
+ ohci->hc_control = OHCI_USB_RESUME;
+ writel (ohci->hc_control, &ohci->regs->control);
+ mdelay (35);
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
writel (ohci->hc_control, &ohci->regs->control);
enable_irq (ohci->irq);
}
static struct pmu_sleep_notifier ohci_sleep_notifier = {
- ohci_sleep_notify, SLEEP_LEVEL_MISC,
+ ohci_sleep_notify, SLEEP_LEVEL_USB,
};
#endif /* CONFIG_PMAC_PBOOK */
{
int ret = -ENODEV;
struct pci_dev * dev = NULL;
-
+
while ((dev = pci_find_class (PCI_CLASS_SERIAL_USB_OHCI, dev))) {
if (hc_start_ohci(dev) >= 0) ret = 0;
}
-
+
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier (&ohci_sleep_notifier);
#endif
struct usb_bus * bus;
struct usb_device * dev[128];
struct virt_root_hub rh;
+ struct pci_dev *pci_dev;
} ohci_t;
#define OVR_CLR 0x0230
#define OVR_WID_LEFT_RIGHT 0x0234
#define OVR_WID_TOP_BOTTOM 0x0238
+#define LVDS_GEN_CNTL 0x02d0
#define DDA_CONFIG 0x02e0
#define DDA_ON_OFF 0x02e4
#define VGA_DDA_CONFIG 0x02e8
#define VGA_DDA_ON_OFF 0x02ec
+#define CRTC2_GEN_CNTL 0x03f8
#define OV0_SCALE_CNTL 0x0420
#define SUBPIC_CNTL 0x0540
#define PM4_BUFFER_OFFSET 0x0700
#define PLL_WR_EN 0x00000080
+/* PLL registers */
#define CLK_PIN_CNTL 0x0001
#define PPLL_CNTL 0x0002
#define PPLL_REF_DIV 0x0003
#define AGP_PLL_CNTL 0x0010
#define FCP_CNTL 0x0012
#define PLL_TEST_CNTL 0x0013
+#define POWER_MANAGEMENT 0x002f
#define PPLL_RESET 0x01
#define PPLL_ATOMIC_UPDATE_EN 0x10000
#define DAC_MASK 0xFF000000
#define DAC_BLANKING 0x00000004
#define DAC_RANGE_CNTL 0x00000003
-#define PALETTE_ACCESS_CNTL 0x00000020
+#define DAC_PALETTE_ACCESS_CNTL 0x00000020
+#define DAC_PDWN 0x00008000
/* GEN_RESET_CNTL bit constants */
#define SOFT_RESET_GUI 0x00000001
#define DP_SRC_HOST 0x00000300
#define DP_SRC_HOST_BYTEALIGN 0x00000400
+/* LVDS_GEN_CNTL constants */
+#define LVDS_BL_MOD_LEVEL_MASK 0x0000ff00
+#define LVDS_BL_MOD_LEVEL_SHIFT 8
+#define LVDS_BL_MOD_EN 0x00010000
+#define LVDS_DIGION 0x00040000
+#define LVDS_BLON 0x00080000
+#define LVDS_ON 0x00000001
+#define LVDS_DISPLAY_DIS 0x00000002
+#define LVDS_PANEL_TYPE_2PIX_PER_CLK 0x00000004
+#define LVDS_PANEL_24BITS_TFT 0x00000008
+#define LVDS_FRAME_MOD_NO 0x00000000
+#define LVDS_FRAME_MOD_2_LEVELS 0x00000010
+#define LVDS_FRAME_MOD_4_LEVELS 0x00000020
+#define LVDS_EN 0x00000080
+
+/* CRTC2_GEN_CNTL constants */
+#define CRTC2_EN 0x02000000
+
+/* POWER_MANAGEMENT constants */
+#define PWR_MGT_ON 0x00000001
+#define PWR_MGT_MODE_MASK 0x00000006
+#define PWR_MGT_MODE_PIN 0x00000000
+#define PWR_MGT_MODE_REGISTER 0x00000002
+#define PWR_MGT_MODE_TIMER 0x00000004
+#define PWR_MGT_MODE_PCI 0x00000006
+#define PWR_MGT_AUTO_PWR_UP_EN 0x00000008
+#define PWR_MGT_ACTIVITY_PIN_ON 0x00000010
+#define PWR_MGT_STANDBY_POL 0x00000020
+#define PWR_MGT_SUSPEND_POL 0x00000040
+#define PWR_MGT_SELF_REFRESH 0x00000080
+#define PWR_MGT_ACTIVITY_PIN_EN 0x00000100
+#define PWR_MGT_KEYBD_SNOOP 0x00000200
+#define PWR_MGT_TRISTATE_MEM_EN 0x00000800
+#define PWR_MGT_SELW4MS 0x00001000
+#define PWR_MGT_SLOWDOWN_MCLK 0x00002000
+
+#define PMI_PMSCR_REG 0x60
+
#endif /* REG_RAGE128_H */
#include <asm/pci-bridge.h>
#include <linux/nvram.h>
#include <video/macmodes.h>
+#include <asm/adb.h>
+#include <asm/pmu.h>
+#include <asm/backlight.h>
#endif
#ifdef CONFIG_FB_COMPAT_XPMAC
struct display disp;
struct display_switch dispsw; /* for cursor and font */
struct { u8 red, green, blue, pad; } palette[256];
+#ifdef CONFIG_PMAC_PBOOK
+ unsigned char *save_framebuffer;
+#endif
union {
#ifdef FBCON_HAS_CFB16
u16 cfb16[16];
static struct fb_info_aty128 *board_list = NULL;
+#ifdef CONFIG_PMAC_PBOOK
+ int aty128_sleep_notify(struct pmu_sleep_notifier *self, int when);
+ static struct pmu_sleep_notifier aty128_sleep_notifier = {
+ aty128_sleep_notify, SLEEP_LEVEL_VIDEO,
+ };
+#endif
+
+
+
#define round_div(n, d) ((n+(d/2))/d)
/*
const struct fb_info_aty128 *info);
static struct fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128
*board_list, struct fb_info_aty128 *new_node);
+#ifndef CONFIG_FB_OF
static int aty128find_ROM(struct fb_info_aty128 *info);
+#endif
#ifndef CONFIG_PPC
static void aty128_get_pllinfo(struct fb_info_aty128 *info);
#endif
aty128fb_set_cmap, aty128fb_pan_display, aty128fb_ioctl
};
+#ifdef CONFIG_PPC
+static int aty128_set_backlight_enable(int on, int level, void* data);
+static int aty128_set_backlight_level(int level, void* data);
+
+static struct backlight_controller aty128_backlight_controller = {
+ aty128_set_backlight_enable,
+ aty128_set_backlight_level
+};
+#endif
/*
* Functions to read from/write to the mmio registers
#else
memset(&var, 0, sizeof(var));
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_FB_OF
if (default_vmode == VMODE_CHOOSE) {
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_FB_OF */
var = default_var;
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_FB_OF
+ /* New iBook */
+ if (machine_is_compatible("PowerBook2,2"))
+ default_vmode = VMODE_800_600_60;
} else {
if (mac_vmode_to_var(default_vmode, default_cmode, &var))
var = default_var;
}
-#endif /* CONFIG_PMAC */
+#endif /* CONFIG_FB_OF */
#endif /* MODULE */
if (register_framebuffer(&info->fb_info) < 0)
return 0;
+#ifdef CONFIG_PPC
+ if (info->chip_gen == rage_M3)
+ register_backlight_controller(&aty128_backlight_controller, info, "ati");
+#endif
+#ifdef CONFIG_PMAC_PBOOK
+ pmu_register_sleep_notifier(&aty128_sleep_notifier);
+#endif
+
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
GET_FB_IDX(info->fb_info.node), aty128fb_name, name);
}
#endif /* ! CONFIG_FB_OF */
+#ifndef CONFIG_FB_OF
static int __init
aty128find_ROM(struct fb_info_aty128 *info)
{
#endif /* !CONFIG_PPC */
return (flag);
}
+#endif /* CONFIG_FB_OF */
#ifndef CONFIG_PPC
static void __init
u8 bus, devfn;
u16 cmd;
- if (device_is_compatible(dp, "ATY,RageM3p")) {
- /* XXX kludge for now */
- if (dp->name == 0 || strcmp(dp->name, "ATY,RageM3pA") != 0
- || dp->parent == 0)
- return;
- dp = dp->parent;
- }
+ if (dp->name && !strcmp(dp->name, "ATY,RageM3pA") && dp->parent)
+ dp = dp->parent;
+ if (dp->name && !strcmp(dp->name, "ATY,RageM3pB"))
+ return;
switch (dp->n_addrs) {
case 3:
struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb;
u8 state = 0;
+#if defined(CONFIG_PPC)
+ if ((_machine == _MACH_Pmac) && blank)
+ set_backlight_enable(0);
+#endif
+
if (blank & VESA_VSYNC_SUSPEND)
state |= 2;
if (blank & VESA_HSYNC_SUSPEND)
state |= 4;
aty_st_8(CRTC_EXT_CNTL+1, state);
+
+#if defined(CONFIG_PPC)
+ if ((_machine == _MACH_Pmac) && !blank)
+ set_backlight_enable(1);
+#endif
}
int i;
if (info->chip_gen == rage_M3)
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL);
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL);
for (i=16; i<256; i++) {
aty_st_8(PALETTE_INDEX, i);
}
if (info->chip_gen == rage_M3) {
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL);
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL);
for (i=16; i<256; i++) {
aty_st_8(PALETTE_INDEX, i);
/* initialize palette */
if (info->chip_gen == rage_M3)
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL);
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL);
if (info->current_par.crtc.bpp == 16)
aty_st_8(PALETTE_INDEX, (regno << 3));
col = (red << 16) | (green << 8) | blue;
aty_st_le32(PALETTE_DATA, col);
if (info->chip_gen == rage_M3) {
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL);
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL);
if (info->current_par.crtc.bpp == 16)
aty_st_8(PALETTE_INDEX, (regno << 3));
else
}
}
+#ifdef CONFIG_PPC
+
+static int backlight_conv[] = {
+ 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
+ 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
+};
+
+static int
+aty128_set_backlight_enable(int on, int level, void* data)
+{
+ struct fb_info_aty128 *info = (struct fb_info_aty128 *)data;
+ unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
+
+ reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+ if (on && level > BACKLIGHT_OFF) {
+ reg |= LVDS_ON | LVDS_EN;
+ reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+ reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+ reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
+ } else {
+ reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+ reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
+ reg &= ~(LVDS_ON | LVDS_EN);
+ }
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+
+ return 0;
+}
+
+static int
+aty128_set_backlight_level(int level, void* data)
+{
+ return aty128_set_backlight_enable(1, level, data);
+}
+
+#endif
/*
* Accelerated functions
wait_for_fifo(2, info);
aty_st_le32(DP_DATATYPE, save_dp_datatype);
aty_st_le32(DP_CNTL, save_dp_cntl);
+}
- wait_for_idle(info);
+
+#ifdef CONFIG_PMAC_PBOOK
+
+static void
+aty128_set_suspend(struct fb_info_aty128 *info, int suspend)
+{
+ u32 pmgt;
+
+ /* Set the chip into the appropriate suspend mode (we use D2,
+ * D3 would require a complete re-initialisation of the chip,
+ * including PCI config registers, clocks, AGP configuration, ...)
+ */
+ if (suspend) {
+ /* Set the power management mode to be PCI based */
+ pmgt = aty_ld_pll(POWER_MANAGEMENT);
+ pmgt &= ~PWR_MGT_MODE_MASK;
+ pmgt |= PWR_MGT_MODE_PCI | PWR_MGT_ON | PWR_MGT_AUTO_PWR_UP_EN;
+ aty_st_pll(POWER_MANAGEMENT, pmgt);
+
+ /* Switch PCI power management to D2 */
+ pci_write_config_word(info->pdev, 0x60, 2);
+ //mdelay(10);
+ } else {
+ /* Switch back PCI power management to D0 */
+ mdelay(100);
+ pci_write_config_word(info->pdev, 0x60, 0);
+ mdelay(100);
+ //aty128_set_backlight_enable(1,10,info);
+
+ }
+}
+
+/*
+ * Save the contents of the frame buffer when we go to sleep,
+ * and restore it when we wake up again.
+ */
+int
+aty128_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+ struct fb_info_aty128 *info;
+ int result;
+
+ result = PBOOK_SLEEP_OK;
+
+ for (info = board_list; info != NULL; info = info->next) {
+ struct fb_fix_screeninfo fix;
+ int nb;
+
+ aty128fb_get_fix(&fix, fg_console, (struct fb_info *)info);
+ nb = fb_display[fg_console].var.yres * fix.line_length;
+
+ switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+ if (!info->pdev)
+ return PBOOK_SLEEP_REFUSE;
+ if (info->chip_gen != rage_M3)
+ return PBOOK_SLEEP_REFUSE;
+ info->save_framebuffer = vmalloc(nb);
+ if (info->save_framebuffer == NULL)
+ return PBOOK_SLEEP_REFUSE;
+ break;
+ case PBOOK_SLEEP_REJECT:
+ if (info->save_framebuffer) {
+ vfree(info->save_framebuffer);
+ info->save_framebuffer = 0;
+ }
+ break;
+ case PBOOK_SLEEP_NOW:
+ wait_for_idle(info);
+ aty128_reset_engine(info);
+ wait_for_idle(info);
+
+ /* Backup fb content */
+ if (info->save_framebuffer)
+ memcpy_fromio(info->save_framebuffer,
+ (void *)info->frame_buffer, nb);
+
+ /* Blank display and LCD */
+ aty128fbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
+
+ /* Sleep the chip */
+ aty128_set_suspend(info, 1);
+
+ break;
+ case PBOOK_WAKE:
+ /* Wake the chip */
+ aty128_set_suspend(info, 0);
+
+ /* Test */
+ aty128fbcon_blank(0, (struct fb_info *)info);
+
+ aty128_reset_engine(info);
+ wait_for_idle(info);
+
+ /* Restore fb content */
+ if (info->save_framebuffer) {
+ memcpy_toio((void *)info->frame_buffer,
+ info->save_framebuffer, nb);
+ vfree(info->save_framebuffer);
+ info->save_framebuffer = 0;
+ }
+ /* Restore display */
+ aty128_set_par(&info->current_par, info);
+ aty128fbcon_blank(0, (struct fb_info *)info);
+ break;
+ }
+ }
+ return result;
}
+#endif /* CONFIG_PMAC_PBOOK */
/*
#include <video/macmodes.h>
#include <asm/adb.h>
#include <asm/pmu.h>
+#include <asm/backlight.h>
#endif
#ifdef __sparc__
#include <asm/pbm.h>
#endif
#ifdef CONFIG_PMAC_PBOOK
unsigned char *save_framebuffer;
- unsigned long save_pll[64];
struct fb_info_aty* next;
#endif
};
#endif
};
+#ifdef CONFIG_PPC
+static int aty_set_backlight_enable(int on, int level, void* data);
+static int aty_set_backlight_level(int level, void* data);
+
+static struct backlight_controller aty_backlight_controller = {
+ aty_set_backlight_enable,
+ aty_set_backlight_level
+};
+#endif
+
static char atyfb_name[16] = "ATY Mach64";
static char fontname[40] __initdata = { 0 };
static char curblink __initdata = 1;
aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info)
| (USE_F32KHZ | TRISTATE_MEM_EN), info);
}
+ if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID))
+ register_backlight_controller(&aty_backlight_controller, info, "ati");
if (default_vmode == VMODE_NVRAM) {
#if 0 /* This is not really supported */
#if defined(CONFIG_PPC)
if ((_machine == _MACH_Pmac) && blank)
- pmu_enable_backlight(0);
+ set_backlight_enable(0);
#endif
gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info);
#if defined(CONFIG_PPC)
if ((_machine == _MACH_Pmac) && !blank)
- pmu_enable_backlight(1);
+ set_backlight_enable(1);
#endif
}
}
#endif /* CONFIG_PMAC_PBOOK */
+#ifdef CONFIG_PPC
+static int backlight_conv[] = {
+ 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
+ 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
+};
+
+static int
+aty_set_backlight_enable(int on, int level, void* data)
+{
+ struct fb_info_aty *info = (struct fb_info_aty *)data;
+ unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info);
+
+ reg |= (BLMOD_EN | BIASMOD_EN);
+ if (on && level > BACKLIGHT_OFF) {
+ reg &= ~BIAS_MOD_LEVEL_MASK;
+ reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
+ } else {
+ reg &= ~BIAS_MOD_LEVEL_MASK;
+ reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
+ }
+ aty_st_lcd(LCD_MISC_CNTL, reg, info);
+ return 0;
+}
+
+static int
+aty_set_backlight_level(int level, void* data)
+{
+ return aty_set_backlight_enable(1, level, data);
+}
+#endif /* CONFIG_PPC */
+
+
#ifdef MODULE
int blink = 1;
static int pll = 0;
static int mclk = 0;
#if defined(CONFIG_PPC)
-static int vmode = VMODE_NVRAM;
+static int vmode = VMODE_CHOOSE;
static int cmode = CMODE_NVRAM;
#endif
#include <asm/pci-bridge.h>
#include <asm/adb.h>
#include <asm/pmu.h>
+#include <asm/backlight.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
// used to disable backlight only for blank > 1, but it seems
// useful at blank = 1 too (saves battery, extends backlight life)
if (blank) {
- pmu_enable_backlight(0);
+ set_backlight_enable(0);
/* get the palette from the chip */
for (i = 0; i < 256; ++i) {
out_8(p->io_base + 0x3c7, i);
out_8(p->io_base + 0x3c9, 0);
}
} else {
- pmu_enable_backlight(1);
+ set_backlight_enable(1);
for (i = 0; i < 256; ++i) {
out_8(p->io_base + 0x3c8, i);
udelay(1);
disp->visual = fix->visual;
disp->var = *var;
-#if (defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_FB_COMPAT_XPMAC))
+#ifdef CONFIG_FB_COMPAT_XPMAC
display_info.depth = bpp;
display_info.pitch = fix->line_length;
#endif
memset(p->frame_buffer, 0, 0x100000);
/* turn on the backlight */
- pmu_enable_backlight(1);
+ set_backlight_enable(1);
init_chips(p);
}
cmap_m64, /* ATI Mach64 */
cmap_r128, /* ATI Rage128 */
cmap_M3A, /* ATI Rage Mobility M3 Head A */
- cmap_M3B /* ATI Rage Mobility M3 Head B */
+ cmap_M3B, /* ATI Rage Mobility M3 Head B */
+ cmap_radeon /* ATI Radeon */
};
struct fb_info_offb {
/* find the device node corresponding to the macos display */
for (dp = displays; dp != NULL; dp = dp->next) {
int i;
+
+ if (!strcmp(dp->name, "offscreen-display"))
+ continue;
+
/*
* Grrr... It looks like the MacOS ATI driver
* munges the assigned-addresses property (but
if (!ofonly) {
for (dp = find_type_devices("display"); dp != NULL; dp = dp->next) {
+ if (!strcmp(dp->name, "offscreen-display"))
+ continue;
for (dpy = 0; dpy < prom_num_displays; dpy++)
if (strcmp(dp->full_name, prom_display_paths[dpy]) == 0)
break;
{
#ifdef CONFIG_FB_ATY128
if (!strncmp(dp->name, "ATY,Rage128", 11) ||
+ !strncmp(dp->name, "ATY,RageM3p1", 12) ||
!strncmp(dp->name, "ATY,RageM3pA", 12)) {
aty128fb_of_init(dp);
return 1;
}
if (!strncmp(dp->name, "ATY,RageM3pB", 12))
- return 0;
+ return 1;
#endif /* CONFIG_FB_ATY128*/
#ifdef CONFIG_FB_ATY
if (!strncmp(dp->name, "ATY", 3)) {
unsigned long regbase = dp->addrs[2].address;
info->cmap_adr = ioremap(regbase, 0x1FFF);
info->cmap_type = cmap_r128;
- } else if (dp && !strncmp(name, "ATY,RageM3pA", 12)) {
+ } else if (dp && (!strncmp(name, "ATY,RageM3pA", 12) ||
+ !strncmp(name, "ATY,RageM3p1", 12))) {
unsigned long regbase = dp->parent->addrs[2].address;
info->cmap_adr = ioremap(regbase, 0x1FFF);
info->cmap_type = cmap_M3A;
unsigned long regbase = dp->parent->addrs[2].address;
info->cmap_adr = ioremap(regbase, 0x1FFF);
info->cmap_type = cmap_M3B;
+ } else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
+ unsigned long regbase = dp->addrs[1].address;
+ info->cmap_adr = ioremap(regbase, 0x1FFF);
+ info->cmap_type = cmap_radeon;
} else if (!strncmp(name, "ATY,", 4)) {
unsigned long base = address & 0xff000000UL;
info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
out_8(info2->cmap_adr + 0xb0, i);
out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
break;
+ case cmap_radeon:
+ out_8(info2->cmap_adr + 0xb0, i);
+ out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0);
+ break;
}
}
else
out_le32((unsigned *)(info2->cmap_adr + 0xb4),
(red << 16 | green << 8 | blue));
break;
+ case cmap_radeon:
+ /* Set palette index & data (could be smarter) */
+ out_8(info2->cmap_adr + 0xb0, regno);
+ out_le32((unsigned *)(info2->cmap_adr + 0xb4),
+ (red << 16 | green << 8 | blue));
+ break;
}
if (regno < 16)
tristate 'NFS server support' CONFIG_NFSD
if [ "$CONFIG_NFSD" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' NFS Version 3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3
+ bool ' NFS server TCP support (VERY EXPERIMENTAL)' CONFIG_NFSD_TCP
fi
if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
define_bool CONFIG_SUNRPC y
if (error < 0)
goto failure;
+#ifdef CONFIG_NFSD_TCP
error = svc_makesock(serv, IPPROTO_TCP, port);
if (error < 0)
goto failure;
+#endif
nfsd_racache_init(); /* Readahead param cache */
"swap %u %u\n"
"intr 1 0",
#else
- "swap %u %u\n"
- "intr %u",
+ "swap %u %u\n"
+ "intr %u",
#endif
kstat.cpu_user,
kstat.cpu_nice,
#ifdef CONFIG_ARCH_S390
kstat.pswpout);
#else
- kstat.pswpout,
+ kstat.pswpout,
sum);
for (i = 0 ; i < NR_IRQS ; i++)
len += sprintf(buffer + len, " %u", kstat_irqs(i));
{
char * orig = buffer;
struct task_struct *tsk;
-#if __s390__
- int line,len;
-#endif
read_lock(&tasklist_lock);
tsk = find_task_by_pid(pid);
buffer = task_sig(tsk, buffer);
buffer = task_cap(tsk, buffer);
#if __s390__
- for(line=0;(len=sprintf_regs(line,buffer,tsk,NULL,NULL))!=0;line++)
- buffer+=len;
+ buffer = task_show_regs(tsk, buffer);
#endif
return buffer - orig;
}
--- /dev/null
+/*
+ * Routines for handling backlight control on PowerBooks
+ *
+ * For now, implementation resides in arch/ppc/kernel/pmac_support.c
+ *
+ */
+#ifndef __ASM_PPC_BACKLIGHT_H
+#define __ASM_PPC_BACKLIGHT_H
+
+/* Abstract values */
+#define BACKLIGHT_OFF 0
+#define BACKLIGHT_MIN 1
+#define BACKLIGHT_MAX 0xf
+
+struct backlight_controller {
+ int (*set_enable)(int enable, int level, void *data);
+ int (*set_level)(int level, void *data);
+};
+
+extern void register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type);
+extern void unregister_backlight_controller(struct backlight_controller *ctrler, void *data);
+
+extern int set_backlight_enable(int enable);
+extern int get_backlight_enable(void);
+extern int set_backlight_level(int level);
+extern int get_backlight_level(void);
+
+#endif
* 2 of the License, or (at your option) any later version.
*/
+extern unsigned long loops_per_jiffy;
+
+/* maximum permitted argument to udelay */
+#define __MAX_UDELAY 1000000
+
extern __inline__ void __delay(unsigned int loops)
{
if (loops != 0)
"r" (loops) : "ctr");
}
-extern __inline__ void udelay(unsigned long usecs)
+/* N.B. the `secs' parameter here is a fixed-point number with
+ the binary point to the left of the most-significant bit. */
+extern __inline__ void __const_udelay(unsigned int secs)
{
- unsigned long loops;
+ unsigned int loops;
- /* compute (usecs * 2^32 / 10^6) * (loops_per_jiffy*HZ) / 2^32 */
- usecs *= 0x10c6; /* 2^32 / 10^6 */
__asm__("mulhwu %0,%1,%2" : "=r" (loops) :
- "r" (usecs), "r" (loops_per_jiffy*HZ));
- __delay(loops);
+ "r" (secs), "r" (loops_per_jiffy));
+ __delay(loops * HZ);
}
+/*
+ * note that 4294 == 2^32 / 10^6, multiplying by 4294 converts from
+ * microseconds to a 32-bit fixed-point number of seconds.
+ */
+extern __inline__ void __udelay(unsigned int usecs)
+{
+ __const_udelay(usecs * 4294);
+}
+
+extern void __bad_udelay(void); /* deliberately undefined */
+
+#define udelay(n) (__builtin_constant_p(n)? \
+ ((n) > __MAX_UDELAY? __bad_udelay(): __const_udelay((n) * 4294u)) : \
+ __udelay(n))
+
#endif /* defined(_PPC_DELAY_H) */
*/
unsigned char ucDmaCmd=0x00;
+#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC)
if(_prep_type==_PREP_Radstone)
{
switch(ucSystemType)
}
}
}
+#endif /* CONFIG_PREP || CONFIG_ALL_PPC */
if (dmanr != 4)
{
FEATURE_IDE2_reset,
FEATURE_Mediabay_IDE_switch, /* MB IDE bus switch */
FEATURE_Mediabay_content, /* MB content indicator enable */
+ FEATURE_Airport_reset, /* Is it actually a reset ? */
FEATURE_last,
};
/* Initialize feature stuff */
extern void feature_init(void);
+/*
+ * Additional functions related to Core99 machines
+ */
+extern void feature_set_gmac_power(struct device_node* device, int power);
+
+ /* use constants in KeyLargo.h for the reset parameter */
+extern void feature_set_gmac_phy_reset(struct device_node* device, int reset);
+
+extern void feature_set_usb_power(struct device_node* device, int power);
+
+extern void feature_set_firewire_power(struct device_node* device, int power);
+
+extern void feature_core99_kick_cpu1(void);
+
+/*
+ * Sleep related functions. At term, they should be high-priority notifiers,
+ * but this would require some changes to the current sleep scheme that won't
+ * be done in 2.2.
+ */
+extern void feature_prepare_for_sleep(void);
+
+extern void feature_wake_up(void);
#endif /* __ASM_PPC_FEATURE_H */
#define HRW_BMAC_IO_ENABLE 0x60000000 /* two bits, not documented in OF */
#define HRW_BMAC_RESET 0x80000000 /* not documented in OF */
+/* We OR those features at boot on desktop G3s */
+#define HRW_DEFAULTS (HRW_SCCA_IO | HRW_SCCB_IO | HRW_SCC_ENABLE)
+
+/* Those seem to be different on paddington */
#define PADD_MODEM_POWER_N 0x00000001 /* modem power on paddington */
+#define PADD_RESET_SCC 0x02000000 /* check this please */
+
#define NUM_8259_INTERRUPTS 16
#define NUM_OPENPIC_INTERRUPTS 20
#define is_8259_irq(n) ((n) < NUM_8259_INTERRUPTS)
-#define openpic_to_irq(n) ((n)+NUM_8259_INTERRUPTS)
-#define irq_to_openpic(n) ((n)-NUM_8259_INTERRUPTS)
#define IRQ_8259_CASCADE NUM_8259_INTERRUPTS
#ifndef CONFIG_APUS
ppc_md.kbd_init_hw();
}
-#define kbd_sysrq_xlate (ppc_md.kbd_sysrq_xlate)
-#define SYSRQ_KEY (ppc_md.SYSRQ_KEY)
+#define kbd_sysrq_xlate (ppc_md.sysrq_xlate)
+extern unsigned long SYSRQ_KEY;
/* resource allocation */
#define kbd_request_region()
--- /dev/null
+/*
+ * keylargo.h: definitions for using the "KeyLargo" I/O controller chip.
+ *
+ */
+
+/* offset from base for feature control registers */
+#define KEYLARGO_MBCR 0x34 /* Media bay control/status */
+#define KEYLARGO_FCR0 0x38
+#define KEYLARGO_FCR1 0x3c
+#define KEYLARGO_FCR2 0x40
+#define KEYLARGO_FCR3 0x44
+#define KEYLARGO_FCR4 0x48
+
+/* GPIO registers */
+#define KEYLARGO_GPIO_LEVELS0 0x50
+#define KEYLARGO_GPIO_LEVELS1 0x54
+#define KEYLARGO_GPIO_EXTINT_0 0x58
+#define KEYLARGO_GPIO_EXTINT_CNT 18
+#define KEYLARGO_GPIO_0 0x6A
+#define KEYLARGO_GPIO_CNT 17
+
+/* Specific GPIO regs */
+
+#define KL_GPIO_ETH_PHY_RESET (KEYLARGO_GPIO_0+0x10)
+#define KL_GPIO_ETH_PHY_RESET_ASSERT 0x04
+#define KL_GPIO_ETH_PHY_RESET_RELEASE 0x05
+#define KL_GPIO_ETH_PHY_RESET_TRISTATE 0x00
+
+#define KL_GPIO_EXTINT_CPU1 (KEYLARGO_GPIO_0+0x0a)
+#define KL_GPIO_EXTINT_CPU1_ASSERT 0x04
+#define KL_GPIO_EXTINT_CPU1_RELEASE 0x38
+
+#define KL_GPIO_RESET_CPU0 (KEYLARGO_GPIO_EXTINT_0+0x03)
+#define KL_GPIO_RESET_CPU1 (KEYLARGO_GPIO_EXTINT_0+0x04)
+#define KL_GPIO_RESET_CPU2 (KEYLARGO_GPIO_EXTINT_0+0x0f)
+#define KL_GPIO_RESET_CPU3 (KEYLARGO_GPIO_EXTINT_0+0x10)
+#define KL_GPIO_RESET_CPU_ASSERT 0x04
+#define KL_GPIO_RESET_CPU_RELEASE 0x05
+
+#define KL_GPIO_PMU_MESSAGE_IRQ (KEYLARGO_GPIO_EXTINT_0+0x09)
+#define KL_GPIO_PMU_MESSAGE_BIT 0x02
+
+/*
+ * Bits in feature control register
+ */
+#define KL_MBCR_MBDEV_ENABLE 0x00001000
+
+#define KL0_SCC_B_INTF_ENABLE 0x00000001 /* ??? */
+#define KL0_SCC_A_INTF_ENABLE 0x00000002 /* ??? */
+#define KL0_SCC_SLOWPCLK 0x00000004
+#define KL0_SCC_RESET 0x00000008
+#define KL0_SCCA_ENABLE 0x00000010
+#define KL0_SCCB_ENABLE 0x00000020
+#define KL0_SCC_CELL_ENABLE 0x00000040
+#define KL0_IRDA_ENABLE 0x00008000
+#define KL0_IRDA_CLK32_ENABLE 0x00010000
+#define KL0_IRDA_CLK19_ENABLE 0x00020000
+#define KL0_USB0_PAD_SUSPEND0 0x00040000
+#define KL0_USB0_PAD_SUSPEND1 0x00080000
+#define KL0_USB0_CELL_ENABLE 0x00100000
+#define KL0_USB1_PAD_SUSPEND0 0x00400000
+#define KL0_USB1_PAD_SUSPEND1 0x00800000
+#define KL0_USB1_CELL_ENABLE 0x01000000
+#define KL0_USB_REF_SUSPEND 0x10000000
+
+#define KL0_SERIAL_ENABLE (KL0_SCC_B_INTF_ENABLE | \
+ KL0_SCC_SLOWPCLK | \
+ KL0_SCC_CELL_ENABLE | KL0_SCCA_ENABLE)
+
+#define KL1_AUDIO_SEL_22MCLK 0x00000002
+#define KL1_AUDIO_CLK_ENABLE_BIT 0x00000008
+#define KL1_AUDIO_CLK_OUT_ENABLE 0x00000020 /* Burgundy only ? */
+#define KL1_AUDIO_CELL_ENABLE 0x00000040
+#define KL1_AUDIO_CHOOSE 0x00000080 /* Burgundy only ? */
+#define KL1_I2S0_CELL_ENABLE 0x00000400
+#define KL1_I2S0_CLK_ENABLE_BIT 0x00001000
+#define KL1_I2S0_ENABLE 0x00002000
+#define KL1_I2S1_CELL_ENABLE 0x00020000
+#define KL1_I2S1_CLK_ENABLE_BIT 0x00080000
+#define KL1_I2S1_ENABLE 0x00100000
+#define KL1_EIDE0_ENABLE 0x00800000
+#define KL1_EIDE0_RESET_N 0x01000000
+#define KL1_EIDE1_ENABLE 0x04000000
+#define KL1_EIDE1_RESET_N 0x08000000
+#define KL1_UIDE_ENABLE 0x20000000
+#define KL1_UIDE_RESET_N 0x40000000
+
+#define KL2_IOBUS_ENABLE 0x00000002
+#define KL2_SLEEP_STATE_BIT 0x00000100
+#define KL2_MPIC_ENABLE 0x00020000
+#define KL2_MODEM_POWER_N 0x02000000
+#define KL2_AIRPORT_RESET_N 0x08000000 /* Or power ? */
+
+#define KL3_SHUTDOWN_PLL_TOTAL 0x00000001
+#define KL3_SHUTDOWN_PLLKW6 0x00000002
+#define KL3_SHUTDOWN_PLLKW4 0x00000004
+#define KL3_SHUTDOWN_PLLKW35 0x00000008
+#define KL3_SHUTDOWN_PLLKW12 0x00000010
+#define KL3_PLL_RESET 0x00000020
+#define KL3_SHUTDOWN_PLL2X 0x00000080
+#define KL3_CLK66_ENABLE 0x00000100
+#define KL3_CLK49_ENABLE 0x00000200
+#define KL3_CLK45_ENABLE 0x00000400
+#define KL3_CLK31_ENABLE 0x00000800
+#define KL3_TIMER_CLK18_ENABLE 0x00001000
+#define KL3_I2S1_CLK18_ENABLE 0x00002000
+#define KL3_I2S0_CLK18_ENABLE 0x00004000
+#define KL3_VIA_CLK16_ENABLE 0x00008000
+#define KL3_STOPPING33_ENABLED 0x00080000
+
+/* Port 0,1 : bus 0, port 2,3 : bus 1 */
+#define KL4_SET_PORT_ENABLE(p) (0x00000008 << ((p)<<3))
+#define KL4_SET_PORT_RESUME(p) (0x00000004 << ((p)<<3))
+#define KL4_SET_PORT_CONNECT(p) (0x00000002 << ((p)<<3))
+#define KL4_SET_PORT_DISCONNECT(p) (0x00000001 << ((p)<<3))
+#define KL4_GET_PORT_RESUME(p) (0x00000040 << ((p)<<3))
+#define KL4_GET_PORT_CONNECT(p) (0x00000020 << ((p)<<3))
+#define KL4_GET_PORT_DISCONNECT(p) (0x00000010 << ((p)<<3))
+
void (*power_off)(void);
void (*halt)(void);
- void (*time_init)(void); /* Optional, may be NULL */
+ long (*time_init)(void); /* Optional, may be NULL */
int (*set_rtc_time)(unsigned long nowtime);
unsigned long (*get_rtc_time)(void);
void (*calibrate_decr)(void);
void (*kbd_leds)(unsigned char leds);
void (*kbd_init_hw)(void);
#ifdef CONFIG_MAGIC_SYSRQ
- unsigned char *kbd_sysrq_xlate;
- unsigned long SYSRQ_KEY;
+ unsigned char *sysrq_xlate;
#endif
/* PCI interfaces */
int (*pcibios_write_config_dword)(unsigned char bus,
unsigned char dev_fn, unsigned char offset, unsigned int val);
void (*pcibios_fixup)(void);
+
+ void* (*pci_dev_io_base)(unsigned char bus, unsigned char devfn, int physical);
+ void* (*pci_dev_mem_base)(unsigned char bus, unsigned char devfn);
+ int (*pci_dev_root_bridge)(unsigned char bus, unsigned char devfn);
+
};
extern struct machdep_calls ppc_md;
pmac_nvram_NR /* MacOS Name Registry partition */
};
+#ifdef __KERNEL__
+
/* Return partition offset in nvram */
extern int pmac_get_partition(int partition);
extern u8 pmac_xpram_read(int xpaddr);
extern void pmac_xpram_write(int xpaddr, u8 data);
+#endif /* __KERNEL__ */
+
/* Some offsets in XPRAM */
#define PMAC_XPRAM_MACHINE_LOC 0xe4
#define PMAC_XPRAM_SOUND_VOLUME 0x08
/* Machine location structure in XPRAM */
struct pmac_machine_location {
- u32 latitude; /* 2+30 bit Fractional number */
- u32 longitude; /* 2+30 bit Fractional number */
- u32 delta; /* mix of GMT delta and DLS */
+ unsigned int latitude; /* 2+30 bit Fractional number */
+ unsigned int longitude; /* 2+30 bit Fractional number */
+ unsigned int delta; /* mix of GMT delta and DLS */
};
+/* /dev/nvram ioctls */
+#define PMAC_NVRAM_GET_OFFSET _IOWR('p', 0x40, int) /* Get NVRAM partition offset */
+
#endif
/*
* pci_io_base returns the memory address at which you can access
* the I/O space for PCI bus number `bus' (or NULL on error).
+ *
+ * NOTE: This doesn't handle the new Uni-N chip which requires
+ * per-device io_base.
*/
void *pci_io_base(unsigned int bus);
+/* This version handles the new Uni-N host bridge, the iobase is now
+ * a per-device thing. I also added the memory base so PReP can
+ * be fixed to return 0xc0000000 (I didn't actually implement it)
+ *
+ * pci_dev_io_base() returns either a virtual (ioremap'ed) address or
+ * a physical address. In-kernel clients will use logical while the
+ * sys_pciconfig_iobase syscall returns a physical one to userland.
+ */
+void *pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical);
+void *pci_dev_mem_base(unsigned char bus, unsigned char devfn);
+
+/* Returns the root-bridge number (Uni-N number) of a device */
+int pci_dev_root_bridge(unsigned char bus, unsigned char devfn);
+
/*
* pci_device_loc returns the bus number and device/function number
* for a device on a PCI bus, given its device_node struct.
struct bridge_data {
volatile unsigned int *cfg_addr;
volatile unsigned char *cfg_data;
+ void *io_base_phys;
void *io_base;
int bus_number;
int max_bus;
--- /dev/null
+#ifndef __PPC_PCI_H
+#define __PPC_PCI_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+
+/* Values for the `which' argument to sys_pciconfig_iobase. */
+#define IOBASE_BRIDGE_NUMBER 0
+#define IOBASE_MEMORY 1
+#define IOBASE_IO 2
+
+
+#endif
/*
* PMU commands
*/
-#define PMU_POWER_CTRL 0x11 /* control power of some devices */
+#define PMU_POWER_CTRL0 0x10 /* control power of some devices */
+#define PMU_POWER_CTRL 0x11 /* control power of more devices */
#define PMU_ADB_CMD 0x20 /* send ADB packet */
#define PMU_ADB_POLL_OFF 0x21 /* disable ADB auto-poll */
#define PMU_WRITE_NVRAM 0x33 /* write non-volatile RAM */
#define PMU_GET_COVER 0xdc /* report cover open/closed */
#define PMU_SYSTEM_READY 0xdf /* tell PMU we are awake */
+/* Bits to use with the PMU_POWER_CTRL0 command */
+#define PMU_POW0_ON 0x80 /* OR this to power ON the device */
+#define PMU_POW0_OFF 0x00 /* leave bit 7 to 0 to power it OFF */
+#define PMU_POW0_HARD_DRIVE 0x04 /* Hard drive power (on wallstreet/lombard ?) */
+
/* Bits to use with the PMU_POWER_CTRL command */
#define PMU_POW_ON 0x80 /* OR this to power ON the device */
#define PMU_POW_OFF 0x00 /* leave bit 7 to 0 to power it OFF */
#define PMU_POW_BACKLIGHT 0x01 /* backlight power */
+#define PMU_POW_CHARGER 0x02 /* battery charger power */
#define PMU_POW_IRLED 0x04 /* IR led power (on wallstreet) */
+#define PMU_POW_MEDIABAY 0x08 /* media bay power (wallstreet/lombard ?) */
/* Bits in PMU interrupt and interrupt mask bytes */
#define PMU_INT_ADB_AUTO 0x04 /* ADB autopoll, when PMU_INT_ADB */
/* no param */
#define PMU_IOC_SLEEP _IO('B', 0)
-/* out param: u32* backlight value: 0 to 31 */
+/* out param: u32* backlight value: 0 to 15 */
#define PMU_IOC_GET_BACKLIGHT _IOR('B', 1, sizeof(__u32*))
-/* in param: u32 backlight value: 0 to 31 */
+/* in param: u32 backlight value: 0 to 15 */
#define PMU_IOC_SET_BACKLIGHT _IOW('B', 2, sizeof(__u32))
/* out param: u32* PMU model */
#define PMU_IOC_GET_MODEL _IOR('B', 3, sizeof(__u32*))
#ifdef __KERNEL__
-int find_via_pmu(void);
-void via_pmu_init(void);
+extern int find_via_pmu(void);
+extern int via_pmu_start(void);
-int pmu_request(struct adb_request *req,
+extern int pmu_request(struct adb_request *req,
void (*done)(struct adb_request *), int nbytes, ...);
-void pmu_poll(void);
-void pmu_enable_backlight(int on);
-void pmu_set_brightness(int level);
+extern void pmu_poll(void);
+
+/* For use before switching interrupts off for a long time;
+ * warning: not stackable
+ */
+extern void pmu_suspend(void);
+extern void pmu_resume(void);
+
+extern void pmu_enable_irled(int on);
-void pmu_enable_irled(int on);
+extern void pmu_restart(void);
+extern void pmu_shutdown(void);
-void pmu_restart(void);
-void pmu_shutdown(void);
+extern int pmu_present(void);
+extern int pmu_get_model(void);
-int pmu_present(void);
-int pmu_get_model(void);
#ifdef CONFIG_PMAC_PBOOK
/*
#define PBOOK_SLEEP_REFUSE -1
/* priority levels in notifiers */
-#define SLEEP_LEVEL_VIDEO 100 /* Video driver (first wake) */
-#define SLEEP_LEVEL_SOUND 90 /* Sound driver */
-#define SLEEP_LEVEL_MEDIABAY 80 /* Media bay driver */
-#define SLEEP_LEVEL_BLOCK 70 /* IDE, SCSI */
-#define SLEEP_LEVEL_NET 60 /* bmac */
-#define SLEEP_LEVEL_ADB 50 /* ADB */
-#define SLEEP_LEVEL_MISC 30 /* Anything */
+#define SLEEP_LEVEL_VIDEO 100 /* Video driver */
+#define SLEEP_LEVEL_USB 95 /* USB */
+#define SLEEP_LEVEL_MEDIABAY 90 /* Media bay driver */
+#define SLEEP_LEVEL_NET 80 /* bmac/gmac */
+#define SLEEP_LEVEL_ADB 70 /* ADB */
+#define SLEEP_LEVEL_BLOCK 60 /* IDE, SCSI */
+#define SLEEP_LEVEL_SOUND 50 /* Sound driver */
+#define SLEEP_LEVEL_MISC 40 /* Anything */
#define SLEEP_LEVEL_LAST 0 /* Anything */
/* special register notifier functions */
#define HID0_BHTE (1<<2) /* Branch History Table Enable */
#define HID0_BTCD (1<<1) /* Branch target cache disable */
+/* L2CR bits */
+#define L2CR_PIPE_LATEWR (0x01800000) /* late-write SRAM */
+#define L2CR_L2CTL (0x00100000) /* RAM control */
+#define L2CR_INST_DISABLE (0x00400000) /* disable for insn's */
+#define L2CR_L2I (0x00200000) /* global invalidate */
+#define L2CR_L2E (0x80000000) /* enable */
+#define L2CR_L2WT (0x00080000) /* write-through */
+
+
/* fpscr settings */
#define FPSCR_FX (1<<31)
#define FPSCR_FEX (1<<30)
__asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
#define __save_and_cli(flags) ({__save_flags(flags);__cli();})
-/* Data cache block flush - write out the cache line containing the
- specified address and then invalidate it in the cache. */
-extern __inline__ void dcbf(void *line)
-{
- asm("dcbf %0,%1; sync" : : "r" (line), "r" (0));
-}
-
extern __inline__ void __restore_flags(unsigned long flags)
{
extern atomic_t ppc_n_lost_interrupts;
extern int _get_PVR(void);
extern long _get_L2CR(void);
extern void _set_L2CR(unsigned long);
+extern long _get_HID0(void);
+extern void _set_HID0(unsigned long);
+extern long _get_ICTC(void);
+extern void _set_ICTC(unsigned long);
extern void via_cuda_init(void);
extern void pmac_nvram_init(void);
extern void read_rtc_time(void);
/* Returns 0 if exception not found and fixup otherwise. */
extern unsigned long search_exception_table(unsigned long);
-
+extern void sort_exception_table(void);
/*
* These are the main single-value transfer routines. They automatically
unsigned long uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
+ struct sigcontext_struct uc_mcontext;
sigset_t uc_sigmask; /* mask last for extensibility */
};
--- /dev/null
+/*
+ * uninorth.h: definitions for using the "UniNorth" host bridge chip
+ * from Apple. This chip is used on "Core99" machines
+ *
+ */
+
+
+/*
+ * Uni-N config space reg. definitions
+ *
+ * (Little endian)
+ */
+
+/* Address ranges selection. This one should work with Bandit too */
+#define UNI_N_ADDR_SELECT 0x48
+#define UNI_N_ADDR_COARSE_MASK 0xffff0000 /* 256Mb regions at *0000000 */
+#define UNI_N_ADDR_FINE_MASK 0x0000ffff /* 16Mb regions at f*000000 */
+
+/* AGP registers */
+#define UNI_N_CFG_GART_BASE 0x8c
+#define UNI_N_CFG_AGP_BASE 0x90
+#define UNI_N_CFG_GART_CTRL 0x94
+#define UNI_N_CFG_INTERNAL_STATUS 0x98
+
+/* UNI_N_CFG_GART_CTRL bits definitions */
+#define UNI_N_CFG_GART_INVAL 0x00000001
+#define UNI_N_CFG_GART_ENABLE 0x00000100
+#define UNI_N_CFG_GART_2xRESET 0x00010000
+
+
+/*
+ * Uni-N memory mapped reg. definitions
+ *
+ * Those registers are Big-Endian !!
+ *
+ * Their meaning come from either Darwin and/or from experiments I made with
+ * the bootrom, I'm not sure about their exact meaning yet
+ *
+ */
+
+/* Version of the UniNorth chip */
+#define UNI_N_VERSION 0x0000 /* Known versions: 3,7 and 8 */
+
+/* This register is used to enable/disable various parts */
+#define UNI_N_CLOCK_CNTL 0x0020
+#define UNI_N_CLOCK_CNTL_PCI 0x00000001 /* guess ? */
+#define UNI_N_CLOCK_CNTL_GMAC 0x00000002
+#define UNI_N_CLOCK_CNTL_FW 0x00000004 /* guess ? */
+
+/* Power Management control */
+#define UNI_N_POWER_MGT 0x0030
+#define UNI_N_POWER_MGT_NORMAL 0x00
+#define UNI_N_POWER_MGT_IDLE2 0x01
+#define UNI_N_POWER_MGT_SLEEP 0x02
+
+/* This register is configured by Darwin depending on the UniN
+ * revision
+ */
+#define UNI_N_ARB_CTRL 0x0040
+#define UNI_N_ARB_CTRL_QACK_DELAY_SHIFT 15
+#define UNI_N_ARB_CTRL_QACK_DELAY_MASK 0x0e1f8000
+#define UNI_N_ARB_CTRL_QACK_DELAY 0x30
+#define UNI_N_ARB_CTRL_QACK_DELAY105 0x00
+
+/* This one _might_ return the CPU number of the CPU reading it;
+ * the bootROM decides wether to boot or to sleep/spinloop depending
+ * on this register beeing 0 or not
+ */
+#define UNI_N_CPU_NUMBER 0x0050
+
+/* This register appear to be read by the bootROM to decide what
+ * to do on a non-recoverable reset (powerup or wakeup)
+ */
+#define UNI_N_HWINIT_STATE 0x0070
+#define UNI_N_HWINIT_STATE_SLEEPING 0x01
+#define UNI_N_HWINIT_STATE_RUNNING 0x02
+/* This last bit appear to be used by the bootROM to know the second
+ * CPU has started and will enter it's sleep loop with IP=0
+ */
+#define UNI_N_HWINIT_STATE_CPU1_FLAG 0x10000000
+
+
+
#define __NR_putpmsg 188 /* some people actually want streams */
#define __NR_vfork 189
-#define __NR_sys_pciconfig_read 198
-#define __NR_sys_pciconfig_write 199
-#define __NR_sys_pciconfig_iobase 200
-#define __NR_multiplexer 201
+#define __NR_pciconfig_read 198
+#define __NR_pciconfig_write 199
+#define __NR_pciconfig_iobase 200
+#define __NR_multiplexer 201
#define __NR(n) #n
{
int retval;
__asm__ __volatile__("bcr 15,0\n\t"
- "l %0,%1"
- : "=d" (retval) : "m" (*v) );
+ "l %0,%1"
+ : "=d" (retval) : "m" (*v) );
return retval;
}
static __inline__ void atomic_add(int i, atomic_t *v)
{
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 2,%0\n"
+ " l 0,%0\n"
"0: lr 1,0\n"
" ar 1,%1\n"
- " cs 0,1,%0\n"
+ " cs 0,1,0(2)\n"
" jl 0b"
- : "+m" (*v) : "d" (i) : "0", "1", "cc" );
+ : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" );
}
static __inline__ void atomic_sub(int i, atomic_t *v)
{
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 2,%0\n"
+ " l 0,%0\n"
"0: lr 1,0\n"
" sr 1,%1\n"
- " cs 0,1,%0\n"
+ " cs 0,1,0(2)\n"
" jl 0b"
- : "+m" (*v) : "d" (i) : "0", "1", "cc" );
+ : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" );
}
static __inline__ void atomic_inc(volatile atomic_t *v)
{
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 2,%0\n"
+ " l 0,%0\n"
"0: lr 1,0\n"
" ahi 1,1\n"
- " cs 0,1,%0\n"
+ " cs 0,1,0(2)\n"
" jl 0b"
- : "+m" (*v) : : "0", "1", "cc" );
+ : "+m" (*v) : : "0", "1", "2", "cc" );
}
static __inline__ int atomic_inc_return(volatile atomic_t *v)
{
int i;
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 1,%0\n"
+ " l 0,%0\n"
"0: lr %1,0\n"
" ahi %1,1\n"
- " cs 0,%1,%0\n"
+ " cs 0,%1,0(1)\n"
" jl 0b"
- : "+m" (*v), "=&d" (i) : : "0", "cc" );
+ : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
return i;
}
static __inline__ void atomic_dec(volatile atomic_t *v)
{
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 2,%0\n"
+ " l 0,%0\n"
"0: lr 1,0\n"
" ahi 1,-1\n"
- " cs 0,1,%0\n"
+ " cs 0,1,0(2)\n"
" jl 0b"
- : "+m" (*v) : : "0", "1", "cc" );
+ : "+m" (*v) : : "0", "1", "2", "cc" );
}
static __inline__ int atomic_dec_return(volatile atomic_t *v)
{
int i;
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 1,%0\n"
+ " l 0,%0\n"
"0: lr %1,0\n"
" ahi %1,-1\n"
- " cs 0,%1,%0\n"
+ " cs 0,%1,0(1)\n"
" jl 0b"
- : "+m" (*v), "=&d" (i) : : "0", "cc" );
+ : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
return i;
}
static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
{
int i;
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 1,%0\n"
+ " l 0,%0\n"
"0: lr %1,0\n"
" ahi %1,-1\n"
- " cs 0,%1,%0\n"
+ " cs 0,%1,0(1)\n"
" jl 0b"
- : "+m" (*v), "=&d" (i) : : "0", "cc");
+ : "+m" (*v), "=&d" (i) : : "0", "1", "cc");
return i == 0;
}
static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
{
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 2,%0\n"
+ " l 0,%0\n"
"0: lr 1,0\n"
" nr 1,%1\n"
- " cs 0,1,%0\n"
+ " cs 0,1,0(2)\n"
" jl 0b"
- : "+m" (*v) : "d" (~(mask)) : "0", "1", "cc" );
+ : "+m" (*v) : "d" (~(mask)) : "0", "1", "2", "cc" );
}
static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
{
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 2,%0\n"
+ " l 0,%0\n"
"0: lr 1,0\n"
" or 1,%1\n"
- " cs 0,1,%0\n"
+ " cs 0,1,0(2)\n"
" jl 0b"
- : "+m" (*v) : "d" (mask) : "0", "1", "cc" );
+ : "+m" (*v) : "d" (mask) : "0", "1", "2", "cc" );
}
/*
int retval;
__asm__ __volatile__(
- " cs %2,%3,%1\n"
+ " la 1,%1\n"
+ " lr 0,%2\n"
+ " cs 0,%3,0(1)\n"
" ipm %0\n"
" srl %0,28\n"
"0:"
: "=&r" (retval), "+m" (*v)
: "d" (expected_oldval) , "d" (new_val)
- : "cc");
+ : "0", "1", "cc");
return retval;
}
atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
{
__asm__ __volatile__(
+ " la 2,%0\n"
"0: lr 1,%1\n"
- " cs 1,%2,%0\n"
+ " cs 1,%2,0(2)\n"
" jl 0b\n"
: "+m" (*v)
: "d" (expected_oldval) , "d" (new_val)
- : "cc", "1");
+ : "cc", "1", "2");
}
/*
extern __inline__ int atomic_inc_and_test_greater_zero(atomic_t *v)
{
int i;
- __asm__ __volatile__(" l 0,%0\n"
+ __asm__ __volatile__(" la 1,%0\n"
+ " l 0,%0\n"
"0: lr %1,0\n"
" ahi %1,1\n"
- " cs 0,%1,%0\n"
+ " cs 0,%1,0(1)\n"
" jl 0b"
- : "+m" (*v), "=&d" (i) : : "0", "cc" );
+ : "+m" (*v), "=&d" (i) : : "0", "1", "cc" );
return i > 0;
}
return 0;
__asm__(" lr %%r1,%1\n"
" sr %0,%0\n"
- " tmh %%r1,0xFFFF\n"
- " jz 0f\n"
+ " tml %%r1,0xFFFF\n"
+ " jnz 0f\n"
" ahi %0,16\n"
" srl %%r1,16\n"
- "0: tml %%r1,0xFF00\n"
- " jz 1f\n"
+ "0: tml %%r1,0x00FF\n"
+ " jnz 1f\n"
" ahi %0,8\n"
" srl %%r1,8\n"
- "1: tml %%r1,0x00F0\n"
- " jz 2f\n"
+ "1: tml %%r1,0x000F\n"
+ " jnz 2f\n"
" ahi %0,4\n"
" srl %%r1,4\n"
- "2: tml %%r1,0x000C\n"
- " jz 3f\n"
+ "2: tml %%r1,0x0003\n"
+ " jnz 3f\n"
" ahi %0,2\n"
" srl %%r1,2\n"
- "3: tml %%r1,0x0002\n"
- " jz 4f\n"
+ "3: tml %%r1,0x0001\n"
+ " jnz 4f\n"
" ahi %0,1\n"
"4:"
: "=&d" (r) : "d" (x) : "cc", "1" );
/*
* ccw_req_t -> status can be:
*/
-#define CQR_STATUS_EMPTY 0x00 /* request is empty */
-#define CQR_STATUS_FILLED 0x01 /* request is ready to be preocessed */
-#define CQR_STATUS_QUEUED 0x02 /* request is queued to be processed */
-#define CQR_STATUS_IN_IO 0x04 /* request is currently in IO */
-#define CQR_STATUS_DONE 0x08 /* request is completed sucessfully */
-#define CQR_STATUS_ERROR 0x10 /* request is completed with error */
-#define CQR_STATUS_FAILED 0x20 /* request is finally failed */
+#define CQR_STATUS_EMPTY 0x00 /* request is empty */
+#define CQR_STATUS_FILLED 0x01 /* request is ready to be preocessed */
+#define CQR_STATUS_QUEUED 0x02 /* request is queued to be processed */
+#define CQR_STATUS_IN_IO 0x04 /* request is currently in IO */
+#define CQR_STATUS_DONE 0x08 /* request is completed sucessfully */
+#define CQR_STATUS_ERROR 0x10 /* request is completed with error */
+#define CQR_STATUS_FAILED 0x20 /* request is finally failed */
+#define CQR_STATUS_FINISHED 0x40 /* request is ready for cleanup */
#ifdef __KERNEL__
#define SMALLEST_SLAB (sizeof(struct ccw_req_t) <= 128 ? 128 :\
* Fold a partial checksum without adding pseudo headers
*/
#if 1
-unsigned short csum_fold(unsigned int sum);
+extern unsigned short csum_fold(unsigned int sum);
#else
extern inline unsigned short
csum_fold(unsigned int sum)
unsigned int sum)
{
__asm__ __volatile__ (
- " sll %3,16\n"
- " or %3,%4\n" /* newproto=proto<<16 in hiword, len in lowword */
- " alr %1,%2\n" /* saddr+=daddr */
- " brc 12,0f\n"
- " ahi %1,1\n" /* add carry */
- "0: alr %1,%3\n" /* add saddr+=newproto */
- " brc 12,1f\n"
- " ahi %1,1\n" /* add carry again */
- "1: alr %0,%1\n" /* sum+=saddr */
+ " alr %0,%1\n" /* sum += saddr */
+ " brc 12,0f\n"
+ " ahi %0,1\n" /* add carry */
+ "0: alr %0,%2\n" /* sum += daddr */
+ " brc 12,1f\n"
+ " ahi %0,1\n" /* add carry */
+ "1: alr %0,%3\n" /* sum += (len<<16) + (proto<<8) */
" brc 12,2f\n"
- " ahi %0,1\n" /* add carry again */
+ " ahi %0,1\n" /* add carry */
"2:"
: "+&d" (sum)
- : "d" (saddr), "d" (daddr), "d" (proto), "d" (len)
+ : "d" (saddr), "d" (daddr),
+ "d" (((unsigned int) len<<16) + (unsigned int) proto)
: "cc" );
return sum;
}
#define DASD_H
/* First of all the external stuff */
+#include <linux/version.h>
#include <linux/ioctl.h>
#include <linux/major.h>
#include <linux/wait.h>
#include <asm/ccwcache.h>
-/* #include <linux/blkdev.h> */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/blkdev.h>
+#endif
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/version.h>
+/*
+ * include/asm-s390/debug.h
+ * S/390 debug facility
+ *
+ * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
+ * IBM Corporation
+ */
+
#ifndef DEBUG_H
#define DEBUG_H
+#ifdef __KERNEL__
+
#include <asm/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/proc_fs.h>
-#ifdef __KERNEL__
+#define DEBUG_MAX_AREAS 16 /* max number of allowed registers */
+#define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */
+#define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */
+#define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */
+#define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */
+
+#define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
+
+#define STCK(x) asm volatile ("STCK %0":"=m" (x))
+
+typedef struct {
+ union {
+ struct {
+ unsigned long long clock:52;
+ unsigned long long unused:2;
+ unsigned long long cpuid:8;
+ unsigned long long exception:1;
+ unsigned long long used:1;
+ } fields;
+
+ unsigned long long stck;
+ } id;
+ void* caller;
+ char data[4];
+} debug_entry_t;
+
+struct debug_view;
+
+typedef struct {
+ atomic_t ref_count;
+ spinlock_t lock;
+ int level;
+ int nr_areas;
+ int page_order;
+ int buf_size;
+ int entry_size;
+ debug_entry_t** areas;
+ int active_area;
+ int active_entry[DEBUG_MAX_AREAS];
+ struct proc_dir_entry* proc_root_entry;
+ struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS];
+ struct debug_view* views[DEBUG_MAX_VIEWS];
+ char name[DEBUG_MAX_PROCF_LEN];
+} debug_info_t;
+
+typedef int (debug_header_proc_t) (debug_info_t* id,
+ struct debug_view* view,
+ int area,
+ debug_entry_t* entry,
+ char* out_buf);
+
+typedef int (debug_format_proc_t) (debug_info_t* id,
+ struct debug_view* view, char* out_buf,
+ const char* in_buf);
+typedef int (debug_prolog_proc_t) (debug_info_t* id,
+ struct debug_view* view,
+ char* out_buf);
+typedef int (debug_input_proc_t) (debug_info_t* id,
+ struct debug_view* view,
+ struct file* file, const char* user_buf,
+ size_t in_buf_size, loff_t* offset);
+
+int debug_dflt_header_fn(debug_info_t* id, struct debug_view* view,
+ int area, debug_entry_t* entry, char* out_buf);
+
+struct debug_view {
+ char name[DEBUG_MAX_PROCF_LEN];
+ debug_prolog_proc_t* prolog_proc;
+ debug_header_proc_t* header_proc;
+ debug_format_proc_t* format_proc;
+ debug_input_proc_t* input_proc;
+};
+
+extern struct debug_view debug_ascii_view;
+extern struct debug_view debug_ebcdic_view;
+extern struct debug_view debug_hex_view;
+
+debug_info_t* debug_register(char* name, int pages_index, int nr_areas,
+ int buf_size);
+void debug_unregister(debug_info_t* id);
+
+debug_entry_t* debug_event(debug_info_t* id, int level, void* data,
+ int length);
+debug_entry_t* debug_int_event(debug_info_t* id, int level,
+ unsigned int tag);
+debug_entry_t* debug_text_event(debug_info_t* id, int level,
+ const char* txt);
+
+debug_entry_t* debug_exception(debug_info_t* id, int level, void* data,
+ int length);
+debug_entry_t* debug_int_exception(debug_info_t* id, int level,
+ unsigned int tag);
+debug_entry_t* debug_text_exception(debug_info_t* id, int level,
+ const char* txt);
-#define MAX_DEBUG_AREAS 16
-
-#define STCK(x) asm volatile ("STCK %0":"=m" (x))
-
-typedef struct
-{
- union
- {
- struct
- {
- unsigned long long cpuid:4;
- unsigned long long clock:60;
- }
- fields;
- unsigned long long stck;
- }
- id;
- void *caller;
- union
- {
- unsigned long tag;
- char text[4];
- }
- tag;
-}
-debug_entry_t;
-
-typedef struct
-{
- char *name;
- int level;
- int nr_areas;
- int page_order;
- debug_entry_t **areas;
- int active_area;
- int *active_entry;
- spinlock_t lock;
-}
-debug_info_t;
-
-int debug_init (void);
-debug_info_t *debug_register (char *name, int pages_index, int nr_areas);
-void debug_unregister (debug_info_t * id, char *name);
-void debug_event (debug_info_t * id, int level, unsigned int tag);
-void debug_text_event (debug_info_t * id, int level, char tag[4]);
-void debug_exception (debug_info_t * id, int level, unsigned int tag);
-void debug_text_exception (debug_info_t * id, int level, char tag[4]);
+int debug_register_view(debug_info_t* id, struct debug_view* view);
+int debug_unregister_view(debug_info_t* id, struct debug_view* view);
/*
define the debug levels:
--- /dev/null
+/*
+ * File...........: linux/include/asm-s390x/idals.h
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
+
+ * History of changes
+ * 07/24/00 new file
+ */
+
+#define IDAL_NUMBER_CACHES 7
+
+typedef unsigned long idaw_t;
+
+#ifdef CONFIG_ARCH_S390
+extern inline int
+normalize_cpa(ccw1_t * ccw, unsigned long address)
+{
+ return address;
+}
+#endif
+
+int idal_alloc ( int nridaws );
+void idal_release ( idaw_t *idal );
+
* to describe about the low-level hardware.
*/
struct hw_interrupt_type {
- const char *typename;
+ const __u8 *typename;
int (*handle)(unsigned int irq,
int cpu,
struct pt_regs * regs);
* path management control word
*/
typedef struct {
- unsigned long intparm; /* interruption parameter */
- unsigned int res0 : 2; /* reserved zeros */
- unsigned int isc : 3; /* interruption sublass */
- unsigned int res5 : 3; /* reserved zeros */
- unsigned int ena : 1; /* enabled */
- unsigned int lm : 2; /* limit mode */
- unsigned int mme : 2; /* measurement-mode enable */
- unsigned int mp : 1; /* multipath mode */
- unsigned int tf : 1; /* timing facility */
- unsigned int dnv : 1; /* device number valid */
- unsigned int dev : 16; /* device number */
- unsigned char lpm; /* logical path mask */
- unsigned char pnom; /* path not operational mask */
- unsigned char lpum; /* last path used mask */
- unsigned char pim; /* path installed mask */
- unsigned short mbi; /* measurement-block index */
- unsigned char pom; /* path operational mask */
- unsigned char pam; /* path available mask */
- unsigned char chpid[8]; /* CHPID 0-7 (if available) */
- unsigned int unused1 : 8; /* reserved zeros */
- unsigned int st : 3; /* subchannel type */
- unsigned int unused2 : 20; /* reserved zeros */
- unsigned int csense : 1; /* concurrent sense; can be enabled ...*/
- /* ... per MSCH, however, if facility */
- /* ... is not installed, this results */
- /* ... in an operand exception. */
+ __u32 intparm; /* interruption parameter */
+ __u32 res0 : 2; /* reserved zeros */
+ __u32 isc : 3; /* interruption sublass */
+ __u32 res5 : 3; /* reserved zeros */
+ __u32 ena : 1; /* enabled */
+ __u32 lm : 2; /* limit mode */
+ __u32 mme : 2; /* measurement-mode enable */
+ __u32 mp : 1; /* multipath mode */
+ __u32 tf : 1; /* timing facility */
+ __u32 dnv : 1; /* device number valid */
+ __u32 dev : 16; /* device number */
+ __u8 lpm; /* logical path mask */
+ __u8 pnom; /* path not operational mask */
+ __u8 lpum; /* last path used mask */
+ __u8 pim; /* path installed mask */
+ __u16 mbi; /* measurement-block index */
+ __u8 pom; /* path operational mask */
+ __u8 pam; /* path available mask */
+ __u8 chpid[8]; /* CHPID 0-7 (if available) */
+ __u32 unused1 : 8; /* reserved zeros */
+ __u32 st : 3; /* subchannel type */
+ __u32 unused2 : 20; /* reserved zeros */
+ __u32 csense : 1; /* concurrent sense; can be enabled ...*/
+ /* ... per MSCH, however, if facility */
+ /* ... is not installed, this results */
+ /* ... in an operand exception. */
} __attribute__ ((packed)) pmcw_t;
#endif /* __KERNEL__ */
-
/*
* subchannel status word
*/
typedef struct {
- unsigned int key : 4; /* subchannel key */
- unsigned int sctl : 1; /* suspend control */
- unsigned int eswf : 1; /* ESW format */
- unsigned int cc : 2; /* deferred condition code */
- unsigned int fmt : 1; /* format */
- unsigned int pfch : 1; /* prefetch */
- unsigned int isic : 1; /* initial-status interruption control */
- unsigned int alcc : 1; /* address-limit checking control */
- unsigned int ssi : 1; /* supress-suspended interruption */
- unsigned int zcc : 1; /* zero condition code */
- unsigned int ectl : 1; /* extended control */
- unsigned int pno : 1; /* path not operational */
- unsigned int res : 1; /* reserved */
- unsigned int fctl : 3; /* function control */
- unsigned int actl : 7; /* activity control */
- unsigned int stctl : 5; /* status control */
- unsigned long cpa; /* channel program address */
- unsigned int dstat : 8; /* device status */
- unsigned int cstat : 8; /* subchannel status */
- unsigned int count : 16; /* residual count */
+ __u32 key : 4; /* subchannel key */
+ __u32 sctl : 1; /* suspend control */
+ __u32 eswf : 1; /* ESW format */
+ __u32 cc : 2; /* deferred condition code */
+ __u32 fmt : 1; /* format */
+ __u32 pfch : 1; /* prefetch */
+ __u32 isic : 1; /* initial-status interruption control */
+ __u32 alcc : 1; /* address-limit checking control */
+ __u32 ssi : 1; /* supress-suspended interruption */
+ __u32 zcc : 1; /* zero condition code */
+ __u32 ectl : 1; /* extended control */
+ __u32 pno : 1; /* path not operational */
+ __u32 res : 1; /* reserved */
+ __u32 fctl : 3; /* function control */
+ __u32 actl : 7; /* activity control */
+ __u32 stctl : 5; /* status control */
+ __u32 cpa; /* channel program address */
+ __u32 dstat : 8; /* device status */
+ __u32 cstat : 8; /* subchannel status */
+ __u32 count : 16; /* residual count */
} __attribute__ ((packed)) scsw_t;
#define SCSW_FCTL_CLEAR_FUNC 0x1
#define SCHN_STAT_CHAIN_CHECK 0x01
#ifdef __KERNEL__
-
/*
* subchannel information block
*/
typedef struct {
pmcw_t pmcw; /* path management control word */
scsw_t scsw; /* subchannel status word */
- char mda[12]; /* model dependent area */
- } schib_t __attribute__ ((packed,aligned(4)));
-
+ __u8 mda[12]; /* model dependent area */
+ } __attribute__ ((packed,aligned(4))) schib_t;
#endif /* __KERNEL__ */
typedef struct {
- char cmd_code;/* command code */
- char flags; /* flags, like IDA adressing, etc. */
- unsigned short count; /* byte count */
- void *cda; /* data address */
- } ccw1_t __attribute__ ((aligned(8)));
+ __u8 cmd_code;/* command code */
+ __u8 flags; /* flags, like IDA adressing, etc. */
+ __u16 count; /* byte count */
+ __u32 cda; /* data address */
+ } __attribute__ ((packed,aligned(8))) ccw1_t;
#define CCW_FLAG_DC 0x80
#define CCW_FLAG_CC 0x40
#define CCW_CMD_SENSE_ID 0xE4
#ifdef __KERNEL__
-
#define SENSE_MAX_COUNT 0x20
/*
* operation request block
*/
typedef struct {
- unsigned long intparm; /* interruption parameter */
- unsigned int key : 4; /* flags, like key, suspend control, etc. */
- unsigned int spnd : 1; /* suspend control */
- unsigned int res1 : 3; /* reserved */
- unsigned int fmt : 1; /* format control */
- unsigned int pfch : 1; /* prefetch control */
- unsigned int isic : 1; /* initial-status-interruption control */
- unsigned int alcc : 1; /* address-limit-checking control */
- unsigned int ssic : 1; /* suppress-suspended-interr. control */
- unsigned int res2 : 3; /* reserved */
- unsigned int lpm : 8; /* logical path mask */
- unsigned int ils : 1; /* incorrect length */
- unsigned int zero : 7; /* reserved zeros */
- ccw1_t *cpa; /* channel program address */
+ __u32 intparm; /* interruption parameter */
+ __u32 key : 4; /* flags, like key, suspend control, etc. */
+ __u32 spnd : 1; /* suspend control */
+ __u32 res1 : 3; /* reserved */
+ __u32 fmt : 1; /* format control */
+ __u32 pfch : 1; /* prefetch control */
+ __u32 isic : 1; /* initial-status-interruption control */
+ __u32 alcc : 1; /* address-limit-checking control */
+ __u32 ssic : 1; /* suppress-suspended-interr. control */
+ __u32 res2 : 3; /* reserved */
+ __u32 lpm : 8; /* logical path mask */
+ __u32 ils : 1; /* incorrect length */
+ __u32 zero : 7; /* reserved zeros */
+ __u32 cpa; /* channel program address */
} __attribute__ ((packed,aligned(4))) orb_t;
#endif /* __KERNEL__ */
-
typedef struct {
- unsigned int res0 : 4; /* reserved */
- unsigned int pvrf : 1; /* path-verification-required flag */
- unsigned int cpt : 1; /* channel-path timeout */
- unsigned int fsavf : 1; /* Failing storage address validity flag */
- unsigned int cons : 1; /* concurrent-sense */
- unsigned int res8 : 2; /* reserved */
- unsigned int scnt : 6; /* sense count if cons == 1 */
- unsigned int res16 : 16; /* reserved */
- } erw_t;
+ __u32 res0 : 4; /* reserved */
+ __u32 pvrf : 1; /* path-verification-required flag */
+ __u32 cpt : 1; /* channel-path timeout */
+ __u32 fsavf : 1; /* Failing storage address validity flag */
+ __u32 cons : 1; /* concurrent-sense */
+ __u32 res8 : 2; /* reserved */
+ __u32 scnt : 6; /* sense count if cons == 1 */
+ __u32 res16 : 16; /* reserved */
+ } __attribute__ ((packed)) erw_t;
/*
* subchannel logout area
*/
typedef struct {
- unsigned int res0 : 1; /* reserved */
- unsigned int esf : 7; /* extended status flags */
- unsigned int lpum : 8; /* last path used mask */
- unsigned int res16 : 1; /* reserved */
- unsigned int fvf : 5; /* field-validity flags */
- unsigned int sacc : 2; /* storage access code */
- unsigned int termc : 2; /* termination code */
- unsigned int devsc : 1; /* device-status check */
- unsigned int serr : 1; /* secondary error */
- unsigned int ioerr : 1; /* i/o-error alert */
- unsigned int seqc : 3; /* sequence code */
- } sublog_t ;
+ __u32 res0 : 1; /* reserved */
+ __u32 esf : 7; /* extended status flags */
+ __u32 lpum : 8; /* last path used mask */
+ __u32 res16 : 1; /* reserved */
+ __u32 fvf : 5; /* field-validity flags */
+ __u32 sacc : 2; /* storage access code */
+ __u32 termc : 2; /* termination code */
+ __u32 devsc : 1; /* device-status check */
+ __u32 serr : 1; /* secondary error */
+ __u32 ioerr : 1; /* i/o-error alert */
+ __u32 seqc : 3; /* sequence code */
+ } __attribute__ ((packed)) sublog_t ;
/*
* Format 0 Extended Status Word (ESW)
*/
typedef struct {
- sublog_t sublog; /* subchannel logout */
- erw_t erw; /* extended report word */
- void *faddr; /* failing address */
- unsigned int zeros[2]; /* 2 fullwords of zeros */
- } esw0_t;
+ sublog_t sublog; /* subchannel logout */
+ erw_t erw; /* extended report word */
+ __u32 faddr; /* failing address */
+ __u32 zeros[2]; /* 2 fullwords of zeros */
+ } __attribute__ ((packed)) esw0_t;
/*
* Format 1 Extended Status Word (ESW)
*/
typedef struct {
- unsigned char zero0; /* reserved zeros */
- unsigned char lpum; /* last path used mask */
- unsigned short zero16; /* reserved zeros */
- erw_t erw; /* extended report word */
- unsigned int zeros[3]; /* 2 fullwords of zeros */
- } esw1_t;
+ __u8 zero0; /* reserved zeros */
+ __u8 lpum; /* last path used mask */
+ __u16 zero16; /* reserved zeros */
+ erw_t erw; /* extended report word */
+ __u32 zeros[3]; /* 2 fullwords of zeros */
+ } __attribute__ ((packed)) esw1_t;
/*
* Format 2 Extended Status Word (ESW)
*/
typedef struct {
- unsigned char zero0; /* reserved zeros */
- unsigned char lpum; /* last path used mask */
- unsigned short dcti; /* device-connect-time interval */
- erw_t erw; /* extended report word */
- unsigned int zeros[3]; /* 2 fullwords of zeros */
- } esw2_t;
+ __u8 zero0; /* reserved zeros */
+ __u8 lpum; /* last path used mask */
+ __u16 dcti; /* device-connect-time interval */
+ erw_t erw; /* extended report word */
+ __u32 zeros[3]; /* 2 fullwords of zeros */
+ } __attribute__ ((packed)) esw2_t;
/*
* Format 3 Extended Status Word (ESW)
*/
typedef struct {
- unsigned char zero0; /* reserved zeros */
- unsigned char lpum; /* last path used mask */
- unsigned short res; /* reserved */
- erw_t erw; /* extended report word */
- unsigned int zeros[3]; /* 2 fullwords of zeros */
- } esw3_t;
+ __u8 zero0; /* reserved zeros */
+ __u8 lpum; /* last path used mask */
+ __u16 res; /* reserved */
+ erw_t erw; /* extended report word */
+ __u32 zeros[3]; /* 2 fullwords of zeros */
+ } __attribute__ ((packed)) esw3_t;
typedef union {
esw0_t esw0;
esw1_t esw1;
esw2_t esw2;
esw3_t esw3;
- } esw_t;
+ } __attribute__ ((packed)) esw_t;
/*
* interruption response block
typedef struct {
scsw_t scsw; /* subchannel status word */
esw_t esw; /* extended status word */
- char ecw[32]; /* extended control word */
- } irb_t __attribute__ ((aligned(4)));
-
+ __u8 ecw[32]; /* extended control word */
+ } irb_t __attribute__ ((packed,aligned(4)));
#ifdef __KERNEL__
/*
* TPI info structure
*/
typedef struct {
- unsigned int res : 16; /* reserved 0x00000001 */
- unsigned int irq : 16; /* aka. subchannel number */
- unsigned int intparm; /* interruption parameter */
- } tpi_info_t;
+ __u32 res : 16; /* reserved 0x00000001 */
+ __u32 irq : 16; /* aka. subchannel number */
+ __u32 intparm; /* interruption parameter */
+ } __attribute__ ((packed)) tpi_info_t;
+
+
//
// command information word (CIW) layout
//
typedef struct _ciw {
- unsigned int et : 2; // entry type
- unsigned int reserved : 2; // reserved
- unsigned int ct : 4; // command type
- unsigned int cmd : 8; // command
- unsigned int count : 16; // count
- } ciw_t;
+ __u32 et : 2; // entry type
+ __u32 reserved : 2; // reserved
+ __u32 ct : 4; // command type
+ __u32 cmd : 8; // command
+ __u32 count : 16; // count
+ } __attribute__ ((packed)) ciw_t;
#define CIW_TYPE_RCD 0x0 // read configuration data
#define CIW_TYPE_SII 0x1 // set interface identifier
//
typedef struct {
/* common part */
- unsigned char reserved; /* always 0x'FF' */
- unsigned short cu_type; /* control unit type */
- unsigned char cu_model; /* control unit model */
- unsigned short dev_type; /* device type */
- unsigned char dev_model; /* device model */
- unsigned char unused; /* padding byte */
+ __u8 reserved; /* always 0x'FF' */
+ __u16 cu_type; /* control unit type */
+ __u8 cu_model; /* control unit model */
+ __u16 dev_type; /* device type */
+ __u8 dev_model; /* device model */
+ __u8 unused; /* padding byte */
/* extended part */
ciw_t ciw[16]; /* variable # of CIWs */
} __attribute__ ((packed,aligned(4))) senseid_t;
#endif /* __KERNEL__ */
-
/*
* sense data
*/
typedef struct {
- unsigned char res[32]; /* reserved */
- unsigned char data[32]; /* sense data */
- } sense_t;
-
+ __u8 res[32]; /* reserved */
+ __u8 data[32]; /* sense data */
+ } __attribute__ ((packed)) sense_t;
/*
* device status area, to be provided by the device driver
*/
typedef struct {
unsigned int devno; /* device number, aka. "cuu" from irb */
- unsigned int intparm; /* interrupt parameter */
- unsigned char cstat; /* channel status - accumulated */
- unsigned char dstat; /* device status - accumulated */
- unsigned char lpum; /* last path used mask from irb */
- unsigned char unused; /* not used - reserved */
+ unsigned long intparm; /* interrupt parameter */
+ __u8 cstat; /* channel status - accumulated */
+ __u8 dstat; /* device status - accumulated */
+ __u8 lpum; /* last path used mask from irb */
+ __u8 unused; /* not used - reserved */
unsigned int flag; /* flag : see below */
- unsigned long cpa; /* CCW address from irb at primary status */
- unsigned int rescnt; /* res. count from irb at primary status */
- unsigned int scnt; /* sense count, if DEVSTAT_FLAG_SENSE_AVAIL */
+ __u32 cpa; /* CCW address from irb at primary status */
+ __u32 rescnt; /* res. count from irb at primary status */
+ __u32 scnt; /* sense count, if DEVSTAT_FLAG_SENSE_AVAIL */
union {
irb_t irb; /* interruption response block */
sense_t sense; /* sense information */
#define DEVSTAT_FINAL_STATUS 0x80000000
#define INTPARM_STATUS_PENDING 0xFFFFFFFF
-
#ifdef __KERNEL__
-typedef void (* io_handler_func1_t) ( int irq,
- devstat_t *devstat,
+typedef void (* io_handler_func1_t) ( int irq,
+ devstat_t *devstat,
struct pt_regs *rgs);
-typedef void (* io_handler_func_t) ( int irq,
+typedef void (* io_handler_func_t) ( int irq,
void *devstat,
struct pt_regs *rgs);
typedef void ( * not_oper_handler_func_t)( int irq,
int status );
-
struct s390_irqaction {
io_handler_func_t handler;
unsigned long flags;
devstat_t *dev_id;
};
-
/*
* This is the "IRQ descriptor", which contains various information
* about the irq, including what kind of hardware handling it has,
#define DOIO_EARLY_NOTIFICATION 0x0001 /* allow for I/O completion ... */
/* ... notification after ... */
/* ... primary interrupt status */
-#define DOIO_RETURN_CHAN_END DOIO_EARLY_NOTIFICATION
+#define DOIO_RETURN_CHAN_END DOIO_EARLY_NOTIFICATION
#define DOIO_VALID_LPM 0x0002 /* LPM input parameter is valid */
#define DOIO_WAIT_FOR_INTERRUPT 0x0004 /* wait synchronously for interrupt */
#define DOIO_REPORT_ALL 0x0008 /* report all interrupt conditions */
*/
int do_IO( int irq, /* IRQ aka. subchannel number */
ccw1_t *cpa, /* logical channel program address */
- unsigned long initparm, /* interruption parameter */
- unsigned char lpm, /* logical path mask */
+ unsigned long intparm, /* interruption parameter */
+ __u8 lpm, /* logical path mask */
unsigned long flag); /* flags : see above */
-int start_IO( int irq, /* IRQ aka. subchannel number */
- ccw1_t *cpa, /* logical channel program address */
+int start_IO( int irq, /* IRQ aka. subchannel number */
+ ccw1_t *cpa, /* logical channel program address */
unsigned long intparm, /* interruption parameter */
- unsigned char lpm, /* logical path mask */
- unsigned long flag); /* flags : see above */
+ __u8 lpm, /* logical path mask */
+ unsigned int flag); /* flags : see above */
void do_crw_pending( void ); /* CRW handler */
-int resume_IO( int irq); /* IRQ aka. subchannel number */
+int resume_IO( int irq); /* IRQ aka. subchannel number */
-int halt_IO( int irq, /* IRQ aka. subchannel number */
- unsigned long intparm, /* dummy intparm */
+int halt_IO( int irq, /* IRQ aka. subchannel number */
+ unsigned long intparm, /* dummy intparm */
unsigned long flag); /* possible DOIO_WAIT_FOR_INTERRUPT */
int clear_IO( int irq, /* IRQ aka. subchannel number */
int read_dev_chars( int irq, void **buffer, int length );
int read_conf_data( int irq, void **buffer, int *length, __u8 lpm );
-int s390_DevicePathVerification( int irq, __u8 domask );
+int s390_DevicePathVerification( int irq, __u8 domask );
int s390_request_irq_special( int irq,
io_handler_func_t io_handler,
return ccode;
}
+extern __inline__ int rchp(int chpid)
+{
+ int ccode;
+
+ __asm__ __volatile__(
+ "LR 1,%1\n\t"
+ "RCHP\n\t"
+ "IPM %0\n\t"
+ "SRL %0,28\n\t"
+ : "=d" (ccode) : "r" (chpid)
+ : "cc", "1" );
+ return ccode;
+}
+
typedef struct {
- unsigned int vrdcdvno : 16; /* device number (input) */
- unsigned int vrdclen : 16; /* data block length (input) */
- unsigned int vrdcvcla : 8; /* virtual device class (output) */
- unsigned int vrdcvtyp : 8; /* virtual device type (output) */
- unsigned int vrdcvsta : 8; /* virtual device status (output) */
- unsigned int vrdcvfla : 8; /* virtual device flags (output) */
- unsigned int vrdcrccl : 8; /* real device class (output) */
- unsigned int vrdccrty : 8; /* real device type (output) */
- unsigned int vrdccrmd : 8; /* real device model (output) */
- unsigned int vrdccrft : 8; /* real device feature (output) */
+ __u16 vrdcdvno : 16; /* device number (input) */
+ __u16 vrdclen : 16; /* data block length (input) */
+ __u32 vrdcvcla : 8; /* virtual device class (output) */
+ __u32 vrdcvtyp : 8; /* virtual device type (output) */
+ __u32 vrdcvsta : 8; /* virtual device status (output) */
+ __u32 vrdcvfla : 8; /* virtual device flags (output) */
+ __u32 vrdcrccl : 8; /* real device class (output) */
+ __u32 vrdccrty : 8; /* real device type (output) */
+ __u32 vrdccrmd : 8; /* real device model (output) */
+ __u32 vrdccrft : 8; /* real device feature (output) */
} __attribute__ ((packed,aligned(4))) diag210_t;
-void VM_virtual_device_info( unsigned int devno, /* device number */
- senseid_t *ps ); /* ptr to senseID data */
+void VM_virtual_device_info( unsigned int devno, /* device number */
+ senseid_t *ps ); /* ptr to senseID data */
extern __inline__ int diag210( diag210_t * addr)
{
extern spinlock_t irq_controller_lock;
-#ifdef __SMP__
+#ifdef CONFIG_SMP
#include <asm/atomic.h>
#else
-#define irq_enter(cpu, irq) (++local_irq_count[cpu])
-#define irq_exit(cpu, irq) (--local_irq_count[cpu])
+#define irq_enter(cpu, irq) (++local_irq_count(cpu))
+#define irq_exit(cpu, irq) (--local_irq_count(cpu))
#endif
#define __STR(x) #x
#define STR(x) __STR(x)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
/*
* SMP has a few special interrupts for IPI messages
*/
-#endif /* __SMP__ */
+#endif /* CONFIG_SMP */
/*
* x86 profiling function, SMP safe. We might want to do this in
* assembly totally?
*/
-extern char _stext[];
-
+extern char _stext;
static inline void s390_do_profile (unsigned long addr)
{
if (prof_buffer && current->pid) {
#define s390irq_spin_lock_irqsave(irq,flags) \
spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags)
-
#define s390irq_spin_unlock_irqrestore(irq,flags) \
spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
#endif /* __KERNEL__ */
-
#endif
__u32 floating_pt_save_area[8]; /* 0x160 */
__u32 gpregs_save_area[16]; /* 0x180 */
__u8 pad7[0x200-0x1c0]; /* 0x1c0 */
-
+
__u32 access_regs_save_area[16];/* 0x200 */
__u32 cregs_save_area[16]; /* 0x240 */
psw_t return_psw; /* 0x280 */
extern int math_emu_b3(__u8 *, struct pt_regs *);
extern int math_emu_ed(__u8 *, struct pt_regs *);
-extern void math_emu_ldr(__u8 *);
-extern void math_emu_ler(__u8 *);
-extern void math_emu_std(__u8 *, struct pt_regs *);
-extern void math_emu_ld(__u8 *, struct pt_regs *);
-extern void math_emu_ste(__u8 *, struct pt_regs *);
-extern void math_emu_le(__u8 *, struct pt_regs *);
+extern int math_emu_ldr(__u8 *);
+extern int math_emu_ler(__u8 *);
+extern int math_emu_std(__u8 *, struct pt_regs *);
+extern int math_emu_ld(__u8 *, struct pt_regs *);
+extern int math_emu_ste(__u8 *, struct pt_regs *);
+extern int math_emu_le(__u8 *, struct pt_regs *);
extern int math_emu_lfpc(__u8 *, struct pt_regs *);
extern int math_emu_stfpc(__u8 *, struct pt_regs *);
extern int math_emu_srnm(__u8 *, struct pt_regs *);
#endif /* __MATHEMU__ */
+
+
+
#define flush_cache_page(vma, vmaddr) do { } while (0)
#define flush_page_to_ram(page) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
-#define flush_dcache_page(page) do { } while (0)
+#define flush_dcache_page(page) do { } while (0)
/*
* TLB flushing:
}
#if 0 /* Arggh, ipte doesn't work correctly !! */
-static inline void flush_tlb_page(struct vm_area_struct *vma,
+static inline void flush_tlb_page(struct vm_area_struct * vma,
unsigned long va)
{
__flush_tlb_one(vma->vm_mm,va);
* The Kernel segment-tables includes the User segment-table
*/
-#define _SEGMENT_TABLE (_USER_SEG_TABLE_LEN|0x80000000)
+#define _SEGMENT_TABLE (_USER_SEG_TABLE_LEN|0x80000000|0x100)
#define _KERNSEG_TABLE (_KERNEL_SEG_TABLE_LEN)
/*
#define SET_PAGE_DIR(tsk,pgdir) \
do { \
- unsigned long __pgdir = (__pa(pgdir) & PAGE_MASK ) | _SEGMENT_TABLE; \
+ unsigned long __pgdir = (__pa(pgdir) & PAGE_MASK ) | _SEGMENT_TABLE; \
(tsk)->tss.user_seg = __pgdir; \
if ((tsk) == current) { \
__asm__ __volatile__("lctl 7,7,%0": :"m" (__pgdir)); \
#define INIT_MMAP \
{ &init_mm, 0, 0, NULL, PAGE_SHARED, \
-VM_READ | VM_WRITE | VM_EXEC, 1, NULL, &init_mm.mmap }
+VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
#define INIT_TSS { (struct pt_regs *) 0, \
{ 0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \
#ifdef __KERNEL__
#define user_mode(regs) ((regs)->psw.mask & PSW_PROBLEM_STATE)
#define instruction_pointer(regs) ((regs)->psw.addr)
-
-struct thread_struct;
-extern int sprintf_regs(int line,char *buff,struct task_struct * task,
- struct thread_struct *tss,struct pt_regs * regs);
-extern void show_regs(struct task_struct * task,struct thread_struct *tss,
- struct pt_regs * regs);
+extern void show_regs(struct pt_regs * regs);
+extern char *task_show_regs(struct task_struct *task, char *buffer);
#endif
freg_t fprs[NUM_FPRS];
} s390_fp_regs;
-#define FPC_DXC_MASK 0x0000FF00
+
#define FPC_EXCEPTION_MASK 0xF8000000
#define FPC_FLAGS_MASK 0x00F80000
+#define FPC_DXC_MASK 0x0000FF00
#define FPC_RM_MASK 0x00000003
+#define FPC_VALID_MASK ((FPC_EXCEPTION_MASK|FPC_FLAGS_MASK| \
+ FPC_DXC_MASK|FPC_RM_MASK))
+
/*
* S/390 data definitions for dynamic device attachment
*
* S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
*/
#define __s390io_h
/*
- * Private data structure used by do_IO()
+ * IRQ data structure used by I/O subroutines
*
* Note : If bit flags are added, the "unused" value must be
* decremented accordingly !
* S/390 data definitions for machine check processing
*
* S390 version
- * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
- * IBM Corporation
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
*/
#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */
#define CRW_ERC_PMOD 0x08 /* installed parameters modified */
-#define MAX_CRW_PENDING 100
-#define MAX_MACH_PENDING 100
+#define MAX_CRW_PENDING 1024
+#define MAX_MACH_PENDING 1024
//
// CRW Entry
#ifndef _ASM_S390_SIGCONTEXT_H
#define _ASM_S390_SIGCONTEXT_H
-#include <asm/s390-regs-common.h>
+
+#define __NUM_GPRS 16
+#define __NUM_FPRS 16
+#define __NUM_ACRS 16
/*
Has to be at least _NSIG_WORDS from asm/signal.h
#define _SIGCONTEXT_NSIG 64
#define _SIGCONTEXT_NSIG_BPW 32
/* Size of stack frame allocated when calling signal handler. */
-#define __SIGNAL_FRAMESIZE STACK_FRAME_OVERHEAD
-#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
-#define SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
+#define __SIGNAL_FRAMESIZE 96
+#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW)
+#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS)
+
+typedef struct
+{
+ unsigned long mask;
+ unsigned long addr;
+} _psw_t __attribute__ ((aligned(8)));
+
+typedef struct
+{
+ _psw_t psw;
+ unsigned long gprs[__NUM_GPRS];
+ unsigned int acrs[__NUM_ACRS];
+} _s390_regs_common __attribute__ ((packed));
+
+typedef struct
+{
+ unsigned int fpc;
+ double fprs[__NUM_FPRS];
+} _s390_fp_regs;
typedef struct
{
- s390_regs_common regs;
- s390_fp_regs fpregs;
-} sigregs;
+ _s390_regs_common regs;
+ _s390_fp_regs fpregs;
+} _sigregs;
struct sigcontext
{
unsigned long oldmask[_SIGCONTEXT_NSIG_WORDS];
- sigregs *sregs;
+ _sigregs *sregs;
};
ec_get_ctl,
ec_set_ctl_masked,
ec_ptlb,
+ ec_callback,
ec_cmd_last
} ec_cmd_sig;
__u32 andvals[16];
} ec_creg_mask_parms;
+/* parameter area for the callback signal */
+typedef struct
+{
+ void (*callback)(void *);
+ void *data;
+} ec_callback_parms;
+
/*
* Signal processor
*/
return ccode;
}
+extern void smp_do_callback_all(void (*callback)(void *), void *data);
+
#endif __SIGP__
__asm__ __volatile(" bras 1,1f\n"
"0: diag 0,0,68\n"
"1: slr 0,0\n"
- " cs 0,1,%1\n"
+ " cs 0,1,%1\n"
" jl 0b\n"
- : "=m" (lp->lock)
+ : "=m" (lp->lock)
: "0" (lp->lock) : "0", "1", "cc" );
}
asm volatile (
" lhi 1,3\n"
" nr 1,%0\n" /* isolate last 2 bits */
- " xr 1,%0\n" /* align ptr */
+ " xr %0,1\n" /* align ptr */
" bras 2,0f\n"
" icm 1,8,%1\n" /* for ptr&3 == 0 */
" stcm 0,8,%1\n"
" stcm 0,1,%1\n"
"0: sll 1,3\n"
" la 2,0(1,2)\n" /* r2 points to an icm */
- " l 0,%1\n" /* get fullword */
+ " l 0,0(%0)\n" /* get fullword */
"1: lr 1,0\n" /* cs loop */
" ex 0,0(2)\n" /* insert x */
- " cs 0,1,%1\n"
+ " cs 0,1,0(%0)\n"
" jl 1b\n"
" ex 0,4(2)" /* store *ptr to x */
- : "+a&" (ptr) : "m" (x)
+ : "+a&" (ptr), "+m" (x) :
: "memory", "0", "1", "2");
case 2:
if(((__u32)ptr)&1)
asm volatile (
" lhi 1,2\n"
" nr 1,%0\n" /* isolate bit 2^1 */
- " xr 1,%0\n" /* align ptr */
+ " xr %0,1\n" /* align ptr */
" bras 2,0f\n"
" icm 1,12,%1\n" /* for ptr&2 == 0 */
" stcm 0,12,%1\n"
" stcm 0,3,%1\n"
"0: sll 1,2\n"
" la 2,0(1,2)\n" /* r2 points to an icm */
- " l 0,%1\n" /* get fullword */
+ " l 0,0(%0)\n" /* get fullword */
"1: lr 1,0\n" /* cs loop */
" ex 0,0(2)\n" /* insert x */
- " cs 0,1,%1\n"
+ " cs 0,1,0(%0)\n"
" jl 1b\n"
" ex 0,4(2)" /* store *ptr to x */
- : "+a&" (ptr) : "m" (x)
+ : "+a&" (ptr), "+m" (x) :
: "memory", "0", "1", "2");
break;
case 4:
extern void save_fp_regs(s390_fp_regs *fpregs);
extern int restore_fp_regs1(s390_fp_regs *fpregs);
extern void restore_fp_regs(s390_fp_regs *fpregs);
-extern void show_crashed_task_info(void);
#endif
#define switch_to(prev,next,last) do { \
get_user(tmp, &(termio)->c_lflag); \
(termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
get_user((termios)->c_line, &(termio)->c_line); \
- copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
})
/*
extern int __put_user_bad(void);
-#define __get_user_asm_4(x, ptr, err) \
-({ \
- __asm__ __volatile__ ( " sr %1,%1\n" \
- " la 4,%2\n" \
- " sacf 512\n" \
- "0: l %0,0(4)\n" \
- " sacf 0\n" \
- "1:\n" \
- ".section .fixup,\"ax\"\n" \
- "2: sacf 0\n" \
- " lhi %1,%h3\n" \
- " bras 4,3f\n" \
- " .long 1b\n" \
- "3: l 4,0(4)\n" \
- " br 4\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 0b,2b\n" \
- ".previous" \
- : "=d" (x) , "=&d" (err) \
- : "m" (*(__u32*) ptr), "K" (-EFAULT) \
- : "4" ); \
+#define __get_user_asm_4(x, ptr, err) \
+({ \
+ __asm__ __volatile__ ( " sr %1,%1\n" \
+ " la 4,%2\n" \
+ " sacf 512\n" \
+ "0: l %0,0(4)\n" \
+ " sacf 0\n" \
+ "1:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "2: sacf 0\n" \
+ " lhi %1,%h3\n" \
+ " bras 4,3f\n" \
+ " .long 1b\n" \
+ "3: l 4,0(4)\n" \
+ " br 4\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 0b,2b\n" \
+ ".previous" \
+ : "=d" (x) , "=&d" (err) \
+ : "m" (*(const __u32*) ptr), "K" (-EFAULT) \
+ : "4" ); \
})
-#define __get_user_asm_2(x, ptr, err) \
-({ \
- __asm__ __volatile__ ( " sr %1,%1\n" \
- " la 4,%2\n" \
- " sacf 512\n" \
- "0: lh %0,0(4)\n" \
- " sacf 0\n" \
- "1:\n" \
- ".section .fixup,\"ax\"\n" \
- "2: sacf 0\n" \
- " lhi %1,%h3\n" \
- " bras 4,3f\n" \
- " .long 1b\n" \
- "3: l 4,0(4)\n" \
- " br 4\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 0b,2b\n" \
- ".previous" \
- : "=d" (x) , "=&d" (err) \
- : "m" (*(__u16*) ptr), "K" (-EFAULT) \
- : "4" ); \
+#define __get_user_asm_2(x, ptr, err) \
+({ \
+ __asm__ __volatile__ ( " sr %1,%1\n" \
+ " la 4,%2\n" \
+ " sacf 512\n" \
+ "0: lh %0,0(4)\n" \
+ " sacf 0\n" \
+ "1:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "2: sacf 0\n" \
+ " lhi %1,%h3\n" \
+ " bras 4,3f\n" \
+ " .long 1b\n" \
+ "3: l 4,0(4)\n" \
+ " br 4\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 0b,2b\n" \
+ ".previous" \
+ : "=d" (x) , "=&d" (err) \
+ : "m" (*(const __u16*) ptr), "K" (-EFAULT) \
+ : "4" ); \
})
-#define __get_user_asm_1(x, ptr, err) \
-({ \
- __asm__ __volatile__ ( " sr %1,%1\n" \
- " la 4,%2\n" \
- " sr %0,%0\n" \
- " sacf 512\n" \
- "0: ic %0,0(4)\n" \
- " sacf 0\n" \
- "1:\n" \
- ".section .fixup,\"ax\"\n" \
- "2: sacf 0\n" \
- " lhi %1,%h3\n" \
- " bras 4,3f\n" \
- " .long 1b\n" \
- "3: l 4,0(4)\n" \
- " br 4\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 0b,2b\n" \
- ".previous" \
- : "=d" (x) , "=&d" (err) \
- : "m" (*(__u8*) ptr), "K" (-EFAULT) \
- : "4" ); \
+#define __get_user_asm_1(x, ptr, err) \
+({ \
+ __asm__ __volatile__ ( " sr %1,%1\n" \
+ " la 4,%2\n" \
+ " sr %0,%0\n" \
+ " sacf 512\n" \
+ "0: ic %0,0(4)\n" \
+ " sacf 0\n" \
+ "1:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "2: sacf 0\n" \
+ " lhi %1,%h3\n" \
+ " bras 4,3f\n" \
+ " .long 1b\n" \
+ "3: l 4,0(4)\n" \
+ " br 4\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 0b,2b\n" \
+ ".previous" \
+ : "=d" (x) , "=&d" (err) \
+ : "m" (*(const __u8*) ptr), "K" (-EFAULT) \
+ : "4" ); \
})
#define __get_user(x, ptr) \
extern int __get_user_bad(void);
+/*
+ * These two fixup routines have a special linkage. Not to be
+ * called directly.
+ */
+extern void __copy_from_user_fixup(void);
+extern void __copy_to_user_fixup(void);
+
/*
* access register are set up, that 4 points to secondary (user) , 2 to primary (kernel)
*/
extern inline unsigned long
__copy_to_user_asm(void* to, const void* from, long n)
{
-
__asm__ __volatile__ ( " lr 2,%2\n"
" lr 4,%1\n"
" lr 3,%0\n"
" jo 0b\n"
" sacf 0\n"
"1: lr %0,3\n"
- ".section .fixup,\"ax\"\n"
- "2: lhi 5,-4096\n"
- " n 5,0x90\n"
- " sr 5,4\n"
- " mvcle 4,2,0\n"
- " sacf 0\n"
- " basr 4,0\n"
- " l 4,3f-.(4)\n"
- " br 4\n"
- "3: .long 1b\n"
- ".previous\n"
".section __ex_table,\"a\"\n"
" .align 4\n"
- " .long 0b,2b\n"
+ " .long 0b,__copy_to_user_fixup\n"
".previous"
: "+&d" (n) : "d" (to), "d" (from)
- : "2", "3", "4", "5" );
+ : "1", "2", "3", "4", "5" );
return n;
}
" jo 0b\n"
" sacf 0\n"
"1: lr %0,5\n"
- ".section .fixup,\"ax\"\n"
- "2: lhi 3,-4096\n"
- " n 3,0x90\n"
- " sr 3,4\n"
- " mvcle 2,4,0\n"
- " sacf 0\n"
- " basr 4,0\n"
- " l 4,3f-.(4)\n"
- " br 4\n"
- "3: .long 1b\n"
- ".previous\n"
".section __ex_table,\"a\"\n"
" .align 4\n"
- " .long 0b,2b\n"
+ " .long 0b,__copy_from_user_fixup\n"
".previous"
: "+&d" (n) : "d" (to), "d" (from)
- : "2", "3", "4", "5" );
+ : "1", "2", "3", "4", "5" );
return n;
}
*/
static inline long
-strncpy_from_user(char *dst, const char *src, long count)
+__strncpy_from_user(char *dst, const char *src, long count)
{
long len;
__asm__ __volatile__ ( " slr %0,%0\n"
"3: lhi %0,%h4\n"
" basr 3,0\n"
" l 3,4f-.(3)\n"
- " br 3\n"
+ " br 3\n"
"4: .long 2b\n"
".previous\n"
".section __ex_table,\"a\"\n"
" .long 1b,3b\n"
".previous"
: "=&a" (len)
- : "a" (dst), "d" (src), "d" (count),
+ : "a" (dst), "d" (src), "d" (count),
"K" (-EFAULT)
: "2", "3", "4", "memory" );
return len;
}
+static inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+ long res = -EFAULT;
+ if (access_ok(VERIFY_READ, src, 1))
+ res = __strncpy_from_user(dst, src, count);
+ return res;
+}
+
/*
* Return the size of a string (including the ending 0)
*
*/
static inline unsigned long
-clear_user(void *to, unsigned long n)
+__clear_user(void *to, unsigned long n)
{
__asm__ __volatile__ ( " sacf 512\n"
" lr 4,%1\n"
" jo 0b\n"
" sacf 0\n"
"1: lr %0,3\n"
- ".section .fixup,\"ax\"\n"
- "2: lhi 5,-4096\n"
- " n 5,0x90\n"
- " sr 5,4\n"
- " mvcle 4,2,0\n"
- " sacf 0\n"
- " basr 4,0\n"
- " l 4,3f-.(4)\n"
- " br 4\n"
- "3: .long 1b\n"
- ".previous\n"
".section __ex_table,\"a\"\n"
" .align 4\n"
- " .long 0b,2b\n"
+ " .long 0b,__copy_to_user_fixup\n"
".previous"
: "+&a" (n)
: "a" (to)
- : "cc", "2", "3", "4", "5" );
+ : "cc", "1", "2", "3", "4", "5" );
+ return n;
+}
+
+static inline unsigned long
+clear_user(void *to, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ n = __clear_user(to, n);
return n;
}
return (type) (res); \
} while (0)
-#define _svc_clobber "cc", "memory"
+#define _svc_clobber "2", "cc", "memory"
#define _syscall0(type,name) \
type name(void) { \
-/* $Id: envctrl.h,v 1.1.2.1 2000/05/02 04:23:33 davem Exp $
+/* $Id: envctrl.h,v 1.1.2.2 2000/11/08 09:43:04 davem Exp $
*
* envctrl.h: Definitions for access to the i2c environment
* monitoring on Ultrasparc systems.
#define ENVCTRL_RD_SCSI_TEMPERATURE _IOR('p', 0x46, int)
#define ENVCTRL_RD_ETHERNET_TEMPERATURE _IOR('p', 0x47, int)
#define ENVCTRL_RD_MTHRBD_TEMPERATURE _IOR('p', 0x48, int)
+#define ENVCTRL_RD_GLOBALADDRESS _IOR('p', 0x49, int)
/* Read return values for a voltage status request. */
#define ENVCTRL_VOLTAGE_POWERSUPPLY_GOOD 0x01
extern struct gendisk *gendisk_head; /* linked list of disks */
+#ifdef CONFIG_ARCH_S390
+/*
+ * dasd_device_name(...)
+ * formats the devicename of the indicated disk
+ * into the supplied buffer, and returns a pointer
+ * to that same buffer (for convenience).
+ * Because the S390 DASDs span a larger namespace than other
+ * platforms we need our own function.
+ */
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*);
+#endif
+
/*
* disk_name() is used by genhd.c and md.c.
* It formats the devicename of the indicated disk
#define KEY_F22 121
#define KEY_F23 122
#define KEY_F24 123
-#define KEY_JPN 124
+#define KEY_KPCOMMA 124
#define KEY_LEFTMETA 125
#define KEY_RIGHTMETA 126
#define KEY_COMPOSE 127
#define KEY_EDIT 176
#define KEY_SCROLLUP 177
#define KEY_SCROLLDOWN 178
-
-#define KEY_UNKNOWN 180
+#define KEY_KPLEFTPAREN 179
+#define KEY_KPRIGHTPAREN 180
+
+#define KEY_INTL1 181
+#define KEY_INTL2 182
+#define KEY_INTL3 183
+#define KEY_INTL4 184
+#define KEY_INTL5 185
+#define KEY_INTL6 186
+#define KEY_INTL7 187
+#define KEY_INTL8 188
+#define KEY_INTL9 189
+#define KEY_LANG1 190
+#define KEY_LANG2 191
+#define KEY_LANG3 192
+#define KEY_LANG4 193
+#define KEY_LANG5 194
+#define KEY_LANG6 195
+#define KEY_LANG7 196
+#define KEY_LANG8 197
+#define KEY_LANG9 198
+
+#define KEY_UNKNOWN 200
#define BTN_MISC 0x100
#define BTN_0 0x100
#define BUS_GAMEPORT 0x14
#define BUS_PARPORT 0x15
#define BUS_AMIGA 0x16
+#define BUS_ADB 0x17
#ifdef __KERNEL__
/* Interrupt Sources */
extern void openpic_enable_irq(u_int irq);
extern void openpic_disable_irq(u_int irq);
+extern u_int openpic_get_enable(u_int irq);
extern void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
int is_level);
extern void openpic_mapirq(u_int irq, u_int cpumask);
#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */
#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */
+/* Power Management Registers */
+
+#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */
+#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */
+#define PCI_PM_CAP_AUX_POWER 0x0010 /* Auxilliary power support */
+#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */
+#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */
+#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */
+#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */
+#define PCI_PM_CTRL 4 /* PM control and status register */
+#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */
+#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */
+#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */
+#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */
+#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */
+#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */
+#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */
+#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */
+#define PCI_PM_DATA_REGISTER 7 /* (??) */
+#define PCI_PM_SIZEOF 8
+
/* Device classes and subclasses */
#define PCI_CLASS_NOT_DEFINED 0x0000
KERN_SHMALL=41, /* int: maximum size of shared memory */
KERN_SPARC_STOP_A=44, /* int: Sparc Stop-A enable */
KERN_HOTPLUG=49, /* string: path to hotplug policy agent */
+ KERN_IEEE_EMULATION_WARNINGS=50 /* int: unimplemented ieee instructions */
};
/* CTL_DEV names: */
enum {
DEV_CDROM=1,
- DEV_HWMON=2
+ DEV_HWMON=2,
+ DEV_MAC_HID=3
};
/* /proc/sys/dev/cdrom */
DEV_CDROM_CHECK_MEDIA=6
};
+/* /proc/sys/dev/mac_hid */
+enum {
+ DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES=1,
+ DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES=2,
+ DEV_MAC_HID_MOUSE_BUTTON_EMULATION=3,
+ DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE=4,
+ DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE=5,
+ DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES=6
+};
+
#ifdef __KERNEL__
extern asmlinkage int sys_sysctl(struct __sysctl_args *);
#include <asm/io.h>
#include <asm/bugs.h>
+#ifdef CONFIG_ARCH_S390
+#include <asm/s390mach.h>
+#endif
+
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif
* Ok, at this point all CPU's should be initialized, so
* we can start looking into devices..
*/
+#ifdef CONFIG_ARCH_S390
+ s390_init_machine_check();
+#endif
+
#ifdef CONFIG_PCI
pci_init();
#endif
extern char reboot_command [];
extern int stop_a_enabled;
#endif
+
+#ifdef CONFIG_ARCH_S390
+#ifdef CONFIG_IEEEFPU_EMULATION
+extern int sysctl_ieee_emulation_warnings;
+#endif
+#endif
+
#ifdef __powerpc__
extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
#ifdef CONFIG_MAGIC_SYSRQ
{KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int),
0644, NULL, &proc_dointvec},
-#endif
+#endif
+#ifdef CONFIG_ARCH_S390
+#ifdef CONFIG_IEEEFPU_EMULATION
+ {KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings",
+ &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec},
+#endif
+#endif
{0}
};
--- /dev/null
+#!/bin/bash
+indent -kr -i8 -ts8 -br -ce -bap -sob -l80 -pcs -cs -ss -bs -di0 -nbc -lp -psl $@